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 <climits>
     29 #include <csignal>
     30 #include <string>
     31 #include <map>
     32 
     33 #include "src/v8.h"
     34 
     35 #if V8_OS_POSIX
     36 #include <unistd.h>  // NOLINT
     37 #endif
     38 
     39 #include "include/v8-util.h"
     40 #include "src/api.h"
     41 #include "src/arguments.h"
     42 #include "src/compilation-cache.h"
     43 #include "src/cpu-profiler.h"
     44 #include "src/execution.h"
     45 #include "src/isolate.h"
     46 #include "src/objects.h"
     47 #include "src/parser.h"
     48 #include "src/platform.h"
     49 #include "src/snapshot.h"
     50 #include "src/unicode-inl.h"
     51 #include "src/utils.h"
     52 #include "src/vm-state.h"
     53 #include "test/cctest/cctest.h"
     54 
     55 static const bool kLogThreading = false;
     56 
     57 using ::v8::Boolean;
     58 using ::v8::BooleanObject;
     59 using ::v8::Context;
     60 using ::v8::Extension;
     61 using ::v8::Function;
     62 using ::v8::FunctionTemplate;
     63 using ::v8::Handle;
     64 using ::v8::HandleScope;
     65 using ::v8::Local;
     66 using ::v8::Message;
     67 using ::v8::MessageCallback;
     68 using ::v8::Object;
     69 using ::v8::ObjectTemplate;
     70 using ::v8::Persistent;
     71 using ::v8::Script;
     72 using ::v8::StackTrace;
     73 using ::v8::String;
     74 using ::v8::TryCatch;
     75 using ::v8::Undefined;
     76 using ::v8::UniqueId;
     77 using ::v8::V8;
     78 using ::v8::Value;
     79 
     80 
     81 #define THREADED_PROFILED_TEST(Name)                                 \
     82   static void Test##Name();                                          \
     83   TEST(Name##WithProfiler) {                                         \
     84     RunWithProfiler(&Test##Name);                                    \
     85   }                                                                  \
     86   THREADED_TEST(Name)
     87 
     88 
     89 void RunWithProfiler(void (*test)()) {
     90   LocalContext env;
     91   v8::HandleScope scope(env->GetIsolate());
     92   v8::Local<v8::String> profile_name =
     93       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
     94   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
     95 
     96   cpu_profiler->StartProfiling(profile_name);
     97   (*test)();
     98   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
     99 }
    100 
    101 
    102 static int signature_callback_count;
    103 static Local<Value> signature_expected_receiver;
    104 static void IncrementingSignatureCallback(
    105     const v8::FunctionCallbackInfo<v8::Value>& args) {
    106   ApiTestFuzzer::Fuzz();
    107   signature_callback_count++;
    108   CHECK_EQ(signature_expected_receiver, args.Holder());
    109   CHECK_EQ(signature_expected_receiver, args.This());
    110   v8::Handle<v8::Array> result =
    111       v8::Array::New(args.GetIsolate(), args.Length());
    112   for (int i = 0; i < args.Length(); i++)
    113     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
    114   args.GetReturnValue().Set(result);
    115 }
    116 
    117 
    118 static void SignatureCallback(
    119     const v8::FunctionCallbackInfo<v8::Value>& args) {
    120   ApiTestFuzzer::Fuzz();
    121   v8::Handle<v8::Array> result =
    122       v8::Array::New(args.GetIsolate(), args.Length());
    123   for (int i = 0; i < args.Length(); i++) {
    124     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
    125   }
    126   args.GetReturnValue().Set(result);
    127 }
    128 
    129 
    130 // Tests that call v8::V8::Dispose() cannot be threaded.
    131 TEST(InitializeAndDisposeOnce) {
    132   CHECK(v8::V8::Initialize());
    133   CHECK(v8::V8::Dispose());
    134 }
    135 
    136 
    137 // Tests that call v8::V8::Dispose() cannot be threaded.
    138 TEST(InitializeAndDisposeMultiple) {
    139   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    140   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
    141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    142   // TODO(mstarzinger): This should fail gracefully instead of asserting.
    143   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
    144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
    145 }
    146 
    147 
    148 THREADED_TEST(Handles) {
    149   v8::HandleScope scope(CcTest::isolate());
    150   Local<Context> local_env;
    151   {
    152     LocalContext env;
    153     local_env = env.local();
    154   }
    155 
    156   // Local context should still be live.
    157   CHECK(!local_env.IsEmpty());
    158   local_env->Enter();
    159 
    160   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
    161   CHECK(!undef.IsEmpty());
    162   CHECK(undef->IsUndefined());
    163 
    164   const char* source = "1 + 2 + 3";
    165   Local<Script> script = v8_compile(source);
    166   CHECK_EQ(6, script->Run()->Int32Value());
    167 
    168   local_env->Exit();
    169 }
    170 
    171 
    172 THREADED_TEST(IsolateOfContext) {
    173   v8::HandleScope scope(CcTest::isolate());
    174   v8::Handle<Context> env = Context::New(CcTest::isolate());
    175 
    176   CHECK(!env->GetIsolate()->InContext());
    177   CHECK(env->GetIsolate() == CcTest::isolate());
    178   env->Enter();
    179   CHECK(env->GetIsolate()->InContext());
    180   CHECK(env->GetIsolate() == CcTest::isolate());
    181   env->Exit();
    182   CHECK(!env->GetIsolate()->InContext());
    183   CHECK(env->GetIsolate() == CcTest::isolate());
    184 }
    185 
    186 
    187 static void TestSignature(const char* loop_js, Local<Value> receiver) {
    188   i::ScopedVector<char> source(200);
    189   i::SNPrintF(source,
    190               "for (var i = 0; i < 10; i++) {"
    191               "  %s"
    192               "}",
    193               loop_js);
    194   signature_callback_count = 0;
    195   signature_expected_receiver = receiver;
    196   bool expected_to_throw = receiver.IsEmpty();
    197   v8::TryCatch try_catch;
    198   CompileRun(source.start());
    199   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
    200   if (!expected_to_throw) {
    201     CHECK_EQ(10, signature_callback_count);
    202   } else {
    203     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
    204              try_catch.Exception()->ToString());
    205   }
    206 }
    207 
    208 
    209 THREADED_TEST(ReceiverSignature) {
    210   LocalContext env;
    211   v8::Isolate* isolate = env->GetIsolate();
    212   v8::HandleScope scope(isolate);
    213   // Setup templates.
    214   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
    215   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
    216   v8::Handle<v8::FunctionTemplate> callback_sig =
    217       v8::FunctionTemplate::New(
    218           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
    219   v8::Handle<v8::FunctionTemplate> callback =
    220       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
    221   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
    222   sub_fun->Inherit(fun);
    223   v8::Handle<v8::FunctionTemplate> unrel_fun =
    224       v8::FunctionTemplate::New(isolate);
    225   // Install properties.
    226   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
    227   fun_proto->Set(v8_str("prop_sig"), callback_sig);
    228   fun_proto->Set(v8_str("prop"), callback);
    229   fun_proto->SetAccessorProperty(
    230       v8_str("accessor_sig"), callback_sig, callback_sig);
    231   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
    232   // Instantiate templates.
    233   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
    234   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
    235   // Setup global variables.
    236   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
    237   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
    238   env->Global()->Set(v8_str("fun_instance"), fun_instance);
    239   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
    240   CompileRun(
    241       "var accessor_sig_key = 'accessor_sig';"
    242       "var accessor_key = 'accessor';"
    243       "var prop_sig_key = 'prop_sig';"
    244       "var prop_key = 'prop';"
    245       ""
    246       "function copy_props(obj) {"
    247       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
    248       "  var source = Fun.prototype;"
    249       "  for (var i in keys) {"
    250       "    var key = keys[i];"
    251       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
    252       "    Object.defineProperty(obj, key, desc);"
    253       "  }"
    254       "}"
    255       ""
    256       "var obj = {};"
    257       "copy_props(obj);"
    258       "var unrel = new UnrelFun();"
    259       "copy_props(unrel);");
    260   // Test with and without ICs
    261   const char* test_objects[] = {
    262       "fun_instance", "sub_fun_instance", "obj", "unrel" };
    263   unsigned bad_signature_start_offset = 2;
    264   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
    265     i::ScopedVector<char> source(200);
    266     i::SNPrintF(
    267         source, "var test_object = %s; test_object", test_objects[i]);
    268     Local<Value> test_object = CompileRun(source.start());
    269     TestSignature("test_object.prop();", test_object);
    270     TestSignature("test_object.accessor;", test_object);
    271     TestSignature("test_object[accessor_key];", test_object);
    272     TestSignature("test_object.accessor = 1;", test_object);
    273     TestSignature("test_object[accessor_key] = 1;", test_object);
    274     if (i >= bad_signature_start_offset) test_object = Local<Value>();
    275     TestSignature("test_object.prop_sig();", test_object);
    276     TestSignature("test_object.accessor_sig;", test_object);
    277     TestSignature("test_object[accessor_sig_key];", test_object);
    278     TestSignature("test_object.accessor_sig = 1;", test_object);
    279     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
    280   }
    281 }
    282 
    283 
    284 THREADED_TEST(ArgumentSignature) {
    285   LocalContext env;
    286   v8::Isolate* isolate = env->GetIsolate();
    287   v8::HandleScope scope(isolate);
    288   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
    289   cons->SetClassName(v8_str("Cons"));
    290   v8::Handle<v8::Signature> sig = v8::Signature::New(
    291       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
    292   v8::Handle<v8::FunctionTemplate> fun =
    293       v8::FunctionTemplate::New(isolate,
    294                                 SignatureCallback,
    295                                 v8::Handle<Value>(),
    296                                 sig);
    297   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
    298   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
    299 
    300   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
    301   CHECK(value1->IsTrue());
    302 
    303   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
    304   CHECK(value2->IsTrue());
    305 
    306   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
    307   CHECK(value3->IsTrue());
    308 
    309   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
    310   cons1->SetClassName(v8_str("Cons1"));
    311   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
    312   cons2->SetClassName(v8_str("Cons2"));
    313   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
    314   cons3->SetClassName(v8_str("Cons3"));
    315 
    316   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
    317   v8::Handle<v8::Signature> wsig = v8::Signature::New(
    318       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
    319   v8::Handle<v8::FunctionTemplate> fun2 =
    320       v8::FunctionTemplate::New(isolate,
    321                                 SignatureCallback,
    322                                 v8::Handle<Value>(),
    323                                 wsig);
    324 
    325   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
    326   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
    327   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
    328   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
    329   v8::Handle<Value> value4 = CompileRun(
    330       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
    331       "'[object Cons1],[object Cons2],[object Cons3]'");
    332   CHECK(value4->IsTrue());
    333 
    334   v8::Handle<Value> value5 = CompileRun(
    335       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
    336   CHECK(value5->IsTrue());
    337 
    338   v8::Handle<Value> value6 = CompileRun(
    339       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
    340   CHECK(value6->IsTrue());
    341 
    342   v8::Handle<Value> value7 = CompileRun(
    343       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
    344       "'[object Cons1],[object Cons2],[object Cons3],d';");
    345   CHECK(value7->IsTrue());
    346 
    347   v8::Handle<Value> value8 = CompileRun(
    348       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
    349   CHECK(value8->IsTrue());
    350 }
    351 
    352 
    353 THREADED_TEST(HulIgennem) {
    354   LocalContext env;
    355   v8::Isolate* isolate = env->GetIsolate();
    356   v8::HandleScope scope(isolate);
    357   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
    358   Local<String> undef_str = undef->ToString();
    359   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
    360   undef_str->WriteUtf8(value);
    361   CHECK_EQ(0, strcmp(value, "undefined"));
    362   i::DeleteArray(value);
    363 }
    364 
    365 
    366 THREADED_TEST(Access) {
    367   LocalContext env;
    368   v8::Isolate* isolate = env->GetIsolate();
    369   v8::HandleScope scope(isolate);
    370   Local<v8::Object> obj = v8::Object::New(isolate);
    371   Local<Value> foo_before = obj->Get(v8_str("foo"));
    372   CHECK(foo_before->IsUndefined());
    373   Local<String> bar_str = v8_str("bar");
    374   obj->Set(v8_str("foo"), bar_str);
    375   Local<Value> foo_after = obj->Get(v8_str("foo"));
    376   CHECK(!foo_after->IsUndefined());
    377   CHECK(foo_after->IsString());
    378   CHECK_EQ(bar_str, foo_after);
    379 }
    380 
    381 
    382 THREADED_TEST(AccessElement) {
    383   LocalContext env;
    384   v8::HandleScope scope(env->GetIsolate());
    385   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
    386   Local<Value> before = obj->Get(1);
    387   CHECK(before->IsUndefined());
    388   Local<String> bar_str = v8_str("bar");
    389   obj->Set(1, bar_str);
    390   Local<Value> after = obj->Get(1);
    391   CHECK(!after->IsUndefined());
    392   CHECK(after->IsString());
    393   CHECK_EQ(bar_str, after);
    394 
    395   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
    396   CHECK_EQ(v8_str("a"), value->Get(0));
    397   CHECK_EQ(v8_str("b"), value->Get(1));
    398 }
    399 
    400 
    401 THREADED_TEST(Script) {
    402   LocalContext env;
    403   v8::HandleScope scope(env->GetIsolate());
    404   const char* source = "1 + 2 + 3";
    405   Local<Script> script = v8_compile(source);
    406   CHECK_EQ(6, script->Run()->Int32Value());
    407 }
    408 
    409 
    410 class TestResource: public String::ExternalStringResource {
    411  public:
    412   TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
    413       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
    414     while (data[length_]) ++length_;
    415   }
    416 
    417   ~TestResource() {
    418     if (owning_data_) i::DeleteArray(data_);
    419     if (counter_ != NULL) ++*counter_;
    420   }
    421 
    422   const uint16_t* data() const {
    423     return data_;
    424   }
    425 
    426   size_t length() const {
    427     return length_;
    428   }
    429 
    430  private:
    431   uint16_t* data_;
    432   size_t length_;
    433   int* counter_;
    434   bool owning_data_;
    435 };
    436 
    437 
    438 class TestAsciiResource: public String::ExternalAsciiStringResource {
    439  public:
    440   TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
    441       : orig_data_(data),
    442         data_(data + offset),
    443         length_(strlen(data) - offset),
    444         counter_(counter) { }
    445 
    446   ~TestAsciiResource() {
    447     i::DeleteArray(orig_data_);
    448     if (counter_ != NULL) ++*counter_;
    449   }
    450 
    451   const char* data() const {
    452     return data_;
    453   }
    454 
    455   size_t length() const {
    456     return length_;
    457   }
    458 
    459  private:
    460   const char* orig_data_;
    461   const char* data_;
    462   size_t length_;
    463   int* counter_;
    464 };
    465 
    466 
    467 THREADED_TEST(ScriptUsingStringResource) {
    468   int dispose_count = 0;
    469   const char* c_source = "1 + 2 * 3";
    470   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
    471   {
    472     LocalContext env;
    473     v8::HandleScope scope(env->GetIsolate());
    474     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
    475     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
    476     Local<Script> script = v8_compile(source);
    477     Local<Value> value = script->Run();
    478     CHECK(value->IsNumber());
    479     CHECK_EQ(7, value->Int32Value());
    480     CHECK(source->IsExternal());
    481     CHECK_EQ(resource,
    482              static_cast<TestResource*>(source->GetExternalStringResource()));
    483     String::Encoding encoding = String::UNKNOWN_ENCODING;
    484     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    485              source->GetExternalStringResourceBase(&encoding));
    486     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
    487     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    488     CHECK_EQ(0, dispose_count);
    489   }
    490   CcTest::i_isolate()->compilation_cache()->Clear();
    491   CcTest::heap()->CollectAllAvailableGarbage();
    492   CHECK_EQ(1, dispose_count);
    493 }
    494 
    495 
    496 THREADED_TEST(ScriptUsingAsciiStringResource) {
    497   int dispose_count = 0;
    498   const char* c_source = "1 + 2 * 3";
    499   {
    500     LocalContext env;
    501     v8::HandleScope scope(env->GetIsolate());
    502     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
    503                                                         &dispose_count);
    504     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
    505     CHECK(source->IsExternalAscii());
    506     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    507              source->GetExternalAsciiStringResource());
    508     String::Encoding encoding = String::UNKNOWN_ENCODING;
    509     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
    510              source->GetExternalStringResourceBase(&encoding));
    511     CHECK_EQ(String::ASCII_ENCODING, encoding);
    512     Local<Script> script = v8_compile(source);
    513     Local<Value> value = script->Run();
    514     CHECK(value->IsNumber());
    515     CHECK_EQ(7, value->Int32Value());
    516     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    517     CHECK_EQ(0, dispose_count);
    518   }
    519   CcTest::i_isolate()->compilation_cache()->Clear();
    520   CcTest::heap()->CollectAllAvailableGarbage();
    521   CHECK_EQ(1, dispose_count);
    522 }
    523 
    524 
    525 THREADED_TEST(ScriptMakingExternalString) {
    526   int dispose_count = 0;
    527   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
    528   {
    529     LocalContext env;
    530     v8::HandleScope scope(env->GetIsolate());
    531     Local<String> source =
    532         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
    533     // Trigger GCs so that the newly allocated string moves to old gen.
    534     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    535     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    536     CHECK_EQ(source->IsExternal(), false);
    537     CHECK_EQ(source->IsExternalAscii(), false);
    538     String::Encoding encoding = String::UNKNOWN_ENCODING;
    539     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
    540     CHECK_EQ(String::ASCII_ENCODING, encoding);
    541     bool success = source->MakeExternal(new TestResource(two_byte_source,
    542                                                          &dispose_count));
    543     CHECK(success);
    544     Local<Script> script = v8_compile(source);
    545     Local<Value> value = script->Run();
    546     CHECK(value->IsNumber());
    547     CHECK_EQ(7, value->Int32Value());
    548     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    549     CHECK_EQ(0, dispose_count);
    550   }
    551   CcTest::i_isolate()->compilation_cache()->Clear();
    552   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
    553   CHECK_EQ(1, dispose_count);
    554 }
    555 
    556 
    557 THREADED_TEST(ScriptMakingExternalAsciiString) {
    558   int dispose_count = 0;
    559   const char* c_source = "1 + 2 * 3";
    560   {
    561     LocalContext env;
    562     v8::HandleScope scope(env->GetIsolate());
    563     Local<String> source = v8_str(c_source);
    564     // Trigger GCs so that the newly allocated string moves to old gen.
    565     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    566     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    567     bool success = source->MakeExternal(
    568         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
    569     CHECK(success);
    570     Local<Script> script = v8_compile(source);
    571     Local<Value> value = script->Run();
    572     CHECK(value->IsNumber());
    573     CHECK_EQ(7, value->Int32Value());
    574     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    575     CHECK_EQ(0, dispose_count);
    576   }
    577   CcTest::i_isolate()->compilation_cache()->Clear();
    578   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
    579   CHECK_EQ(1, dispose_count);
    580 }
    581 
    582 
    583 TEST(MakingExternalStringConditions) {
    584   LocalContext env;
    585   v8::HandleScope scope(env->GetIsolate());
    586 
    587   // Free some space in the new space so that we can check freshness.
    588   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    589   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    590 
    591   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
    592   Local<String> small_string =
    593       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
    594   i::DeleteArray(two_byte_string);
    595 
    596   // We should refuse to externalize newly created small string.
    597   CHECK(!small_string->CanMakeExternal());
    598   // Trigger GCs so that the newly allocated string moves to old gen.
    599   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    600   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    601   // Old space strings should be accepted.
    602   CHECK(small_string->CanMakeExternal());
    603 
    604   two_byte_string = AsciiToTwoByteString("small string 2");
    605   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
    606   i::DeleteArray(two_byte_string);
    607 
    608   // We should refuse externalizing newly created small string.
    609   CHECK(!small_string->CanMakeExternal());
    610   for (int i = 0; i < 100; i++) {
    611     String::Value value(small_string);
    612   }
    613   // Frequently used strings should be accepted.
    614   CHECK(small_string->CanMakeExternal());
    615 
    616   const int buf_size = 10 * 1024;
    617   char* buf = i::NewArray<char>(buf_size);
    618   memset(buf, 'a', buf_size);
    619   buf[buf_size - 1] = '\0';
    620 
    621   two_byte_string = AsciiToTwoByteString(buf);
    622   Local<String> large_string =
    623       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
    624   i::DeleteArray(buf);
    625   i::DeleteArray(two_byte_string);
    626   // Large strings should be immediately accepted.
    627   CHECK(large_string->CanMakeExternal());
    628 }
    629 
    630 
    631 TEST(MakingExternalAsciiStringConditions) {
    632   LocalContext env;
    633   v8::HandleScope scope(env->GetIsolate());
    634 
    635   // Free some space in the new space so that we can check freshness.
    636   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    637   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    638 
    639   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
    640   // We should refuse to externalize newly created small string.
    641   CHECK(!small_string->CanMakeExternal());
    642   // Trigger GCs so that the newly allocated string moves to old gen.
    643   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    644   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    645   // Old space strings should be accepted.
    646   CHECK(small_string->CanMakeExternal());
    647 
    648   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
    649   // We should refuse externalizing newly created small string.
    650   CHECK(!small_string->CanMakeExternal());
    651   for (int i = 0; i < 100; i++) {
    652     String::Value value(small_string);
    653   }
    654   // Frequently used strings should be accepted.
    655   CHECK(small_string->CanMakeExternal());
    656 
    657   const int buf_size = 10 * 1024;
    658   char* buf = i::NewArray<char>(buf_size);
    659   memset(buf, 'a', buf_size);
    660   buf[buf_size - 1] = '\0';
    661   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
    662   i::DeleteArray(buf);
    663   // Large strings should be immediately accepted.
    664   CHECK(large_string->CanMakeExternal());
    665 }
    666 
    667 
    668 TEST(MakingExternalUnalignedAsciiString) {
    669   LocalContext env;
    670   v8::HandleScope scope(env->GetIsolate());
    671 
    672   CompileRun("function cons(a, b) { return a + b; }"
    673              "function slice(a) { return a.substring(1); }");
    674   // Create a cons string that will land in old pointer space.
    675   Local<String> cons = Local<String>::Cast(CompileRun(
    676       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
    677   // Create a sliced string that will land in old pointer space.
    678   Local<String> slice = Local<String>::Cast(CompileRun(
    679       "slice('abcdefghijklmnopqrstuvwxyz');"));
    680 
    681   // Trigger GCs so that the newly allocated string moves to old gen.
    682   SimulateFullSpace(CcTest::heap()->old_pointer_space());
    683   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    684   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    685 
    686   // Turn into external string with unaligned resource data.
    687   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
    688   bool success = cons->MakeExternal(
    689       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
    690   CHECK(success);
    691   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
    692   success = slice->MakeExternal(
    693       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
    694   CHECK(success);
    695 
    696   // Trigger GCs and force evacuation.
    697   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    698   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
    699 }
    700 
    701 
    702 THREADED_TEST(UsingExternalString) {
    703   i::Factory* factory = CcTest::i_isolate()->factory();
    704   {
    705     v8::HandleScope scope(CcTest::isolate());
    706     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    707     Local<String> string = String::NewExternal(
    708         CcTest::isolate(), new TestResource(two_byte_string));
    709     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    710     // Trigger GCs so that the newly allocated string moves to old gen.
    711     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    712     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    713     i::Handle<i::String> isymbol =
    714         factory->InternalizeString(istring);
    715     CHECK(isymbol->IsInternalizedString());
    716   }
    717   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    718   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    719 }
    720 
    721 
    722 THREADED_TEST(UsingExternalAsciiString) {
    723   i::Factory* factory = CcTest::i_isolate()->factory();
    724   {
    725     v8::HandleScope scope(CcTest::isolate());
    726     const char* one_byte_string = "test string";
    727     Local<String> string = String::NewExternal(
    728         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
    729     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    730     // Trigger GCs so that the newly allocated string moves to old gen.
    731     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
    732     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
    733     i::Handle<i::String> isymbol =
    734         factory->InternalizeString(istring);
    735     CHECK(isymbol->IsInternalizedString());
    736   }
    737   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    738   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    739 }
    740 
    741 
    742 THREADED_TEST(ScavengeExternalString) {
    743   i::FLAG_stress_compaction = false;
    744   i::FLAG_gc_global = false;
    745   int dispose_count = 0;
    746   bool in_new_space = false;
    747   {
    748     v8::HandleScope scope(CcTest::isolate());
    749     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
    750     Local<String> string = String::NewExternal(
    751         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
    752     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    753     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    754     in_new_space = CcTest::heap()->InNewSpace(*istring);
    755     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
    756     CHECK_EQ(0, dispose_count);
    757   }
    758   CcTest::heap()->CollectGarbage(
    759       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
    760   CHECK_EQ(1, dispose_count);
    761 }
    762 
    763 
    764 THREADED_TEST(ScavengeExternalAsciiString) {
    765   i::FLAG_stress_compaction = false;
    766   i::FLAG_gc_global = false;
    767   int dispose_count = 0;
    768   bool in_new_space = false;
    769   {
    770     v8::HandleScope scope(CcTest::isolate());
    771     const char* one_byte_string = "test string";
    772     Local<String> string = String::NewExternal(
    773         CcTest::isolate(),
    774         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
    775     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
    776     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
    777     in_new_space = CcTest::heap()->InNewSpace(*istring);
    778     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
    779     CHECK_EQ(0, dispose_count);
    780   }
    781   CcTest::heap()->CollectGarbage(
    782       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
    783   CHECK_EQ(1, dispose_count);
    784 }
    785 
    786 
    787 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
    788  public:
    789   // Only used by non-threaded tests, so it can use static fields.
    790   static int dispose_calls;
    791   static int dispose_count;
    792 
    793   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
    794       : TestAsciiResource(data, &dispose_count),
    795         dispose_(dispose) { }
    796 
    797   void Dispose() {
    798     ++dispose_calls;
    799     if (dispose_) delete this;
    800   }
    801  private:
    802   bool dispose_;
    803 };
    804 
    805 
    806 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
    807 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
    808 
    809 
    810 TEST(ExternalStringWithDisposeHandling) {
    811   const char* c_source = "1 + 2 * 3";
    812 
    813   // Use a stack allocated external string resource allocated object.
    814   TestAsciiResourceWithDisposeControl::dispose_count = 0;
    815   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
    816   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
    817   {
    818     LocalContext env;
    819     v8::HandleScope scope(env->GetIsolate());
    820     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
    821     Local<Script> script = v8_compile(source);
    822     Local<Value> value = script->Run();
    823     CHECK(value->IsNumber());
    824     CHECK_EQ(7, value->Int32Value());
    825     CcTest::heap()->CollectAllAvailableGarbage();
    826     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
    827   }
    828   CcTest::i_isolate()->compilation_cache()->Clear();
    829   CcTest::heap()->CollectAllAvailableGarbage();
    830   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
    831   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
    832 
    833   // Use a heap allocated external string resource allocated object.
    834   TestAsciiResourceWithDisposeControl::dispose_count = 0;
    835   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
    836   TestAsciiResource* res_heap =
    837       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
    838   {
    839     LocalContext env;
    840     v8::HandleScope scope(env->GetIsolate());
    841     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
    842     Local<Script> script = v8_compile(source);
    843     Local<Value> value = script->Run();
    844     CHECK(value->IsNumber());
    845     CHECK_EQ(7, value->Int32Value());
    846     CcTest::heap()->CollectAllAvailableGarbage();
    847     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
    848   }
    849   CcTest::i_isolate()->compilation_cache()->Clear();
    850   CcTest::heap()->CollectAllAvailableGarbage();
    851   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
    852   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
    853 }
    854 
    855 
    856 THREADED_TEST(StringConcat) {
    857   {
    858     LocalContext env;
    859     v8::HandleScope scope(env->GetIsolate());
    860     const char* one_byte_string_1 = "function a_times_t";
    861     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
    862     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
    863     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
    864     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    865     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
    866     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
    867     Local<String> left = v8_str(one_byte_string_1);
    868 
    869     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
    870     Local<String> right =
    871         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
    872     i::DeleteArray(two_byte_source);
    873 
    874     Local<String> source = String::Concat(left, right);
    875     right = String::NewExternal(
    876         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
    877     source = String::Concat(source, right);
    878     right = String::NewExternal(
    879         env->GetIsolate(),
    880         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
    881     source = String::Concat(source, right);
    882     right = v8_str(one_byte_string_2);
    883     source = String::Concat(source, right);
    884 
    885     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
    886     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
    887     i::DeleteArray(two_byte_source);
    888 
    889     source = String::Concat(source, right);
    890     right = String::NewExternal(
    891         env->GetIsolate(),
    892         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
    893     source = String::Concat(source, right);
    894     Local<Script> script = v8_compile(source);
    895     Local<Value> value = script->Run();
    896     CHECK(value->IsNumber());
    897     CHECK_EQ(68, value->Int32Value());
    898   }
    899   CcTest::i_isolate()->compilation_cache()->Clear();
    900   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    901   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
    902 }
    903 
    904 
    905 THREADED_TEST(GlobalProperties) {
    906   LocalContext env;
    907   v8::HandleScope scope(env->GetIsolate());
    908   v8::Handle<v8::Object> global = env->Global();
    909   global->Set(v8_str("pi"), v8_num(3.1415926));
    910   Local<Value> pi = global->Get(v8_str("pi"));
    911   CHECK_EQ(3.1415926, pi->NumberValue());
    912 }
    913 
    914 
    915 template<typename T>
    916 static void CheckReturnValue(const T& t, i::Address callback) {
    917   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
    918   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
    919   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
    920   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
    921   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
    922   // Verify reset
    923   bool is_runtime = (*o)->IsTheHole();
    924   rv.Set(true);
    925   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
    926   rv.Set(v8::Handle<v8::Object>());
    927   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
    928   CHECK_EQ(is_runtime, (*o)->IsTheHole());
    929 
    930   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
    931   // If CPU profiler is active check that when API callback is invoked
    932   // VMState is set to EXTERNAL.
    933   if (isolate->cpu_profiler()->is_profiling()) {
    934     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
    935     CHECK(isolate->external_callback_scope());
    936     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
    937   }
    938 }
    939 
    940 
    941 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
    942                                  i::Address callback) {
    943   ApiTestFuzzer::Fuzz();
    944   CheckReturnValue(info, callback);
    945   info.GetReturnValue().Set(v8_str("bad value"));
    946   info.GetReturnValue().Set(v8_num(102));
    947 }
    948 
    949 
    950 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
    951   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
    952 }
    953 
    954 
    955 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
    956   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
    957 }
    958 
    959 static void construct_callback(
    960     const v8::FunctionCallbackInfo<Value>& info) {
    961   ApiTestFuzzer::Fuzz();
    962   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
    963   info.This()->Set(v8_str("x"), v8_num(1));
    964   info.This()->Set(v8_str("y"), v8_num(2));
    965   info.GetReturnValue().Set(v8_str("bad value"));
    966   info.GetReturnValue().Set(info.This());
    967 }
    968 
    969 
    970 static void Return239Callback(
    971     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
    972   ApiTestFuzzer::Fuzz();
    973   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
    974   info.GetReturnValue().Set(v8_str("bad value"));
    975   info.GetReturnValue().Set(v8_num(239));
    976 }
    977 
    978 
    979 template<typename Handler>
    980 static void TestFunctionTemplateInitializer(Handler handler,
    981                                             Handler handler_2) {
    982   // Test constructor calls.
    983   {
    984     LocalContext env;
    985     v8::Isolate* isolate = env->GetIsolate();
    986     v8::HandleScope scope(isolate);
    987 
    988     Local<v8::FunctionTemplate> fun_templ =
    989         v8::FunctionTemplate::New(isolate, handler);
    990     Local<Function> fun = fun_templ->GetFunction();
    991     env->Global()->Set(v8_str("obj"), fun);
    992     Local<Script> script = v8_compile("obj()");
    993     for (int i = 0; i < 30; i++) {
    994       CHECK_EQ(102, script->Run()->Int32Value());
    995     }
    996   }
    997   // Use SetCallHandler to initialize a function template, should work like
    998   // the previous one.
    999   {
   1000     LocalContext env;
   1001     v8::Isolate* isolate = env->GetIsolate();
   1002     v8::HandleScope scope(isolate);
   1003 
   1004     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   1005     fun_templ->SetCallHandler(handler_2);
   1006     Local<Function> fun = fun_templ->GetFunction();
   1007     env->Global()->Set(v8_str("obj"), fun);
   1008     Local<Script> script = v8_compile("obj()");
   1009     for (int i = 0; i < 30; i++) {
   1010       CHECK_EQ(102, script->Run()->Int32Value());
   1011     }
   1012   }
   1013 }
   1014 
   1015 
   1016 template<typename Constructor, typename Accessor>
   1017 static void TestFunctionTemplateAccessor(Constructor constructor,
   1018                                          Accessor accessor) {
   1019   LocalContext env;
   1020   v8::HandleScope scope(env->GetIsolate());
   1021 
   1022   Local<v8::FunctionTemplate> fun_templ =
   1023       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
   1024   fun_templ->SetClassName(v8_str("funky"));
   1025   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
   1026   Local<Function> fun = fun_templ->GetFunction();
   1027   env->Global()->Set(v8_str("obj"), fun);
   1028   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
   1029   CHECK_EQ(v8_str("[object funky]"), result);
   1030   CompileRun("var obj_instance = new obj();");
   1031   Local<Script> script;
   1032   script = v8_compile("obj_instance.x");
   1033   for (int i = 0; i < 30; i++) {
   1034     CHECK_EQ(1, script->Run()->Int32Value());
   1035   }
   1036   script = v8_compile("obj_instance.m");
   1037   for (int i = 0; i < 30; i++) {
   1038     CHECK_EQ(239, script->Run()->Int32Value());
   1039   }
   1040 }
   1041 
   1042 
   1043 THREADED_PROFILED_TEST(FunctionTemplate) {
   1044   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
   1045   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
   1046 }
   1047 
   1048 
   1049 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
   1050   ApiTestFuzzer::Fuzz();
   1051   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
   1052   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
   1053 }
   1054 
   1055 
   1056 template<typename Callback>
   1057 static void TestSimpleCallback(Callback callback) {
   1058   LocalContext env;
   1059   v8::Isolate* isolate = env->GetIsolate();
   1060   v8::HandleScope scope(isolate);
   1061 
   1062   v8::Handle<v8::ObjectTemplate> object_template =
   1063       v8::ObjectTemplate::New(isolate);
   1064   object_template->Set(isolate, "callback",
   1065                        v8::FunctionTemplate::New(isolate, callback));
   1066   v8::Local<v8::Object> object = object_template->NewInstance();
   1067   (*env)->Global()->Set(v8_str("callback_object"), object);
   1068   v8::Handle<v8::Script> script;
   1069   script = v8_compile("callback_object.callback(17)");
   1070   for (int i = 0; i < 30; i++) {
   1071     CHECK_EQ(51424, script->Run()->Int32Value());
   1072   }
   1073   script = v8_compile("callback_object.callback(17, 24)");
   1074   for (int i = 0; i < 30; i++) {
   1075     CHECK_EQ(51425, script->Run()->Int32Value());
   1076   }
   1077 }
   1078 
   1079 
   1080 THREADED_PROFILED_TEST(SimpleCallback) {
   1081   TestSimpleCallback(SimpleCallback);
   1082 }
   1083 
   1084 
   1085 template<typename T>
   1086 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
   1087 
   1088 // constant return values
   1089 static int32_t fast_return_value_int32 = 471;
   1090 static uint32_t fast_return_value_uint32 = 571;
   1091 static const double kFastReturnValueDouble = 2.7;
   1092 // variable return values
   1093 static bool fast_return_value_bool = false;
   1094 enum ReturnValueOddball {
   1095   kNullReturnValue,
   1096   kUndefinedReturnValue,
   1097   kEmptyStringReturnValue
   1098 };
   1099 static ReturnValueOddball fast_return_value_void;
   1100 static bool fast_return_value_object_is_empty = false;
   1101 
   1102 // Helper function to avoid compiler error: insufficient contextual information
   1103 // to determine type when applying FUNCTION_ADDR to a template function.
   1104 static i::Address address_of(v8::FunctionCallback callback) {
   1105   return FUNCTION_ADDR(callback);
   1106 }
   1107 
   1108 template<>
   1109 void FastReturnValueCallback<int32_t>(
   1110     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1111   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
   1112   info.GetReturnValue().Set(fast_return_value_int32);
   1113 }
   1114 
   1115 template<>
   1116 void FastReturnValueCallback<uint32_t>(
   1117     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1118   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
   1119   info.GetReturnValue().Set(fast_return_value_uint32);
   1120 }
   1121 
   1122 template<>
   1123 void FastReturnValueCallback<double>(
   1124     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1125   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
   1126   info.GetReturnValue().Set(kFastReturnValueDouble);
   1127 }
   1128 
   1129 template<>
   1130 void FastReturnValueCallback<bool>(
   1131     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1132   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
   1133   info.GetReturnValue().Set(fast_return_value_bool);
   1134 }
   1135 
   1136 template<>
   1137 void FastReturnValueCallback<void>(
   1138     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1139   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
   1140   switch (fast_return_value_void) {
   1141     case kNullReturnValue:
   1142       info.GetReturnValue().SetNull();
   1143       break;
   1144     case kUndefinedReturnValue:
   1145       info.GetReturnValue().SetUndefined();
   1146       break;
   1147     case kEmptyStringReturnValue:
   1148       info.GetReturnValue().SetEmptyString();
   1149       break;
   1150   }
   1151 }
   1152 
   1153 template<>
   1154 void FastReturnValueCallback<Object>(
   1155     const v8::FunctionCallbackInfo<v8::Value>& info) {
   1156   v8::Handle<v8::Object> object;
   1157   if (!fast_return_value_object_is_empty) {
   1158     object = Object::New(info.GetIsolate());
   1159   }
   1160   info.GetReturnValue().Set(object);
   1161 }
   1162 
   1163 template<typename T>
   1164 Handle<Value> TestFastReturnValues() {
   1165   LocalContext env;
   1166   v8::Isolate* isolate = env->GetIsolate();
   1167   v8::EscapableHandleScope scope(isolate);
   1168   v8::Handle<v8::ObjectTemplate> object_template =
   1169       v8::ObjectTemplate::New(isolate);
   1170   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
   1171   object_template->Set(isolate, "callback",
   1172                        v8::FunctionTemplate::New(isolate, callback));
   1173   v8::Local<v8::Object> object = object_template->NewInstance();
   1174   (*env)->Global()->Set(v8_str("callback_object"), object);
   1175   return scope.Escape(CompileRun("callback_object.callback()"));
   1176 }
   1177 
   1178 
   1179 THREADED_PROFILED_TEST(FastReturnValues) {
   1180   LocalContext env;
   1181   v8::HandleScope scope(CcTest::isolate());
   1182   v8::Handle<v8::Value> value;
   1183   // check int32_t and uint32_t
   1184   int32_t int_values[] = {
   1185       0, 234, -723,
   1186       i::Smi::kMinValue, i::Smi::kMaxValue
   1187   };
   1188   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
   1189     for (int modifier = -1; modifier <= 1; modifier++) {
   1190       int int_value = int_values[i] + modifier;
   1191       // check int32_t
   1192       fast_return_value_int32 = int_value;
   1193       value = TestFastReturnValues<int32_t>();
   1194       CHECK(value->IsInt32());
   1195       CHECK(fast_return_value_int32 == value->Int32Value());
   1196       // check uint32_t
   1197       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
   1198       value = TestFastReturnValues<uint32_t>();
   1199       CHECK(value->IsUint32());
   1200       CHECK(fast_return_value_uint32 == value->Uint32Value());
   1201     }
   1202   }
   1203   // check double
   1204   value = TestFastReturnValues<double>();
   1205   CHECK(value->IsNumber());
   1206   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
   1207   // check bool values
   1208   for (int i = 0; i < 2; i++) {
   1209     fast_return_value_bool = i == 0;
   1210     value = TestFastReturnValues<bool>();
   1211     CHECK(value->IsBoolean());
   1212     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
   1213   }
   1214   // check oddballs
   1215   ReturnValueOddball oddballs[] = {
   1216       kNullReturnValue,
   1217       kUndefinedReturnValue,
   1218       kEmptyStringReturnValue
   1219   };
   1220   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
   1221     fast_return_value_void = oddballs[i];
   1222     value = TestFastReturnValues<void>();
   1223     switch (fast_return_value_void) {
   1224       case kNullReturnValue:
   1225         CHECK(value->IsNull());
   1226         break;
   1227       case kUndefinedReturnValue:
   1228         CHECK(value->IsUndefined());
   1229         break;
   1230       case kEmptyStringReturnValue:
   1231         CHECK(value->IsString());
   1232         CHECK_EQ(0, v8::String::Cast(*value)->Length());
   1233         break;
   1234     }
   1235   }
   1236   // check handles
   1237   fast_return_value_object_is_empty = false;
   1238   value = TestFastReturnValues<Object>();
   1239   CHECK(value->IsObject());
   1240   fast_return_value_object_is_empty = true;
   1241   value = TestFastReturnValues<Object>();
   1242   CHECK(value->IsUndefined());
   1243 }
   1244 
   1245 
   1246 THREADED_TEST(FunctionTemplateSetLength) {
   1247   LocalContext env;
   1248   v8::Isolate* isolate = env->GetIsolate();
   1249   v8::HandleScope scope(isolate);
   1250   {
   1251     Local<v8::FunctionTemplate> fun_templ =
   1252         v8::FunctionTemplate::New(isolate,
   1253                                   handle_callback,
   1254                                   Handle<v8::Value>(),
   1255                                   Handle<v8::Signature>(),
   1256                                   23);
   1257     Local<Function> fun = fun_templ->GetFunction();
   1258     env->Global()->Set(v8_str("obj"), fun);
   1259     Local<Script> script = v8_compile("obj.length");
   1260     CHECK_EQ(23, script->Run()->Int32Value());
   1261   }
   1262   {
   1263     Local<v8::FunctionTemplate> fun_templ =
   1264         v8::FunctionTemplate::New(isolate, handle_callback);
   1265     fun_templ->SetLength(22);
   1266     Local<Function> fun = fun_templ->GetFunction();
   1267     env->Global()->Set(v8_str("obj"), fun);
   1268     Local<Script> script = v8_compile("obj.length");
   1269     CHECK_EQ(22, script->Run()->Int32Value());
   1270   }
   1271   {
   1272     // Without setting length it defaults to 0.
   1273     Local<v8::FunctionTemplate> fun_templ =
   1274         v8::FunctionTemplate::New(isolate, handle_callback);
   1275     Local<Function> fun = fun_templ->GetFunction();
   1276     env->Global()->Set(v8_str("obj"), fun);
   1277     Local<Script> script = v8_compile("obj.length");
   1278     CHECK_EQ(0, script->Run()->Int32Value());
   1279   }
   1280 }
   1281 
   1282 
   1283 static void* expected_ptr;
   1284 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1285   void* ptr = v8::External::Cast(*args.Data())->Value();
   1286   CHECK_EQ(expected_ptr, ptr);
   1287   args.GetReturnValue().Set(true);
   1288 }
   1289 
   1290 
   1291 static void TestExternalPointerWrapping() {
   1292   LocalContext env;
   1293   v8::Isolate* isolate = env->GetIsolate();
   1294   v8::HandleScope scope(isolate);
   1295 
   1296   v8::Handle<v8::Value> data =
   1297       v8::External::New(isolate, expected_ptr);
   1298 
   1299   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   1300   obj->Set(v8_str("func"),
   1301            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
   1302   env->Global()->Set(v8_str("obj"), obj);
   1303 
   1304   CHECK(CompileRun(
   1305         "function foo() {\n"
   1306         "  for (var i = 0; i < 13; i++) obj.func();\n"
   1307         "}\n"
   1308         "foo(), true")->BooleanValue());
   1309 }
   1310 
   1311 
   1312 THREADED_TEST(ExternalWrap) {
   1313   // Check heap allocated object.
   1314   int* ptr = new int;
   1315   expected_ptr = ptr;
   1316   TestExternalPointerWrapping();
   1317   delete ptr;
   1318 
   1319   // Check stack allocated object.
   1320   int foo;
   1321   expected_ptr = &foo;
   1322   TestExternalPointerWrapping();
   1323 
   1324   // Check not aligned addresses.
   1325   const int n = 100;
   1326   char* s = new char[n];
   1327   for (int i = 0; i < n; i++) {
   1328     expected_ptr = s + i;
   1329     TestExternalPointerWrapping();
   1330   }
   1331 
   1332   delete[] s;
   1333 
   1334   // Check several invalid addresses.
   1335   expected_ptr = reinterpret_cast<void*>(1);
   1336   TestExternalPointerWrapping();
   1337 
   1338   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
   1339   TestExternalPointerWrapping();
   1340 
   1341   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
   1342   TestExternalPointerWrapping();
   1343 
   1344 #if defined(V8_HOST_ARCH_X64)
   1345   // Check a value with a leading 1 bit in x64 Smi encoding.
   1346   expected_ptr = reinterpret_cast<void*>(0x400000000);
   1347   TestExternalPointerWrapping();
   1348 
   1349   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
   1350   TestExternalPointerWrapping();
   1351 
   1352   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
   1353   TestExternalPointerWrapping();
   1354 #endif
   1355 }
   1356 
   1357 
   1358 THREADED_TEST(FindInstanceInPrototypeChain) {
   1359   LocalContext env;
   1360   v8::Isolate* isolate = env->GetIsolate();
   1361   v8::HandleScope scope(isolate);
   1362 
   1363   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
   1364   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
   1365   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
   1366   derived->Inherit(base);
   1367 
   1368   Local<v8::Function> base_function = base->GetFunction();
   1369   Local<v8::Function> derived_function = derived->GetFunction();
   1370   Local<v8::Function> other_function = other->GetFunction();
   1371 
   1372   Local<v8::Object> base_instance = base_function->NewInstance();
   1373   Local<v8::Object> derived_instance = derived_function->NewInstance();
   1374   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
   1375   Local<v8::Object> other_instance = other_function->NewInstance();
   1376   derived_instance2->Set(v8_str("__proto__"), derived_instance);
   1377   other_instance->Set(v8_str("__proto__"), derived_instance2);
   1378 
   1379   // base_instance is only an instance of base.
   1380   CHECK_EQ(base_instance,
   1381            base_instance->FindInstanceInPrototypeChain(base));
   1382   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
   1383   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
   1384 
   1385   // derived_instance is an instance of base and derived.
   1386   CHECK_EQ(derived_instance,
   1387            derived_instance->FindInstanceInPrototypeChain(base));
   1388   CHECK_EQ(derived_instance,
   1389            derived_instance->FindInstanceInPrototypeChain(derived));
   1390   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
   1391 
   1392   // other_instance is an instance of other and its immediate
   1393   // prototype derived_instance2 is an instance of base and derived.
   1394   // Note, derived_instance is an instance of base and derived too,
   1395   // but it comes after derived_instance2 in the prototype chain of
   1396   // other_instance.
   1397   CHECK_EQ(derived_instance2,
   1398            other_instance->FindInstanceInPrototypeChain(base));
   1399   CHECK_EQ(derived_instance2,
   1400            other_instance->FindInstanceInPrototypeChain(derived));
   1401   CHECK_EQ(other_instance,
   1402            other_instance->FindInstanceInPrototypeChain(other));
   1403 }
   1404 
   1405 
   1406 THREADED_TEST(TinyInteger) {
   1407   LocalContext env;
   1408   v8::Isolate* isolate = env->GetIsolate();
   1409   v8::HandleScope scope(isolate);
   1410 
   1411   int32_t value = 239;
   1412   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1413   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1414 
   1415   value_obj = v8::Integer::New(isolate, value);
   1416   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1417 }
   1418 
   1419 
   1420 THREADED_TEST(BigSmiInteger) {
   1421   LocalContext env;
   1422   v8::HandleScope scope(env->GetIsolate());
   1423   v8::Isolate* isolate = CcTest::isolate();
   1424 
   1425   int32_t value = i::Smi::kMaxValue;
   1426   // We cannot add one to a Smi::kMaxValue without wrapping.
   1427   if (i::SmiValuesAre31Bits()) {
   1428     CHECK(i::Smi::IsValid(value));
   1429     CHECK(!i::Smi::IsValid(value + 1));
   1430 
   1431     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1432     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1433 
   1434     value_obj = v8::Integer::New(isolate, value);
   1435     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1436   }
   1437 }
   1438 
   1439 
   1440 THREADED_TEST(BigInteger) {
   1441   LocalContext env;
   1442   v8::HandleScope scope(env->GetIsolate());
   1443   v8::Isolate* isolate = CcTest::isolate();
   1444 
   1445   // We cannot add one to a Smi::kMaxValue without wrapping.
   1446   if (i::SmiValuesAre31Bits()) {
   1447     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
   1448     // The code will not be run in that case, due to the "if" guard.
   1449     int32_t value =
   1450         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
   1451     CHECK(value > i::Smi::kMaxValue);
   1452     CHECK(!i::Smi::IsValid(value));
   1453 
   1454     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
   1455     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1456 
   1457     value_obj = v8::Integer::New(isolate, value);
   1458     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1459   }
   1460 }
   1461 
   1462 
   1463 THREADED_TEST(TinyUnsignedInteger) {
   1464   LocalContext env;
   1465   v8::HandleScope scope(env->GetIsolate());
   1466   v8::Isolate* isolate = CcTest::isolate();
   1467 
   1468   uint32_t value = 239;
   1469 
   1470   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1471   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1472 
   1473   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1474   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1475 }
   1476 
   1477 
   1478 THREADED_TEST(BigUnsignedSmiInteger) {
   1479   LocalContext env;
   1480   v8::HandleScope scope(env->GetIsolate());
   1481   v8::Isolate* isolate = CcTest::isolate();
   1482 
   1483   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
   1484   CHECK(i::Smi::IsValid(value));
   1485   CHECK(!i::Smi::IsValid(value + 1));
   1486 
   1487   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1488   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1489 
   1490   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1491   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1492 }
   1493 
   1494 
   1495 THREADED_TEST(BigUnsignedInteger) {
   1496   LocalContext env;
   1497   v8::HandleScope scope(env->GetIsolate());
   1498   v8::Isolate* isolate = CcTest::isolate();
   1499 
   1500   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
   1501   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
   1502   CHECK(!i::Smi::IsValid(value));
   1503 
   1504   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1505   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1506 
   1507   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1508   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1509 }
   1510 
   1511 
   1512 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
   1513   LocalContext env;
   1514   v8::HandleScope scope(env->GetIsolate());
   1515   v8::Isolate* isolate = CcTest::isolate();
   1516 
   1517   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
   1518   uint32_t value = INT32_MAX_AS_UINT + 1;
   1519   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
   1520 
   1521   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1522   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1523 
   1524   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
   1525   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
   1526 }
   1527 
   1528 
   1529 THREADED_TEST(IsNativeError) {
   1530   LocalContext env;
   1531   v8::HandleScope scope(env->GetIsolate());
   1532   v8::Handle<Value> syntax_error = CompileRun(
   1533       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
   1534   CHECK(syntax_error->IsNativeError());
   1535   v8::Handle<Value> not_error = CompileRun("{a:42}");
   1536   CHECK(!not_error->IsNativeError());
   1537   v8::Handle<Value> not_object = CompileRun("42");
   1538   CHECK(!not_object->IsNativeError());
   1539 }
   1540 
   1541 
   1542 THREADED_TEST(StringObject) {
   1543   LocalContext env;
   1544   v8::HandleScope scope(env->GetIsolate());
   1545   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
   1546   CHECK(boxed_string->IsStringObject());
   1547   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
   1548   CHECK(!unboxed_string->IsStringObject());
   1549   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
   1550   CHECK(!boxed_not_string->IsStringObject());
   1551   v8::Handle<Value> not_object = CompileRun("0");
   1552   CHECK(!not_object->IsStringObject());
   1553   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
   1554   CHECK(!as_boxed.IsEmpty());
   1555   Local<v8::String> the_string = as_boxed->ValueOf();
   1556   CHECK(!the_string.IsEmpty());
   1557   ExpectObject("\"test\"", the_string);
   1558   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
   1559   CHECK(new_boxed_string->IsStringObject());
   1560   as_boxed = new_boxed_string.As<v8::StringObject>();
   1561   the_string = as_boxed->ValueOf();
   1562   CHECK(!the_string.IsEmpty());
   1563   ExpectObject("\"test\"", the_string);
   1564 }
   1565 
   1566 
   1567 THREADED_TEST(NumberObject) {
   1568   LocalContext env;
   1569   v8::HandleScope scope(env->GetIsolate());
   1570   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
   1571   CHECK(boxed_number->IsNumberObject());
   1572   v8::Handle<Value> unboxed_number = CompileRun("42");
   1573   CHECK(!unboxed_number->IsNumberObject());
   1574   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
   1575   CHECK(!boxed_not_number->IsNumberObject());
   1576   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
   1577   CHECK(!as_boxed.IsEmpty());
   1578   double the_number = as_boxed->ValueOf();
   1579   CHECK_EQ(42.0, the_number);
   1580   v8::Handle<v8::Value> new_boxed_number =
   1581       v8::NumberObject::New(env->GetIsolate(), 43);
   1582   CHECK(new_boxed_number->IsNumberObject());
   1583   as_boxed = new_boxed_number.As<v8::NumberObject>();
   1584   the_number = as_boxed->ValueOf();
   1585   CHECK_EQ(43.0, the_number);
   1586 }
   1587 
   1588 
   1589 THREADED_TEST(BooleanObject) {
   1590   LocalContext env;
   1591   v8::HandleScope scope(env->GetIsolate());
   1592   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
   1593   CHECK(boxed_boolean->IsBooleanObject());
   1594   v8::Handle<Value> unboxed_boolean = CompileRun("true");
   1595   CHECK(!unboxed_boolean->IsBooleanObject());
   1596   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
   1597   CHECK(!boxed_not_boolean->IsBooleanObject());
   1598   v8::Handle<v8::BooleanObject> as_boxed =
   1599       boxed_boolean.As<v8::BooleanObject>();
   1600   CHECK(!as_boxed.IsEmpty());
   1601   bool the_boolean = as_boxed->ValueOf();
   1602   CHECK_EQ(true, the_boolean);
   1603   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
   1604   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
   1605   CHECK(boxed_true->IsBooleanObject());
   1606   CHECK(boxed_false->IsBooleanObject());
   1607   as_boxed = boxed_true.As<v8::BooleanObject>();
   1608   CHECK_EQ(true, as_boxed->ValueOf());
   1609   as_boxed = boxed_false.As<v8::BooleanObject>();
   1610   CHECK_EQ(false, as_boxed->ValueOf());
   1611 }
   1612 
   1613 
   1614 THREADED_TEST(PrimitiveAndWrappedBooleans) {
   1615   LocalContext env;
   1616   v8::HandleScope scope(env->GetIsolate());
   1617 
   1618   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
   1619   CHECK(primitive_false->IsBoolean());
   1620   CHECK(!primitive_false->IsBooleanObject());
   1621   CHECK(!primitive_false->BooleanValue());
   1622   CHECK(!primitive_false->IsTrue());
   1623   CHECK(primitive_false->IsFalse());
   1624 
   1625   Local<Value> false_value = BooleanObject::New(false);
   1626   CHECK(!false_value->IsBoolean());
   1627   CHECK(false_value->IsBooleanObject());
   1628   CHECK(false_value->BooleanValue());
   1629   CHECK(!false_value->IsTrue());
   1630   CHECK(!false_value->IsFalse());
   1631 
   1632   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
   1633   CHECK(!false_boolean_object->IsBoolean());
   1634   CHECK(false_boolean_object->IsBooleanObject());
   1635   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
   1636   // CHECK(false_boolean_object->BooleanValue());
   1637   CHECK(!false_boolean_object->ValueOf());
   1638   CHECK(!false_boolean_object->IsTrue());
   1639   CHECK(!false_boolean_object->IsFalse());
   1640 
   1641   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
   1642   CHECK(primitive_true->IsBoolean());
   1643   CHECK(!primitive_true->IsBooleanObject());
   1644   CHECK(primitive_true->BooleanValue());
   1645   CHECK(primitive_true->IsTrue());
   1646   CHECK(!primitive_true->IsFalse());
   1647 
   1648   Local<Value> true_value = BooleanObject::New(true);
   1649   CHECK(!true_value->IsBoolean());
   1650   CHECK(true_value->IsBooleanObject());
   1651   CHECK(true_value->BooleanValue());
   1652   CHECK(!true_value->IsTrue());
   1653   CHECK(!true_value->IsFalse());
   1654 
   1655   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
   1656   CHECK(!true_boolean_object->IsBoolean());
   1657   CHECK(true_boolean_object->IsBooleanObject());
   1658   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
   1659   // CHECK(true_boolean_object->BooleanValue());
   1660   CHECK(true_boolean_object->ValueOf());
   1661   CHECK(!true_boolean_object->IsTrue());
   1662   CHECK(!true_boolean_object->IsFalse());
   1663 }
   1664 
   1665 
   1666 THREADED_TEST(Number) {
   1667   LocalContext env;
   1668   v8::HandleScope scope(env->GetIsolate());
   1669   double PI = 3.1415926;
   1670   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
   1671   CHECK_EQ(PI, pi_obj->NumberValue());
   1672 }
   1673 
   1674 
   1675 THREADED_TEST(ToNumber) {
   1676   LocalContext env;
   1677   v8::Isolate* isolate = CcTest::isolate();
   1678   v8::HandleScope scope(isolate);
   1679   Local<String> str = v8_str("3.1415926");
   1680   CHECK_EQ(3.1415926, str->NumberValue());
   1681   v8::Handle<v8::Boolean> t = v8::True(isolate);
   1682   CHECK_EQ(1.0, t->NumberValue());
   1683   v8::Handle<v8::Boolean> f = v8::False(isolate);
   1684   CHECK_EQ(0.0, f->NumberValue());
   1685 }
   1686 
   1687 
   1688 THREADED_TEST(Date) {
   1689   LocalContext env;
   1690   v8::HandleScope scope(env->GetIsolate());
   1691   double PI = 3.1415926;
   1692   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
   1693   CHECK_EQ(3.0, date->NumberValue());
   1694   date.As<v8::Date>()->Set(v8_str("property"),
   1695                            v8::Integer::New(env->GetIsolate(), 42));
   1696   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
   1697 }
   1698 
   1699 
   1700 THREADED_TEST(Boolean) {
   1701   LocalContext env;
   1702   v8::Isolate* isolate = env->GetIsolate();
   1703   v8::HandleScope scope(isolate);
   1704   v8::Handle<v8::Boolean> t = v8::True(isolate);
   1705   CHECK(t->Value());
   1706   v8::Handle<v8::Boolean> f = v8::False(isolate);
   1707   CHECK(!f->Value());
   1708   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
   1709   CHECK(!u->BooleanValue());
   1710   v8::Handle<v8::Primitive> n = v8::Null(isolate);
   1711   CHECK(!n->BooleanValue());
   1712   v8::Handle<String> str1 = v8_str("");
   1713   CHECK(!str1->BooleanValue());
   1714   v8::Handle<String> str2 = v8_str("x");
   1715   CHECK(str2->BooleanValue());
   1716   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
   1717   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
   1718   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
   1719   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
   1720   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
   1721 }
   1722 
   1723 
   1724 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1725   ApiTestFuzzer::Fuzz();
   1726   args.GetReturnValue().Set(v8_num(13.4));
   1727 }
   1728 
   1729 
   1730 static void GetM(Local<String> name,
   1731                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   1732   ApiTestFuzzer::Fuzz();
   1733   info.GetReturnValue().Set(v8_num(876));
   1734 }
   1735 
   1736 
   1737 THREADED_TEST(GlobalPrototype) {
   1738   v8::Isolate* isolate = CcTest::isolate();
   1739   v8::HandleScope scope(isolate);
   1740   v8::Handle<v8::FunctionTemplate> func_templ =
   1741       v8::FunctionTemplate::New(isolate);
   1742   func_templ->PrototypeTemplate()->Set(
   1743       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
   1744   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
   1745   templ->Set(isolate, "x", v8_num(200));
   1746   templ->SetAccessor(v8_str("m"), GetM);
   1747   LocalContext env(0, templ);
   1748   v8::Handle<Script> script(v8_compile("dummy()"));
   1749   v8::Handle<Value> result(script->Run());
   1750   CHECK_EQ(13.4, result->NumberValue());
   1751   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
   1752   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
   1753 }
   1754 
   1755 
   1756 THREADED_TEST(ObjectTemplate) {
   1757   v8::Isolate* isolate = CcTest::isolate();
   1758   v8::HandleScope scope(isolate);
   1759   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
   1760   templ1->Set(isolate, "x", v8_num(10));
   1761   templ1->Set(isolate, "y", v8_num(13));
   1762   LocalContext env;
   1763   Local<v8::Object> instance1 = templ1->NewInstance();
   1764   env->Global()->Set(v8_str("p"), instance1);
   1765   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
   1766   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
   1767   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
   1768   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
   1769   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
   1770   templ2->Set(isolate, "a", v8_num(12));
   1771   templ2->Set(isolate, "b", templ1);
   1772   Local<v8::Object> instance2 = templ2->NewInstance();
   1773   env->Global()->Set(v8_str("q"), instance2);
   1774   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
   1775   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
   1776   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
   1777   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
   1778 }
   1779 
   1780 
   1781 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
   1782   ApiTestFuzzer::Fuzz();
   1783   args.GetReturnValue().Set(v8_num(17.2));
   1784 }
   1785 
   1786 
   1787 static void GetKnurd(Local<String> property,
   1788                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   1789   ApiTestFuzzer::Fuzz();
   1790   info.GetReturnValue().Set(v8_num(15.2));
   1791 }
   1792 
   1793 
   1794 THREADED_TEST(DescriptorInheritance) {
   1795   v8::Isolate* isolate = CcTest::isolate();
   1796   v8::HandleScope scope(isolate);
   1797   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
   1798   super->PrototypeTemplate()->Set(isolate, "flabby",
   1799                                   v8::FunctionTemplate::New(isolate,
   1800                                                             GetFlabby));
   1801   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
   1802 
   1803   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
   1804 
   1805   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
   1806   base1->Inherit(super);
   1807   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
   1808 
   1809   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
   1810   base2->Inherit(super);
   1811   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
   1812 
   1813   LocalContext env;
   1814 
   1815   env->Global()->Set(v8_str("s"), super->GetFunction());
   1816   env->Global()->Set(v8_str("base1"), base1->GetFunction());
   1817   env->Global()->Set(v8_str("base2"), base2->GetFunction());
   1818 
   1819   // Checks right __proto__ chain.
   1820   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
   1821   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
   1822 
   1823   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
   1824 
   1825   // Instance accessor should not be visible on function object or its prototype
   1826   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
   1827   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
   1828   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
   1829 
   1830   env->Global()->Set(v8_str("obj"),
   1831                      base1->GetFunction()->NewInstance());
   1832   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
   1833   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
   1834   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
   1835   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
   1836   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
   1837 
   1838   env->Global()->Set(v8_str("obj2"),
   1839                      base2->GetFunction()->NewInstance());
   1840   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
   1841   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
   1842   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
   1843   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
   1844   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
   1845 
   1846   // base1 and base2 cannot cross reference to each's prototype
   1847   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
   1848   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
   1849 }
   1850 
   1851 
   1852 int echo_named_call_count;
   1853 
   1854 
   1855 static void EchoNamedProperty(Local<String> name,
   1856                               const v8::PropertyCallbackInfo<v8::Value>& info) {
   1857   ApiTestFuzzer::Fuzz();
   1858   CHECK_EQ(v8_str("data"), info.Data());
   1859   echo_named_call_count++;
   1860   info.GetReturnValue().Set(name);
   1861 }
   1862 
   1863 
   1864 // Helper functions for Interceptor/Accessor interaction tests
   1865 
   1866 void SimpleAccessorGetter(Local<String> name,
   1867                           const v8::PropertyCallbackInfo<v8::Value>& info) {
   1868   Handle<Object> self = Handle<Object>::Cast(info.This());
   1869   info.GetReturnValue().Set(
   1870       self->Get(String::Concat(v8_str("accessor_"), name)));
   1871 }
   1872 
   1873 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
   1874                           const v8::PropertyCallbackInfo<void>& info) {
   1875   Handle<Object> self = Handle<Object>::Cast(info.This());
   1876   self->Set(String::Concat(v8_str("accessor_"), name), value);
   1877 }
   1878 
   1879 void EmptyInterceptorGetter(Local<String> name,
   1880                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   1881 }
   1882 
   1883 void EmptyInterceptorSetter(Local<String> name,
   1884                             Local<Value> value,
   1885                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   1886 }
   1887 
   1888 void InterceptorGetter(Local<String> name,
   1889                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   1890   // Intercept names that start with 'interceptor_'.
   1891   String::Utf8Value utf8(name);
   1892   char* name_str = *utf8;
   1893   char prefix[] = "interceptor_";
   1894   int i;
   1895   for (i = 0; name_str[i] && prefix[i]; ++i) {
   1896     if (name_str[i] != prefix[i]) return;
   1897   }
   1898   Handle<Object> self = Handle<Object>::Cast(info.This());
   1899   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
   1900 }
   1901 
   1902 void InterceptorSetter(Local<String> name,
   1903                        Local<Value> value,
   1904                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   1905   // Intercept accesses that set certain integer values, for which the name does
   1906   // not start with 'accessor_'.
   1907   String::Utf8Value utf8(name);
   1908   char* name_str = *utf8;
   1909   char prefix[] = "accessor_";
   1910   int i;
   1911   for (i = 0; name_str[i] && prefix[i]; ++i) {
   1912     if (name_str[i] != prefix[i]) break;
   1913   }
   1914   if (!prefix[i]) return;
   1915 
   1916   if (value->IsInt32() && value->Int32Value() < 10000) {
   1917     Handle<Object> self = Handle<Object>::Cast(info.This());
   1918     self->SetHiddenValue(name, value);
   1919     info.GetReturnValue().Set(value);
   1920   }
   1921 }
   1922 
   1923 void AddAccessor(Handle<FunctionTemplate> templ,
   1924                  Handle<String> name,
   1925                  v8::AccessorGetterCallback getter,
   1926                  v8::AccessorSetterCallback setter) {
   1927   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
   1928 }
   1929 
   1930 void AddInterceptor(Handle<FunctionTemplate> templ,
   1931                     v8::NamedPropertyGetterCallback getter,
   1932                     v8::NamedPropertySetterCallback setter) {
   1933   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
   1934 }
   1935 
   1936 
   1937 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   1938   v8::HandleScope scope(CcTest::isolate());
   1939   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   1940   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   1941   child->Inherit(parent);
   1942   AddAccessor(parent, v8_str("age"),
   1943               SimpleAccessorGetter, SimpleAccessorSetter);
   1944   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   1945   LocalContext env;
   1946   env->Global()->Set(v8_str("Child"), child->GetFunction());
   1947   CompileRun("var child = new Child;"
   1948              "child.age = 10;");
   1949   ExpectBoolean("child.hasOwnProperty('age')", false);
   1950   ExpectInt32("child.age", 10);
   1951   ExpectInt32("child.accessor_age", 10);
   1952 }
   1953 
   1954 
   1955 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
   1956   v8::Isolate* isolate = CcTest::isolate();
   1957   v8::HandleScope scope(isolate);
   1958   LocalContext env;
   1959   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
   1960   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
   1961   CHECK(a->map()->instance_descriptors()->IsFixedArray());
   1962   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
   1963   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
   1964   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
   1965   // But we should still have an ExecutableAccessorInfo.
   1966   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   1967   i::LookupResult lookup(i_isolate);
   1968   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
   1969   a->LookupOwnRealNamedProperty(name, &lookup);
   1970   CHECK(lookup.IsPropertyCallbacks());
   1971   i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate);
   1972   CHECK(callback->IsExecutableAccessorInfo());
   1973 }
   1974 
   1975 
   1976 THREADED_TEST(EmptyInterceptorBreakTransitions) {
   1977   v8::HandleScope scope(CcTest::isolate());
   1978   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   1979   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
   1980   LocalContext env;
   1981   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
   1982   CompileRun("var o1 = new Constructor;"
   1983              "o1.a = 1;"  // Ensure a and x share the descriptor array.
   1984              "Object.defineProperty(o1, 'x', {value: 10});");
   1985   CompileRun("var o2 = new Constructor;"
   1986              "o2.a = 1;"
   1987              "Object.defineProperty(o2, 'x', {value: 10});");
   1988 }
   1989 
   1990 
   1991 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
   1992   v8::Isolate* isolate = CcTest::isolate();
   1993   v8::HandleScope scope(isolate);
   1994   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
   1995   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
   1996   child->Inherit(parent);
   1997   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   1998   LocalContext env;
   1999   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2000   CompileRun("var child = new Child;"
   2001              "var parent = child.__proto__;"
   2002              "Object.defineProperty(parent, 'age', "
   2003              "  {get: function(){ return this.accessor_age; }, "
   2004              "   set: function(v){ this.accessor_age = v; }, "
   2005              "   enumerable: true, configurable: true});"
   2006              "child.age = 10;");
   2007   ExpectBoolean("child.hasOwnProperty('age')", false);
   2008   ExpectInt32("child.age", 10);
   2009   ExpectInt32("child.accessor_age", 10);
   2010 }
   2011 
   2012 
   2013 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
   2014   v8::Isolate* isolate = CcTest::isolate();
   2015   v8::HandleScope scope(isolate);
   2016   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
   2017   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
   2018   child->Inherit(parent);
   2019   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
   2020   LocalContext env;
   2021   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2022   CompileRun("var child = new Child;"
   2023              "var parent = child.__proto__;"
   2024              "parent.name = 'Alice';");
   2025   ExpectBoolean("child.hasOwnProperty('name')", false);
   2026   ExpectString("child.name", "Alice");
   2027   CompileRun("child.name = 'Bob';");
   2028   ExpectString("child.name", "Bob");
   2029   ExpectBoolean("child.hasOwnProperty('name')", true);
   2030   ExpectString("parent.name", "Alice");
   2031 }
   2032 
   2033 
   2034 THREADED_TEST(SwitchFromInterceptorToAccessor) {
   2035   v8::HandleScope scope(CcTest::isolate());
   2036   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2037   AddAccessor(templ, v8_str("age"),
   2038               SimpleAccessorGetter, SimpleAccessorSetter);
   2039   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2040   LocalContext env;
   2041   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2042   CompileRun("var obj = new Obj;"
   2043              "function setAge(i){ obj.age = i; };"
   2044              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2045   // All i < 10000 go to the interceptor.
   2046   ExpectInt32("obj.interceptor_age", 9999);
   2047   // The last i goes to the accessor.
   2048   ExpectInt32("obj.accessor_age", 10000);
   2049 }
   2050 
   2051 
   2052 THREADED_TEST(SwitchFromAccessorToInterceptor) {
   2053   v8::HandleScope scope(CcTest::isolate());
   2054   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2055   AddAccessor(templ, v8_str("age"),
   2056               SimpleAccessorGetter, SimpleAccessorSetter);
   2057   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2058   LocalContext env;
   2059   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2060   CompileRun("var obj = new Obj;"
   2061              "function setAge(i){ obj.age = i; };"
   2062              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2063   // All i >= 10000 go to the accessor.
   2064   ExpectInt32("obj.accessor_age", 10000);
   2065   // The last i goes to the interceptor.
   2066   ExpectInt32("obj.interceptor_age", 9999);
   2067 }
   2068 
   2069 
   2070 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
   2071   v8::HandleScope scope(CcTest::isolate());
   2072   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2073   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2074   child->Inherit(parent);
   2075   AddAccessor(parent, v8_str("age"),
   2076               SimpleAccessorGetter, SimpleAccessorSetter);
   2077   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2078   LocalContext env;
   2079   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2080   CompileRun("var child = new Child;"
   2081              "function setAge(i){ child.age = i; };"
   2082              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2083   // All i < 10000 go to the interceptor.
   2084   ExpectInt32("child.interceptor_age", 9999);
   2085   // The last i goes to the accessor.
   2086   ExpectInt32("child.accessor_age", 10000);
   2087 }
   2088 
   2089 
   2090 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
   2091   v8::HandleScope scope(CcTest::isolate());
   2092   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2093   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2094   child->Inherit(parent);
   2095   AddAccessor(parent, v8_str("age"),
   2096               SimpleAccessorGetter, SimpleAccessorSetter);
   2097   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2098   LocalContext env;
   2099   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2100   CompileRun("var child = new Child;"
   2101              "function setAge(i){ child.age = i; };"
   2102              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2103   // All i >= 10000 go to the accessor.
   2104   ExpectInt32("child.accessor_age", 10000);
   2105   // The last i goes to the interceptor.
   2106   ExpectInt32("child.interceptor_age", 9999);
   2107 }
   2108 
   2109 
   2110 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
   2111   v8::HandleScope scope(CcTest::isolate());
   2112   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2113   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2114   LocalContext env;
   2115   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2116   CompileRun("var obj = new Obj;"
   2117              "function setter(i) { this.accessor_age = i; };"
   2118              "function getter() { return this.accessor_age; };"
   2119              "function setAge(i) { obj.age = i; };"
   2120              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   2121              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2122   // All i < 10000 go to the interceptor.
   2123   ExpectInt32("obj.interceptor_age", 9999);
   2124   // The last i goes to the JavaScript accessor.
   2125   ExpectInt32("obj.accessor_age", 10000);
   2126   // The installed JavaScript getter is still intact.
   2127   // This last part is a regression test for issue 1651 and relies on the fact
   2128   // that both interceptor and accessor are being installed on the same object.
   2129   ExpectInt32("obj.age", 10000);
   2130   ExpectBoolean("obj.hasOwnProperty('age')", true);
   2131   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
   2132 }
   2133 
   2134 
   2135 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
   2136   v8::HandleScope scope(CcTest::isolate());
   2137   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   2138   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   2139   LocalContext env;
   2140   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   2141   CompileRun("var obj = new Obj;"
   2142              "function setter(i) { this.accessor_age = i; };"
   2143              "function getter() { return this.accessor_age; };"
   2144              "function setAge(i) { obj.age = i; };"
   2145              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   2146              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2147   // All i >= 10000 go to the accessor.
   2148   ExpectInt32("obj.accessor_age", 10000);
   2149   // The last i goes to the interceptor.
   2150   ExpectInt32("obj.interceptor_age", 9999);
   2151   // The installed JavaScript getter is still intact.
   2152   // This last part is a regression test for issue 1651 and relies on the fact
   2153   // that both interceptor and accessor are being installed on the same object.
   2154   ExpectInt32("obj.age", 10000);
   2155   ExpectBoolean("obj.hasOwnProperty('age')", true);
   2156   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
   2157 }
   2158 
   2159 
   2160 THREADED_TEST(SwitchFromInterceptorToProperty) {
   2161   v8::HandleScope scope(CcTest::isolate());
   2162   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2163   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2164   child->Inherit(parent);
   2165   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2166   LocalContext env;
   2167   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2168   CompileRun("var child = new Child;"
   2169              "function setAge(i){ child.age = i; };"
   2170              "for(var i = 0; i <= 10000; i++) setAge(i);");
   2171   // All i < 10000 go to the interceptor.
   2172   ExpectInt32("child.interceptor_age", 9999);
   2173   // The last i goes to child's own property.
   2174   ExpectInt32("child.age", 10000);
   2175 }
   2176 
   2177 
   2178 THREADED_TEST(SwitchFromPropertyToInterceptor) {
   2179   v8::HandleScope scope(CcTest::isolate());
   2180   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
   2181   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   2182   child->Inherit(parent);
   2183   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
   2184   LocalContext env;
   2185   env->Global()->Set(v8_str("Child"), child->GetFunction());
   2186   CompileRun("var child = new Child;"
   2187              "function setAge(i){ child.age = i; };"
   2188              "for(var i = 20000; i >= 9999; i--) setAge(i);");
   2189   // All i >= 10000 go to child's own property.
   2190   ExpectInt32("child.age", 10000);
   2191   // The last i goes to the interceptor.
   2192   ExpectInt32("child.interceptor_age", 9999);
   2193 }
   2194 
   2195 
   2196 THREADED_TEST(NamedPropertyHandlerGetter) {
   2197   echo_named_call_count = 0;
   2198   v8::HandleScope scope(CcTest::isolate());
   2199   v8::Handle<v8::FunctionTemplate> templ =
   2200       v8::FunctionTemplate::New(CcTest::isolate());
   2201   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
   2202                                                      0, 0, 0, 0,
   2203                                                      v8_str("data"));
   2204   LocalContext env;
   2205   env->Global()->Set(v8_str("obj"),
   2206                      templ->GetFunction()->NewInstance());
   2207   CHECK_EQ(echo_named_call_count, 0);
   2208   v8_compile("obj.x")->Run();
   2209   CHECK_EQ(echo_named_call_count, 1);
   2210   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
   2211   v8::Handle<Value> str = CompileRun(code);
   2212   String::Utf8Value value(str);
   2213   CHECK_EQ(*value, "oddlepoddle");
   2214   // Check default behavior
   2215   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
   2216   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
   2217   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
   2218 }
   2219 
   2220 
   2221 int echo_indexed_call_count = 0;
   2222 
   2223 
   2224 static void EchoIndexedProperty(
   2225     uint32_t index,
   2226     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2227   ApiTestFuzzer::Fuzz();
   2228   CHECK_EQ(v8_num(637), info.Data());
   2229   echo_indexed_call_count++;
   2230   info.GetReturnValue().Set(v8_num(index));
   2231 }
   2232 
   2233 
   2234 THREADED_TEST(IndexedPropertyHandlerGetter) {
   2235   v8::Isolate* isolate = CcTest::isolate();
   2236   v8::HandleScope scope(isolate);
   2237   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2238   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
   2239                                                        0, 0, 0, 0,
   2240                                                        v8_num(637));
   2241   LocalContext env;
   2242   env->Global()->Set(v8_str("obj"),
   2243                      templ->GetFunction()->NewInstance());
   2244   Local<Script> script = v8_compile("obj[900]");
   2245   CHECK_EQ(script->Run()->Int32Value(), 900);
   2246 }
   2247 
   2248 
   2249 v8::Handle<v8::Object> bottom;
   2250 
   2251 static void CheckThisIndexedPropertyHandler(
   2252     uint32_t index,
   2253     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2254   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
   2255   ApiTestFuzzer::Fuzz();
   2256   CHECK(info.This()->Equals(bottom));
   2257 }
   2258 
   2259 static void CheckThisNamedPropertyHandler(
   2260     Local<String> name,
   2261     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2262   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
   2263   ApiTestFuzzer::Fuzz();
   2264   CHECK(info.This()->Equals(bottom));
   2265 }
   2266 
   2267 void CheckThisIndexedPropertySetter(
   2268     uint32_t index,
   2269     Local<Value> value,
   2270     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2271   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
   2272   ApiTestFuzzer::Fuzz();
   2273   CHECK(info.This()->Equals(bottom));
   2274 }
   2275 
   2276 
   2277 void CheckThisNamedPropertySetter(
   2278     Local<String> property,
   2279     Local<Value> value,
   2280     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2281   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
   2282   ApiTestFuzzer::Fuzz();
   2283   CHECK(info.This()->Equals(bottom));
   2284 }
   2285 
   2286 void CheckThisIndexedPropertyQuery(
   2287     uint32_t index,
   2288     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   2289   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
   2290   ApiTestFuzzer::Fuzz();
   2291   CHECK(info.This()->Equals(bottom));
   2292 }
   2293 
   2294 
   2295 void CheckThisNamedPropertyQuery(
   2296     Local<String> property,
   2297     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   2298   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
   2299   ApiTestFuzzer::Fuzz();
   2300   CHECK(info.This()->Equals(bottom));
   2301 }
   2302 
   2303 
   2304 void CheckThisIndexedPropertyDeleter(
   2305     uint32_t index,
   2306     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   2307   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
   2308   ApiTestFuzzer::Fuzz();
   2309   CHECK(info.This()->Equals(bottom));
   2310 }
   2311 
   2312 
   2313 void CheckThisNamedPropertyDeleter(
   2314     Local<String> property,
   2315     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   2316   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
   2317   ApiTestFuzzer::Fuzz();
   2318   CHECK(info.This()->Equals(bottom));
   2319 }
   2320 
   2321 
   2322 void CheckThisIndexedPropertyEnumerator(
   2323     const v8::PropertyCallbackInfo<v8::Array>& info) {
   2324   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
   2325   ApiTestFuzzer::Fuzz();
   2326   CHECK(info.This()->Equals(bottom));
   2327 }
   2328 
   2329 
   2330 void CheckThisNamedPropertyEnumerator(
   2331     const v8::PropertyCallbackInfo<v8::Array>& info) {
   2332   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
   2333   ApiTestFuzzer::Fuzz();
   2334   CHECK(info.This()->Equals(bottom));
   2335 }
   2336 
   2337 
   2338 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
   2339   LocalContext env;
   2340   v8::Isolate* isolate = env->GetIsolate();
   2341   v8::HandleScope scope(isolate);
   2342 
   2343   // Set up a prototype chain with three interceptors.
   2344   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2345   templ->InstanceTemplate()->SetIndexedPropertyHandler(
   2346       CheckThisIndexedPropertyHandler,
   2347       CheckThisIndexedPropertySetter,
   2348       CheckThisIndexedPropertyQuery,
   2349       CheckThisIndexedPropertyDeleter,
   2350       CheckThisIndexedPropertyEnumerator);
   2351 
   2352   templ->InstanceTemplate()->SetNamedPropertyHandler(
   2353       CheckThisNamedPropertyHandler,
   2354       CheckThisNamedPropertySetter,
   2355       CheckThisNamedPropertyQuery,
   2356       CheckThisNamedPropertyDeleter,
   2357       CheckThisNamedPropertyEnumerator);
   2358 
   2359   bottom = templ->GetFunction()->NewInstance();
   2360   Local<v8::Object> top = templ->GetFunction()->NewInstance();
   2361   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
   2362 
   2363   bottom->SetPrototype(middle);
   2364   middle->SetPrototype(top);
   2365   env->Global()->Set(v8_str("obj"), bottom);
   2366 
   2367   // Indexed and named get.
   2368   CompileRun("obj[0]");
   2369   CompileRun("obj.x");
   2370 
   2371   // Indexed and named set.
   2372   CompileRun("obj[1] = 42");
   2373   CompileRun("obj.y = 42");
   2374 
   2375   // Indexed and named query.
   2376   CompileRun("0 in obj");
   2377   CompileRun("'x' in obj");
   2378 
   2379   // Indexed and named deleter.
   2380   CompileRun("delete obj[0]");
   2381   CompileRun("delete obj.x");
   2382 
   2383   // Enumerators.
   2384   CompileRun("for (var p in obj) ;");
   2385 }
   2386 
   2387 
   2388 static void PrePropertyHandlerGet(
   2389     Local<String> key,
   2390     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2391   ApiTestFuzzer::Fuzz();
   2392   if (v8_str("pre")->Equals(key)) {
   2393     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
   2394   }
   2395 }
   2396 
   2397 
   2398 static void PrePropertyHandlerQuery(
   2399     Local<String> key,
   2400     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   2401   if (v8_str("pre")->Equals(key)) {
   2402     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
   2403   }
   2404 }
   2405 
   2406 
   2407 THREADED_TEST(PrePropertyHandler) {
   2408   v8::Isolate* isolate = CcTest::isolate();
   2409   v8::HandleScope scope(isolate);
   2410   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
   2411   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
   2412                                                     0,
   2413                                                     PrePropertyHandlerQuery);
   2414   LocalContext env(NULL, desc->InstanceTemplate());
   2415   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
   2416   v8::Handle<Value> result_pre = CompileRun("pre");
   2417   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
   2418   v8::Handle<Value> result_on = CompileRun("on");
   2419   CHECK_EQ(v8_str("Object: on"), result_on);
   2420   v8::Handle<Value> result_post = CompileRun("post");
   2421   CHECK(result_post.IsEmpty());
   2422 }
   2423 
   2424 
   2425 THREADED_TEST(UndefinedIsNotEnumerable) {
   2426   LocalContext env;
   2427   v8::HandleScope scope(env->GetIsolate());
   2428   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
   2429   CHECK(result->IsFalse());
   2430 }
   2431 
   2432 
   2433 v8::Handle<Script> call_recursively_script;
   2434 static const int kTargetRecursionDepth = 200;  // near maximum
   2435 
   2436 
   2437 static void CallScriptRecursivelyCall(
   2438     const v8::FunctionCallbackInfo<v8::Value>& args) {
   2439   ApiTestFuzzer::Fuzz();
   2440   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   2441   if (depth == kTargetRecursionDepth) return;
   2442   args.This()->Set(v8_str("depth"),
   2443                    v8::Integer::New(args.GetIsolate(), depth + 1));
   2444   args.GetReturnValue().Set(call_recursively_script->Run());
   2445 }
   2446 
   2447 
   2448 static void CallFunctionRecursivelyCall(
   2449     const v8::FunctionCallbackInfo<v8::Value>& args) {
   2450   ApiTestFuzzer::Fuzz();
   2451   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
   2452   if (depth == kTargetRecursionDepth) {
   2453     printf("[depth = %d]\n", depth);
   2454     return;
   2455   }
   2456   args.This()->Set(v8_str("depth"),
   2457                    v8::Integer::New(args.GetIsolate(), depth + 1));
   2458   v8::Handle<Value> function =
   2459       args.This()->Get(v8_str("callFunctionRecursively"));
   2460   args.GetReturnValue().Set(
   2461       function.As<Function>()->Call(args.This(), 0, NULL));
   2462 }
   2463 
   2464 
   2465 THREADED_TEST(DeepCrossLanguageRecursion) {
   2466   v8::Isolate* isolate = CcTest::isolate();
   2467   v8::HandleScope scope(isolate);
   2468   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
   2469   global->Set(v8_str("callScriptRecursively"),
   2470               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
   2471   global->Set(v8_str("callFunctionRecursively"),
   2472               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
   2473   LocalContext env(NULL, global);
   2474 
   2475   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
   2476   call_recursively_script = v8_compile("callScriptRecursively()");
   2477   call_recursively_script->Run();
   2478   call_recursively_script = v8::Handle<Script>();
   2479 
   2480   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
   2481   CompileRun("callFunctionRecursively()");
   2482 }
   2483 
   2484 
   2485 static void ThrowingPropertyHandlerGet(
   2486     Local<String> key,
   2487     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2488   ApiTestFuzzer::Fuzz();
   2489   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
   2490 }
   2491 
   2492 
   2493 static void ThrowingPropertyHandlerSet(
   2494     Local<String> key,
   2495     Local<Value>,
   2496     const v8::PropertyCallbackInfo<v8::Value>& info) {
   2497   info.GetIsolate()->ThrowException(key);
   2498   info.GetReturnValue().SetUndefined();  // not the same as empty handle
   2499 }
   2500 
   2501 
   2502 THREADED_TEST(CallbackExceptionRegression) {
   2503   v8::Isolate* isolate = CcTest::isolate();
   2504   v8::HandleScope scope(isolate);
   2505   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   2506   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
   2507                                ThrowingPropertyHandlerSet);
   2508   LocalContext env;
   2509   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   2510   v8::Handle<Value> otto = CompileRun(
   2511       "try { with (obj) { otto; } } catch (e) { e; }");
   2512   CHECK_EQ(v8_str("otto"), otto);
   2513   v8::Handle<Value> netto = CompileRun(
   2514       "try { with (obj) { netto = 4; } } catch (e) { e; }");
   2515   CHECK_EQ(v8_str("netto"), netto);
   2516 }
   2517 
   2518 
   2519 THREADED_TEST(FunctionPrototype) {
   2520   v8::Isolate* isolate = CcTest::isolate();
   2521   v8::HandleScope scope(isolate);
   2522   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
   2523   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
   2524   LocalContext env;
   2525   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
   2526   Local<Script> script = v8_compile("Foo.prototype.plak");
   2527   CHECK_EQ(script->Run()->Int32Value(), 321);
   2528 }
   2529 
   2530 
   2531 THREADED_TEST(InternalFields) {
   2532   LocalContext env;
   2533   v8::Isolate* isolate = env->GetIsolate();
   2534   v8::HandleScope scope(isolate);
   2535 
   2536   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2537   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   2538   instance_templ->SetInternalFieldCount(1);
   2539   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   2540   CHECK_EQ(1, obj->InternalFieldCount());
   2541   CHECK(obj->GetInternalField(0)->IsUndefined());
   2542   obj->SetInternalField(0, v8_num(17));
   2543   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
   2544 }
   2545 
   2546 
   2547 THREADED_TEST(GlobalObjectInternalFields) {
   2548   v8::Isolate* isolate = CcTest::isolate();
   2549   v8::HandleScope scope(isolate);
   2550   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
   2551   global_template->SetInternalFieldCount(1);
   2552   LocalContext env(NULL, global_template);
   2553   v8::Handle<v8::Object> global_proxy = env->Global();
   2554   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
   2555   CHECK_EQ(1, global->InternalFieldCount());
   2556   CHECK(global->GetInternalField(0)->IsUndefined());
   2557   global->SetInternalField(0, v8_num(17));
   2558   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
   2559 }
   2560 
   2561 
   2562 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
   2563   LocalContext env;
   2564   v8::HandleScope scope(CcTest::isolate());
   2565 
   2566   v8::Local<v8::Object> global = env->Global();
   2567   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
   2568   CHECK(global->HasRealIndexedProperty(0));
   2569 }
   2570 
   2571 
   2572 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
   2573                                                void* value) {
   2574   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
   2575   obj->SetAlignedPointerInInternalField(0, value);
   2576   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2577   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
   2578 }
   2579 
   2580 
   2581 THREADED_TEST(InternalFieldsAlignedPointers) {
   2582   LocalContext env;
   2583   v8::Isolate* isolate = env->GetIsolate();
   2584   v8::HandleScope scope(isolate);
   2585 
   2586   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   2587   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
   2588   instance_templ->SetInternalFieldCount(1);
   2589   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
   2590   CHECK_EQ(1, obj->InternalFieldCount());
   2591 
   2592   CheckAlignedPointerInInternalField(obj, NULL);
   2593 
   2594   int* heap_allocated = new int[100];
   2595   CheckAlignedPointerInInternalField(obj, heap_allocated);
   2596   delete[] heap_allocated;
   2597 
   2598   int stack_allocated[100];
   2599   CheckAlignedPointerInInternalField(obj, stack_allocated);
   2600 
   2601   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   2602   CheckAlignedPointerInInternalField(obj, huge);
   2603 
   2604   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
   2605   CHECK_EQ(1, Object::InternalFieldCount(persistent));
   2606   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
   2607 }
   2608 
   2609 
   2610 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
   2611                                               int index,
   2612                                               void* value) {
   2613   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
   2614   (*env)->SetAlignedPointerInEmbedderData(index, value);
   2615   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2616   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
   2617 }
   2618 
   2619 
   2620 static void* AlignedTestPointer(int i) {
   2621   return reinterpret_cast<void*>(i * 1234);
   2622 }
   2623 
   2624 
   2625 THREADED_TEST(EmbedderDataAlignedPointers) {
   2626   LocalContext env;
   2627   v8::HandleScope scope(env->GetIsolate());
   2628 
   2629   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
   2630 
   2631   int* heap_allocated = new int[100];
   2632   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
   2633   delete[] heap_allocated;
   2634 
   2635   int stack_allocated[100];
   2636   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
   2637 
   2638   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
   2639   CheckAlignedPointerInEmbedderData(&env, 3, huge);
   2640 
   2641   // Test growing of the embedder data's backing store.
   2642   for (int i = 0; i < 100; i++) {
   2643     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
   2644   }
   2645   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2646   for (int i = 0; i < 100; i++) {
   2647     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
   2648   }
   2649 }
   2650 
   2651 
   2652 static void CheckEmbedderData(LocalContext* env,
   2653                               int index,
   2654                               v8::Handle<Value> data) {
   2655   (*env)->SetEmbedderData(index, data);
   2656   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
   2657 }
   2658 
   2659 
   2660 THREADED_TEST(EmbedderData) {
   2661   LocalContext env;
   2662   v8::Isolate* isolate = env->GetIsolate();
   2663   v8::HandleScope scope(isolate);
   2664 
   2665   CheckEmbedderData(
   2666       &env, 3,
   2667       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
   2668   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
   2669                                                      "over the lazy dog."));
   2670   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
   2671   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
   2672 }
   2673 
   2674 
   2675 THREADED_TEST(IdentityHash) {
   2676   LocalContext env;
   2677   v8::Isolate* isolate = env->GetIsolate();
   2678   v8::HandleScope scope(isolate);
   2679 
   2680   // Ensure that the test starts with an fresh heap to test whether the hash
   2681   // code is based on the address.
   2682   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2683   Local<v8::Object> obj = v8::Object::New(isolate);
   2684   int hash = obj->GetIdentityHash();
   2685   int hash1 = obj->GetIdentityHash();
   2686   CHECK_EQ(hash, hash1);
   2687   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
   2688   // Since the identity hash is essentially a random number two consecutive
   2689   // objects should not be assigned the same hash code. If the test below fails
   2690   // the random number generator should be evaluated.
   2691   CHECK_NE(hash, hash2);
   2692   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2693   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
   2694   // Make sure that the identity hash is not based on the initial address of
   2695   // the object alone. If the test below fails the random number generator
   2696   // should be evaluated.
   2697   CHECK_NE(hash, hash3);
   2698   int hash4 = obj->GetIdentityHash();
   2699   CHECK_EQ(hash, hash4);
   2700 
   2701   // Check identity hashes behaviour in the presence of JS accessors.
   2702   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
   2703   {
   2704     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
   2705     Local<v8::Object> o1 = v8::Object::New(isolate);
   2706     Local<v8::Object> o2 = v8::Object::New(isolate);
   2707     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2708   }
   2709   {
   2710     CompileRun(
   2711         "function cnst() { return 42; };\n"
   2712         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
   2713     Local<v8::Object> o1 = v8::Object::New(isolate);
   2714     Local<v8::Object> o2 = v8::Object::New(isolate);
   2715     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
   2716   }
   2717 }
   2718 
   2719 
   2720 THREADED_TEST(GlobalProxyIdentityHash) {
   2721   LocalContext env;
   2722   v8::Isolate* isolate = env->GetIsolate();
   2723   v8::HandleScope scope(isolate);
   2724   Handle<Object> global_proxy = env->Global();
   2725   int hash1 = global_proxy->GetIdentityHash();
   2726   // Hash should be retained after being detached.
   2727   env->DetachGlobal();
   2728   int hash2 = global_proxy->GetIdentityHash();
   2729   CHECK_EQ(hash1, hash2);
   2730   {
   2731     // Re-attach global proxy to a new context, hash should stay the same.
   2732     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
   2733     int hash3 = global_proxy->GetIdentityHash();
   2734     CHECK_EQ(hash1, hash3);
   2735   }
   2736 }
   2737 
   2738 
   2739 THREADED_TEST(SymbolProperties) {
   2740   i::FLAG_harmony_symbols = true;
   2741 
   2742   LocalContext env;
   2743   v8::Isolate* isolate = env->GetIsolate();
   2744   v8::HandleScope scope(isolate);
   2745 
   2746   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   2747   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
   2748   v8::Local<v8::Symbol> sym2 =
   2749       v8::Symbol::New(isolate, v8_str("my-symbol"));
   2750 
   2751   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2752 
   2753   // Check basic symbol functionality.
   2754   CHECK(sym1->IsSymbol());
   2755   CHECK(sym2->IsSymbol());
   2756   CHECK(!obj->IsSymbol());
   2757 
   2758   CHECK(sym1->Equals(sym1));
   2759   CHECK(sym2->Equals(sym2));
   2760   CHECK(!sym1->Equals(sym2));
   2761   CHECK(!sym2->Equals(sym1));
   2762   CHECK(sym1->StrictEquals(sym1));
   2763   CHECK(sym2->StrictEquals(sym2));
   2764   CHECK(!sym1->StrictEquals(sym2));
   2765   CHECK(!sym2->StrictEquals(sym1));
   2766 
   2767   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
   2768 
   2769   v8::Local<v8::Value> sym_val = sym2;
   2770   CHECK(sym_val->IsSymbol());
   2771   CHECK(sym_val->Equals(sym2));
   2772   CHECK(sym_val->StrictEquals(sym2));
   2773   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
   2774 
   2775   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
   2776   CHECK(sym_obj->IsSymbolObject());
   2777   CHECK(!sym2->IsSymbolObject());
   2778   CHECK(!obj->IsSymbolObject());
   2779   CHECK(!sym_obj->Equals(sym2));
   2780   CHECK(!sym_obj->StrictEquals(sym2));
   2781   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
   2782   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
   2783 
   2784   // Make sure delete of a non-existent symbol property works.
   2785   CHECK(obj->Delete(sym1));
   2786   CHECK(!obj->Has(sym1));
   2787 
   2788   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
   2789   CHECK(obj->Has(sym1));
   2790   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
   2791   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
   2792   CHECK(obj->Has(sym1));
   2793   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2794   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
   2795 
   2796   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
   2797   int num_props = obj->GetPropertyNames()->Length();
   2798   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
   2799                  v8::Integer::New(isolate, 20)));
   2800   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2801   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
   2802 
   2803   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2804 
   2805   // Add another property and delete it afterwards to force the object in
   2806   // slow case.
   2807   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
   2808   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2809   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
   2810   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2811   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2812 
   2813   CHECK(obj->Has(sym1));
   2814   CHECK(obj->Has(sym2));
   2815   CHECK(obj->Delete(sym2));
   2816   CHECK(obj->Has(sym1));
   2817   CHECK(!obj->Has(sym2));
   2818   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
   2819   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2820 
   2821   // Symbol properties are inherited.
   2822   v8::Local<v8::Object> child = v8::Object::New(isolate);
   2823   child->SetPrototype(obj);
   2824   CHECK(child->Has(sym1));
   2825   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
   2826   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
   2827 }
   2828 
   2829 
   2830 THREADED_TEST(PrivateProperties) {
   2831   LocalContext env;
   2832   v8::Isolate* isolate = env->GetIsolate();
   2833   v8::HandleScope scope(isolate);
   2834 
   2835   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   2836   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
   2837   v8::Local<v8::Private> priv2 =
   2838       v8::Private::New(isolate, v8_str("my-private"));
   2839 
   2840   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2841 
   2842   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
   2843 
   2844   // Make sure delete of a non-existent private symbol property works.
   2845   CHECK(obj->DeletePrivate(priv1));
   2846   CHECK(!obj->HasPrivate(priv1));
   2847 
   2848   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
   2849   CHECK(obj->HasPrivate(priv1));
   2850   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
   2851   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
   2852   CHECK(obj->HasPrivate(priv1));
   2853   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2854 
   2855   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
   2856   int num_props = obj->GetPropertyNames()->Length();
   2857   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
   2858                  v8::Integer::New(isolate, 20)));
   2859   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2860   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
   2861 
   2862   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2863 
   2864   // Add another property and delete it afterwards to force the object in
   2865   // slow case.
   2866   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
   2867   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2868   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
   2869   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2870   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2871 
   2872   CHECK(obj->HasPrivate(priv1));
   2873   CHECK(obj->HasPrivate(priv2));
   2874   CHECK(obj->DeletePrivate(priv2));
   2875   CHECK(obj->HasPrivate(priv1));
   2876   CHECK(!obj->HasPrivate(priv2));
   2877   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
   2878   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
   2879 
   2880   // Private properties are inherited (for the time being).
   2881   v8::Local<v8::Object> child = v8::Object::New(isolate);
   2882   child->SetPrototype(obj);
   2883   CHECK(child->HasPrivate(priv1));
   2884   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
   2885   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
   2886 }
   2887 
   2888 
   2889 THREADED_TEST(GlobalSymbols) {
   2890   i::FLAG_harmony_symbols = true;
   2891 
   2892   LocalContext env;
   2893   v8::Isolate* isolate = env->GetIsolate();
   2894   v8::HandleScope scope(isolate);
   2895 
   2896   v8::Local<String> name = v8_str("my-symbol");
   2897   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
   2898   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
   2899   CHECK(glob2->SameValue(glob));
   2900 
   2901   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
   2902   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
   2903   CHECK(glob_api2->SameValue(glob_api));
   2904   CHECK(!glob_api->SameValue(glob));
   2905 
   2906   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
   2907   CHECK(!sym->SameValue(glob));
   2908 
   2909   CompileRun("var sym2 = Symbol.for('my-symbol')");
   2910   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
   2911   CHECK(sym2->SameValue(glob));
   2912   CHECK(!sym2->SameValue(glob_api));
   2913 }
   2914 
   2915 
   2916 THREADED_TEST(GlobalPrivates) {
   2917   LocalContext env;
   2918   v8::Isolate* isolate = env->GetIsolate();
   2919   v8::HandleScope scope(isolate);
   2920 
   2921   v8::Local<String> name = v8_str("my-private");
   2922   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
   2923   v8::Local<v8::Object> obj = v8::Object::New(isolate);
   2924   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
   2925 
   2926   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
   2927   CHECK(obj->HasPrivate(glob2));
   2928 
   2929   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
   2930   CHECK(!obj->HasPrivate(priv));
   2931 
   2932   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
   2933   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
   2934   CHECK(!obj->Has(intern));
   2935 }
   2936 
   2937 
   2938 class ScopedArrayBufferContents {
   2939  public:
   2940   explicit ScopedArrayBufferContents(
   2941       const v8::ArrayBuffer::Contents& contents)
   2942     : contents_(contents) {}
   2943   ~ScopedArrayBufferContents() { free(contents_.Data()); }
   2944   void* Data() const { return contents_.Data(); }
   2945   size_t ByteLength() const { return contents_.ByteLength(); }
   2946  private:
   2947   const v8::ArrayBuffer::Contents contents_;
   2948 };
   2949 
   2950 template <typename T>
   2951 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
   2952   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
   2953   for (int i = 0; i < value->InternalFieldCount(); i++) {
   2954     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
   2955   }
   2956 }
   2957 
   2958 
   2959 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
   2960   LocalContext env;
   2961   v8::Isolate* isolate = env->GetIsolate();
   2962   v8::HandleScope handle_scope(isolate);
   2963 
   2964   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
   2965   CheckInternalFieldsAreZero(ab);
   2966   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
   2967   CHECK(!ab->IsExternal());
   2968   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   2969 
   2970   ScopedArrayBufferContents ab_contents(ab->Externalize());
   2971   CHECK(ab->IsExternal());
   2972 
   2973   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
   2974   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
   2975   ASSERT(data != NULL);
   2976   env->Global()->Set(v8_str("ab"), ab);
   2977 
   2978   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
   2979   CHECK_EQ(1024, result->Int32Value());
   2980 
   2981   result = CompileRun("var u8 = new Uint8Array(ab);"
   2982                       "u8[0] = 0xFF;"
   2983                       "u8[1] = 0xAA;"
   2984                       "u8.length");
   2985   CHECK_EQ(1024, result->Int32Value());
   2986   CHECK_EQ(0xFF, data[0]);
   2987   CHECK_EQ(0xAA, data[1]);
   2988   data[0] = 0xCC;
   2989   data[1] = 0x11;
   2990   result = CompileRun("u8[0] + u8[1]");
   2991   CHECK_EQ(0xDD, result->Int32Value());
   2992 }
   2993 
   2994 
   2995 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
   2996   LocalContext env;
   2997   v8::Isolate* isolate = env->GetIsolate();
   2998   v8::HandleScope handle_scope(isolate);
   2999 
   3000 
   3001   v8::Local<v8::Value> result =
   3002       CompileRun("var ab1 = new ArrayBuffer(2);"
   3003                  "var u8_a = new Uint8Array(ab1);"
   3004                  "u8_a[0] = 0xAA;"
   3005                  "u8_a[1] = 0xFF; u8_a.buffer");
   3006   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
   3007   CheckInternalFieldsAreZero(ab1);
   3008   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
   3009   CHECK(!ab1->IsExternal());
   3010   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
   3011   CHECK(ab1->IsExternal());
   3012 
   3013   result = CompileRun("ab1.byteLength");
   3014   CHECK_EQ(2, result->Int32Value());
   3015   result = CompileRun("u8_a[0]");
   3016   CHECK_EQ(0xAA, result->Int32Value());
   3017   result = CompileRun("u8_a[1]");
   3018   CHECK_EQ(0xFF, result->Int32Value());
   3019   result = CompileRun("var u8_b = new Uint8Array(ab1);"
   3020                       "u8_b[0] = 0xBB;"
   3021                       "u8_a[0]");
   3022   CHECK_EQ(0xBB, result->Int32Value());
   3023   result = CompileRun("u8_b[1]");
   3024   CHECK_EQ(0xFF, result->Int32Value());
   3025 
   3026   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
   3027   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
   3028   CHECK_EQ(0xBB, ab1_data[0]);
   3029   CHECK_EQ(0xFF, ab1_data[1]);
   3030   ab1_data[0] = 0xCC;
   3031   ab1_data[1] = 0x11;
   3032   result = CompileRun("u8_a[0] + u8_a[1]");
   3033   CHECK_EQ(0xDD, result->Int32Value());
   3034 }
   3035 
   3036 
   3037 THREADED_TEST(ArrayBuffer_External) {
   3038   LocalContext env;
   3039   v8::Isolate* isolate = env->GetIsolate();
   3040   v8::HandleScope handle_scope(isolate);
   3041 
   3042   i::ScopedVector<uint8_t> my_data(100);
   3043   memset(my_data.start(), 0, 100);
   3044   Local<v8::ArrayBuffer> ab3 =
   3045       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
   3046   CheckInternalFieldsAreZero(ab3);
   3047   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
   3048   CHECK(ab3->IsExternal());
   3049 
   3050   env->Global()->Set(v8_str("ab3"), ab3);
   3051 
   3052   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
   3053   CHECK_EQ(100, result->Int32Value());
   3054 
   3055   result = CompileRun("var u8_b = new Uint8Array(ab3);"
   3056                       "u8_b[0] = 0xBB;"
   3057                       "u8_b[1] = 0xCC;"
   3058                       "u8_b.length");
   3059   CHECK_EQ(100, result->Int32Value());
   3060   CHECK_EQ(0xBB, my_data[0]);
   3061   CHECK_EQ(0xCC, my_data[1]);
   3062   my_data[0] = 0xCC;
   3063   my_data[1] = 0x11;
   3064   result = CompileRun("u8_b[0] + u8_b[1]");
   3065   CHECK_EQ(0xDD, result->Int32Value());
   3066 }
   3067 
   3068 
   3069 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
   3070   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
   3071   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
   3072 }
   3073 
   3074 
   3075 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
   3076   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
   3077   CHECK_EQ(0, static_cast<int>(ta->Length()));
   3078   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
   3079 }
   3080 
   3081 
   3082 static void CheckIsTypedArrayVarNeutered(const char* name) {
   3083   i::ScopedVector<char> source(1024);
   3084   i::SNPrintF(source,
   3085       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
   3086       name, name, name);
   3087   CHECK(CompileRun(source.start())->IsTrue());
   3088   v8::Handle<v8::TypedArray> ta =
   3089     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
   3090   CheckIsNeutered(ta);
   3091 }
   3092 
   3093 
   3094 template <typename TypedArray, int kElementSize>
   3095 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
   3096                                          int byteOffset,
   3097                                          int length) {
   3098   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
   3099   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
   3100   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
   3101   CHECK_EQ(length, static_cast<int>(ta->Length()));
   3102   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
   3103   return ta;
   3104 }
   3105 
   3106 
   3107 THREADED_TEST(ArrayBuffer_NeuteringApi) {
   3108   LocalContext env;
   3109   v8::Isolate* isolate = env->GetIsolate();
   3110   v8::HandleScope handle_scope(isolate);
   3111 
   3112   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
   3113 
   3114   v8::Handle<v8::Uint8Array> u8a =
   3115     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
   3116   v8::Handle<v8::Uint8ClampedArray> u8c =
   3117     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
   3118   v8::Handle<v8::Int8Array> i8a =
   3119     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
   3120 
   3121   v8::Handle<v8::Uint16Array> u16a =
   3122     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
   3123   v8::Handle<v8::Int16Array> i16a =
   3124     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
   3125 
   3126   v8::Handle<v8::Uint32Array> u32a =
   3127     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
   3128   v8::Handle<v8::Int32Array> i32a =
   3129     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
   3130 
   3131   v8::Handle<v8::Float32Array> f32a =
   3132     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
   3133   v8::Handle<v8::Float64Array> f64a =
   3134     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
   3135 
   3136   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
   3137   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
   3138   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
   3139   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
   3140 
   3141   ScopedArrayBufferContents contents(buffer->Externalize());
   3142   buffer->Neuter();
   3143   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
   3144   CheckIsNeutered(u8a);
   3145   CheckIsNeutered(u8c);
   3146   CheckIsNeutered(i8a);
   3147   CheckIsNeutered(u16a);
   3148   CheckIsNeutered(i16a);
   3149   CheckIsNeutered(u32a);
   3150   CheckIsNeutered(i32a);
   3151   CheckIsNeutered(f32a);
   3152   CheckIsNeutered(f64a);
   3153   CheckDataViewIsNeutered(dv);
   3154 }
   3155 
   3156 
   3157 THREADED_TEST(ArrayBuffer_NeuteringScript) {
   3158   LocalContext env;
   3159   v8::Isolate* isolate = env->GetIsolate();
   3160   v8::HandleScope handle_scope(isolate);
   3161 
   3162   CompileRun(
   3163       "var ab = new ArrayBuffer(1024);"
   3164       "var u8a = new Uint8Array(ab, 1, 1023);"
   3165       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
   3166       "var i8a = new Int8Array(ab, 1, 1023);"
   3167       "var u16a = new Uint16Array(ab, 2, 511);"
   3168       "var i16a = new Int16Array(ab, 2, 511);"
   3169       "var u32a = new Uint32Array(ab, 4, 255);"
   3170       "var i32a = new Int32Array(ab, 4, 255);"
   3171       "var f32a = new Float32Array(ab, 4, 255);"
   3172       "var f64a = new Float64Array(ab, 8, 127);"
   3173       "var dv = new DataView(ab, 1, 1023);");
   3174 
   3175   v8::Handle<v8::ArrayBuffer> ab =
   3176       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
   3177 
   3178   v8::Handle<v8::DataView> dv =
   3179     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
   3180 
   3181   ScopedArrayBufferContents contents(ab->Externalize());
   3182   ab->Neuter();
   3183   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
   3184   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
   3185 
   3186   CheckIsTypedArrayVarNeutered("u8a");
   3187   CheckIsTypedArrayVarNeutered("u8c");
   3188   CheckIsTypedArrayVarNeutered("i8a");
   3189   CheckIsTypedArrayVarNeutered("u16a");
   3190   CheckIsTypedArrayVarNeutered("i16a");
   3191   CheckIsTypedArrayVarNeutered("u32a");
   3192   CheckIsTypedArrayVarNeutered("i32a");
   3193   CheckIsTypedArrayVarNeutered("f32a");
   3194   CheckIsTypedArrayVarNeutered("f64a");
   3195 
   3196   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
   3197   CheckDataViewIsNeutered(dv);
   3198 }
   3199 
   3200 
   3201 
   3202 THREADED_TEST(HiddenProperties) {
   3203   LocalContext env;
   3204   v8::Isolate* isolate = env->GetIsolate();
   3205   v8::HandleScope scope(isolate);
   3206 
   3207   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
   3208   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   3209   v8::Local<v8::String> empty = v8_str("");
   3210   v8::Local<v8::String> prop_name = v8_str("prop_name");
   3211 
   3212   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3213 
   3214   // Make sure delete of a non-existent hidden value works
   3215   CHECK(obj->DeleteHiddenValue(key));
   3216 
   3217   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
   3218   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
   3219   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
   3220   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3221 
   3222   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3223 
   3224   // Make sure we do not find the hidden property.
   3225   CHECK(!obj->Has(empty));
   3226   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3227   CHECK(obj->Get(empty)->IsUndefined());
   3228   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3229   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
   3230   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3231   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
   3232 
   3233   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3234 
   3235   // Add another property and delete it afterwards to force the object in
   3236   // slow case.
   3237   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
   3238   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3239   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
   3240   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3241   CHECK(obj->Delete(prop_name));
   3242   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
   3243 
   3244   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   3245 
   3246   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
   3247   CHECK(obj->GetHiddenValue(key).IsEmpty());
   3248 
   3249   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
   3250   CHECK(obj->DeleteHiddenValue(key));
   3251   CHECK(obj->GetHiddenValue(key).IsEmpty());
   3252 }
   3253 
   3254 
   3255 THREADED_TEST(Regress97784) {
   3256   // Regression test for crbug.com/97784
   3257   // Messing with the Object.prototype should not have effect on
   3258   // hidden properties.
   3259   LocalContext env;
   3260   v8::HandleScope scope(env->GetIsolate());
   3261 
   3262   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
   3263   v8::Local<v8::String> key = v8_str("hidden");
   3264 
   3265   CompileRun(
   3266       "set_called = false;"
   3267       "Object.defineProperty("
   3268       "    Object.prototype,"
   3269       "    'hidden',"
   3270       "    {get: function() { return 45; },"
   3271       "     set: function() { set_called = true; }})");
   3272 
   3273   CHECK(obj->GetHiddenValue(key).IsEmpty());
   3274   // Make sure that the getter and setter from Object.prototype is not invoked.
   3275   // If it did we would have full access to the hidden properties in
   3276   // the accessor.
   3277   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
   3278   ExpectFalse("set_called");
   3279   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
   3280 }
   3281 
   3282 
   3283 static bool interceptor_for_hidden_properties_called;
   3284 static void InterceptorForHiddenProperties(
   3285     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   3286   interceptor_for_hidden_properties_called = true;
   3287 }
   3288 
   3289 
   3290 THREADED_TEST(HiddenPropertiesWithInterceptors) {
   3291   LocalContext context;
   3292   v8::Isolate* isolate = context->GetIsolate();
   3293   v8::HandleScope scope(isolate);
   3294 
   3295   interceptor_for_hidden_properties_called = false;
   3296 
   3297   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
   3298 
   3299   // Associate an interceptor with an object and start setting hidden values.
   3300   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   3301   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   3302   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
   3303   Local<v8::Function> function = fun_templ->GetFunction();
   3304   Local<v8::Object> obj = function->NewInstance();
   3305   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
   3306   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
   3307   CHECK(!interceptor_for_hidden_properties_called);
   3308 }
   3309 
   3310 
   3311 THREADED_TEST(External) {
   3312   v8::HandleScope scope(CcTest::isolate());
   3313   int x = 3;
   3314   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
   3315   LocalContext env;
   3316   env->Global()->Set(v8_str("ext"), ext);
   3317   Local<Value> reext_obj = CompileRun("this.ext");
   3318   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
   3319   int* ptr = static_cast<int*>(reext->Value());
   3320   CHECK_EQ(x, 3);
   3321   *ptr = 10;
   3322   CHECK_EQ(x, 10);
   3323 
   3324   // Make sure unaligned pointers are wrapped properly.
   3325   char* data = i::StrDup("0123456789");
   3326   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
   3327   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
   3328   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
   3329   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
   3330 
   3331   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
   3332   CHECK_EQ('0', *char_ptr);
   3333   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
   3334   CHECK_EQ('1', *char_ptr);
   3335   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
   3336   CHECK_EQ('2', *char_ptr);
   3337   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
   3338   CHECK_EQ('3', *char_ptr);
   3339   i::DeleteArray(data);
   3340 }
   3341 
   3342 
   3343 THREADED_TEST(GlobalHandle) {
   3344   v8::Isolate* isolate = CcTest::isolate();
   3345   v8::Persistent<String> global;
   3346   {
   3347     v8::HandleScope scope(isolate);
   3348     global.Reset(isolate, v8_str("str"));
   3349   }
   3350   {
   3351     v8::HandleScope scope(isolate);
   3352     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3353   }
   3354   global.Reset();
   3355   {
   3356     v8::HandleScope scope(isolate);
   3357     global.Reset(isolate, v8_str("str"));
   3358   }
   3359   {
   3360     v8::HandleScope scope(isolate);
   3361     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3362   }
   3363   global.Reset();
   3364 }
   3365 
   3366 
   3367 THREADED_TEST(ResettingGlobalHandle) {
   3368   v8::Isolate* isolate = CcTest::isolate();
   3369   v8::Persistent<String> global;
   3370   {
   3371     v8::HandleScope scope(isolate);
   3372     global.Reset(isolate, v8_str("str"));
   3373   }
   3374   v8::internal::GlobalHandles* global_handles =
   3375       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3376   int initial_handle_count = global_handles->global_handles_count();
   3377   {
   3378     v8::HandleScope scope(isolate);
   3379     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3380   }
   3381   {
   3382     v8::HandleScope scope(isolate);
   3383     global.Reset(isolate, v8_str("longer"));
   3384   }
   3385   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
   3386   {
   3387     v8::HandleScope scope(isolate);
   3388     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
   3389   }
   3390   global.Reset();
   3391   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
   3392 }
   3393 
   3394 
   3395 THREADED_TEST(ResettingGlobalHandleToEmpty) {
   3396   v8::Isolate* isolate = CcTest::isolate();
   3397   v8::Persistent<String> global;
   3398   {
   3399     v8::HandleScope scope(isolate);
   3400     global.Reset(isolate, v8_str("str"));
   3401   }
   3402   v8::internal::GlobalHandles* global_handles =
   3403       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3404   int initial_handle_count = global_handles->global_handles_count();
   3405   {
   3406     v8::HandleScope scope(isolate);
   3407     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
   3408   }
   3409   {
   3410     v8::HandleScope scope(isolate);
   3411     Local<String> empty;
   3412     global.Reset(isolate, empty);
   3413   }
   3414   CHECK(global.IsEmpty());
   3415   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
   3416 }
   3417 
   3418 
   3419 template<class T>
   3420 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
   3421   return unique.Pass();
   3422 }
   3423 
   3424 
   3425 template<class T>
   3426 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
   3427                                             const v8::Persistent<T> & global) {
   3428   v8::UniquePersistent<String> unique(isolate, global);
   3429   return unique.Pass();
   3430 }
   3431 
   3432 
   3433 THREADED_TEST(UniquePersistent) {
   3434   v8::Isolate* isolate = CcTest::isolate();
   3435   v8::Persistent<String> global;
   3436   {
   3437     v8::HandleScope scope(isolate);
   3438     global.Reset(isolate, v8_str("str"));
   3439   }
   3440   v8::internal::GlobalHandles* global_handles =
   3441       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3442   int initial_handle_count = global_handles->global_handles_count();
   3443   {
   3444     v8::UniquePersistent<String> unique(isolate, global);
   3445     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3446     // Test assignment via Pass
   3447     {
   3448       v8::UniquePersistent<String> copy = unique.Pass();
   3449       CHECK(unique.IsEmpty());
   3450       CHECK(copy == global);
   3451       CHECK_EQ(initial_handle_count + 1,
   3452                global_handles->global_handles_count());
   3453       unique = copy.Pass();
   3454     }
   3455     // Test ctor via Pass
   3456     {
   3457       v8::UniquePersistent<String> copy(unique.Pass());
   3458       CHECK(unique.IsEmpty());
   3459       CHECK(copy == global);
   3460       CHECK_EQ(initial_handle_count + 1,
   3461                global_handles->global_handles_count());
   3462       unique = copy.Pass();
   3463     }
   3464     // Test pass through function call
   3465     {
   3466       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
   3467       CHECK(unique.IsEmpty());
   3468       CHECK(copy == global);
   3469       CHECK_EQ(initial_handle_count + 1,
   3470                global_handles->global_handles_count());
   3471       unique = copy.Pass();
   3472     }
   3473     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3474   }
   3475   // Test pass from function call
   3476   {
   3477     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
   3478     CHECK(unique == global);
   3479     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3480   }
   3481   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   3482   global.Reset();
   3483 }
   3484 
   3485 
   3486 template<typename K, typename V>
   3487 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
   3488  public:
   3489   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
   3490       MapType;
   3491   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
   3492   struct WeakCallbackDataType {
   3493     MapType* map;
   3494     K key;
   3495   };
   3496   static WeakCallbackDataType* WeakCallbackParameter(
   3497       MapType* map, const K& key, Local<V> value) {
   3498     WeakCallbackDataType* data = new WeakCallbackDataType;
   3499     data->map = map;
   3500     data->key = key;
   3501     return data;
   3502   }
   3503   static MapType* MapFromWeakCallbackData(
   3504       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
   3505     return data.GetParameter()->map;
   3506   }
   3507   static K KeyFromWeakCallbackData(
   3508       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
   3509     return data.GetParameter()->key;
   3510   }
   3511   static void DisposeCallbackData(WeakCallbackDataType* data) {
   3512     delete data;
   3513   }
   3514   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
   3515       K key) { }
   3516 };
   3517 
   3518 
   3519 template<typename Map>
   3520 static void TestPersistentValueMap() {
   3521   LocalContext env;
   3522   v8::Isolate* isolate = env->GetIsolate();
   3523   Map map(isolate);
   3524   v8::internal::GlobalHandles* global_handles =
   3525       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3526   int initial_handle_count = global_handles->global_handles_count();
   3527   CHECK_EQ(0, static_cast<int>(map.Size()));
   3528   {
   3529     HandleScope scope(isolate);
   3530     Local<v8::Object> obj = map.Get(7);
   3531     CHECK(obj.IsEmpty());
   3532     Local<v8::Object> expected = v8::Object::New(isolate);
   3533     map.Set(7, expected);
   3534     CHECK_EQ(1, static_cast<int>(map.Size()));
   3535     obj = map.Get(7);
   3536     CHECK_EQ(expected, obj);
   3537     {
   3538       typename Map::PersistentValueReference ref = map.GetReference(7);
   3539       CHECK_EQ(expected, ref.NewLocal(isolate));
   3540     }
   3541     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
   3542     CHECK_EQ(0, static_cast<int>(map.Size()));
   3543     CHECK(expected == removed);
   3544     removed = map.Remove(7);
   3545     CHECK(removed.IsEmpty());
   3546     map.Set(8, expected);
   3547     CHECK_EQ(1, static_cast<int>(map.Size()));
   3548     map.Set(8, expected);
   3549     CHECK_EQ(1, static_cast<int>(map.Size()));
   3550     {
   3551       typename Map::PersistentValueReference ref;
   3552       Local<v8::Object> expected2 = v8::Object::New(isolate);
   3553       removed = map.Set(8,
   3554           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
   3555       CHECK_EQ(1, static_cast<int>(map.Size()));
   3556       CHECK(expected == removed);
   3557       CHECK_EQ(expected2, ref.NewLocal(isolate));
   3558     }
   3559   }
   3560   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
   3561   if (map.IsWeak()) {
   3562     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
   3563         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3564   } else {
   3565     map.Clear();
   3566   }
   3567   CHECK_EQ(0, static_cast<int>(map.Size()));
   3568   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
   3569 }
   3570 
   3571 
   3572 TEST(PersistentValueMap) {
   3573   // Default case, w/o weak callbacks:
   3574   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
   3575 
   3576   // Custom traits with weak callbacks:
   3577   typedef v8::PersistentValueMap<int, v8::Object,
   3578       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
   3579   TestPersistentValueMap<WeakPersistentValueMap>();
   3580 }
   3581 
   3582 
   3583 TEST(PersistentValueVector) {
   3584   LocalContext env;
   3585   v8::Isolate* isolate = env->GetIsolate();
   3586   v8::internal::GlobalHandles* global_handles =
   3587       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
   3588   int handle_count = global_handles->global_handles_count();
   3589   HandleScope scope(isolate);
   3590 
   3591   v8::PersistentValueVector<v8::Object> vector(isolate);
   3592 
   3593   Local<v8::Object> obj1 = v8::Object::New(isolate);
   3594   Local<v8::Object> obj2 = v8::Object::New(isolate);
   3595   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
   3596 
   3597   CHECK(vector.IsEmpty());
   3598   CHECK_EQ(0, static_cast<int>(vector.Size()));
   3599 
   3600   vector.ReserveCapacity(3);
   3601   CHECK(vector.IsEmpty());
   3602 
   3603   vector.Append(obj1);
   3604   vector.Append(obj2);
   3605   vector.Append(obj1);
   3606   vector.Append(obj3.Pass());
   3607   vector.Append(obj1);
   3608 
   3609   CHECK(!vector.IsEmpty());
   3610   CHECK_EQ(5, static_cast<int>(vector.Size()));
   3611   CHECK(obj3.IsEmpty());
   3612   CHECK_EQ(obj1, vector.Get(0));
   3613   CHECK_EQ(obj1, vector.Get(2));
   3614   CHECK_EQ(obj1, vector.Get(4));
   3615   CHECK_EQ(obj2, vector.Get(1));
   3616 
   3617   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
   3618 
   3619   vector.Clear();
   3620   CHECK(vector.IsEmpty());
   3621   CHECK_EQ(0, static_cast<int>(vector.Size()));
   3622   CHECK_EQ(handle_count, global_handles->global_handles_count());
   3623 }
   3624 
   3625 
   3626 THREADED_TEST(GlobalHandleUpcast) {
   3627   v8::Isolate* isolate = CcTest::isolate();
   3628   v8::HandleScope scope(isolate);
   3629   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
   3630   v8::Persistent<String> global_string(isolate, local);
   3631   v8::Persistent<Value>& global_value =
   3632       v8::Persistent<Value>::Cast(global_string);
   3633   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
   3634   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
   3635   global_string.Reset();
   3636 }
   3637 
   3638 
   3639 THREADED_TEST(HandleEquality) {
   3640   v8::Isolate* isolate = CcTest::isolate();
   3641   v8::Persistent<String> global1;
   3642   v8::Persistent<String> global2;
   3643   {
   3644     v8::HandleScope scope(isolate);
   3645     global1.Reset(isolate, v8_str("str"));
   3646     global2.Reset(isolate, v8_str("str2"));
   3647   }
   3648   CHECK_EQ(global1 == global1, true);
   3649   CHECK_EQ(global1 != global1, false);
   3650   {
   3651     v8::HandleScope scope(isolate);
   3652     Local<String> local1 = Local<String>::New(isolate, global1);
   3653     Local<String> local2 = Local<String>::New(isolate, global2);
   3654 
   3655     CHECK_EQ(global1 == local1, true);
   3656     CHECK_EQ(global1 != local1, false);
   3657     CHECK_EQ(local1 == global1, true);
   3658     CHECK_EQ(local1 != global1, false);
   3659 
   3660     CHECK_EQ(global1 == local2, false);
   3661     CHECK_EQ(global1 != local2, true);
   3662     CHECK_EQ(local2 == global1, false);
   3663     CHECK_EQ(local2 != global1, true);
   3664 
   3665     CHECK_EQ(local1 == local2, false);
   3666     CHECK_EQ(local1 != local2, true);
   3667 
   3668     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
   3669     CHECK_EQ(local1 == anotherLocal1, true);
   3670     CHECK_EQ(local1 != anotherLocal1, false);
   3671   }
   3672   global1.Reset();
   3673   global2.Reset();
   3674 }
   3675 
   3676 
   3677 THREADED_TEST(LocalHandle) {
   3678   v8::HandleScope scope(CcTest::isolate());
   3679   v8::Local<String> local =
   3680       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
   3681   CHECK_EQ(local->Length(), 3);
   3682 }
   3683 
   3684 
   3685 class WeakCallCounter {
   3686  public:
   3687   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
   3688   int id() { return id_; }
   3689   void increment() { number_of_weak_calls_++; }
   3690   int NumberOfWeakCalls() { return number_of_weak_calls_; }
   3691  private:
   3692   int id_;
   3693   int number_of_weak_calls_;
   3694 };
   3695 
   3696 
   3697 template<typename T>
   3698 struct WeakCallCounterAndPersistent {
   3699   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
   3700       : counter(counter) {}
   3701   WeakCallCounter* counter;
   3702   v8::Persistent<T> handle;
   3703 };
   3704 
   3705 
   3706 template <typename T>
   3707 static void WeakPointerCallback(
   3708     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
   3709   CHECK_EQ(1234, data.GetParameter()->counter->id());
   3710   data.GetParameter()->counter->increment();
   3711   data.GetParameter()->handle.Reset();
   3712 }
   3713 
   3714 
   3715 template<typename T>
   3716 static UniqueId MakeUniqueId(const Persistent<T>& p) {
   3717   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
   3718 }
   3719 
   3720 
   3721 THREADED_TEST(ApiObjectGroups) {
   3722   LocalContext env;
   3723   v8::Isolate* iso = env->GetIsolate();
   3724   HandleScope scope(iso);
   3725 
   3726   WeakCallCounter counter(1234);
   3727 
   3728   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   3729   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   3730   WeakCallCounterAndPersistent<Value> g1c1(&counter);
   3731   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   3732   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   3733   WeakCallCounterAndPersistent<Value> g2c1(&counter);
   3734 
   3735   {
   3736     HandleScope scope(iso);
   3737     g1s1.handle.Reset(iso, Object::New(iso));
   3738     g1s2.handle.Reset(iso, Object::New(iso));
   3739     g1c1.handle.Reset(iso, Object::New(iso));
   3740     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   3741     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   3742     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3743 
   3744     g2s1.handle.Reset(iso, Object::New(iso));
   3745     g2s2.handle.Reset(iso, Object::New(iso));
   3746     g2c1.handle.Reset(iso, Object::New(iso));
   3747     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   3748     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   3749     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3750   }
   3751 
   3752   WeakCallCounterAndPersistent<Value> root(&counter);
   3753   root.handle.Reset(iso, g1s1.handle);  // make a root.
   3754 
   3755   // Connect group 1 and 2, make a cycle.
   3756   {
   3757     HandleScope scope(iso);
   3758     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
   3759             Set(0, Local<Value>::New(iso, g2s2.handle)));
   3760     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
   3761             Set(0, Local<Value>::New(iso, g1s1.handle)));
   3762   }
   3763 
   3764   {
   3765     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3766     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3767     iso->SetObjectGroupId(g1s1.handle, id1);
   3768     iso->SetObjectGroupId(g1s2.handle, id1);
   3769     iso->SetReferenceFromGroup(id1, g1c1.handle);
   3770     iso->SetObjectGroupId(g2s1.handle, id2);
   3771     iso->SetObjectGroupId(g2s2.handle, id2);
   3772     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3773   }
   3774   // Do a single full GC, ensure incremental marking is stopped.
   3775   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   3776       iso)->heap();
   3777   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3778 
   3779   // All object should be alive.
   3780   CHECK_EQ(0, counter.NumberOfWeakCalls());
   3781 
   3782   // Weaken the root.
   3783   root.handle.SetWeak(&root, &WeakPointerCallback);
   3784   // But make children strong roots---all the objects (except for children)
   3785   // should be collectable now.
   3786   g1c1.handle.ClearWeak();
   3787   g2c1.handle.ClearWeak();
   3788 
   3789   // Groups are deleted, rebuild groups.
   3790   {
   3791     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3792     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3793     iso->SetObjectGroupId(g1s1.handle, id1);
   3794     iso->SetObjectGroupId(g1s2.handle, id1);
   3795     iso->SetReferenceFromGroup(id1, g1c1.handle);
   3796     iso->SetObjectGroupId(g2s1.handle, id2);
   3797     iso->SetObjectGroupId(g2s2.handle, id2);
   3798     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3799   }
   3800 
   3801   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3802 
   3803   // All objects should be gone. 5 global handles in total.
   3804   CHECK_EQ(5, counter.NumberOfWeakCalls());
   3805 
   3806   // And now make children weak again and collect them.
   3807   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3808   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3809 
   3810   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3811   CHECK_EQ(7, counter.NumberOfWeakCalls());
   3812 }
   3813 
   3814 
   3815 THREADED_TEST(ApiObjectGroupsForSubtypes) {
   3816   LocalContext env;
   3817   v8::Isolate* iso = env->GetIsolate();
   3818   HandleScope scope(iso);
   3819 
   3820   WeakCallCounter counter(1234);
   3821 
   3822   WeakCallCounterAndPersistent<Object> g1s1(&counter);
   3823   WeakCallCounterAndPersistent<String> g1s2(&counter);
   3824   WeakCallCounterAndPersistent<String> g1c1(&counter);
   3825   WeakCallCounterAndPersistent<Object> g2s1(&counter);
   3826   WeakCallCounterAndPersistent<String> g2s2(&counter);
   3827   WeakCallCounterAndPersistent<String> g2c1(&counter);
   3828 
   3829   {
   3830     HandleScope scope(iso);
   3831     g1s1.handle.Reset(iso, Object::New(iso));
   3832     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
   3833     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
   3834     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   3835     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   3836     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3837 
   3838     g2s1.handle.Reset(iso, Object::New(iso));
   3839     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
   3840     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
   3841     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   3842     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   3843     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3844   }
   3845 
   3846   WeakCallCounterAndPersistent<Value> root(&counter);
   3847   root.handle.Reset(iso, g1s1.handle);  // make a root.
   3848 
   3849   // Connect group 1 and 2, make a cycle.
   3850   {
   3851     HandleScope scope(iso);
   3852     CHECK(Local<Object>::New(iso, g1s1.handle)
   3853               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
   3854     CHECK(Local<Object>::New(iso, g2s1.handle)
   3855               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
   3856   }
   3857 
   3858   {
   3859     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3860     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3861     iso->SetObjectGroupId(g1s1.handle, id1);
   3862     iso->SetObjectGroupId(g1s2.handle, id1);
   3863     iso->SetReference(g1s1.handle, g1c1.handle);
   3864     iso->SetObjectGroupId(g2s1.handle, id2);
   3865     iso->SetObjectGroupId(g2s2.handle, id2);
   3866     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3867   }
   3868   // Do a single full GC, ensure incremental marking is stopped.
   3869   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   3870       iso)->heap();
   3871   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3872 
   3873   // All object should be alive.
   3874   CHECK_EQ(0, counter.NumberOfWeakCalls());
   3875 
   3876   // Weaken the root.
   3877   root.handle.SetWeak(&root, &WeakPointerCallback);
   3878   // But make children strong roots---all the objects (except for children)
   3879   // should be collectable now.
   3880   g1c1.handle.ClearWeak();
   3881   g2c1.handle.ClearWeak();
   3882 
   3883   // Groups are deleted, rebuild groups.
   3884   {
   3885     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3886     UniqueId id2 = MakeUniqueId(g2s2.handle);
   3887     iso->SetObjectGroupId(g1s1.handle, id1);
   3888     iso->SetObjectGroupId(g1s2.handle, id1);
   3889     iso->SetReference(g1s1.handle, g1c1.handle);
   3890     iso->SetObjectGroupId(g2s1.handle, id2);
   3891     iso->SetObjectGroupId(g2s2.handle, id2);
   3892     iso->SetReferenceFromGroup(id2, g2c1.handle);
   3893   }
   3894 
   3895   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3896 
   3897   // All objects should be gone. 5 global handles in total.
   3898   CHECK_EQ(5, counter.NumberOfWeakCalls());
   3899 
   3900   // And now make children weak again and collect them.
   3901   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
   3902   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
   3903 
   3904   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3905   CHECK_EQ(7, counter.NumberOfWeakCalls());
   3906 }
   3907 
   3908 
   3909 THREADED_TEST(ApiObjectGroupsCycle) {
   3910   LocalContext env;
   3911   v8::Isolate* iso = env->GetIsolate();
   3912   HandleScope scope(iso);
   3913 
   3914   WeakCallCounter counter(1234);
   3915 
   3916   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   3917   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   3918   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   3919   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   3920   WeakCallCounterAndPersistent<Value> g3s1(&counter);
   3921   WeakCallCounterAndPersistent<Value> g3s2(&counter);
   3922   WeakCallCounterAndPersistent<Value> g4s1(&counter);
   3923   WeakCallCounterAndPersistent<Value> g4s2(&counter);
   3924 
   3925   {
   3926     HandleScope scope(iso);
   3927     g1s1.handle.Reset(iso, Object::New(iso));
   3928     g1s2.handle.Reset(iso, Object::New(iso));
   3929     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   3930     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   3931     CHECK(g1s1.handle.IsWeak());
   3932     CHECK(g1s2.handle.IsWeak());
   3933 
   3934     g2s1.handle.Reset(iso, Object::New(iso));
   3935     g2s2.handle.Reset(iso, Object::New(iso));
   3936     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   3937     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   3938     CHECK(g2s1.handle.IsWeak());
   3939     CHECK(g2s2.handle.IsWeak());
   3940 
   3941     g3s1.handle.Reset(iso, Object::New(iso));
   3942     g3s2.handle.Reset(iso, Object::New(iso));
   3943     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
   3944     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
   3945     CHECK(g3s1.handle.IsWeak());
   3946     CHECK(g3s2.handle.IsWeak());
   3947 
   3948     g4s1.handle.Reset(iso, Object::New(iso));
   3949     g4s2.handle.Reset(iso, Object::New(iso));
   3950     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
   3951     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
   3952     CHECK(g4s1.handle.IsWeak());
   3953     CHECK(g4s2.handle.IsWeak());
   3954   }
   3955 
   3956   WeakCallCounterAndPersistent<Value> root(&counter);
   3957   root.handle.Reset(iso, g1s1.handle);  // make a root.
   3958 
   3959   // Connect groups.  We're building the following cycle:
   3960   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
   3961   // groups.
   3962   {
   3963     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3964     UniqueId id2 = MakeUniqueId(g2s1.handle);
   3965     UniqueId id3 = MakeUniqueId(g3s1.handle);
   3966     UniqueId id4 = MakeUniqueId(g4s1.handle);
   3967     iso->SetObjectGroupId(g1s1.handle, id1);
   3968     iso->SetObjectGroupId(g1s2.handle, id1);
   3969     iso->SetReferenceFromGroup(id1, g2s1.handle);
   3970     iso->SetObjectGroupId(g2s1.handle, id2);
   3971     iso->SetObjectGroupId(g2s2.handle, id2);
   3972     iso->SetReferenceFromGroup(id2, g3s1.handle);
   3973     iso->SetObjectGroupId(g3s1.handle, id3);
   3974     iso->SetObjectGroupId(g3s2.handle, id3);
   3975     iso->SetReferenceFromGroup(id3, g4s1.handle);
   3976     iso->SetObjectGroupId(g4s1.handle, id4);
   3977     iso->SetObjectGroupId(g4s2.handle, id4);
   3978     iso->SetReferenceFromGroup(id4, g1s1.handle);
   3979   }
   3980   // Do a single full GC
   3981   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   3982       iso)->heap();
   3983   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   3984 
   3985   // All object should be alive.
   3986   CHECK_EQ(0, counter.NumberOfWeakCalls());
   3987 
   3988   // Weaken the root.
   3989   root.handle.SetWeak(&root, &WeakPointerCallback);
   3990 
   3991   // Groups are deleted, rebuild groups.
   3992   {
   3993     UniqueId id1 = MakeUniqueId(g1s1.handle);
   3994     UniqueId id2 = MakeUniqueId(g2s1.handle);
   3995     UniqueId id3 = MakeUniqueId(g3s1.handle);
   3996     UniqueId id4 = MakeUniqueId(g4s1.handle);
   3997     iso->SetObjectGroupId(g1s1.handle, id1);
   3998     iso->SetObjectGroupId(g1s2.handle, id1);
   3999     iso->SetReferenceFromGroup(id1, g2s1.handle);
   4000     iso->SetObjectGroupId(g2s1.handle, id2);
   4001     iso->SetObjectGroupId(g2s2.handle, id2);
   4002     iso->SetReferenceFromGroup(id2, g3s1.handle);
   4003     iso->SetObjectGroupId(g3s1.handle, id3);
   4004     iso->SetObjectGroupId(g3s2.handle, id3);
   4005     iso->SetReferenceFromGroup(id3, g4s1.handle);
   4006     iso->SetObjectGroupId(g4s1.handle, id4);
   4007     iso->SetObjectGroupId(g4s2.handle, id4);
   4008     iso->SetReferenceFromGroup(id4, g1s1.handle);
   4009   }
   4010 
   4011   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   4012 
   4013   // All objects should be gone. 9 global handles in total.
   4014   CHECK_EQ(9, counter.NumberOfWeakCalls());
   4015 }
   4016 
   4017 
   4018 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
   4019 // on the buildbots, so was made non-threaded for the time being.
   4020 TEST(ApiObjectGroupsCycleForScavenger) {
   4021   i::FLAG_stress_compaction = false;
   4022   i::FLAG_gc_global = false;
   4023   LocalContext env;
   4024   v8::Isolate* iso = env->GetIsolate();
   4025   HandleScope scope(iso);
   4026 
   4027   WeakCallCounter counter(1234);
   4028 
   4029   WeakCallCounterAndPersistent<Value> g1s1(&counter);
   4030   WeakCallCounterAndPersistent<Value> g1s2(&counter);
   4031   WeakCallCounterAndPersistent<Value> g2s1(&counter);
   4032   WeakCallCounterAndPersistent<Value> g2s2(&counter);
   4033   WeakCallCounterAndPersistent<Value> g3s1(&counter);
   4034   WeakCallCounterAndPersistent<Value> g3s2(&counter);
   4035 
   4036   {
   4037     HandleScope scope(iso);
   4038     g1s1.handle.Reset(iso, Object::New(iso));
   4039     g1s2.handle.Reset(iso, Object::New(iso));
   4040     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
   4041     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
   4042 
   4043     g2s1.handle.Reset(iso, Object::New(iso));
   4044     g2s2.handle.Reset(iso, Object::New(iso));
   4045     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
   4046     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
   4047 
   4048     g3s1.handle.Reset(iso, Object::New(iso));
   4049     g3s2.handle.Reset(iso, Object::New(iso));
   4050     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
   4051     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
   4052   }
   4053 
   4054   // Make a root.
   4055   WeakCallCounterAndPersistent<Value> root(&counter);
   4056   root.handle.Reset(iso, g1s1.handle);
   4057   root.handle.MarkPartiallyDependent();
   4058 
   4059   // Connect groups.  We're building the following cycle:
   4060   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
   4061   // groups.
   4062   {
   4063     HandleScope handle_scope(iso);
   4064     g1s1.handle.MarkPartiallyDependent();
   4065     g1s2.handle.MarkPartiallyDependent();
   4066     g2s1.handle.MarkPartiallyDependent();
   4067     g2s2.handle.MarkPartiallyDependent();
   4068     g3s1.handle.MarkPartiallyDependent();
   4069     g3s2.handle.MarkPartiallyDependent();
   4070     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
   4071     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
   4072     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
   4073         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
   4074     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
   4075     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
   4076     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
   4077         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
   4078     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
   4079     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
   4080     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
   4081         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
   4082   }
   4083 
   4084   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
   4085       iso)->heap();
   4086   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
   4087 
   4088   // All objects should be alive.
   4089   CHECK_EQ(0, counter.NumberOfWeakCalls());
   4090 
   4091   // Weaken the root.
   4092   root.handle.SetWeak(&root, &WeakPointerCallback);
   4093   root.handle.MarkPartiallyDependent();
   4094 
   4095   // Groups are deleted, rebuild groups.
   4096   {
   4097     HandleScope handle_scope(iso);
   4098     g1s1.handle.MarkPartiallyDependent();
   4099     g1s2.handle.MarkPartiallyDependent();
   4100     g2s1.handle.MarkPartiallyDependent();
   4101     g2s2.handle.MarkPartiallyDependent();
   4102     g3s1.handle.MarkPartiallyDependent();
   4103     g3s2.handle.MarkPartiallyDependent();
   4104     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
   4105     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
   4106     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
   4107         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
   4108     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
   4109     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
   4110     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
   4111         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
   4112     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
   4113     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
   4114     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
   4115         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
   4116   }
   4117 
   4118   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
   4119 
   4120   // All objects should be gone. 7 global handles in total.
   4121   CHECK_EQ(7, counter.NumberOfWeakCalls());
   4122 }
   4123 
   4124 
   4125 THREADED_TEST(ScriptException) {
   4126   LocalContext env;
   4127   v8::HandleScope scope(env->GetIsolate());
   4128   Local<Script> script = v8_compile("throw 'panama!';");
   4129   v8::TryCatch try_catch;
   4130   Local<Value> result = script->Run();
   4131   CHECK(result.IsEmpty());
   4132   CHECK(try_catch.HasCaught());
   4133   String::Utf8Value exception_value(try_catch.Exception());
   4134   CHECK_EQ(*exception_value, "panama!");
   4135 }
   4136 
   4137 
   4138 TEST(TryCatchCustomException) {
   4139   LocalContext env;
   4140   v8::HandleScope scope(env->GetIsolate());
   4141   v8::TryCatch try_catch;
   4142   CompileRun("function CustomError() { this.a = 'b'; }"
   4143              "(function f() { throw new CustomError(); })();");
   4144   CHECK(try_catch.HasCaught());
   4145   CHECK(try_catch.Exception()->ToObject()->
   4146             Get(v8_str("a"))->Equals(v8_str("b")));
   4147 }
   4148 
   4149 
   4150 bool message_received;
   4151 
   4152 
   4153 static void check_message_0(v8::Handle<v8::Message> message,
   4154                             v8::Handle<Value> data) {
   4155   CHECK_EQ(5.76, data->NumberValue());
   4156   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   4157   CHECK(!message->IsSharedCrossOrigin());
   4158   message_received = true;
   4159 }
   4160 
   4161 
   4162 THREADED_TEST(MessageHandler0) {
   4163   message_received = false;
   4164   v8::HandleScope scope(CcTest::isolate());
   4165   CHECK(!message_received);
   4166   LocalContext context;
   4167   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
   4168   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
   4169   script->Run();
   4170   CHECK(message_received);
   4171   // clear out the message listener
   4172   v8::V8::RemoveMessageListeners(check_message_0);
   4173 }
   4174 
   4175 
   4176 static void check_message_1(v8::Handle<v8::Message> message,
   4177                             v8::Handle<Value> data) {
   4178   CHECK(data->IsNumber());
   4179   CHECK_EQ(1337, data->Int32Value());
   4180   CHECK(!message->IsSharedCrossOrigin());
   4181   message_received = true;
   4182 }
   4183 
   4184 
   4185 TEST(MessageHandler1) {
   4186   message_received = false;
   4187   v8::HandleScope scope(CcTest::isolate());
   4188   CHECK(!message_received);
   4189   v8::V8::AddMessageListener(check_message_1);
   4190   LocalContext context;
   4191   CompileRun("throw 1337;");
   4192   CHECK(message_received);
   4193   // clear out the message listener
   4194   v8::V8::RemoveMessageListeners(check_message_1);
   4195 }
   4196 
   4197 
   4198 static void check_message_2(v8::Handle<v8::Message> message,
   4199                             v8::Handle<Value> data) {
   4200   LocalContext context;
   4201   CHECK(data->IsObject());
   4202   v8::Local<v8::Value> hidden_property =
   4203       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
   4204   CHECK(v8_str("hidden value")->Equals(hidden_property));
   4205   CHECK(!message->IsSharedCrossOrigin());
   4206   message_received = true;
   4207 }
   4208 
   4209 
   4210 TEST(MessageHandler2) {
   4211   message_received = false;
   4212   v8::HandleScope scope(CcTest::isolate());
   4213   CHECK(!message_received);
   4214   v8::V8::AddMessageListener(check_message_2);
   4215   LocalContext context;
   4216   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
   4217   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
   4218                                            v8_str("hidden value"));
   4219   context->Global()->Set(v8_str("error"), error);
   4220   CompileRun("throw error;");
   4221   CHECK(message_received);
   4222   // clear out the message listener
   4223   v8::V8::RemoveMessageListeners(check_message_2);
   4224 }
   4225 
   4226 
   4227 static void check_message_3(v8::Handle<v8::Message> message,
   4228                             v8::Handle<Value> data) {
   4229   CHECK(message->IsSharedCrossOrigin());
   4230   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   4231   message_received = true;
   4232 }
   4233 
   4234 
   4235 TEST(MessageHandler3) {
   4236   message_received = false;
   4237   v8::Isolate* isolate = CcTest::isolate();
   4238   v8::HandleScope scope(isolate);
   4239   CHECK(!message_received);
   4240   v8::V8::AddMessageListener(check_message_3);
   4241   LocalContext context;
   4242   v8::ScriptOrigin origin =
   4243       v8::ScriptOrigin(v8_str("6.75"),
   4244                        v8::Integer::New(isolate, 1),
   4245                        v8::Integer::New(isolate, 2),
   4246                        v8::True(isolate));
   4247   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   4248                                                   &origin);
   4249   script->Run();
   4250   CHECK(message_received);
   4251   // clear out the message listener
   4252   v8::V8::RemoveMessageListeners(check_message_3);
   4253 }
   4254 
   4255 
   4256 static void check_message_4(v8::Handle<v8::Message> message,
   4257                             v8::Handle<Value> data) {
   4258   CHECK(!message->IsSharedCrossOrigin());
   4259   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   4260   message_received = true;
   4261 }
   4262 
   4263 
   4264 TEST(MessageHandler4) {
   4265   message_received = false;
   4266   v8::Isolate* isolate = CcTest::isolate();
   4267   v8::HandleScope scope(isolate);
   4268   CHECK(!message_received);
   4269   v8::V8::AddMessageListener(check_message_4);
   4270   LocalContext context;
   4271   v8::ScriptOrigin origin =
   4272       v8::ScriptOrigin(v8_str("6.75"),
   4273                        v8::Integer::New(isolate, 1),
   4274                        v8::Integer::New(isolate, 2),
   4275                        v8::False(isolate));
   4276   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   4277                                                   &origin);
   4278   script->Run();
   4279   CHECK(message_received);
   4280   // clear out the message listener
   4281   v8::V8::RemoveMessageListeners(check_message_4);
   4282 }
   4283 
   4284 
   4285 static void check_message_5a(v8::Handle<v8::Message> message,
   4286                             v8::Handle<Value> data) {
   4287   CHECK(message->IsSharedCrossOrigin());
   4288   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   4289   message_received = true;
   4290 }
   4291 
   4292 
   4293 static void check_message_5b(v8::Handle<v8::Message> message,
   4294                             v8::Handle<Value> data) {
   4295   CHECK(!message->IsSharedCrossOrigin());
   4296   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
   4297   message_received = true;
   4298 }
   4299 
   4300 
   4301 TEST(MessageHandler5) {
   4302   message_received = false;
   4303   v8::Isolate* isolate = CcTest::isolate();
   4304   v8::HandleScope scope(isolate);
   4305   CHECK(!message_received);
   4306   v8::V8::AddMessageListener(check_message_5a);
   4307   LocalContext context;
   4308   v8::ScriptOrigin origin =
   4309       v8::ScriptOrigin(v8_str("6.75"),
   4310                        v8::Integer::New(isolate, 1),
   4311                        v8::Integer::New(isolate, 2),
   4312                        v8::True(isolate));
   4313   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
   4314                                                   &origin);
   4315   script->Run();
   4316   CHECK(message_received);
   4317   // clear out the message listener
   4318   v8::V8::RemoveMessageListeners(check_message_5a);
   4319 
   4320   message_received = false;
   4321   v8::V8::AddMessageListener(check_message_5b);
   4322   origin =
   4323       v8::ScriptOrigin(v8_str("6.75"),
   4324                        v8::Integer::New(isolate, 1),
   4325                        v8::Integer::New(isolate, 2),
   4326                        v8::False(isolate));
   4327   script = Script::Compile(v8_str("throw 'error'"),
   4328                            &origin);
   4329   script->Run();
   4330   CHECK(message_received);
   4331   // clear out the message listener
   4332   v8::V8::RemoveMessageListeners(check_message_5b);
   4333 }
   4334 
   4335 
   4336 THREADED_TEST(GetSetProperty) {
   4337   LocalContext context;
   4338   v8::Isolate* isolate = context->GetIsolate();
   4339   v8::HandleScope scope(isolate);
   4340   context->Global()->Set(v8_str("foo"), v8_num(14));
   4341   context->Global()->Set(v8_str("12"), v8_num(92));
   4342   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
   4343   context->Global()->Set(v8_num(13), v8_num(56));
   4344   Local<Value> foo = CompileRun("this.foo");
   4345   CHECK_EQ(14, foo->Int32Value());
   4346   Local<Value> twelve = CompileRun("this[12]");
   4347   CHECK_EQ(92, twelve->Int32Value());
   4348   Local<Value> sixteen = CompileRun("this[16]");
   4349   CHECK_EQ(32, sixteen->Int32Value());
   4350   Local<Value> thirteen = CompileRun("this[13]");
   4351   CHECK_EQ(56, thirteen->Int32Value());
   4352   CHECK_EQ(92,
   4353            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
   4354   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
   4355   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
   4356   CHECK_EQ(32,
   4357            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
   4358   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
   4359   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
   4360   CHECK_EQ(56,
   4361            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
   4362   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
   4363   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
   4364 }
   4365 
   4366 
   4367 THREADED_TEST(PropertyAttributes) {
   4368   LocalContext context;
   4369   v8::HandleScope scope(context->GetIsolate());
   4370   // none
   4371   Local<String> prop = v8_str("none");
   4372   context->Global()->Set(prop, v8_num(7));
   4373   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
   4374   // read-only
   4375   prop = v8_str("read_only");
   4376   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
   4377   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   4378   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
   4379   CompileRun("read_only = 9");
   4380   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   4381   context->Global()->Set(prop, v8_num(10));
   4382   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
   4383   // dont-delete
   4384   prop = v8_str("dont_delete");
   4385   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
   4386   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   4387   CompileRun("delete dont_delete");
   4388   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
   4389   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
   4390   // dont-enum
   4391   prop = v8_str("dont_enum");
   4392   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
   4393   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
   4394   // absent
   4395   prop = v8_str("absent");
   4396   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
   4397   Local<Value> fake_prop = v8_num(1);
   4398   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
   4399   // exception
   4400   TryCatch try_catch;
   4401   Local<Value> exception =
   4402       CompileRun("({ toString: function() { throw 'exception';} })");
   4403   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
   4404   CHECK(try_catch.HasCaught());
   4405   String::Utf8Value exception_value(try_catch.Exception());
   4406   CHECK_EQ("exception", *exception_value);
   4407   try_catch.Reset();
   4408 }
   4409 
   4410 
   4411 THREADED_TEST(Array) {
   4412   LocalContext context;
   4413   v8::HandleScope scope(context->GetIsolate());
   4414   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
   4415   CHECK_EQ(0, array->Length());
   4416   CHECK(array->Get(0)->IsUndefined());
   4417   CHECK(!array->Has(0));
   4418   CHECK(array->Get(100)->IsUndefined());
   4419   CHECK(!array->Has(100));
   4420   array->Set(2, v8_num(7));
   4421   CHECK_EQ(3, array->Length());
   4422   CHECK(!array->Has(0));
   4423   CHECK(!array->Has(1));
   4424   CHECK(array->Has(2));
   4425   CHECK_EQ(7, array->Get(2)->Int32Value());
   4426   Local<Value> obj = CompileRun("[1, 2, 3]");
   4427   Local<v8::Array> arr = obj.As<v8::Array>();
   4428   CHECK_EQ(3, arr->Length());
   4429   CHECK_EQ(1, arr->Get(0)->Int32Value());
   4430   CHECK_EQ(2, arr->Get(1)->Int32Value());
   4431   CHECK_EQ(3, arr->Get(2)->Int32Value());
   4432   array = v8::Array::New(context->GetIsolate(), 27);
   4433   CHECK_EQ(27, array->Length());
   4434   array = v8::Array::New(context->GetIsolate(), -27);
   4435   CHECK_EQ(0, array->Length());
   4436 }
   4437 
   4438 
   4439 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4440   v8::EscapableHandleScope scope(args.GetIsolate());
   4441   ApiTestFuzzer::Fuzz();
   4442   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
   4443   for (int i = 0; i < args.Length(); i++)
   4444     result->Set(i, args[i]);
   4445   args.GetReturnValue().Set(scope.Escape(result));
   4446 }
   4447 
   4448 
   4449 THREADED_TEST(Vector) {
   4450   v8::Isolate* isolate = CcTest::isolate();
   4451   v8::HandleScope scope(isolate);
   4452   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
   4453   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
   4454   LocalContext context(0, global);
   4455 
   4456   const char* fun = "f()";
   4457   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
   4458   CHECK_EQ(0, a0->Length());
   4459 
   4460   const char* fun2 = "f(11)";
   4461   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
   4462   CHECK_EQ(1, a1->Length());
   4463   CHECK_EQ(11, a1->Get(0)->Int32Value());
   4464 
   4465   const char* fun3 = "f(12, 13)";
   4466   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
   4467   CHECK_EQ(2, a2->Length());
   4468   CHECK_EQ(12, a2->Get(0)->Int32Value());
   4469   CHECK_EQ(13, a2->Get(1)->Int32Value());
   4470 
   4471   const char* fun4 = "f(14, 15, 16)";
   4472   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
   4473   CHECK_EQ(3, a3->Length());
   4474   CHECK_EQ(14, a3->Get(0)->Int32Value());
   4475   CHECK_EQ(15, a3->Get(1)->Int32Value());
   4476   CHECK_EQ(16, a3->Get(2)->Int32Value());
   4477 
   4478   const char* fun5 = "f(17, 18, 19, 20)";
   4479   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
   4480   CHECK_EQ(4, a4->Length());
   4481   CHECK_EQ(17, a4->Get(0)->Int32Value());
   4482   CHECK_EQ(18, a4->Get(1)->Int32Value());
   4483   CHECK_EQ(19, a4->Get(2)->Int32Value());
   4484   CHECK_EQ(20, a4->Get(3)->Int32Value());
   4485 }
   4486 
   4487 
   4488 THREADED_TEST(FunctionCall) {
   4489   LocalContext context;
   4490   v8::Isolate* isolate = context->GetIsolate();
   4491   v8::HandleScope scope(isolate);
   4492   CompileRun(
   4493     "function Foo() {"
   4494     "  var result = [];"
   4495     "  for (var i = 0; i < arguments.length; i++) {"
   4496     "    result.push(arguments[i]);"
   4497     "  }"
   4498     "  return result;"
   4499     "}"
   4500     "function ReturnThisSloppy() {"
   4501     "  return this;"
   4502     "}"
   4503     "function ReturnThisStrict() {"
   4504     "  'use strict';"
   4505     "  return this;"
   4506     "}");
   4507   Local<Function> Foo =
   4508       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   4509   Local<Function> ReturnThisSloppy =
   4510       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
   4511   Local<Function> ReturnThisStrict =
   4512       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
   4513 
   4514   v8::Handle<Value>* args0 = NULL;
   4515   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
   4516   CHECK_EQ(0, a0->Length());
   4517 
   4518   v8::Handle<Value> args1[] = { v8_num(1.1) };
   4519   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
   4520   CHECK_EQ(1, a1->Length());
   4521   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4522 
   4523   v8::Handle<Value> args2[] = { v8_num(2.2),
   4524                                 v8_num(3.3) };
   4525   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
   4526   CHECK_EQ(2, a2->Length());
   4527   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4528   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4529 
   4530   v8::Handle<Value> args3[] = { v8_num(4.4),
   4531                                 v8_num(5.5),
   4532                                 v8_num(6.6) };
   4533   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
   4534   CHECK_EQ(3, a3->Length());
   4535   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4536   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4537   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4538 
   4539   v8::Handle<Value> args4[] = { v8_num(7.7),
   4540                                 v8_num(8.8),
   4541                                 v8_num(9.9),
   4542                                 v8_num(10.11) };
   4543   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
   4544   CHECK_EQ(4, a4->Length());
   4545   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4546   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4547   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4548   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
   4549 
   4550   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
   4551   CHECK(r1->StrictEquals(context->Global()));
   4552   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
   4553   CHECK(r2->StrictEquals(context->Global()));
   4554   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
   4555   CHECK(r3->IsNumberObject());
   4556   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
   4557   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
   4558   CHECK(r4->IsStringObject());
   4559   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
   4560   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
   4561   CHECK(r5->IsBooleanObject());
   4562   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
   4563 
   4564   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
   4565   CHECK(r6->IsUndefined());
   4566   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
   4567   CHECK(r7->IsNull());
   4568   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
   4569   CHECK(r8->StrictEquals(v8_num(42)));
   4570   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
   4571   CHECK(r9->StrictEquals(v8_str("hello")));
   4572   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
   4573   CHECK(r10->StrictEquals(v8::True(isolate)));
   4574 }
   4575 
   4576 
   4577 THREADED_TEST(ConstructCall) {
   4578   LocalContext context;
   4579   v8::Isolate* isolate = context->GetIsolate();
   4580   v8::HandleScope scope(isolate);
   4581   CompileRun(
   4582     "function Foo() {"
   4583     "  var result = [];"
   4584     "  for (var i = 0; i < arguments.length; i++) {"
   4585     "    result.push(arguments[i]);"
   4586     "  }"
   4587     "  return result;"
   4588     "}");
   4589   Local<Function> Foo =
   4590       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
   4591 
   4592   v8::Handle<Value>* args0 = NULL;
   4593   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
   4594   CHECK_EQ(0, a0->Length());
   4595 
   4596   v8::Handle<Value> args1[] = { v8_num(1.1) };
   4597   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
   4598   CHECK_EQ(1, a1->Length());
   4599   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4600 
   4601   v8::Handle<Value> args2[] = { v8_num(2.2),
   4602                                 v8_num(3.3) };
   4603   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
   4604   CHECK_EQ(2, a2->Length());
   4605   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4606   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4607 
   4608   v8::Handle<Value> args3[] = { v8_num(4.4),
   4609                                 v8_num(5.5),
   4610                                 v8_num(6.6) };
   4611   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
   4612   CHECK_EQ(3, a3->Length());
   4613   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4614   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4615   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4616 
   4617   v8::Handle<Value> args4[] = { v8_num(7.7),
   4618                                 v8_num(8.8),
   4619                                 v8_num(9.9),
   4620                                 v8_num(10.11) };
   4621   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
   4622   CHECK_EQ(4, a4->Length());
   4623   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
   4624   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
   4625   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
   4626   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
   4627 }
   4628 
   4629 
   4630 static void CheckUncle(v8::TryCatch* try_catch) {
   4631   CHECK(try_catch->HasCaught());
   4632   String::Utf8Value str_value(try_catch->Exception());
   4633   CHECK_EQ(*str_value, "uncle?");
   4634   try_catch->Reset();
   4635 }
   4636 
   4637 
   4638 THREADED_TEST(ConversionNumber) {
   4639   LocalContext env;
   4640   v8::HandleScope scope(env->GetIsolate());
   4641   // Very large number.
   4642   CompileRun("var obj = Math.pow(2,32) * 1237;");
   4643   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   4644   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
   4645   CHECK_EQ(0, obj->ToInt32()->Value());
   4646   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
   4647   // Large number.
   4648   CompileRun("var obj = -1234567890123;");
   4649   obj = env->Global()->Get(v8_str("obj"));
   4650   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
   4651   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
   4652   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
   4653   // Small positive integer.
   4654   CompileRun("var obj = 42;");
   4655   obj = env->Global()->Get(v8_str("obj"));
   4656   CHECK_EQ(42.0, obj->ToNumber()->Value());
   4657   CHECK_EQ(42, obj->ToInt32()->Value());
   4658   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
   4659   // Negative integer.
   4660   CompileRun("var obj = -37;");
   4661   obj = env->Global()->Get(v8_str("obj"));
   4662   CHECK_EQ(-37.0, obj->ToNumber()->Value());
   4663   CHECK_EQ(-37, obj->ToInt32()->Value());
   4664   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
   4665   // Positive non-int32 integer.
   4666   CompileRun("var obj = 0x81234567;");
   4667   obj = env->Global()->Get(v8_str("obj"));
   4668   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
   4669   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
   4670   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
   4671   // Fraction.
   4672   CompileRun("var obj = 42.3;");
   4673   obj = env->Global()->Get(v8_str("obj"));
   4674   CHECK_EQ(42.3, obj->ToNumber()->Value());
   4675   CHECK_EQ(42, obj->ToInt32()->Value());
   4676   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
   4677   // Large negative fraction.
   4678   CompileRun("var obj = -5726623061.75;");
   4679   obj = env->Global()->Get(v8_str("obj"));
   4680   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
   4681   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
   4682   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
   4683 }
   4684 
   4685 
   4686 THREADED_TEST(isNumberType) {
   4687   LocalContext env;
   4688   v8::HandleScope scope(env->GetIsolate());
   4689   // Very large number.
   4690   CompileRun("var obj = Math.pow(2,32) * 1237;");
   4691   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   4692   CHECK(!obj->IsInt32());
   4693   CHECK(!obj->IsUint32());
   4694   // Large negative number.
   4695   CompileRun("var obj = -1234567890123;");
   4696   obj = env->Global()->Get(v8_str("obj"));
   4697   CHECK(!obj->IsInt32());
   4698   CHECK(!obj->IsUint32());
   4699   // Small positive integer.
   4700   CompileRun("var obj = 42;");
   4701   obj = env->Global()->Get(v8_str("obj"));
   4702   CHECK(obj->IsInt32());
   4703   CHECK(obj->IsUint32());
   4704   // Negative integer.
   4705   CompileRun("var obj = -37;");
   4706   obj = env->Global()->Get(v8_str("obj"));
   4707   CHECK(obj->IsInt32());
   4708   CHECK(!obj->IsUint32());
   4709   // Positive non-int32 integer.
   4710   CompileRun("var obj = 0x81234567;");
   4711   obj = env->Global()->Get(v8_str("obj"));
   4712   CHECK(!obj->IsInt32());
   4713   CHECK(obj->IsUint32());
   4714   // Fraction.
   4715   CompileRun("var obj = 42.3;");
   4716   obj = env->Global()->Get(v8_str("obj"));
   4717   CHECK(!obj->IsInt32());
   4718   CHECK(!obj->IsUint32());
   4719   // Large negative fraction.
   4720   CompileRun("var obj = -5726623061.75;");
   4721   obj = env->Global()->Get(v8_str("obj"));
   4722   CHECK(!obj->IsInt32());
   4723   CHECK(!obj->IsUint32());
   4724   // Positive zero
   4725   CompileRun("var obj = 0.0;");
   4726   obj = env->Global()->Get(v8_str("obj"));
   4727   CHECK(obj->IsInt32());
   4728   CHECK(obj->IsUint32());
   4729   // Positive zero
   4730   CompileRun("var obj = -0.0;");
   4731   obj = env->Global()->Get(v8_str("obj"));
   4732   CHECK(!obj->IsInt32());
   4733   CHECK(!obj->IsUint32());
   4734 }
   4735 
   4736 
   4737 THREADED_TEST(ConversionException) {
   4738   LocalContext env;
   4739   v8::Isolate* isolate = env->GetIsolate();
   4740   v8::HandleScope scope(isolate);
   4741   CompileRun(
   4742     "function TestClass() { };"
   4743     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
   4744     "var obj = new TestClass();");
   4745   Local<Value> obj = env->Global()->Get(v8_str("obj"));
   4746 
   4747   v8::TryCatch try_catch;
   4748 
   4749   Local<Value> to_string_result = obj->ToString();
   4750   CHECK(to_string_result.IsEmpty());
   4751   CheckUncle(&try_catch);
   4752 
   4753   Local<Value> to_number_result = obj->ToNumber();
   4754   CHECK(to_number_result.IsEmpty());
   4755   CheckUncle(&try_catch);
   4756 
   4757   Local<Value> to_integer_result = obj->ToInteger();
   4758   CHECK(to_integer_result.IsEmpty());
   4759   CheckUncle(&try_catch);
   4760 
   4761   Local<Value> to_uint32_result = obj->ToUint32();
   4762   CHECK(to_uint32_result.IsEmpty());
   4763   CheckUncle(&try_catch);
   4764 
   4765   Local<Value> to_int32_result = obj->ToInt32();
   4766   CHECK(to_int32_result.IsEmpty());
   4767   CheckUncle(&try_catch);
   4768 
   4769   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
   4770   CHECK(to_object_result.IsEmpty());
   4771   CHECK(try_catch.HasCaught());
   4772   try_catch.Reset();
   4773 
   4774   int32_t int32_value = obj->Int32Value();
   4775   CHECK_EQ(0, int32_value);
   4776   CheckUncle(&try_catch);
   4777 
   4778   uint32_t uint32_value = obj->Uint32Value();
   4779   CHECK_EQ(0, uint32_value);
   4780   CheckUncle(&try_catch);
   4781 
   4782   double number_value = obj->NumberValue();
   4783   CHECK_NE(0, std::isnan(number_value));
   4784   CheckUncle(&try_catch);
   4785 
   4786   int64_t integer_value = obj->IntegerValue();
   4787   CHECK_EQ(0.0, static_cast<double>(integer_value));
   4788   CheckUncle(&try_catch);
   4789 }
   4790 
   4791 
   4792 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4793   ApiTestFuzzer::Fuzz();
   4794   args.GetIsolate()->ThrowException(v8_str("konto"));
   4795 }
   4796 
   4797 
   4798 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4799   if (args.Length() < 1) {
   4800     args.GetReturnValue().Set(false);
   4801     return;
   4802   }
   4803   v8::HandleScope scope(args.GetIsolate());
   4804   v8::TryCatch try_catch;
   4805   Local<Value> result = CompileRun(args[0]->ToString());
   4806   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   4807   args.GetReturnValue().Set(try_catch.HasCaught());
   4808 }
   4809 
   4810 
   4811 THREADED_TEST(APICatch) {
   4812   v8::Isolate* isolate = CcTest::isolate();
   4813   v8::HandleScope scope(isolate);
   4814   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4815   templ->Set(v8_str("ThrowFromC"),
   4816              v8::FunctionTemplate::New(isolate, ThrowFromC));
   4817   LocalContext context(0, templ);
   4818   CompileRun(
   4819     "var thrown = false;"
   4820     "try {"
   4821     "  ThrowFromC();"
   4822     "} catch (e) {"
   4823     "  thrown = true;"
   4824     "}");
   4825   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
   4826   CHECK(thrown->BooleanValue());
   4827 }
   4828 
   4829 
   4830 THREADED_TEST(APIThrowTryCatch) {
   4831   v8::Isolate* isolate = CcTest::isolate();
   4832   v8::HandleScope scope(isolate);
   4833   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4834   templ->Set(v8_str("ThrowFromC"),
   4835              v8::FunctionTemplate::New(isolate, ThrowFromC));
   4836   LocalContext context(0, templ);
   4837   v8::TryCatch try_catch;
   4838   CompileRun("ThrowFromC();");
   4839   CHECK(try_catch.HasCaught());
   4840 }
   4841 
   4842 
   4843 // Test that a try-finally block doesn't shadow a try-catch block
   4844 // when setting up an external handler.
   4845 //
   4846 // BUG(271): Some of the exception propagation does not work on the
   4847 // ARM simulator because the simulator separates the C++ stack and the
   4848 // JS stack.  This test therefore fails on the simulator.  The test is
   4849 // not threaded to allow the threading tests to run on the simulator.
   4850 TEST(TryCatchInTryFinally) {
   4851   v8::Isolate* isolate = CcTest::isolate();
   4852   v8::HandleScope scope(isolate);
   4853   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4854   templ->Set(v8_str("CCatcher"),
   4855              v8::FunctionTemplate::New(isolate, CCatcher));
   4856   LocalContext context(0, templ);
   4857   Local<Value> result = CompileRun("try {"
   4858                                    "  try {"
   4859                                    "    CCatcher('throw 7;');"
   4860                                    "  } finally {"
   4861                                    "  }"
   4862                                    "} catch (e) {"
   4863                                    "}");
   4864   CHECK(result->IsTrue());
   4865 }
   4866 
   4867 
   4868 static void check_reference_error_message(
   4869     v8::Handle<v8::Message> message,
   4870     v8::Handle<v8::Value> data) {
   4871   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
   4872   CHECK(message->Get()->Equals(v8_str(reference_error)));
   4873 }
   4874 
   4875 
   4876 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
   4877   ApiTestFuzzer::Fuzz();
   4878   CHECK(false);
   4879 }
   4880 
   4881 
   4882 // Test that overwritten methods are not invoked on uncaught exception
   4883 // formatting. However, they are invoked when performing normal error
   4884 // string conversions.
   4885 TEST(APIThrowMessageOverwrittenToString) {
   4886   v8::Isolate* isolate = CcTest::isolate();
   4887   v8::HandleScope scope(isolate);
   4888   v8::V8::AddMessageListener(check_reference_error_message);
   4889   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   4890   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
   4891   LocalContext context(NULL, templ);
   4892   CompileRun("asdf;");
   4893   CompileRun("var limit = {};"
   4894              "limit.valueOf = fail;"
   4895              "Error.stackTraceLimit = limit;");
   4896   CompileRun("asdf");
   4897   CompileRun("Array.prototype.pop = fail;");
   4898   CompileRun("Object.prototype.hasOwnProperty = fail;");
   4899   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
   4900   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
   4901   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
   4902   CompileRun("ReferenceError.prototype.toString ="
   4903              "  function() { return 'Whoops' }");
   4904   CompileRun("asdf;");
   4905   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
   4906   CompileRun("asdf;");
   4907   CompileRun("ReferenceError.prototype.constructor = void 0;");
   4908   CompileRun("asdf;");
   4909   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
   4910   CompileRun("asdf;");
   4911   CompileRun("ReferenceError.prototype = new Object();");
   4912   CompileRun("asdf;");
   4913   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
   4914   CHECK(string->Equals(v8_str("Whoops")));
   4915   CompileRun("ReferenceError.prototype.constructor = new Object();"
   4916              "ReferenceError.prototype.constructor.name = 1;"
   4917              "Number.prototype.toString = function() { return 'Whoops'; };"
   4918              "ReferenceError.prototype.toString = Object.prototype.toString;");
   4919   CompileRun("asdf;");
   4920   v8::V8::RemoveMessageListeners(check_reference_error_message);
   4921 }
   4922 
   4923 
   4924 static void check_custom_error_tostring(
   4925     v8::Handle<v8::Message> message,
   4926     v8::Handle<v8::Value> data) {
   4927   const char* uncaught_error = "Uncaught MyError toString";
   4928   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
   4929 }
   4930 
   4931 
   4932 TEST(CustomErrorToString) {
   4933   LocalContext context;
   4934   v8::HandleScope scope(context->GetIsolate());
   4935   v8::V8::AddMessageListener(check_custom_error_tostring);
   4936   CompileRun(
   4937     "function MyError(name, message) {                   "
   4938     "  this.name = name;                                 "
   4939     "  this.message = message;                           "
   4940     "}                                                   "
   4941     "MyError.prototype = Object.create(Error.prototype); "
   4942     "MyError.prototype.toString = function() {           "
   4943     "  return 'MyError toString';                        "
   4944     "};                                                  "
   4945     "throw new MyError('my name', 'my message');         ");
   4946   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
   4947 }
   4948 
   4949 
   4950 static void check_custom_error_message(
   4951     v8::Handle<v8::Message> message,
   4952     v8::Handle<v8::Value> data) {
   4953   const char* uncaught_error = "Uncaught MyError: my message";
   4954   printf("%s\n", *v8::String::Utf8Value(message->Get()));
   4955   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
   4956 }
   4957 
   4958 
   4959 TEST(CustomErrorMessage) {
   4960   LocalContext context;
   4961   v8::HandleScope scope(context->GetIsolate());
   4962   v8::V8::AddMessageListener(check_custom_error_message);
   4963 
   4964   // Handlebars.
   4965   CompileRun(
   4966     "function MyError(msg) {                             "
   4967     "  this.name = 'MyError';                            "
   4968     "  this.message = msg;                               "
   4969     "}                                                   "
   4970     "MyError.prototype = new Error();                    "
   4971     "throw new MyError('my message');                    ");
   4972 
   4973   // Closure.
   4974   CompileRun(
   4975     "function MyError(msg) {                             "
   4976     "  this.name = 'MyError';                            "
   4977     "  this.message = msg;                               "
   4978     "}                                                   "
   4979     "inherits = function(childCtor, parentCtor) {        "
   4980     "    function tempCtor() {};                         "
   4981     "    tempCtor.prototype = parentCtor.prototype;      "
   4982     "    childCtor.superClass_ = parentCtor.prototype;   "
   4983     "    childCtor.prototype = new tempCtor();           "
   4984     "    childCtor.prototype.constructor = childCtor;    "
   4985     "};                                                  "
   4986     "inherits(MyError, Error);                           "
   4987     "throw new MyError('my message');                    ");
   4988 
   4989   // Object.create.
   4990   CompileRun(
   4991     "function MyError(msg) {                             "
   4992     "  this.name = 'MyError';                            "
   4993     "  this.message = msg;                               "
   4994     "}                                                   "
   4995     "MyError.prototype = Object.create(Error.prototype); "
   4996     "throw new MyError('my message');                    ");
   4997 
   4998   v8::V8::RemoveMessageListeners(check_custom_error_message);
   4999 }
   5000 
   5001 
   5002 static void receive_message(v8::Handle<v8::Message> message,
   5003                             v8::Handle<v8::Value> data) {
   5004   message->Get();
   5005   message_received = true;
   5006 }
   5007 
   5008 
   5009 TEST(APIThrowMessage) {
   5010   message_received = false;
   5011   v8::Isolate* isolate = CcTest::isolate();
   5012   v8::HandleScope scope(isolate);
   5013   v8::V8::AddMessageListener(receive_message);
   5014   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5015   templ->Set(v8_str("ThrowFromC"),
   5016              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5017   LocalContext context(0, templ);
   5018   CompileRun("ThrowFromC();");
   5019   CHECK(message_received);
   5020   v8::V8::RemoveMessageListeners(receive_message);
   5021 }
   5022 
   5023 
   5024 TEST(APIThrowMessageAndVerboseTryCatch) {
   5025   message_received = false;
   5026   v8::Isolate* isolate = CcTest::isolate();
   5027   v8::HandleScope scope(isolate);
   5028   v8::V8::AddMessageListener(receive_message);
   5029   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5030   templ->Set(v8_str("ThrowFromC"),
   5031              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5032   LocalContext context(0, templ);
   5033   v8::TryCatch try_catch;
   5034   try_catch.SetVerbose(true);
   5035   Local<Value> result = CompileRun("ThrowFromC();");
   5036   CHECK(try_catch.HasCaught());
   5037   CHECK(result.IsEmpty());
   5038   CHECK(message_received);
   5039   v8::V8::RemoveMessageListeners(receive_message);
   5040 }
   5041 
   5042 
   5043 TEST(APIStackOverflowAndVerboseTryCatch) {
   5044   message_received = false;
   5045   LocalContext context;
   5046   v8::HandleScope scope(context->GetIsolate());
   5047   v8::V8::AddMessageListener(receive_message);
   5048   v8::TryCatch try_catch;
   5049   try_catch.SetVerbose(true);
   5050   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
   5051   CHECK(try_catch.HasCaught());
   5052   CHECK(result.IsEmpty());
   5053   CHECK(message_received);
   5054   v8::V8::RemoveMessageListeners(receive_message);
   5055 }
   5056 
   5057 
   5058 THREADED_TEST(ExternalScriptException) {
   5059   v8::Isolate* isolate = CcTest::isolate();
   5060   v8::HandleScope scope(isolate);
   5061   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5062   templ->Set(v8_str("ThrowFromC"),
   5063              v8::FunctionTemplate::New(isolate, ThrowFromC));
   5064   LocalContext context(0, templ);
   5065 
   5066   v8::TryCatch try_catch;
   5067   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
   5068   CHECK(result.IsEmpty());
   5069   CHECK(try_catch.HasCaught());
   5070   String::Utf8Value exception_value(try_catch.Exception());
   5071   CHECK_EQ("konto", *exception_value);
   5072 }
   5073 
   5074 
   5075 
   5076 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5077   ApiTestFuzzer::Fuzz();
   5078   CHECK_EQ(4, args.Length());
   5079   int count = args[0]->Int32Value();
   5080   int cInterval = args[2]->Int32Value();
   5081   if (count == 0) {
   5082     args.GetIsolate()->ThrowException(v8_str("FromC"));
   5083     return;
   5084   } else {
   5085     Local<v8::Object> global =
   5086         args.GetIsolate()->GetCurrentContext()->Global();
   5087     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
   5088     v8::Handle<Value> argv[] = { v8_num(count - 1),
   5089                                  args[1],
   5090                                  args[2],
   5091                                  args[3] };
   5092     if (count % cInterval == 0) {
   5093       v8::TryCatch try_catch;
   5094       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
   5095       int expected = args[3]->Int32Value();
   5096       if (try_catch.HasCaught()) {
   5097         CHECK_EQ(expected, count);
   5098         CHECK(result.IsEmpty());
   5099         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
   5100       } else {
   5101         CHECK_NE(expected, count);
   5102       }
   5103       args.GetReturnValue().Set(result);
   5104       return;
   5105     } else {
   5106       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
   5107       return;
   5108     }
   5109   }
   5110 }
   5111 
   5112 
   5113 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5114   ApiTestFuzzer::Fuzz();
   5115   CHECK_EQ(3, args.Length());
   5116   bool equality = args[0]->BooleanValue();
   5117   int count = args[1]->Int32Value();
   5118   int expected = args[2]->Int32Value();
   5119   if (equality) {
   5120     CHECK_EQ(count, expected);
   5121   } else {
   5122     CHECK_NE(count, expected);
   5123   }
   5124 }
   5125 
   5126 
   5127 THREADED_TEST(EvalInTryFinally) {
   5128   LocalContext context;
   5129   v8::HandleScope scope(context->GetIsolate());
   5130   v8::TryCatch try_catch;
   5131   CompileRun("(function() {"
   5132              "  try {"
   5133              "    eval('asldkf (*&^&*^');"
   5134              "  } finally {"
   5135              "    return;"
   5136              "  }"
   5137              "})()");
   5138   CHECK(!try_catch.HasCaught());
   5139 }
   5140 
   5141 
   5142 // This test works by making a stack of alternating JavaScript and C
   5143 // activations.  These activations set up exception handlers with regular
   5144 // intervals, one interval for C activations and another for JavaScript
   5145 // activations.  When enough activations have been created an exception is
   5146 // thrown and we check that the right activation catches the exception and that
   5147 // no other activations do.  The right activation is always the topmost one with
   5148 // a handler, regardless of whether it is in JavaScript or C.
   5149 //
   5150 // The notation used to describe a test case looks like this:
   5151 //
   5152 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
   5153 //
   5154 // Each entry is an activation, either JS or C.  The index is the count at that
   5155 // level.  Stars identify activations with exception handlers, the @ identifies
   5156 // the exception handler that should catch the exception.
   5157 //
   5158 // BUG(271): Some of the exception propagation does not work on the
   5159 // ARM simulator because the simulator separates the C++ stack and the
   5160 // JS stack.  This test therefore fails on the simulator.  The test is
   5161 // not threaded to allow the threading tests to run on the simulator.
   5162 TEST(ExceptionOrder) {
   5163   v8::Isolate* isolate = CcTest::isolate();
   5164   v8::HandleScope scope(isolate);
   5165   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5166   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
   5167   templ->Set(v8_str("CThrowCountDown"),
   5168              v8::FunctionTemplate::New(isolate, CThrowCountDown));
   5169   LocalContext context(0, templ);
   5170   CompileRun(
   5171     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
   5172     "  if (count == 0) throw 'FromJS';"
   5173     "  if (count % jsInterval == 0) {"
   5174     "    try {"
   5175     "      var value = CThrowCountDown(count - 1,"
   5176     "                                  jsInterval,"
   5177     "                                  cInterval,"
   5178     "                                  expected);"
   5179     "      check(false, count, expected);"
   5180     "      return value;"
   5181     "    } catch (e) {"
   5182     "      check(true, count, expected);"
   5183     "    }"
   5184     "  } else {"
   5185     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
   5186     "  }"
   5187     "}");
   5188   Local<Function> fun =
   5189       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
   5190 
   5191   const int argc = 4;
   5192   //                             count      jsInterval cInterval  expected
   5193 
   5194   // *JS[4] *C[3] @JS[2] C[1] JS[0]
   5195   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
   5196   fun->Call(fun, argc, a0);
   5197 
   5198   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
   5199   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
   5200   fun->Call(fun, argc, a1);
   5201 
   5202   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
   5203   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
   5204   fun->Call(fun, argc, a2);
   5205 
   5206   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
   5207   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
   5208   fun->Call(fun, argc, a3);
   5209 
   5210   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
   5211   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
   5212   fun->Call(fun, argc, a4);
   5213 
   5214   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
   5215   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
   5216   fun->Call(fun, argc, a5);
   5217 }
   5218 
   5219 
   5220 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5221   ApiTestFuzzer::Fuzz();
   5222   CHECK_EQ(1, args.Length());
   5223   args.GetIsolate()->ThrowException(args[0]);
   5224 }
   5225 
   5226 
   5227 THREADED_TEST(ThrowValues) {
   5228   v8::Isolate* isolate = CcTest::isolate();
   5229   v8::HandleScope scope(isolate);
   5230   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5231   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
   5232   LocalContext context(0, templ);
   5233   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   5234     "function Run(obj) {"
   5235     "  try {"
   5236     "    Throw(obj);"
   5237     "  } catch (e) {"
   5238     "    return e;"
   5239     "  }"
   5240     "  return 'no exception';"
   5241     "}"
   5242     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
   5243   CHECK_EQ(5, result->Length());
   5244   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
   5245   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
   5246   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
   5247   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
   5248   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
   5249   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
   5250   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
   5251 }
   5252 
   5253 
   5254 THREADED_TEST(CatchZero) {
   5255   LocalContext context;
   5256   v8::HandleScope scope(context->GetIsolate());
   5257   v8::TryCatch try_catch;
   5258   CHECK(!try_catch.HasCaught());
   5259   CompileRun("throw 10");
   5260   CHECK(try_catch.HasCaught());
   5261   CHECK_EQ(10, try_catch.Exception()->Int32Value());
   5262   try_catch.Reset();
   5263   CHECK(!try_catch.HasCaught());
   5264   CompileRun("throw 0");
   5265   CHECK(try_catch.HasCaught());
   5266   CHECK_EQ(0, try_catch.Exception()->Int32Value());
   5267 }
   5268 
   5269 
   5270 THREADED_TEST(CatchExceptionFromWith) {
   5271   LocalContext context;
   5272   v8::HandleScope scope(context->GetIsolate());
   5273   v8::TryCatch try_catch;
   5274   CHECK(!try_catch.HasCaught());
   5275   CompileRun("var o = {}; with (o) { throw 42; }");
   5276   CHECK(try_catch.HasCaught());
   5277 }
   5278 
   5279 
   5280 THREADED_TEST(TryCatchAndFinallyHidingException) {
   5281   LocalContext context;
   5282   v8::HandleScope scope(context->GetIsolate());
   5283   v8::TryCatch try_catch;
   5284   CHECK(!try_catch.HasCaught());
   5285   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
   5286   CompileRun("f({toString: function() { throw 42; }});");
   5287   CHECK(!try_catch.HasCaught());
   5288 }
   5289 
   5290 
   5291 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
   5292   v8::TryCatch try_catch;
   5293 }
   5294 
   5295 
   5296 THREADED_TEST(TryCatchAndFinally) {
   5297   LocalContext context;
   5298   v8::Isolate* isolate = context->GetIsolate();
   5299   v8::HandleScope scope(isolate);
   5300   context->Global()->Set(
   5301       v8_str("native_with_try_catch"),
   5302       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
   5303   v8::TryCatch try_catch;
   5304   CHECK(!try_catch.HasCaught());
   5305   CompileRun(
   5306       "try {\n"
   5307       "  throw new Error('a');\n"
   5308       "} finally {\n"
   5309       "  native_with_try_catch();\n"
   5310       "}\n");
   5311   CHECK(try_catch.HasCaught());
   5312 }
   5313 
   5314 
   5315 static void TryCatchNestedHelper(int depth) {
   5316   if (depth > 0) {
   5317     v8::TryCatch try_catch;
   5318     try_catch.SetVerbose(true);
   5319     TryCatchNestedHelper(depth - 1);
   5320     CHECK(try_catch.HasCaught());
   5321     try_catch.ReThrow();
   5322   } else {
   5323     CcTest::isolate()->ThrowException(v8_str("back"));
   5324   }
   5325 }
   5326 
   5327 
   5328 TEST(TryCatchNested) {
   5329   v8::V8::Initialize();
   5330   LocalContext context;
   5331   v8::HandleScope scope(context->GetIsolate());
   5332   v8::TryCatch try_catch;
   5333   TryCatchNestedHelper(5);
   5334   CHECK(try_catch.HasCaught());
   5335   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
   5336 }
   5337 
   5338 
   5339 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
   5340   CHECK(try_catch->HasCaught());
   5341   Handle<Message> message = try_catch->Message();
   5342   Handle<Value> resource = message->GetScriptResourceName();
   5343   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
   5344   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
   5345                      "Uncaught Error: a"));
   5346   CHECK_EQ(1, message->GetLineNumber());
   5347   CHECK_EQ(6, message->GetStartColumn());
   5348 }
   5349 
   5350 
   5351 void TryCatchMixedNestingHelper(
   5352     const v8::FunctionCallbackInfo<v8::Value>& args) {
   5353   ApiTestFuzzer::Fuzz();
   5354   v8::TryCatch try_catch;
   5355   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
   5356   CHECK(try_catch.HasCaught());
   5357   TryCatchMixedNestingCheck(&try_catch);
   5358   try_catch.ReThrow();
   5359 }
   5360 
   5361 
   5362 // This test ensures that an outer TryCatch in the following situation:
   5363 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
   5364 // does not clobber the Message object generated for the inner TryCatch.
   5365 // This exercises the ability of TryCatch.ReThrow() to restore the
   5366 // inner pending Message before throwing the exception again.
   5367 TEST(TryCatchMixedNesting) {
   5368   v8::Isolate* isolate = CcTest::isolate();
   5369   v8::HandleScope scope(isolate);
   5370   v8::V8::Initialize();
   5371   v8::TryCatch try_catch;
   5372   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5373   templ->Set(v8_str("TryCatchMixedNestingHelper"),
   5374              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
   5375   LocalContext context(0, templ);
   5376   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
   5377   TryCatchMixedNestingCheck(&try_catch);
   5378 }
   5379 
   5380 
   5381 THREADED_TEST(Equality) {
   5382   LocalContext context;
   5383   v8::Isolate* isolate = context->GetIsolate();
   5384   v8::HandleScope scope(context->GetIsolate());
   5385   // Check that equality works at all before relying on CHECK_EQ
   5386   CHECK(v8_str("a")->Equals(v8_str("a")));
   5387   CHECK(!v8_str("a")->Equals(v8_str("b")));
   5388 
   5389   CHECK_EQ(v8_str("a"), v8_str("a"));
   5390   CHECK_NE(v8_str("a"), v8_str("b"));
   5391   CHECK_EQ(v8_num(1), v8_num(1));
   5392   CHECK_EQ(v8_num(1.00), v8_num(1));
   5393   CHECK_NE(v8_num(1), v8_num(2));
   5394 
   5395   // Assume String is not internalized.
   5396   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
   5397   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
   5398   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
   5399   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
   5400   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
   5401   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
   5402   Local<Value> not_a_number = v8_num(i::OS::nan_value());
   5403   CHECK(!not_a_number->StrictEquals(not_a_number));
   5404   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
   5405   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
   5406 
   5407   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   5408   v8::Persistent<v8::Object> alias(isolate, obj);
   5409   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
   5410   alias.Reset();
   5411 
   5412   CHECK(v8_str("a")->SameValue(v8_str("a")));
   5413   CHECK(!v8_str("a")->SameValue(v8_str("b")));
   5414   CHECK(!v8_str("5")->SameValue(v8_num(5)));
   5415   CHECK(v8_num(1)->SameValue(v8_num(1)));
   5416   CHECK(!v8_num(1)->SameValue(v8_num(2)));
   5417   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
   5418   CHECK(not_a_number->SameValue(not_a_number));
   5419   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
   5420   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
   5421 }
   5422 
   5423 
   5424 THREADED_TEST(MultiRun) {
   5425   LocalContext context;
   5426   v8::HandleScope scope(context->GetIsolate());
   5427   Local<Script> script = v8_compile("x");
   5428   for (int i = 0; i < 10; i++)
   5429     script->Run();
   5430 }
   5431 
   5432 
   5433 static void GetXValue(Local<String> name,
   5434                       const v8::PropertyCallbackInfo<v8::Value>& info) {
   5435   ApiTestFuzzer::Fuzz();
   5436   CHECK_EQ(info.Data(), v8_str("donut"));
   5437   CHECK_EQ(name, v8_str("x"));
   5438   info.GetReturnValue().Set(name);
   5439 }
   5440 
   5441 
   5442 THREADED_TEST(SimplePropertyRead) {
   5443   LocalContext context;
   5444   v8::Isolate* isolate = context->GetIsolate();
   5445   v8::HandleScope scope(isolate);
   5446   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5447   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   5448   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5449   Local<Script> script = v8_compile("obj.x");
   5450   for (int i = 0; i < 10; i++) {
   5451     Local<Value> result = script->Run();
   5452     CHECK_EQ(result, v8_str("x"));
   5453   }
   5454 }
   5455 
   5456 
   5457 THREADED_TEST(DefinePropertyOnAPIAccessor) {
   5458   LocalContext context;
   5459   v8::Isolate* isolate = context->GetIsolate();
   5460   v8::HandleScope scope(isolate);
   5461   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5462   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   5463   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5464 
   5465   // Uses getOwnPropertyDescriptor to check the configurable status
   5466   Local<Script> script_desc = v8_compile(
   5467       "var prop = Object.getOwnPropertyDescriptor( "
   5468       "obj, 'x');"
   5469       "prop.configurable;");
   5470   Local<Value> result = script_desc->Run();
   5471   CHECK_EQ(result->BooleanValue(), true);
   5472 
   5473   // Redefine get - but still configurable
   5474   Local<Script> script_define = v8_compile(
   5475       "var desc = { get: function(){return 42; },"
   5476       "            configurable: true };"
   5477       "Object.defineProperty(obj, 'x', desc);"
   5478       "obj.x");
   5479   result = script_define->Run();
   5480   CHECK_EQ(result, v8_num(42));
   5481 
   5482   // Check that the accessor is still configurable
   5483   result = script_desc->Run();
   5484   CHECK_EQ(result->BooleanValue(), true);
   5485 
   5486   // Redefine to a non-configurable
   5487   script_define = v8_compile(
   5488       "var desc = { get: function(){return 43; },"
   5489       "             configurable: false };"
   5490       "Object.defineProperty(obj, 'x', desc);"
   5491       "obj.x");
   5492   result = script_define->Run();
   5493   CHECK_EQ(result, v8_num(43));
   5494   result = script_desc->Run();
   5495   CHECK_EQ(result->BooleanValue(), false);
   5496 
   5497   // Make sure that it is not possible to redefine again
   5498   v8::TryCatch try_catch;
   5499   result = script_define->Run();
   5500   CHECK(try_catch.HasCaught());
   5501   String::Utf8Value exception_value(try_catch.Exception());
   5502   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5503 }
   5504 
   5505 
   5506 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
   5507   v8::Isolate* isolate = CcTest::isolate();
   5508   v8::HandleScope scope(isolate);
   5509   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5510   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
   5511   LocalContext context;
   5512   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5513 
   5514   Local<Script> script_desc = v8_compile(
   5515       "var prop ="
   5516       "Object.getOwnPropertyDescriptor( "
   5517       "obj, 'x');"
   5518       "prop.configurable;");
   5519   Local<Value> result = script_desc->Run();
   5520   CHECK_EQ(result->BooleanValue(), true);
   5521 
   5522   Local<Script> script_define = v8_compile(
   5523       "var desc = {get: function(){return 42; },"
   5524       "            configurable: true };"
   5525       "Object.defineProperty(obj, 'x', desc);"
   5526       "obj.x");
   5527   result = script_define->Run();
   5528   CHECK_EQ(result, v8_num(42));
   5529 
   5530 
   5531   result = script_desc->Run();
   5532   CHECK_EQ(result->BooleanValue(), true);
   5533 
   5534 
   5535   script_define = v8_compile(
   5536       "var desc = {get: function(){return 43; },"
   5537       "            configurable: false };"
   5538       "Object.defineProperty(obj, 'x', desc);"
   5539       "obj.x");
   5540   result = script_define->Run();
   5541   CHECK_EQ(result, v8_num(43));
   5542   result = script_desc->Run();
   5543 
   5544   CHECK_EQ(result->BooleanValue(), false);
   5545 
   5546   v8::TryCatch try_catch;
   5547   result = script_define->Run();
   5548   CHECK(try_catch.HasCaught());
   5549   String::Utf8Value exception_value(try_catch.Exception());
   5550   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5551 }
   5552 
   5553 
   5554 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
   5555                                                 char const* name) {
   5556   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
   5557 }
   5558 
   5559 
   5560 THREADED_TEST(DefineAPIAccessorOnObject) {
   5561   v8::Isolate* isolate = CcTest::isolate();
   5562   v8::HandleScope scope(isolate);
   5563   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5564   LocalContext context;
   5565 
   5566   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   5567   CompileRun("var obj2 = {};");
   5568 
   5569   CHECK(CompileRun("obj1.x")->IsUndefined());
   5570   CHECK(CompileRun("obj2.x")->IsUndefined());
   5571 
   5572   CHECK(GetGlobalProperty(&context, "obj1")->
   5573       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5574 
   5575   ExpectString("obj1.x", "x");
   5576   CHECK(CompileRun("obj2.x")->IsUndefined());
   5577 
   5578   CHECK(GetGlobalProperty(&context, "obj2")->
   5579       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5580 
   5581   ExpectString("obj1.x", "x");
   5582   ExpectString("obj2.x", "x");
   5583 
   5584   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5585   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5586 
   5587   CompileRun("Object.defineProperty(obj1, 'x',"
   5588              "{ get: function() { return 'y'; }, configurable: true })");
   5589 
   5590   ExpectString("obj1.x", "y");
   5591   ExpectString("obj2.x", "x");
   5592 
   5593   CompileRun("Object.defineProperty(obj2, 'x',"
   5594              "{ get: function() { return 'y'; }, configurable: true })");
   5595 
   5596   ExpectString("obj1.x", "y");
   5597   ExpectString("obj2.x", "y");
   5598 
   5599   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5600   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5601 
   5602   CHECK(GetGlobalProperty(&context, "obj1")->
   5603       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5604   CHECK(GetGlobalProperty(&context, "obj2")->
   5605       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5606 
   5607   ExpectString("obj1.x", "x");
   5608   ExpectString("obj2.x", "x");
   5609 
   5610   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5611   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5612 
   5613   // Define getters/setters, but now make them not configurable.
   5614   CompileRun("Object.defineProperty(obj1, 'x',"
   5615              "{ get: function() { return 'z'; }, configurable: false })");
   5616   CompileRun("Object.defineProperty(obj2, 'x',"
   5617              "{ get: function() { return 'z'; }, configurable: false })");
   5618 
   5619   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5620   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5621 
   5622   ExpectString("obj1.x", "z");
   5623   ExpectString("obj2.x", "z");
   5624 
   5625   CHECK(!GetGlobalProperty(&context, "obj1")->
   5626       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5627   CHECK(!GetGlobalProperty(&context, "obj2")->
   5628       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5629 
   5630   ExpectString("obj1.x", "z");
   5631   ExpectString("obj2.x", "z");
   5632 }
   5633 
   5634 
   5635 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
   5636   v8::Isolate* isolate = CcTest::isolate();
   5637   v8::HandleScope scope(isolate);
   5638   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5639   LocalContext context;
   5640 
   5641   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   5642   CompileRun("var obj2 = {};");
   5643 
   5644   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
   5645         v8_str("x"),
   5646         GetXValue, NULL,
   5647         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
   5648   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
   5649         v8_str("x"),
   5650         GetXValue, NULL,
   5651         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
   5652 
   5653   ExpectString("obj1.x", "x");
   5654   ExpectString("obj2.x", "x");
   5655 
   5656   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
   5657   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
   5658 
   5659   CHECK(!GetGlobalProperty(&context, "obj1")->
   5660       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5661   CHECK(!GetGlobalProperty(&context, "obj2")->
   5662       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
   5663 
   5664   {
   5665     v8::TryCatch try_catch;
   5666     CompileRun("Object.defineProperty(obj1, 'x',"
   5667         "{get: function() { return 'func'; }})");
   5668     CHECK(try_catch.HasCaught());
   5669     String::Utf8Value exception_value(try_catch.Exception());
   5670     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5671   }
   5672   {
   5673     v8::TryCatch try_catch;
   5674     CompileRun("Object.defineProperty(obj2, 'x',"
   5675         "{get: function() { return 'func'; }})");
   5676     CHECK(try_catch.HasCaught());
   5677     String::Utf8Value exception_value(try_catch.Exception());
   5678     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
   5679   }
   5680 }
   5681 
   5682 
   5683 static void Get239Value(Local<String> name,
   5684                         const v8::PropertyCallbackInfo<v8::Value>& info) {
   5685   ApiTestFuzzer::Fuzz();
   5686   CHECK_EQ(info.Data(), v8_str("donut"));
   5687   CHECK_EQ(name, v8_str("239"));
   5688   info.GetReturnValue().Set(name);
   5689 }
   5690 
   5691 
   5692 THREADED_TEST(ElementAPIAccessor) {
   5693   v8::Isolate* isolate = CcTest::isolate();
   5694   v8::HandleScope scope(isolate);
   5695   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5696   LocalContext context;
   5697 
   5698   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
   5699   CompileRun("var obj2 = {};");
   5700 
   5701   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
   5702         v8_str("239"),
   5703         Get239Value, NULL,
   5704         v8_str("donut")));
   5705   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
   5706         v8_str("239"),
   5707         Get239Value, NULL,
   5708         v8_str("donut")));
   5709 
   5710   ExpectString("obj1[239]", "239");
   5711   ExpectString("obj2[239]", "239");
   5712   ExpectString("obj1['239']", "239");
   5713   ExpectString("obj2['239']", "239");
   5714 }
   5715 
   5716 
   5717 v8::Persistent<Value> xValue;
   5718 
   5719 
   5720 static void SetXValue(Local<String> name,
   5721                       Local<Value> value,
   5722                       const v8::PropertyCallbackInfo<void>& info) {
   5723   CHECK_EQ(value, v8_num(4));
   5724   CHECK_EQ(info.Data(), v8_str("donut"));
   5725   CHECK_EQ(name, v8_str("x"));
   5726   CHECK(xValue.IsEmpty());
   5727   xValue.Reset(info.GetIsolate(), value);
   5728 }
   5729 
   5730 
   5731 THREADED_TEST(SimplePropertyWrite) {
   5732   v8::Isolate* isolate = CcTest::isolate();
   5733   v8::HandleScope scope(isolate);
   5734   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5735   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
   5736   LocalContext context;
   5737   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5738   Local<Script> script = v8_compile("obj.x = 4");
   5739   for (int i = 0; i < 10; i++) {
   5740     CHECK(xValue.IsEmpty());
   5741     script->Run();
   5742     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
   5743     xValue.Reset();
   5744   }
   5745 }
   5746 
   5747 
   5748 THREADED_TEST(SetterOnly) {
   5749   v8::Isolate* isolate = CcTest::isolate();
   5750   v8::HandleScope scope(isolate);
   5751   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5752   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
   5753   LocalContext context;
   5754   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5755   Local<Script> script = v8_compile("obj.x = 4; obj.x");
   5756   for (int i = 0; i < 10; i++) {
   5757     CHECK(xValue.IsEmpty());
   5758     script->Run();
   5759     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
   5760     xValue.Reset();
   5761   }
   5762 }
   5763 
   5764 
   5765 THREADED_TEST(NoAccessors) {
   5766   v8::Isolate* isolate = CcTest::isolate();
   5767   v8::HandleScope scope(isolate);
   5768   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5769   templ->SetAccessor(v8_str("x"),
   5770                      static_cast<v8::AccessorGetterCallback>(NULL),
   5771                      NULL,
   5772                      v8_str("donut"));
   5773   LocalContext context;
   5774   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5775   Local<Script> script = v8_compile("obj.x = 4; obj.x");
   5776   for (int i = 0; i < 10; i++) {
   5777     script->Run();
   5778   }
   5779 }
   5780 
   5781 
   5782 static void XPropertyGetter(Local<String> property,
   5783                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   5784   ApiTestFuzzer::Fuzz();
   5785   CHECK(info.Data()->IsUndefined());
   5786   info.GetReturnValue().Set(property);
   5787 }
   5788 
   5789 
   5790 THREADED_TEST(NamedInterceptorPropertyRead) {
   5791   v8::Isolate* isolate = CcTest::isolate();
   5792   v8::HandleScope scope(isolate);
   5793   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5794   templ->SetNamedPropertyHandler(XPropertyGetter);
   5795   LocalContext context;
   5796   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5797   Local<Script> script = v8_compile("obj.x");
   5798   for (int i = 0; i < 10; i++) {
   5799     Local<Value> result = script->Run();
   5800     CHECK_EQ(result, v8_str("x"));
   5801   }
   5802 }
   5803 
   5804 
   5805 THREADED_TEST(NamedInterceptorDictionaryIC) {
   5806   v8::Isolate* isolate = CcTest::isolate();
   5807   v8::HandleScope scope(isolate);
   5808   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5809   templ->SetNamedPropertyHandler(XPropertyGetter);
   5810   LocalContext context;
   5811   // Create an object with a named interceptor.
   5812   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
   5813   Local<Script> script = v8_compile("interceptor_obj.x");
   5814   for (int i = 0; i < 10; i++) {
   5815     Local<Value> result = script->Run();
   5816     CHECK_EQ(result, v8_str("x"));
   5817   }
   5818   // Create a slow case object and a function accessing a property in
   5819   // that slow case object (with dictionary probing in generated
   5820   // code). Then force object with a named interceptor into slow-case,
   5821   // pass it to the function, and check that the interceptor is called
   5822   // instead of accessing the local property.
   5823   Local<Value> result =
   5824       CompileRun("function get_x(o) { return o.x; };"
   5825                  "var obj = { x : 42, y : 0 };"
   5826                  "delete obj.y;"
   5827                  "for (var i = 0; i < 10; i++) get_x(obj);"
   5828                  "interceptor_obj.x = 42;"
   5829                  "interceptor_obj.y = 10;"
   5830                  "delete interceptor_obj.y;"
   5831                  "get_x(interceptor_obj)");
   5832   CHECK_EQ(result, v8_str("x"));
   5833 }
   5834 
   5835 
   5836 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
   5837   v8::Isolate* isolate = CcTest::isolate();
   5838   v8::HandleScope scope(isolate);
   5839   v8::Local<Context> context1 = Context::New(isolate);
   5840 
   5841   context1->Enter();
   5842   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5843   templ->SetNamedPropertyHandler(XPropertyGetter);
   5844   // Create an object with a named interceptor.
   5845   v8::Local<v8::Object> object = templ->NewInstance();
   5846   context1->Global()->Set(v8_str("interceptor_obj"), object);
   5847 
   5848   // Force the object into the slow case.
   5849   CompileRun("interceptor_obj.y = 0;"
   5850              "delete interceptor_obj.y;");
   5851   context1->Exit();
   5852 
   5853   {
   5854     // Introduce the object into a different context.
   5855     // Repeat named loads to exercise ICs.
   5856     LocalContext context2;
   5857     context2->Global()->Set(v8_str("interceptor_obj"), object);
   5858     Local<Value> result =
   5859       CompileRun("function get_x(o) { return o.x; }"
   5860                  "interceptor_obj.x = 42;"
   5861                  "for (var i=0; i != 10; i++) {"
   5862                  "  get_x(interceptor_obj);"
   5863                  "}"
   5864                  "get_x(interceptor_obj)");
   5865     // Check that the interceptor was actually invoked.
   5866     CHECK_EQ(result, v8_str("x"));
   5867   }
   5868 
   5869   // Return to the original context and force some object to the slow case
   5870   // to cause the NormalizedMapCache to verify.
   5871   context1->Enter();
   5872   CompileRun("var obj = { x : 0 }; delete obj.x;");
   5873   context1->Exit();
   5874 }
   5875 
   5876 
   5877 static void SetXOnPrototypeGetter(
   5878     Local<String> property,
   5879     const v8::PropertyCallbackInfo<v8::Value>& info) {
   5880   // Set x on the prototype object and do not handle the get request.
   5881   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   5882   proto.As<v8::Object>()->Set(v8_str("x"),
   5883                               v8::Integer::New(info.GetIsolate(), 23));
   5884 }
   5885 
   5886 
   5887 // This is a regression test for http://crbug.com/20104. Map
   5888 // transitions should not interfere with post interceptor lookup.
   5889 THREADED_TEST(NamedInterceptorMapTransitionRead) {
   5890   v8::Isolate* isolate = CcTest::isolate();
   5891   v8::HandleScope scope(isolate);
   5892   Local<v8::FunctionTemplate> function_template =
   5893       v8::FunctionTemplate::New(isolate);
   5894   Local<v8::ObjectTemplate> instance_template
   5895       = function_template->InstanceTemplate();
   5896   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
   5897   LocalContext context;
   5898   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   5899   // Create an instance of F and introduce a map transition for x.
   5900   CompileRun("var o = new F(); o.x = 23;");
   5901   // Create an instance of F and invoke the getter. The result should be 23.
   5902   Local<Value> result = CompileRun("o = new F(); o.x");
   5903   CHECK_EQ(result->Int32Value(), 23);
   5904 }
   5905 
   5906 
   5907 static void IndexedPropertyGetter(
   5908     uint32_t index,
   5909     const v8::PropertyCallbackInfo<v8::Value>& info) {
   5910   ApiTestFuzzer::Fuzz();
   5911   if (index == 37) {
   5912     info.GetReturnValue().Set(v8_num(625));
   5913   }
   5914 }
   5915 
   5916 
   5917 static void IndexedPropertySetter(
   5918     uint32_t index,
   5919     Local<Value> value,
   5920     const v8::PropertyCallbackInfo<v8::Value>& info) {
   5921   ApiTestFuzzer::Fuzz();
   5922   if (index == 39) {
   5923     info.GetReturnValue().Set(value);
   5924   }
   5925 }
   5926 
   5927 
   5928 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
   5929   v8::Isolate* isolate = CcTest::isolate();
   5930   v8::HandleScope scope(isolate);
   5931   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5932   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
   5933                                    IndexedPropertySetter);
   5934   LocalContext context;
   5935   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   5936   Local<Script> getter_script = v8_compile(
   5937       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
   5938   Local<Script> setter_script = v8_compile(
   5939       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
   5940       "obj[17] = 23;"
   5941       "obj.foo;");
   5942   Local<Script> interceptor_setter_script = v8_compile(
   5943       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
   5944       "obj[39] = 47;"
   5945       "obj.foo;");  // This setter should not run, due to the interceptor.
   5946   Local<Script> interceptor_getter_script = v8_compile(
   5947       "obj[37];");
   5948   Local<Value> result = getter_script->Run();
   5949   CHECK_EQ(v8_num(5), result);
   5950   result = setter_script->Run();
   5951   CHECK_EQ(v8_num(23), result);
   5952   result = interceptor_setter_script->Run();
   5953   CHECK_EQ(v8_num(23), result);
   5954   result = interceptor_getter_script->Run();
   5955   CHECK_EQ(v8_num(625), result);
   5956 }
   5957 
   5958 
   5959 static void UnboxedDoubleIndexedPropertyGetter(
   5960     uint32_t index,
   5961     const v8::PropertyCallbackInfo<v8::Value>& info) {
   5962   ApiTestFuzzer::Fuzz();
   5963   if (index < 25) {
   5964     info.GetReturnValue().Set(v8_num(index));
   5965   }
   5966 }
   5967 
   5968 
   5969 static void UnboxedDoubleIndexedPropertySetter(
   5970     uint32_t index,
   5971     Local<Value> value,
   5972     const v8::PropertyCallbackInfo<v8::Value>& info) {
   5973   ApiTestFuzzer::Fuzz();
   5974   if (index < 25) {
   5975     info.GetReturnValue().Set(v8_num(index));
   5976   }
   5977 }
   5978 
   5979 
   5980 void UnboxedDoubleIndexedPropertyEnumerator(
   5981     const v8::PropertyCallbackInfo<v8::Array>& info) {
   5982   // Force the list of returned keys to be stored in a FastDoubleArray.
   5983   Local<Script> indexed_property_names_script = v8_compile(
   5984       "keys = new Array(); keys[125000] = 1;"
   5985       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
   5986       "keys.length = 25; keys;");
   5987   Local<Value> result = indexed_property_names_script->Run();
   5988   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
   5989 }
   5990 
   5991 
   5992 // Make sure that the the interceptor code in the runtime properly handles
   5993 // merging property name lists for double-array-backed arrays.
   5994 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
   5995   v8::Isolate* isolate = CcTest::isolate();
   5996   v8::HandleScope scope(isolate);
   5997   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   5998   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
   5999                                    UnboxedDoubleIndexedPropertySetter,
   6000                                    0,
   6001                                    0,
   6002                                    UnboxedDoubleIndexedPropertyEnumerator);
   6003   LocalContext context;
   6004   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6005   // When obj is created, force it to be Stored in a FastDoubleArray.
   6006   Local<Script> create_unboxed_double_script = v8_compile(
   6007       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
   6008       "key_count = 0; "
   6009       "for (x in obj) {key_count++;};"
   6010       "obj;");
   6011   Local<Value> result = create_unboxed_double_script->Run();
   6012   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
   6013   Local<Script> key_count_check = v8_compile("key_count;");
   6014   result = key_count_check->Run();
   6015   CHECK_EQ(v8_num(40013), result);
   6016 }
   6017 
   6018 
   6019 void SloppyArgsIndexedPropertyEnumerator(
   6020     const v8::PropertyCallbackInfo<v8::Array>& info) {
   6021   // Force the list of returned keys to be stored in a Arguments object.
   6022   Local<Script> indexed_property_names_script = v8_compile(
   6023       "function f(w,x) {"
   6024       " return arguments;"
   6025       "}"
   6026       "keys = f(0, 1, 2, 3);"
   6027       "keys;");
   6028   Local<Object> result =
   6029       Local<Object>::Cast(indexed_property_names_script->Run());
   6030   // Have to populate the handle manually, as it's not Cast-able.
   6031   i::Handle<i::JSObject> o =
   6032       v8::Utils::OpenHandle<Object, i::JSObject>(result);
   6033   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
   6034   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
   6035 }
   6036 
   6037 
   6038 static void SloppyIndexedPropertyGetter(
   6039     uint32_t index,
   6040     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6041   ApiTestFuzzer::Fuzz();
   6042   if (index < 4) {
   6043     info.GetReturnValue().Set(v8_num(index));
   6044   }
   6045 }
   6046 
   6047 
   6048 // Make sure that the the interceptor code in the runtime properly handles
   6049 // merging property name lists for non-string arguments arrays.
   6050 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
   6051   v8::Isolate* isolate = CcTest::isolate();
   6052   v8::HandleScope scope(isolate);
   6053   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6054   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
   6055                                    0,
   6056                                    0,
   6057                                    0,
   6058                                    SloppyArgsIndexedPropertyEnumerator);
   6059   LocalContext context;
   6060   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6061   Local<Script> create_args_script = v8_compile(
   6062       "var key_count = 0;"
   6063       "for (x in obj) {key_count++;} key_count;");
   6064   Local<Value> result = create_args_script->Run();
   6065   CHECK_EQ(v8_num(4), result);
   6066 }
   6067 
   6068 
   6069 static void IdentityIndexedPropertyGetter(
   6070     uint32_t index,
   6071     const v8::PropertyCallbackInfo<v8::Value>& info) {
   6072   info.GetReturnValue().Set(index);
   6073 }
   6074 
   6075 
   6076 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
   6077   v8::Isolate* isolate = CcTest::isolate();
   6078   v8::HandleScope scope(isolate);
   6079   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6080   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6081 
   6082   LocalContext context;
   6083   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6084 
   6085   // Check fast object case.
   6086   const char* fast_case_code =
   6087       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
   6088   ExpectString(fast_case_code, "0");
   6089 
   6090   // Check slow case.
   6091   const char* slow_case_code =
   6092       "obj.x = 1; delete obj.x;"
   6093       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
   6094   ExpectString(slow_case_code, "1");
   6095 }
   6096 
   6097 
   6098 THREADED_TEST(IndexedInterceptorWithNoSetter) {
   6099   v8::Isolate* isolate = CcTest::isolate();
   6100   v8::HandleScope scope(isolate);
   6101   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6102   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6103 
   6104   LocalContext context;
   6105   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   6106 
   6107   const char* code =
   6108       "try {"
   6109       "  obj[0] = 239;"
   6110       "  for (var i = 0; i < 100; i++) {"
   6111       "    var v = obj[0];"
   6112       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6113       "  }"
   6114       "  'PASSED'"
   6115       "} catch(e) {"
   6116       "  e"
   6117       "}";
   6118   ExpectString(code, "PASSED");
   6119 }
   6120 
   6121 
   6122 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
   6123   v8::Isolate* isolate = CcTest::isolate();
   6124   v8::HandleScope scope(isolate);
   6125   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6126   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6127 
   6128   LocalContext context;
   6129   Local<v8::Object> obj = templ->NewInstance();
   6130   obj->TurnOnAccessCheck();
   6131   context->Global()->Set(v8_str("obj"), obj);
   6132 
   6133   const char* code =
   6134       "try {"
   6135       "  for (var i = 0; i < 100; i++) {"
   6136       "    var v = obj[0];"
   6137       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6138       "  }"
   6139       "  'PASSED'"
   6140       "} catch(e) {"
   6141       "  e"
   6142       "}";
   6143   ExpectString(code, "PASSED");
   6144 }
   6145 
   6146 
   6147 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
   6148   i::FLAG_allow_natives_syntax = true;
   6149   v8::Isolate* isolate = CcTest::isolate();
   6150   v8::HandleScope scope(isolate);
   6151   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6152   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6153 
   6154   LocalContext context;
   6155   Local<v8::Object> obj = templ->NewInstance();
   6156   context->Global()->Set(v8_str("obj"), obj);
   6157 
   6158   const char* code =
   6159       "try {"
   6160       "  for (var i = 0; i < 100; i++) {"
   6161       "    var expected = i;"
   6162       "    if (i == 5) {"
   6163       "      %EnableAccessChecks(obj);"
   6164       "      expected = undefined;"
   6165       "    }"
   6166       "    var v = obj[i];"
   6167       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6168       "    if (i == 5) %DisableAccessChecks(obj);"
   6169       "  }"
   6170       "  'PASSED'"
   6171       "} catch(e) {"
   6172       "  e"
   6173       "}";
   6174   ExpectString(code, "PASSED");
   6175 }
   6176 
   6177 
   6178 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
   6179   v8::Isolate* isolate = CcTest::isolate();
   6180   v8::HandleScope scope(isolate);
   6181   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6182   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6183 
   6184   LocalContext context;
   6185   Local<v8::Object> obj = templ->NewInstance();
   6186   context->Global()->Set(v8_str("obj"), obj);
   6187 
   6188   const char* code =
   6189       "try {"
   6190       "  for (var i = 0; i < 100; i++) {"
   6191       "    var v = obj[i];"
   6192       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6193       "  }"
   6194       "  'PASSED'"
   6195       "} catch(e) {"
   6196       "  e"
   6197       "}";
   6198   ExpectString(code, "PASSED");
   6199 }
   6200 
   6201 
   6202 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
   6203   v8::Isolate* isolate = CcTest::isolate();
   6204   v8::HandleScope scope(isolate);
   6205   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6206   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6207 
   6208   LocalContext context;
   6209   Local<v8::Object> obj = templ->NewInstance();
   6210   context->Global()->Set(v8_str("obj"), obj);
   6211 
   6212   const char* code =
   6213       "try {"
   6214       "  for (var i = 0; i < 100; i++) {"
   6215       "    var expected = i;"
   6216       "    var key = i;"
   6217       "    if (i == 25) {"
   6218       "       key = -1;"
   6219       "       expected = undefined;"
   6220       "    }"
   6221       "    if (i == 50) {"
   6222       "       /* probe minimal Smi number on 32-bit platforms */"
   6223       "       key = -(1 << 30);"
   6224       "       expected = undefined;"
   6225       "    }"
   6226       "    if (i == 75) {"
   6227       "       /* probe minimal Smi number on 64-bit platforms */"
   6228       "       key = 1 << 31;"
   6229       "       expected = undefined;"
   6230       "    }"
   6231       "    var v = obj[key];"
   6232       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6233       "  }"
   6234       "  'PASSED'"
   6235       "} catch(e) {"
   6236       "  e"
   6237       "}";
   6238   ExpectString(code, "PASSED");
   6239 }
   6240 
   6241 
   6242 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
   6243   v8::Isolate* isolate = CcTest::isolate();
   6244   v8::HandleScope scope(isolate);
   6245   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6246   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6247 
   6248   LocalContext context;
   6249   Local<v8::Object> obj = templ->NewInstance();
   6250   context->Global()->Set(v8_str("obj"), obj);
   6251 
   6252   const char* code =
   6253       "try {"
   6254       "  for (var i = 0; i < 100; i++) {"
   6255       "    var expected = i;"
   6256       "    var key = i;"
   6257       "    if (i == 50) {"
   6258       "       key = 'foobar';"
   6259       "       expected = undefined;"
   6260       "    }"
   6261       "    var v = obj[key];"
   6262       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6263       "  }"
   6264       "  'PASSED'"
   6265       "} catch(e) {"
   6266       "  e"
   6267       "}";
   6268   ExpectString(code, "PASSED");
   6269 }
   6270 
   6271 
   6272 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
   6273   v8::Isolate* isolate = CcTest::isolate();
   6274   v8::HandleScope scope(isolate);
   6275   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6276   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6277 
   6278   LocalContext context;
   6279   Local<v8::Object> obj = templ->NewInstance();
   6280   context->Global()->Set(v8_str("obj"), obj);
   6281 
   6282   const char* code =
   6283       "var original = obj;"
   6284       "try {"
   6285       "  for (var i = 0; i < 100; i++) {"
   6286       "    var expected = i;"
   6287       "    if (i == 50) {"
   6288       "       obj = {50: 'foobar'};"
   6289       "       expected = 'foobar';"
   6290       "    }"
   6291       "    var v = obj[i];"
   6292       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6293       "    if (i == 50) obj = original;"
   6294       "  }"
   6295       "  'PASSED'"
   6296       "} catch(e) {"
   6297       "  e"
   6298       "}";
   6299   ExpectString(code, "PASSED");
   6300 }
   6301 
   6302 
   6303 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
   6304   v8::Isolate* isolate = CcTest::isolate();
   6305   v8::HandleScope scope(isolate);
   6306   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6307   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6308 
   6309   LocalContext context;
   6310   Local<v8::Object> obj = templ->NewInstance();
   6311   context->Global()->Set(v8_str("obj"), obj);
   6312 
   6313   const char* code =
   6314       "var original = obj;"
   6315       "try {"
   6316       "  for (var i = 0; i < 100; i++) {"
   6317       "    var expected = i;"
   6318       "    if (i == 5) {"
   6319       "       obj = 239;"
   6320       "       expected = undefined;"
   6321       "    }"
   6322       "    var v = obj[i];"
   6323       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6324       "    if (i == 5) obj = original;"
   6325       "  }"
   6326       "  'PASSED'"
   6327       "} catch(e) {"
   6328       "  e"
   6329       "}";
   6330   ExpectString(code, "PASSED");
   6331 }
   6332 
   6333 
   6334 THREADED_TEST(IndexedInterceptorOnProto) {
   6335   v8::Isolate* isolate = CcTest::isolate();
   6336   v8::HandleScope scope(isolate);
   6337   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6338   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
   6339 
   6340   LocalContext context;
   6341   Local<v8::Object> obj = templ->NewInstance();
   6342   context->Global()->Set(v8_str("obj"), obj);
   6343 
   6344   const char* code =
   6345       "var o = {__proto__: obj};"
   6346       "try {"
   6347       "  for (var i = 0; i < 100; i++) {"
   6348       "    var v = o[i];"
   6349       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
   6350       "  }"
   6351       "  'PASSED'"
   6352       "} catch(e) {"
   6353       "  e"
   6354       "}";
   6355   ExpectString(code, "PASSED");
   6356 }
   6357 
   6358 
   6359 THREADED_TEST(MultiContexts) {
   6360   v8::Isolate* isolate = CcTest::isolate();
   6361   v8::HandleScope scope(isolate);
   6362   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6363   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
   6364                                                         DummyCallHandler));
   6365 
   6366   Local<String> password = v8_str("Password");
   6367 
   6368   // Create an environment
   6369   LocalContext context0(0, templ);
   6370   context0->SetSecurityToken(password);
   6371   v8::Handle<v8::Object> global0 = context0->Global();
   6372   global0->Set(v8_str("custom"), v8_num(1234));
   6373   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   6374 
   6375   // Create an independent environment
   6376   LocalContext context1(0, templ);
   6377   context1->SetSecurityToken(password);
   6378   v8::Handle<v8::Object> global1 = context1->Global();
   6379   global1->Set(v8_str("custom"), v8_num(1234));
   6380   CHECK_NE(global0, global1);
   6381   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
   6382   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
   6383 
   6384   // Now create a new context with the old global
   6385   LocalContext context2(0, templ, global1);
   6386   context2->SetSecurityToken(password);
   6387   v8::Handle<v8::Object> global2 = context2->Global();
   6388   CHECK_EQ(global1, global2);
   6389   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
   6390   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
   6391 }
   6392 
   6393 
   6394 THREADED_TEST(FunctionPrototypeAcrossContexts) {
   6395   // Make sure that functions created by cloning boilerplates cannot
   6396   // communicate through their __proto__ field.
   6397 
   6398   v8::HandleScope scope(CcTest::isolate());
   6399 
   6400   LocalContext env0;
   6401   v8::Handle<v8::Object> global0 =
   6402       env0->Global();
   6403   v8::Handle<v8::Object> object0 =
   6404       global0->Get(v8_str("Object")).As<v8::Object>();
   6405   v8::Handle<v8::Object> tostring0 =
   6406       object0->Get(v8_str("toString")).As<v8::Object>();
   6407   v8::Handle<v8::Object> proto0 =
   6408       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
   6409   proto0->Set(v8_str("custom"), v8_num(1234));
   6410 
   6411   LocalContext env1;
   6412   v8::Handle<v8::Object> global1 =
   6413       env1->Global();
   6414   v8::Handle<v8::Object> object1 =
   6415       global1->Get(v8_str("Object")).As<v8::Object>();
   6416   v8::Handle<v8::Object> tostring1 =
   6417       object1->Get(v8_str("toString")).As<v8::Object>();
   6418   v8::Handle<v8::Object> proto1 =
   6419       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
   6420   CHECK(!proto1->Has(v8_str("custom")));
   6421 }
   6422 
   6423 
   6424 THREADED_TEST(Regress892105) {
   6425   // Make sure that object and array literals created by cloning
   6426   // boilerplates cannot communicate through their __proto__
   6427   // field. This is rather difficult to check, but we try to add stuff
   6428   // to Object.prototype and Array.prototype and create a new
   6429   // environment. This should succeed.
   6430 
   6431   v8::HandleScope scope(CcTest::isolate());
   6432 
   6433   Local<String> source = v8_str("Object.prototype.obj = 1234;"
   6434                                 "Array.prototype.arr = 4567;"
   6435                                 "8901");
   6436 
   6437   LocalContext env0;
   6438   Local<Script> script0 = v8_compile(source);
   6439   CHECK_EQ(8901.0, script0->Run()->NumberValue());
   6440 
   6441   LocalContext env1;
   6442   Local<Script> script1 = v8_compile(source);
   6443   CHECK_EQ(8901.0, script1->Run()->NumberValue());
   6444 }
   6445 
   6446 
   6447 THREADED_TEST(UndetectableObject) {
   6448   LocalContext env;
   6449   v8::HandleScope scope(env->GetIsolate());
   6450 
   6451   Local<v8::FunctionTemplate> desc =
   6452       v8::FunctionTemplate::New(env->GetIsolate());
   6453   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   6454 
   6455   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   6456   env->Global()->Set(v8_str("undetectable"), obj);
   6457 
   6458   ExpectString("undetectable.toString()", "[object Object]");
   6459   ExpectString("typeof undetectable", "undefined");
   6460   ExpectString("typeof(undetectable)", "undefined");
   6461   ExpectBoolean("typeof undetectable == 'undefined'", true);
   6462   ExpectBoolean("typeof undetectable == 'object'", false);
   6463   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   6464   ExpectBoolean("!undetectable", true);
   6465 
   6466   ExpectObject("true&&undetectable", obj);
   6467   ExpectBoolean("false&&undetectable", false);
   6468   ExpectBoolean("true||undetectable", true);
   6469   ExpectObject("false||undetectable", obj);
   6470 
   6471   ExpectObject("undetectable&&true", obj);
   6472   ExpectObject("undetectable&&false", obj);
   6473   ExpectBoolean("undetectable||true", true);
   6474   ExpectBoolean("undetectable||false", false);
   6475 
   6476   ExpectBoolean("undetectable==null", true);
   6477   ExpectBoolean("null==undetectable", true);
   6478   ExpectBoolean("undetectable==undefined", true);
   6479   ExpectBoolean("undefined==undetectable", true);
   6480   ExpectBoolean("undetectable==undetectable", true);
   6481 
   6482 
   6483   ExpectBoolean("undetectable===null", false);
   6484   ExpectBoolean("null===undetectable", false);
   6485   ExpectBoolean("undetectable===undefined", false);
   6486   ExpectBoolean("undefined===undetectable", false);
   6487   ExpectBoolean("undetectable===undetectable", true);
   6488 }
   6489 
   6490 
   6491 THREADED_TEST(VoidLiteral) {
   6492   LocalContext env;
   6493   v8::Isolate* isolate = env->GetIsolate();
   6494   v8::HandleScope scope(isolate);
   6495 
   6496   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
   6497   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   6498 
   6499   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   6500   env->Global()->Set(v8_str("undetectable"), obj);
   6501 
   6502   ExpectBoolean("undefined == void 0", true);
   6503   ExpectBoolean("undetectable == void 0", true);
   6504   ExpectBoolean("null == void 0", true);
   6505   ExpectBoolean("undefined === void 0", true);
   6506   ExpectBoolean("undetectable === void 0", false);
   6507   ExpectBoolean("null === void 0", false);
   6508 
   6509   ExpectBoolean("void 0 == undefined", true);
   6510   ExpectBoolean("void 0 == undetectable", true);
   6511   ExpectBoolean("void 0 == null", true);
   6512   ExpectBoolean("void 0 === undefined", true);
   6513   ExpectBoolean("void 0 === undetectable", false);
   6514   ExpectBoolean("void 0 === null", false);
   6515 
   6516   ExpectString("(function() {"
   6517                "  try {"
   6518                "    return x === void 0;"
   6519                "  } catch(e) {"
   6520                "    return e.toString();"
   6521                "  }"
   6522                "})()",
   6523                "ReferenceError: x is not defined");
   6524   ExpectString("(function() {"
   6525                "  try {"
   6526                "    return void 0 === x;"
   6527                "  } catch(e) {"
   6528                "    return e.toString();"
   6529                "  }"
   6530                "})()",
   6531                "ReferenceError: x is not defined");
   6532 }
   6533 
   6534 
   6535 THREADED_TEST(ExtensibleOnUndetectable) {
   6536   LocalContext env;
   6537   v8::Isolate* isolate = env->GetIsolate();
   6538   v8::HandleScope scope(isolate);
   6539 
   6540   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
   6541   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
   6542 
   6543   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
   6544   env->Global()->Set(v8_str("undetectable"), obj);
   6545 
   6546   Local<String> source = v8_str("undetectable.x = 42;"
   6547                                 "undetectable.x");
   6548 
   6549   Local<Script> script = v8_compile(source);
   6550 
   6551   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
   6552 
   6553   ExpectBoolean("Object.isExtensible(undetectable)", true);
   6554 
   6555   source = v8_str("Object.preventExtensions(undetectable);");
   6556   script = v8_compile(source);
   6557   script->Run();
   6558   ExpectBoolean("Object.isExtensible(undetectable)", false);
   6559 
   6560   source = v8_str("undetectable.y = 2000;");
   6561   script = v8_compile(source);
   6562   script->Run();
   6563   ExpectBoolean("undetectable.y == undefined", true);
   6564 }
   6565 
   6566 
   6567 
   6568 THREADED_TEST(UndetectableString) {
   6569   LocalContext env;
   6570   v8::HandleScope scope(env->GetIsolate());
   6571 
   6572   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
   6573                                           String::kUndetectableString);
   6574   env->Global()->Set(v8_str("undetectable"), obj);
   6575 
   6576   ExpectString("undetectable", "foo");
   6577   ExpectString("typeof undetectable", "undefined");
   6578   ExpectString("typeof(undetectable)", "undefined");
   6579   ExpectBoolean("typeof undetectable == 'undefined'", true);
   6580   ExpectBoolean("typeof undetectable == 'string'", false);
   6581   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
   6582   ExpectBoolean("!undetectable", true);
   6583 
   6584   ExpectObject("true&&undetectable", obj);
   6585   ExpectBoolean("false&&undetectable", false);
   6586   ExpectBoolean("true||undetectable", true);
   6587   ExpectObject("false||undetectable", obj);
   6588 
   6589   ExpectObject("undetectable&&true", obj);
   6590   ExpectObject("undetectable&&false", obj);
   6591   ExpectBoolean("undetectable||true", true);
   6592   ExpectBoolean("undetectable||false", false);
   6593 
   6594   ExpectBoolean("undetectable==null", true);
   6595   ExpectBoolean("null==undetectable", true);
   6596   ExpectBoolean("undetectable==undefined", true);
   6597   ExpectBoolean("undefined==undetectable", true);
   6598   ExpectBoolean("undetectable==undetectable", true);
   6599 
   6600 
   6601   ExpectBoolean("undetectable===null", false);
   6602   ExpectBoolean("null===undetectable", false);
   6603   ExpectBoolean("undetectable===undefined", false);
   6604   ExpectBoolean("undefined===undetectable", false);
   6605   ExpectBoolean("undetectable===undetectable", true);
   6606 }
   6607 
   6608 
   6609 TEST(UndetectableOptimized) {
   6610   i::FLAG_allow_natives_syntax = true;
   6611   LocalContext env;
   6612   v8::HandleScope scope(env->GetIsolate());
   6613 
   6614   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
   6615                                           String::kUndetectableString);
   6616   env->Global()->Set(v8_str("undetectable"), obj);
   6617   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
   6618 
   6619   ExpectString(
   6620       "function testBranch() {"
   6621       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
   6622       "  if (%_IsUndetectableObject(detectable)) throw 2;"
   6623       "}\n"
   6624       "function testBool() {"
   6625       "  var b1 = !%_IsUndetectableObject(undetectable);"
   6626       "  var b2 = %_IsUndetectableObject(detectable);"
   6627       "  if (b1) throw 3;"
   6628       "  if (b2) throw 4;"
   6629       "  return b1 == b2;"
   6630       "}\n"
   6631       "%OptimizeFunctionOnNextCall(testBranch);"
   6632       "%OptimizeFunctionOnNextCall(testBool);"
   6633       "for (var i = 0; i < 10; i++) {"
   6634       "  testBranch();"
   6635       "  testBool();"
   6636       "}\n"
   6637       "\"PASS\"",
   6638       "PASS");
   6639 }
   6640 
   6641 
   6642 // The point of this test is type checking. We run it only so compilers
   6643 // don't complain about an unused function.
   6644 TEST(PersistentHandles) {
   6645   LocalContext env;
   6646   v8::Isolate* isolate = CcTest::isolate();
   6647   v8::HandleScope scope(isolate);
   6648   Local<String> str = v8_str("foo");
   6649   v8::Persistent<String> p_str(isolate, str);
   6650   p_str.Reset();
   6651   Local<Script> scr = v8_compile("");
   6652   v8::Persistent<Script> p_scr(isolate, scr);
   6653   p_scr.Reset();
   6654   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   6655   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
   6656   p_templ.Reset();
   6657 }
   6658 
   6659 
   6660 static void HandleLogDelegator(
   6661     const v8::FunctionCallbackInfo<v8::Value>& args) {
   6662   ApiTestFuzzer::Fuzz();
   6663 }
   6664 
   6665 
   6666 THREADED_TEST(GlobalObjectTemplate) {
   6667   v8::Isolate* isolate = CcTest::isolate();
   6668   v8::HandleScope handle_scope(isolate);
   6669   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
   6670   global_template->Set(v8_str("JSNI_Log"),
   6671                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
   6672   v8::Local<Context> context = Context::New(isolate, 0, global_template);
   6673   Context::Scope context_scope(context);
   6674   CompileRun("JSNI_Log('LOG')");
   6675 }
   6676 
   6677 
   6678 static const char* kSimpleExtensionSource =
   6679   "function Foo() {"
   6680   "  return 4;"
   6681   "}";
   6682 
   6683 
   6684 TEST(SimpleExtensions) {
   6685   v8::HandleScope handle_scope(CcTest::isolate());
   6686   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
   6687   const char* extension_names[] = { "simpletest" };
   6688   v8::ExtensionConfiguration extensions(1, extension_names);
   6689   v8::Handle<Context> context =
   6690       Context::New(CcTest::isolate(), &extensions);
   6691   Context::Scope lock(context);
   6692   v8::Handle<Value> result = CompileRun("Foo()");
   6693   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
   6694 }
   6695 
   6696 
   6697 TEST(NullExtensions) {
   6698   v8::HandleScope handle_scope(CcTest::isolate());
   6699   v8::RegisterExtension(new Extension("nulltest", NULL));
   6700   const char* extension_names[] = { "nulltest" };
   6701   v8::ExtensionConfiguration extensions(1, extension_names);
   6702   v8::Handle<Context> context =
   6703       Context::New(CcTest::isolate(), &extensions);
   6704   Context::Scope lock(context);
   6705   v8::Handle<Value> result = CompileRun("1+3");
   6706   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
   6707 }
   6708 
   6709 
   6710 static const char* kEmbeddedExtensionSource =
   6711     "function Ret54321(){return 54321;}~~@@$"
   6712     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
   6713 static const int kEmbeddedExtensionSourceValidLen = 34;
   6714 
   6715 
   6716 TEST(ExtensionMissingSourceLength) {
   6717   v8::HandleScope handle_scope(CcTest::isolate());
   6718   v8::RegisterExtension(new Extension("srclentest_fail",
   6719                                       kEmbeddedExtensionSource));
   6720   const char* extension_names[] = { "srclentest_fail" };
   6721   v8::ExtensionConfiguration extensions(1, extension_names);
   6722   v8::Handle<Context> context =
   6723       Context::New(CcTest::isolate(), &extensions);
   6724   CHECK_EQ(0, *context);
   6725 }
   6726 
   6727 
   6728 TEST(ExtensionWithSourceLength) {
   6729   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
   6730        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
   6731     v8::HandleScope handle_scope(CcTest::isolate());
   6732     i::ScopedVector<char> extension_name(32);
   6733     i::SNPrintF(extension_name, "ext #%d", source_len);
   6734     v8::RegisterExtension(new Extension(extension_name.start(),
   6735                                         kEmbeddedExtensionSource, 0, 0,
   6736                                         source_len));
   6737     const char* extension_names[1] = { extension_name.start() };
   6738     v8::ExtensionConfiguration extensions(1, extension_names);
   6739     v8::Handle<Context> context =
   6740       Context::New(CcTest::isolate(), &extensions);
   6741     if (source_len == kEmbeddedExtensionSourceValidLen) {
   6742       Context::Scope lock(context);
   6743       v8::Handle<Value> result = CompileRun("Ret54321()");
   6744       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
   6745     } else {
   6746       // Anything but exactly the right length should fail to compile.
   6747       CHECK_EQ(0, *context);
   6748     }
   6749   }
   6750 }
   6751 
   6752 
   6753 static const char* kEvalExtensionSource1 =
   6754   "function UseEval1() {"
   6755   "  var x = 42;"
   6756   "  return eval('x');"
   6757   "}";
   6758 
   6759 
   6760 static const char* kEvalExtensionSource2 =
   6761   "(function() {"
   6762   "  var x = 42;"
   6763   "  function e() {"
   6764   "    return eval('x');"
   6765   "  }"
   6766   "  this.UseEval2 = e;"
   6767   "})()";
   6768 
   6769 
   6770 TEST(UseEvalFromExtension) {
   6771   v8::HandleScope handle_scope(CcTest::isolate());
   6772   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
   6773   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
   6774   const char* extension_names[] = { "evaltest1", "evaltest2" };
   6775   v8::ExtensionConfiguration extensions(2, extension_names);
   6776   v8::Handle<Context> context =
   6777       Context::New(CcTest::isolate(), &extensions);
   6778   Context::Scope lock(context);
   6779   v8::Handle<Value> result = CompileRun("UseEval1()");
   6780   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
   6781   result = CompileRun("UseEval2()");
   6782   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
   6783 }
   6784 
   6785 
   6786 static const char* kWithExtensionSource1 =
   6787   "function UseWith1() {"
   6788   "  var x = 42;"
   6789   "  with({x:87}) { return x; }"
   6790   "}";
   6791 
   6792 
   6793 
   6794 static const char* kWithExtensionSource2 =
   6795   "(function() {"
   6796   "  var x = 42;"
   6797   "  function e() {"
   6798   "    with ({x:87}) { return x; }"
   6799   "  }"
   6800   "  this.UseWith2 = e;"
   6801   "})()";
   6802 
   6803 
   6804 TEST(UseWithFromExtension) {
   6805   v8::HandleScope handle_scope(CcTest::isolate());
   6806   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
   6807   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
   6808   const char* extension_names[] = { "withtest1", "withtest2" };
   6809   v8::ExtensionConfiguration extensions(2, extension_names);
   6810   v8::Handle<Context> context =
   6811       Context::New(CcTest::isolate(), &extensions);
   6812   Context::Scope lock(context);
   6813   v8::Handle<Value> result = CompileRun("UseWith1()");
   6814   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
   6815   result = CompileRun("UseWith2()");
   6816   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
   6817 }
   6818 
   6819 
   6820 TEST(AutoExtensions) {
   6821   v8::HandleScope handle_scope(CcTest::isolate());
   6822   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
   6823   extension->set_auto_enable(true);
   6824   v8::RegisterExtension(extension);
   6825   v8::Handle<Context> context =
   6826       Context::New(CcTest::isolate());
   6827   Context::Scope lock(context);
   6828   v8::Handle<Value> result = CompileRun("Foo()");
   6829   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
   6830 }
   6831 
   6832 
   6833 static const char* kSyntaxErrorInExtensionSource =
   6834     "[";
   6835 
   6836 
   6837 // Test that a syntax error in an extension does not cause a fatal
   6838 // error but results in an empty context.
   6839 TEST(SyntaxErrorExtensions) {
   6840   v8::HandleScope handle_scope(CcTest::isolate());
   6841   v8::RegisterExtension(new Extension("syntaxerror",
   6842                                       kSyntaxErrorInExtensionSource));
   6843   const char* extension_names[] = { "syntaxerror" };
   6844   v8::ExtensionConfiguration extensions(1, extension_names);
   6845   v8::Handle<Context> context =
   6846       Context::New(CcTest::isolate(), &extensions);
   6847   CHECK(context.IsEmpty());
   6848 }
   6849 
   6850 
   6851 static const char* kExceptionInExtensionSource =
   6852     "throw 42";
   6853 
   6854 
   6855 // Test that an exception when installing an extension does not cause
   6856 // a fatal error but results in an empty context.
   6857 TEST(ExceptionExtensions) {
   6858   v8::HandleScope handle_scope(CcTest::isolate());
   6859   v8::RegisterExtension(new Extension("exception",
   6860                                       kExceptionInExtensionSource));
   6861   const char* extension_names[] = { "exception" };
   6862   v8::ExtensionConfiguration extensions(1, extension_names);
   6863   v8::Handle<Context> context =
   6864       Context::New(CcTest::isolate(), &extensions);
   6865   CHECK(context.IsEmpty());
   6866 }
   6867 
   6868 
   6869 static const char* kNativeCallInExtensionSource =
   6870     "function call_runtime_last_index_of(x) {"
   6871     "  return %StringLastIndexOf(x, 'bob', 10);"
   6872     "}";
   6873 
   6874 
   6875 static const char* kNativeCallTest =
   6876     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
   6877 
   6878 // Test that a native runtime calls are supported in extensions.
   6879 TEST(NativeCallInExtensions) {
   6880   v8::HandleScope handle_scope(CcTest::isolate());
   6881   v8::RegisterExtension(new Extension("nativecall",
   6882                                       kNativeCallInExtensionSource));
   6883   const char* extension_names[] = { "nativecall" };
   6884   v8::ExtensionConfiguration extensions(1, extension_names);
   6885   v8::Handle<Context> context =
   6886       Context::New(CcTest::isolate(), &extensions);
   6887   Context::Scope lock(context);
   6888   v8::Handle<Value> result = CompileRun(kNativeCallTest);
   6889   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
   6890 }
   6891 
   6892 
   6893 class NativeFunctionExtension : public Extension {
   6894  public:
   6895   NativeFunctionExtension(const char* name,
   6896                           const char* source,
   6897                           v8::FunctionCallback fun = &Echo)
   6898       : Extension(name, source),
   6899         function_(fun) { }
   6900 
   6901   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
   6902       v8::Isolate* isolate,
   6903       v8::Handle<v8::String> name) {
   6904     return v8::FunctionTemplate::New(isolate, function_);
   6905   }
   6906 
   6907   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
   6908     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
   6909   }
   6910  private:
   6911   v8::FunctionCallback function_;
   6912 };
   6913 
   6914 
   6915 TEST(NativeFunctionDeclaration) {
   6916   v8::HandleScope handle_scope(CcTest::isolate());
   6917   const char* name = "nativedecl";
   6918   v8::RegisterExtension(new NativeFunctionExtension(name,
   6919                                                     "native function foo();"));
   6920   const char* extension_names[] = { name };
   6921   v8::ExtensionConfiguration extensions(1, extension_names);
   6922   v8::Handle<Context> context =
   6923       Context::New(CcTest::isolate(), &extensions);
   6924   Context::Scope lock(context);
   6925   v8::Handle<Value> result = CompileRun("foo(42);");
   6926   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
   6927 }
   6928 
   6929 
   6930 TEST(NativeFunctionDeclarationError) {
   6931   v8::HandleScope handle_scope(CcTest::isolate());
   6932   const char* name = "nativedeclerr";
   6933   // Syntax error in extension code.
   6934   v8::RegisterExtension(new NativeFunctionExtension(name,
   6935                                                     "native\nfunction foo();"));
   6936   const char* extension_names[] = { name };
   6937   v8::ExtensionConfiguration extensions(1, extension_names);
   6938   v8::Handle<Context> context =
   6939       Context::New(CcTest::isolate(), &extensions);
   6940   CHECK(context.IsEmpty());
   6941 }
   6942 
   6943 
   6944 TEST(NativeFunctionDeclarationErrorEscape) {
   6945   v8::HandleScope handle_scope(CcTest::isolate());
   6946   const char* name = "nativedeclerresc";
   6947   // Syntax error in extension code - escape code in "native" means that
   6948   // it's not treated as a keyword.
   6949   v8::RegisterExtension(new NativeFunctionExtension(
   6950       name,
   6951       "nativ\\u0065 function foo();"));
   6952   const char* extension_names[] = { name };
   6953   v8::ExtensionConfiguration extensions(1, extension_names);
   6954   v8::Handle<Context> context =
   6955       Context::New(CcTest::isolate(), &extensions);
   6956   CHECK(context.IsEmpty());
   6957 }
   6958 
   6959 
   6960 static void CheckDependencies(const char* name, const char* expected) {
   6961   v8::HandleScope handle_scope(CcTest::isolate());
   6962   v8::ExtensionConfiguration config(1, &name);
   6963   LocalContext context(&config);
   6964   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
   6965            context->Global()->Get(v8_str("loaded")));
   6966 }
   6967 
   6968 
   6969 /*
   6970  * Configuration:
   6971  *
   6972  *     /-- B <--\
   6973  * A <-          -- D <-- E
   6974  *     \-- C <--/
   6975  */
   6976 THREADED_TEST(ExtensionDependency) {
   6977   static const char* kEDeps[] = { "D" };
   6978   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
   6979   static const char* kDDeps[] = { "B", "C" };
   6980   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
   6981   static const char* kBCDeps[] = { "A" };
   6982   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
   6983   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
   6984   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
   6985   CheckDependencies("A", "undefinedA");
   6986   CheckDependencies("B", "undefinedAB");
   6987   CheckDependencies("C", "undefinedAC");
   6988   CheckDependencies("D", "undefinedABCD");
   6989   CheckDependencies("E", "undefinedABCDE");
   6990   v8::HandleScope handle_scope(CcTest::isolate());
   6991   static const char* exts[2] = { "C", "E" };
   6992   v8::ExtensionConfiguration config(2, exts);
   6993   LocalContext context(&config);
   6994   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
   6995 }
   6996 
   6997 
   6998 static const char* kExtensionTestScript =
   6999   "native function A();"
   7000   "native function B();"
   7001   "native function C();"
   7002   "function Foo(i) {"
   7003   "  if (i == 0) return A();"
   7004   "  if (i == 1) return B();"
   7005   "  if (i == 2) return C();"
   7006   "}";
   7007 
   7008 
   7009 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
   7010   ApiTestFuzzer::Fuzz();
   7011   if (args.IsConstructCall()) {
   7012     args.This()->Set(v8_str("data"), args.Data());
   7013     args.GetReturnValue().SetNull();
   7014     return;
   7015   }
   7016   args.GetReturnValue().Set(args.Data());
   7017 }
   7018 
   7019 
   7020 class FunctionExtension : public Extension {
   7021  public:
   7022   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
   7023   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
   7024       v8::Isolate* isolate,
   7025       v8::Handle<String> name);
   7026 };
   7027 
   7028 
   7029 static int lookup_count = 0;
   7030 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
   7031     v8::Isolate* isolate, v8::Handle<String> name) {
   7032   lookup_count++;
   7033   if (name->Equals(v8_str("A"))) {
   7034     return v8::FunctionTemplate::New(
   7035         isolate, CallFun, v8::Integer::New(isolate, 8));
   7036   } else if (name->Equals(v8_str("B"))) {
   7037     return v8::FunctionTemplate::New(
   7038         isolate, CallFun, v8::Integer::New(isolate, 7));
   7039   } else if (name->Equals(v8_str("C"))) {
   7040     return v8::FunctionTemplate::New(
   7041         isolate, CallFun, v8::Integer::New(isolate, 6));
   7042   } else {
   7043     return v8::Handle<v8::FunctionTemplate>();
   7044   }
   7045 }
   7046 
   7047 
   7048 THREADED_TEST(FunctionLookup) {
   7049   v8::RegisterExtension(new FunctionExtension());
   7050   v8::HandleScope handle_scope(CcTest::isolate());
   7051   static const char* exts[1] = { "functiontest" };
   7052   v8::ExtensionConfiguration config(1, exts);
   7053   LocalContext context(&config);
   7054   CHECK_EQ(3, lookup_count);
   7055   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
   7056            CompileRun("Foo(0)"));
   7057   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
   7058            CompileRun("Foo(1)"));
   7059   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
   7060            CompileRun("Foo(2)"));
   7061 }
   7062 
   7063 
   7064 THREADED_TEST(NativeFunctionConstructCall) {
   7065   v8::RegisterExtension(new FunctionExtension());
   7066   v8::HandleScope handle_scope(CcTest::isolate());
   7067   static const char* exts[1] = { "functiontest" };
   7068   v8::ExtensionConfiguration config(1, exts);
   7069   LocalContext context(&config);
   7070   for (int i = 0; i < 10; i++) {
   7071     // Run a few times to ensure that allocation of objects doesn't
   7072     // change behavior of a constructor function.
   7073     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
   7074              CompileRun("(new A()).data"));
   7075     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
   7076              CompileRun("(new B()).data"));
   7077     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
   7078              CompileRun("(new C()).data"));
   7079   }
   7080 }
   7081 
   7082 
   7083 static const char* last_location;
   7084 static const char* last_message;
   7085 void StoringErrorCallback(const char* location, const char* message) {
   7086   if (last_location == NULL) {
   7087     last_location = location;
   7088     last_message = message;
   7089   }
   7090 }
   7091 
   7092 
   7093 // ErrorReporting creates a circular extensions configuration and
   7094 // tests that the fatal error handler gets called.  This renders V8
   7095 // unusable and therefore this test cannot be run in parallel.
   7096 TEST(ErrorReporting) {
   7097   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   7098   static const char* aDeps[] = { "B" };
   7099   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
   7100   static const char* bDeps[] = { "A" };
   7101   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
   7102   last_location = NULL;
   7103   v8::ExtensionConfiguration config(1, bDeps);
   7104   v8::Handle<Context> context =
   7105       Context::New(CcTest::isolate(), &config);
   7106   CHECK(context.IsEmpty());
   7107   CHECK_NE(last_location, NULL);
   7108 }
   7109 
   7110 
   7111 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
   7112                                              v8::Handle<Value> data) {
   7113   CHECK(message->GetScriptResourceName()->IsUndefined());
   7114   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
   7115   message->GetLineNumber();
   7116   message->GetSourceLine();
   7117 }
   7118 
   7119 
   7120 THREADED_TEST(ErrorWithMissingScriptInfo) {
   7121   LocalContext context;
   7122   v8::HandleScope scope(context->GetIsolate());
   7123   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
   7124   CompileRun("throw Error()");
   7125   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
   7126 }
   7127 
   7128 
   7129 struct FlagAndPersistent {
   7130   bool flag;
   7131   v8::Persistent<v8::Object> handle;
   7132 };
   7133 
   7134 
   7135 static void DisposeAndSetFlag(
   7136     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7137   data.GetParameter()->handle.Reset();
   7138   data.GetParameter()->flag = true;
   7139 }
   7140 
   7141 
   7142 THREADED_TEST(IndependentWeakHandle) {
   7143   v8::Isolate* iso = CcTest::isolate();
   7144   v8::HandleScope scope(iso);
   7145   v8::Handle<Context> context = Context::New(iso);
   7146   Context::Scope context_scope(context);
   7147 
   7148   FlagAndPersistent object_a, object_b;
   7149 
   7150   {
   7151     v8::HandleScope handle_scope(iso);
   7152     object_a.handle.Reset(iso, v8::Object::New(iso));
   7153     object_b.handle.Reset(iso, v8::Object::New(iso));
   7154   }
   7155 
   7156   object_a.flag = false;
   7157   object_b.flag = false;
   7158   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
   7159   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
   7160   CHECK(!object_b.handle.IsIndependent());
   7161   object_a.handle.MarkIndependent();
   7162   object_b.handle.MarkIndependent();
   7163   CHECK(object_b.handle.IsIndependent());
   7164   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   7165   CHECK(object_a.flag);
   7166   CHECK(object_b.flag);
   7167 }
   7168 
   7169 
   7170 static void InvokeScavenge() {
   7171   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   7172 }
   7173 
   7174 
   7175 static void InvokeMarkSweep() {
   7176   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   7177 }
   7178 
   7179 
   7180 static void ForceScavenge(
   7181     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7182   data.GetParameter()->handle.Reset();
   7183   data.GetParameter()->flag = true;
   7184   InvokeScavenge();
   7185 }
   7186 
   7187 
   7188 static void ForceMarkSweep(
   7189     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7190   data.GetParameter()->handle.Reset();
   7191   data.GetParameter()->flag = true;
   7192   InvokeMarkSweep();
   7193 }
   7194 
   7195 
   7196 THREADED_TEST(GCFromWeakCallbacks) {
   7197   v8::Isolate* isolate = CcTest::isolate();
   7198   v8::HandleScope scope(isolate);
   7199   v8::Handle<Context> context = Context::New(isolate);
   7200   Context::Scope context_scope(context);
   7201 
   7202   static const int kNumberOfGCTypes = 2;
   7203   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
   7204       Callback;
   7205   Callback gc_forcing_callback[kNumberOfGCTypes] =
   7206       {&ForceScavenge, &ForceMarkSweep};
   7207 
   7208   typedef void (*GCInvoker)();
   7209   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
   7210 
   7211   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
   7212     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
   7213       FlagAndPersistent object;
   7214       {
   7215         v8::HandleScope handle_scope(isolate);
   7216         object.handle.Reset(isolate, v8::Object::New(isolate));
   7217       }
   7218       object.flag = false;
   7219       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
   7220       object.handle.MarkIndependent();
   7221       invoke_gc[outer_gc]();
   7222       CHECK(object.flag);
   7223     }
   7224   }
   7225 }
   7226 
   7227 
   7228 static void RevivingCallback(
   7229     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
   7230   data.GetParameter()->handle.ClearWeak();
   7231   data.GetParameter()->flag = true;
   7232 }
   7233 
   7234 
   7235 THREADED_TEST(IndependentHandleRevival) {
   7236   v8::Isolate* isolate = CcTest::isolate();
   7237   v8::HandleScope scope(isolate);
   7238   v8::Handle<Context> context = Context::New(isolate);
   7239   Context::Scope context_scope(context);
   7240 
   7241   FlagAndPersistent object;
   7242   {
   7243     v8::HandleScope handle_scope(isolate);
   7244     v8::Local<v8::Object> o = v8::Object::New(isolate);
   7245     object.handle.Reset(isolate, o);
   7246     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
   7247     v8::Local<String> y_str = v8_str("y");
   7248     o->Set(y_str, y_str);
   7249   }
   7250   object.flag = false;
   7251   object.handle.SetWeak(&object, &RevivingCallback);
   7252   object.handle.MarkIndependent();
   7253   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   7254   CHECK(object.flag);
   7255   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   7256   {
   7257     v8::HandleScope handle_scope(isolate);
   7258     v8::Local<v8::Object> o =
   7259         v8::Local<v8::Object>::New(isolate, object.handle);
   7260     v8::Local<String> y_str = v8_str("y");
   7261     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
   7262     CHECK(o->Get(y_str)->Equals(y_str));
   7263   }
   7264 }
   7265 
   7266 
   7267 v8::Handle<Function> args_fun;
   7268 
   7269 
   7270 static void ArgumentsTestCallback(
   7271     const v8::FunctionCallbackInfo<v8::Value>& args) {
   7272   ApiTestFuzzer::Fuzz();
   7273   v8::Isolate* isolate = args.GetIsolate();
   7274   CHECK_EQ(args_fun, args.Callee());
   7275   CHECK_EQ(3, args.Length());
   7276   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
   7277   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
   7278   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
   7279   CHECK_EQ(v8::Undefined(isolate), args[3]);
   7280   v8::HandleScope scope(args.GetIsolate());
   7281   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   7282 }
   7283 
   7284 
   7285 THREADED_TEST(Arguments) {
   7286   v8::Isolate* isolate = CcTest::isolate();
   7287   v8::HandleScope scope(isolate);
   7288   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
   7289   global->Set(v8_str("f"),
   7290               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
   7291   LocalContext context(NULL, global);
   7292   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
   7293   v8_compile("f(1, 2, 3)")->Run();
   7294 }
   7295 
   7296 
   7297 static void NoBlockGetterX(Local<String> name,
   7298                            const v8::PropertyCallbackInfo<v8::Value>&) {
   7299 }
   7300 
   7301 
   7302 static void NoBlockGetterI(uint32_t index,
   7303                            const v8::PropertyCallbackInfo<v8::Value>&) {
   7304 }
   7305 
   7306 
   7307 static void PDeleter(Local<String> name,
   7308                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   7309   if (!name->Equals(v8_str("foo"))) {
   7310     return;  // not intercepted
   7311   }
   7312 
   7313   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
   7314 }
   7315 
   7316 
   7317 static void IDeleter(uint32_t index,
   7318                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   7319   if (index != 2) {
   7320     return;  // not intercepted
   7321   }
   7322 
   7323   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
   7324 }
   7325 
   7326 
   7327 THREADED_TEST(Deleter) {
   7328   v8::Isolate* isolate = CcTest::isolate();
   7329   v8::HandleScope scope(isolate);
   7330   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   7331   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
   7332   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
   7333   LocalContext context;
   7334   context->Global()->Set(v8_str("k"), obj->NewInstance());
   7335   CompileRun(
   7336     "k.foo = 'foo';"
   7337     "k.bar = 'bar';"
   7338     "k[2] = 2;"
   7339     "k[4] = 4;");
   7340   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
   7341   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
   7342 
   7343   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
   7344   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
   7345 
   7346   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
   7347   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
   7348 
   7349   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
   7350   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
   7351 }
   7352 
   7353 
   7354 static void GetK(Local<String> name,
   7355                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   7356   ApiTestFuzzer::Fuzz();
   7357   if (name->Equals(v8_str("foo")) ||
   7358       name->Equals(v8_str("bar")) ||
   7359       name->Equals(v8_str("baz"))) {
   7360     info.GetReturnValue().SetUndefined();
   7361   }
   7362 }
   7363 
   7364 
   7365 static void IndexedGetK(uint32_t index,
   7366                         const v8::PropertyCallbackInfo<v8::Value>& info) {
   7367   ApiTestFuzzer::Fuzz();
   7368   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
   7369 }
   7370 
   7371 
   7372 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
   7373   ApiTestFuzzer::Fuzz();
   7374   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
   7375   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
   7376   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
   7377   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
   7378   info.GetReturnValue().Set(result);
   7379 }
   7380 
   7381 
   7382 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
   7383   ApiTestFuzzer::Fuzz();
   7384   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   7385   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
   7386   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
   7387   info.GetReturnValue().Set(result);
   7388 }
   7389 
   7390 
   7391 THREADED_TEST(Enumerators) {
   7392   v8::Isolate* isolate = CcTest::isolate();
   7393   v8::HandleScope scope(isolate);
   7394   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   7395   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
   7396   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
   7397   LocalContext context;
   7398   context->Global()->Set(v8_str("k"), obj->NewInstance());
   7399   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   7400     "k[10] = 0;"
   7401     "k.a = 0;"
   7402     "k[5] = 0;"
   7403     "k.b = 0;"
   7404     "k[4294967295] = 0;"
   7405     "k.c = 0;"
   7406     "k[4294967296] = 0;"
   7407     "k.d = 0;"
   7408     "k[140000] = 0;"
   7409     "k.e = 0;"
   7410     "k[30000000000] = 0;"
   7411     "k.f = 0;"
   7412     "var result = [];"
   7413     "for (var prop in k) {"
   7414     "  result.push(prop);"
   7415     "}"
   7416     "result"));
   7417   // Check that we get all the property names returned including the
   7418   // ones from the enumerators in the right order: indexed properties
   7419   // in numerical order, indexed interceptor properties, named
   7420   // properties in insertion order, named interceptor properties.
   7421   // This order is not mandated by the spec, so this test is just
   7422   // documenting our behavior.
   7423   CHECK_EQ(17, result->Length());
   7424   // Indexed properties in numerical order.
   7425   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
   7426   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
   7427   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
   7428   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
   7429   // Indexed interceptor properties in the order they are returned
   7430   // from the enumerator interceptor.
   7431   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
   7432   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
   7433   // Named properties in insertion order.
   7434   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
   7435   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
   7436   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
   7437   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
   7438   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
   7439   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
   7440   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
   7441   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
   7442   // Named interceptor properties.
   7443   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
   7444   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
   7445   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
   7446 }
   7447 
   7448 
   7449 int p_getter_count;
   7450 int p_getter_count2;
   7451 
   7452 
   7453 static void PGetter(Local<String> name,
   7454                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   7455   ApiTestFuzzer::Fuzz();
   7456   p_getter_count++;
   7457   v8::Handle<v8::Object> global =
   7458       info.GetIsolate()->GetCurrentContext()->Global();
   7459   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
   7460   if (name->Equals(v8_str("p1"))) {
   7461     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
   7462   } else if (name->Equals(v8_str("p2"))) {
   7463     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
   7464   } else if (name->Equals(v8_str("p3"))) {
   7465     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
   7466   } else if (name->Equals(v8_str("p4"))) {
   7467     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
   7468   }
   7469 }
   7470 
   7471 
   7472 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
   7473   ApiTestFuzzer::Fuzz();
   7474   LocalContext context;
   7475   context->Global()->Set(v8_str("o1"), obj->NewInstance());
   7476   CompileRun(
   7477     "o1.__proto__ = { };"
   7478     "var o2 = { __proto__: o1 };"
   7479     "var o3 = { __proto__: o2 };"
   7480     "var o4 = { __proto__: o3 };"
   7481     "for (var i = 0; i < 10; i++) o4.p4;"
   7482     "for (var i = 0; i < 10; i++) o3.p3;"
   7483     "for (var i = 0; i < 10; i++) o2.p2;"
   7484     "for (var i = 0; i < 10; i++) o1.p1;");
   7485 }
   7486 
   7487 
   7488 static void PGetter2(Local<String> name,
   7489                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   7490   ApiTestFuzzer::Fuzz();
   7491   p_getter_count2++;
   7492   v8::Handle<v8::Object> global =
   7493       info.GetIsolate()->GetCurrentContext()->Global();
   7494   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
   7495   if (name->Equals(v8_str("p1"))) {
   7496     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
   7497   } else if (name->Equals(v8_str("p2"))) {
   7498     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
   7499   } else if (name->Equals(v8_str("p3"))) {
   7500     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
   7501   } else if (name->Equals(v8_str("p4"))) {
   7502     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
   7503   }
   7504 }
   7505 
   7506 
   7507 THREADED_TEST(GetterHolders) {
   7508   v8::Isolate* isolate = CcTest::isolate();
   7509   v8::HandleScope scope(isolate);
   7510   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   7511   obj->SetAccessor(v8_str("p1"), PGetter);
   7512   obj->SetAccessor(v8_str("p2"), PGetter);
   7513   obj->SetAccessor(v8_str("p3"), PGetter);
   7514   obj->SetAccessor(v8_str("p4"), PGetter);
   7515   p_getter_count = 0;
   7516   RunHolderTest(obj);
   7517   CHECK_EQ(40, p_getter_count);
   7518 }
   7519 
   7520 
   7521 THREADED_TEST(PreInterceptorHolders) {
   7522   v8::Isolate* isolate = CcTest::isolate();
   7523   v8::HandleScope scope(isolate);
   7524   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   7525   obj->SetNamedPropertyHandler(PGetter2);
   7526   p_getter_count2 = 0;
   7527   RunHolderTest(obj);
   7528   CHECK_EQ(40, p_getter_count2);
   7529 }
   7530 
   7531 
   7532 THREADED_TEST(ObjectInstantiation) {
   7533   v8::Isolate* isolate = CcTest::isolate();
   7534   v8::HandleScope scope(isolate);
   7535   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   7536   templ->SetAccessor(v8_str("t"), PGetter2);
   7537   LocalContext context;
   7538   context->Global()->Set(v8_str("o"), templ->NewInstance());
   7539   for (int i = 0; i < 100; i++) {
   7540     v8::HandleScope inner_scope(CcTest::isolate());
   7541     v8::Handle<v8::Object> obj = templ->NewInstance();
   7542     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
   7543     context->Global()->Set(v8_str("o2"), obj);
   7544     v8::Handle<Value> value =
   7545         CompileRun("o.__proto__ === o2.__proto__");
   7546     CHECK_EQ(v8::True(isolate), value);
   7547     context->Global()->Set(v8_str("o"), obj);
   7548   }
   7549 }
   7550 
   7551 
   7552 static int StrCmp16(uint16_t* a, uint16_t* b) {
   7553   while (true) {
   7554     if (*a == 0 && *b == 0) return 0;
   7555     if (*a != *b) return 0 + *a - *b;
   7556     a++;
   7557     b++;
   7558   }
   7559 }
   7560 
   7561 
   7562 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
   7563   while (true) {
   7564     if (n-- == 0) return 0;
   7565     if (*a == 0 && *b == 0) return 0;
   7566     if (*a != *b) return 0 + *a - *b;
   7567     a++;
   7568     b++;
   7569   }
   7570 }
   7571 
   7572 
   7573 int GetUtf8Length(Handle<String> str) {
   7574   int len = str->Utf8Length();
   7575   if (len < 0) {
   7576     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
   7577     i::String::Flatten(istr);
   7578     len = str->Utf8Length();
   7579   }
   7580   return len;
   7581 }
   7582 
   7583 
   7584 THREADED_TEST(StringWrite) {
   7585   LocalContext context;
   7586   v8::HandleScope scope(context->GetIsolate());
   7587   v8::Handle<String> str = v8_str("abcde");
   7588   // abc<Icelandic eth><Unicode snowman>.
   7589   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
   7590   v8::Handle<String> str3 = v8::String::NewFromUtf8(
   7591       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
   7592   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
   7593   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
   7594   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
   7595       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
   7596   // single lead surrogate
   7597   uint16_t lead[1] = { 0xd800 };
   7598   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
   7599       context->GetIsolate(), lead, v8::String::kNormalString, 1);
   7600   // single trail surrogate
   7601   uint16_t trail[1] = { 0xdc00 };
   7602   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
   7603       context->GetIsolate(), trail, v8::String::kNormalString, 1);
   7604   // surrogate pair
   7605   uint16_t pair[2] = { 0xd800,  0xdc00 };
   7606   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
   7607       context->GetIsolate(), pair, v8::String::kNormalString, 2);
   7608   const int kStride = 4;  // Must match stride in for loops in JS below.
   7609   CompileRun(
   7610       "var left = '';"
   7611       "for (var i = 0; i < 0xd800; i += 4) {"
   7612       "  left = left + String.fromCharCode(i);"
   7613       "}");
   7614   CompileRun(
   7615       "var right = '';"
   7616       "for (var i = 0; i < 0xd800; i += 4) {"
   7617       "  right = String.fromCharCode(i) + right;"
   7618       "}");
   7619   v8::Handle<v8::Object> global = context->Global();
   7620   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
   7621   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
   7622 
   7623   CHECK_EQ(5, str2->Length());
   7624   CHECK_EQ(0xd800 / kStride, left_tree->Length());
   7625   CHECK_EQ(0xd800 / kStride, right_tree->Length());
   7626 
   7627   char buf[100];
   7628   char utf8buf[0xd800 * 3];
   7629   uint16_t wbuf[100];
   7630   int len;
   7631   int charlen;
   7632 
   7633   memset(utf8buf, 0x1, 1000);
   7634   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
   7635   CHECK_EQ(9, len);
   7636   CHECK_EQ(5, charlen);
   7637   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
   7638 
   7639   memset(utf8buf, 0x1, 1000);
   7640   len = str2->WriteUtf8(utf8buf, 8, &charlen);
   7641   CHECK_EQ(8, len);
   7642   CHECK_EQ(5, charlen);
   7643   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
   7644 
   7645   memset(utf8buf, 0x1, 1000);
   7646   len = str2->WriteUtf8(utf8buf, 7, &charlen);
   7647   CHECK_EQ(5, len);
   7648   CHECK_EQ(4, charlen);
   7649   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
   7650 
   7651   memset(utf8buf, 0x1, 1000);
   7652   len = str2->WriteUtf8(utf8buf, 6, &charlen);
   7653   CHECK_EQ(5, len);
   7654   CHECK_EQ(4, charlen);
   7655   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
   7656 
   7657   memset(utf8buf, 0x1, 1000);
   7658   len = str2->WriteUtf8(utf8buf, 5, &charlen);
   7659   CHECK_EQ(5, len);
   7660   CHECK_EQ(4, charlen);
   7661   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
   7662 
   7663   memset(utf8buf, 0x1, 1000);
   7664   len = str2->WriteUtf8(utf8buf, 4, &charlen);
   7665   CHECK_EQ(3, len);
   7666   CHECK_EQ(3, charlen);
   7667   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
   7668 
   7669   memset(utf8buf, 0x1, 1000);
   7670   len = str2->WriteUtf8(utf8buf, 3, &charlen);
   7671   CHECK_EQ(3, len);
   7672   CHECK_EQ(3, charlen);
   7673   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
   7674 
   7675   memset(utf8buf, 0x1, 1000);
   7676   len = str2->WriteUtf8(utf8buf, 2, &charlen);
   7677   CHECK_EQ(2, len);
   7678   CHECK_EQ(2, charlen);
   7679   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
   7680 
   7681   // allow orphan surrogates by default
   7682   memset(utf8buf, 0x1, 1000);
   7683   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
   7684   CHECK_EQ(13, len);
   7685   CHECK_EQ(8, charlen);
   7686   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
   7687 
   7688   // replace orphan surrogates with unicode replacement character
   7689   memset(utf8buf, 0x1, 1000);
   7690   len = orphans_str->WriteUtf8(utf8buf,
   7691                                sizeof(utf8buf),
   7692                                &charlen,
   7693                                String::REPLACE_INVALID_UTF8);
   7694   CHECK_EQ(13, len);
   7695   CHECK_EQ(8, charlen);
   7696   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
   7697 
   7698   // replace single lead surrogate with unicode replacement character
   7699   memset(utf8buf, 0x1, 1000);
   7700   len = lead_str->WriteUtf8(utf8buf,
   7701                             sizeof(utf8buf),
   7702                             &charlen,
   7703                             String::REPLACE_INVALID_UTF8);
   7704   CHECK_EQ(4, len);
   7705   CHECK_EQ(1, charlen);
   7706   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
   7707 
   7708   // replace single trail surrogate with unicode replacement character
   7709   memset(utf8buf, 0x1, 1000);
   7710   len = trail_str->WriteUtf8(utf8buf,
   7711                              sizeof(utf8buf),
   7712                              &charlen,
   7713                              String::REPLACE_INVALID_UTF8);
   7714   CHECK_EQ(4, len);
   7715   CHECK_EQ(1, charlen);
   7716   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
   7717 
   7718   // do not replace / write anything if surrogate pair does not fit the buffer
   7719   // space
   7720   memset(utf8buf, 0x1, 1000);
   7721   len = pair_str->WriteUtf8(utf8buf,
   7722                              3,
   7723                              &charlen,
   7724                              String::REPLACE_INVALID_UTF8);
   7725   CHECK_EQ(0, len);
   7726   CHECK_EQ(0, charlen);
   7727 
   7728   memset(utf8buf, 0x1, sizeof(utf8buf));
   7729   len = GetUtf8Length(left_tree);
   7730   int utf8_expected =
   7731       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
   7732   CHECK_EQ(utf8_expected, len);
   7733   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
   7734   CHECK_EQ(utf8_expected, len);
   7735   CHECK_EQ(0xd800 / kStride, charlen);
   7736   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
   7737   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
   7738   CHECK_EQ(0xc0 - kStride,
   7739            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
   7740   CHECK_EQ(1, utf8buf[utf8_expected]);
   7741 
   7742   memset(utf8buf, 0x1, sizeof(utf8buf));
   7743   len = GetUtf8Length(right_tree);
   7744   CHECK_EQ(utf8_expected, len);
   7745   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
   7746   CHECK_EQ(utf8_expected, len);
   7747   CHECK_EQ(0xd800 / kStride, charlen);
   7748   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
   7749   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
   7750   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
   7751   CHECK_EQ(1, utf8buf[utf8_expected]);
   7752 
   7753   memset(buf, 0x1, sizeof(buf));
   7754   memset(wbuf, 0x1, sizeof(wbuf));
   7755   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
   7756   CHECK_EQ(5, len);
   7757   len = str->Write(wbuf);
   7758   CHECK_EQ(5, len);
   7759   CHECK_EQ(0, strcmp("abcde", buf));
   7760   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
   7761   CHECK_EQ(0, StrCmp16(answer1, wbuf));
   7762 
   7763   memset(buf, 0x1, sizeof(buf));
   7764   memset(wbuf, 0x1, sizeof(wbuf));
   7765   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
   7766   CHECK_EQ(4, len);
   7767   len = str->Write(wbuf, 0, 4);
   7768   CHECK_EQ(4, len);
   7769   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
   7770   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
   7771   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
   7772 
   7773   memset(buf, 0x1, sizeof(buf));
   7774   memset(wbuf, 0x1, sizeof(wbuf));
   7775   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
   7776   CHECK_EQ(5, len);
   7777   len = str->Write(wbuf, 0, 5);
   7778   CHECK_EQ(5, len);
   7779   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
   7780   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
   7781   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
   7782 
   7783   memset(buf, 0x1, sizeof(buf));
   7784   memset(wbuf, 0x1, sizeof(wbuf));
   7785   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
   7786   CHECK_EQ(5, len);
   7787   len = str->Write(wbuf, 0, 6);
   7788   CHECK_EQ(5, len);
   7789   CHECK_EQ(0, strcmp("abcde", buf));
   7790   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
   7791   CHECK_EQ(0, StrCmp16(answer4, wbuf));
   7792 
   7793   memset(buf, 0x1, sizeof(buf));
   7794   memset(wbuf, 0x1, sizeof(wbuf));
   7795   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
   7796   CHECK_EQ(1, len);
   7797   len = str->Write(wbuf, 4, -1);
   7798   CHECK_EQ(1, len);
   7799   CHECK_EQ(0, strcmp("e", buf));
   7800   uint16_t answer5[] = {'e', '\0'};
   7801   CHECK_EQ(0, StrCmp16(answer5, wbuf));
   7802 
   7803   memset(buf, 0x1, sizeof(buf));
   7804   memset(wbuf, 0x1, sizeof(wbuf));
   7805   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
   7806   CHECK_EQ(1, len);
   7807   len = str->Write(wbuf, 4, 6);
   7808   CHECK_EQ(1, len);
   7809   CHECK_EQ(0, strcmp("e", buf));
   7810   CHECK_EQ(0, StrCmp16(answer5, wbuf));
   7811 
   7812   memset(buf, 0x1, sizeof(buf));
   7813   memset(wbuf, 0x1, sizeof(wbuf));
   7814   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
   7815   CHECK_EQ(1, len);
   7816   len = str->Write(wbuf, 4, 1);
   7817   CHECK_EQ(1, len);
   7818   CHECK_EQ(0, strncmp("e\1", buf, 2));
   7819   uint16_t answer6[] = {'e', 0x101};
   7820   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
   7821 
   7822   memset(buf, 0x1, sizeof(buf));
   7823   memset(wbuf, 0x1, sizeof(wbuf));
   7824   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
   7825   CHECK_EQ(1, len);
   7826   len = str->Write(wbuf, 3, 1);
   7827   CHECK_EQ(1, len);
   7828   CHECK_EQ(0, strncmp("d\1", buf, 2));
   7829   uint16_t answer7[] = {'d', 0x101};
   7830   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
   7831 
   7832   memset(wbuf, 0x1, sizeof(wbuf));
   7833   wbuf[5] = 'X';
   7834   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
   7835   CHECK_EQ(5, len);
   7836   CHECK_EQ('X', wbuf[5]);
   7837   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
   7838   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
   7839   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
   7840   CHECK_NE(0, StrCmp16(answer8b, wbuf));
   7841   wbuf[5] = '\0';
   7842   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
   7843 
   7844   memset(buf, 0x1, sizeof(buf));
   7845   buf[5] = 'X';
   7846   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
   7847                           0,
   7848                           6,
   7849                           String::NO_NULL_TERMINATION);
   7850   CHECK_EQ(5, len);
   7851   CHECK_EQ('X', buf[5]);
   7852   CHECK_EQ(0, strncmp("abcde", buf, 5));
   7853   CHECK_NE(0, strcmp("abcde", buf));
   7854   buf[5] = '\0';
   7855   CHECK_EQ(0, strcmp("abcde", buf));
   7856 
   7857   memset(utf8buf, 0x1, sizeof(utf8buf));
   7858   utf8buf[8] = 'X';
   7859   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
   7860                         String::NO_NULL_TERMINATION);
   7861   CHECK_EQ(8, len);
   7862   CHECK_EQ('X', utf8buf[8]);
   7863   CHECK_EQ(5, charlen);
   7864   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
   7865   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
   7866   utf8buf[8] = '\0';
   7867   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
   7868 
   7869   memset(utf8buf, 0x1, sizeof(utf8buf));
   7870   utf8buf[5] = 'X';
   7871   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
   7872                         String::NO_NULL_TERMINATION);
   7873   CHECK_EQ(5, len);
   7874   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
   7875   CHECK_EQ(5, charlen);
   7876   utf8buf[5] = '\0';
   7877   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
   7878 
   7879   memset(buf, 0x1, sizeof(buf));
   7880   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
   7881   CHECK_EQ(7, len);
   7882   CHECK_EQ(0, strcmp("abc", buf));
   7883   CHECK_EQ(0, buf[3]);
   7884   CHECK_EQ(0, strcmp("def", buf + 4));
   7885 
   7886   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
   7887   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
   7888   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
   7889 }
   7890 
   7891 
   7892 static void Utf16Helper(
   7893     LocalContext& context,  // NOLINT
   7894     const char* name,
   7895     const char* lengths_name,
   7896     int len) {
   7897   Local<v8::Array> a =
   7898       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
   7899   Local<v8::Array> alens =
   7900       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
   7901   for (int i = 0; i < len; i++) {
   7902     Local<v8::String> string =
   7903       Local<v8::String>::Cast(a->Get(i));
   7904     Local<v8::Number> expected_len =
   7905       Local<v8::Number>::Cast(alens->Get(i));
   7906     int length = GetUtf8Length(string);
   7907     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
   7908   }
   7909 }
   7910 
   7911 
   7912 static uint16_t StringGet(Handle<String> str, int index) {
   7913   i::Handle<i::String> istring =
   7914       v8::Utils::OpenHandle(String::Cast(*str));
   7915   return istring->Get(index);
   7916 }
   7917 
   7918 
   7919 static void WriteUtf8Helper(
   7920     LocalContext& context,  // NOLINT
   7921     const char* name,
   7922     const char* lengths_name,
   7923     int len) {
   7924   Local<v8::Array> b =
   7925       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
   7926   Local<v8::Array> alens =
   7927       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
   7928   char buffer[1000];
   7929   char buffer2[1000];
   7930   for (int i = 0; i < len; i++) {
   7931     Local<v8::String> string =
   7932       Local<v8::String>::Cast(b->Get(i));
   7933     Local<v8::Number> expected_len =
   7934       Local<v8::Number>::Cast(alens->Get(i));
   7935     int utf8_length = static_cast<int>(expected_len->Value());
   7936     for (int j = utf8_length + 1; j >= 0; j--) {
   7937       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
   7938       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
   7939       int nchars;
   7940       int utf8_written =
   7941           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
   7942       int utf8_written2 =
   7943           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
   7944       CHECK_GE(utf8_length + 1, utf8_written);
   7945       CHECK_GE(utf8_length, utf8_written2);
   7946       for (int k = 0; k < utf8_written2; k++) {
   7947         CHECK_EQ(buffer[k], buffer2[k]);
   7948       }
   7949       CHECK(nchars * 3 >= utf8_written - 1);
   7950       CHECK(nchars <= utf8_written);
   7951       if (j == utf8_length + 1) {
   7952         CHECK_EQ(utf8_written2, utf8_length);
   7953         CHECK_EQ(utf8_written2 + 1, utf8_written);
   7954       }
   7955       CHECK_EQ(buffer[utf8_written], 42);
   7956       if (j > utf8_length) {
   7957         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
   7958         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
   7959         Handle<String> roundtrip = v8_str(buffer);
   7960         CHECK(roundtrip->Equals(string));
   7961       } else {
   7962         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
   7963       }
   7964       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
   7965       if (nchars >= 2) {
   7966         uint16_t trail = StringGet(string, nchars - 1);
   7967         uint16_t lead = StringGet(string, nchars - 2);
   7968         if (((lead & 0xfc00) == 0xd800) &&
   7969             ((trail & 0xfc00) == 0xdc00)) {
   7970           unsigned char u1 = buffer2[utf8_written2 - 4];
   7971           unsigned char u2 = buffer2[utf8_written2 - 3];
   7972           unsigned char u3 = buffer2[utf8_written2 - 2];
   7973           unsigned char u4 = buffer2[utf8_written2 - 1];
   7974           CHECK_EQ((u1 & 0xf8), 0xf0);
   7975           CHECK_EQ((u2 & 0xc0), 0x80);
   7976           CHECK_EQ((u3 & 0xc0), 0x80);
   7977           CHECK_EQ((u4 & 0xc0), 0x80);
   7978           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
   7979           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
   7980           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
   7981           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
   7982           CHECK_EQ((u1 & 0x3), c >> 18);
   7983         }
   7984       }
   7985     }
   7986   }
   7987 }
   7988 
   7989 
   7990 THREADED_TEST(Utf16) {
   7991   LocalContext context;
   7992   v8::HandleScope scope(context->GetIsolate());
   7993   CompileRun(
   7994       "var pad = '01234567890123456789';"
   7995       "var p = [];"
   7996       "var plens = [20, 3, 3];"
   7997       "p.push('01234567890123456789');"
   7998       "var lead = 0xd800;"
   7999       "var trail = 0xdc00;"
   8000       "p.push(String.fromCharCode(0xd800));"
   8001       "p.push(String.fromCharCode(0xdc00));"
   8002       "var a = [];"
   8003       "var b = [];"
   8004       "var c = [];"
   8005       "var alens = [];"
   8006       "for (var i = 0; i < 3; i++) {"
   8007       "  p[1] = String.fromCharCode(lead++);"
   8008       "  for (var j = 0; j < 3; j++) {"
   8009       "    p[2] = String.fromCharCode(trail++);"
   8010       "    a.push(p[i] + p[j]);"
   8011       "    b.push(p[i] + p[j]);"
   8012       "    c.push(p[i] + p[j]);"
   8013       "    alens.push(plens[i] + plens[j]);"
   8014       "  }"
   8015       "}"
   8016       "alens[5] -= 2;"  // Here the surrogate pairs match up.
   8017       "var a2 = [];"
   8018       "var b2 = [];"
   8019       "var c2 = [];"
   8020       "var a2lens = [];"
   8021       "for (var m = 0; m < 9; m++) {"
   8022       "  for (var n = 0; n < 9; n++) {"
   8023       "    a2.push(a[m] + a[n]);"
   8024       "    b2.push(b[m] + b[n]);"
   8025       "    var newc = 'x' + c[m] + c[n] + 'y';"
   8026       "    c2.push(newc.substring(1, newc.length - 1));"
   8027       "    var utf = alens[m] + alens[n];"  // And here.
   8028            // The 'n's that start with 0xdc.. are 6-8
   8029            // The 'm's that end with 0xd8.. are 1, 4 and 7
   8030       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
   8031       "    a2lens.push(utf);"
   8032       "  }"
   8033       "}");
   8034   Utf16Helper(context, "a", "alens", 9);
   8035   Utf16Helper(context, "a2", "a2lens", 81);
   8036   WriteUtf8Helper(context, "b", "alens", 9);
   8037   WriteUtf8Helper(context, "b2", "a2lens", 81);
   8038   WriteUtf8Helper(context, "c2", "a2lens", 81);
   8039 }
   8040 
   8041 
   8042 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
   8043   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
   8044   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
   8045   return *is1 == *is2;
   8046 }
   8047 
   8048 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
   8049                              const char* b) {
   8050   Handle<String> symbol1 =
   8051       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
   8052   Handle<String> symbol2 =
   8053       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
   8054   CHECK(SameSymbol(symbol1, symbol2));
   8055 }
   8056 
   8057 
   8058 THREADED_TEST(Utf16Symbol) {
   8059   LocalContext context;
   8060   v8::HandleScope scope(context->GetIsolate());
   8061 
   8062   Handle<String> symbol1 = v8::String::NewFromUtf8(
   8063       context->GetIsolate(), "abc", v8::String::kInternalizedString);
   8064   Handle<String> symbol2 = v8::String::NewFromUtf8(
   8065       context->GetIsolate(), "abc", v8::String::kInternalizedString);
   8066   CHECK(SameSymbol(symbol1, symbol2));
   8067 
   8068   SameSymbolHelper(context->GetIsolate(),
   8069                    "\360\220\220\205",  // 4 byte encoding.
   8070                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
   8071   SameSymbolHelper(context->GetIsolate(),
   8072                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
   8073                    "\360\220\220\206");  // 4 byte encoding.
   8074   SameSymbolHelper(context->GetIsolate(),
   8075                    "x\360\220\220\205",  // 4 byte encoding.
   8076                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
   8077   SameSymbolHelper(context->GetIsolate(),
   8078                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
   8079                    "x\360\220\220\206");  // 4 byte encoding.
   8080   CompileRun(
   8081       "var sym0 = 'benedictus';"
   8082       "var sym0b = 'S\303\270ren';"
   8083       "var sym1 = '\355\240\201\355\260\207';"
   8084       "var sym2 = '\360\220\220\210';"
   8085       "var sym3 = 'x\355\240\201\355\260\207';"
   8086       "var sym4 = 'x\360\220\220\210';"
   8087       "if (sym1.length != 2) throw sym1;"
   8088       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
   8089       "if (sym2.length != 2) throw sym2;"
   8090       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
   8091       "if (sym3.length != 3) throw sym3;"
   8092       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
   8093       "if (sym4.length != 3) throw sym4;"
   8094       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
   8095   Handle<String> sym0 = v8::String::NewFromUtf8(
   8096       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
   8097   Handle<String> sym0b = v8::String::NewFromUtf8(
   8098       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
   8099   Handle<String> sym1 =
   8100       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
   8101                               v8::String::kInternalizedString);
   8102   Handle<String> sym2 =
   8103       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
   8104                               v8::String::kInternalizedString);
   8105   Handle<String> sym3 = v8::String::NewFromUtf8(
   8106       context->GetIsolate(), "x\355\240\201\355\260\207",
   8107       v8::String::kInternalizedString);
   8108   Handle<String> sym4 =
   8109       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
   8110                               v8::String::kInternalizedString);
   8111   v8::Local<v8::Object> global = context->Global();
   8112   Local<Value> s0 = global->Get(v8_str("sym0"));
   8113   Local<Value> s0b = global->Get(v8_str("sym0b"));
   8114   Local<Value> s1 = global->Get(v8_str("sym1"));
   8115   Local<Value> s2 = global->Get(v8_str("sym2"));
   8116   Local<Value> s3 = global->Get(v8_str("sym3"));
   8117   Local<Value> s4 = global->Get(v8_str("sym4"));
   8118   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
   8119   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
   8120   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
   8121   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
   8122   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
   8123   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
   8124 }
   8125 
   8126 
   8127 THREADED_TEST(ToArrayIndex) {
   8128   LocalContext context;
   8129   v8::Isolate* isolate = context->GetIsolate();
   8130   v8::HandleScope scope(isolate);
   8131 
   8132   v8::Handle<String> str = v8_str("42");
   8133   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
   8134   CHECK(!index.IsEmpty());
   8135   CHECK_EQ(42.0, index->Uint32Value());
   8136   str = v8_str("42asdf");
   8137   index = str->ToArrayIndex();
   8138   CHECK(index.IsEmpty());
   8139   str = v8_str("-42");
   8140   index = str->ToArrayIndex();
   8141   CHECK(index.IsEmpty());
   8142   str = v8_str("4294967295");
   8143   index = str->ToArrayIndex();
   8144   CHECK(!index.IsEmpty());
   8145   CHECK_EQ(4294967295.0, index->Uint32Value());
   8146   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
   8147   index = num->ToArrayIndex();
   8148   CHECK(!index.IsEmpty());
   8149   CHECK_EQ(1.0, index->Uint32Value());
   8150   num = v8::Number::New(isolate, -1);
   8151   index = num->ToArrayIndex();
   8152   CHECK(index.IsEmpty());
   8153   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   8154   index = obj->ToArrayIndex();
   8155   CHECK(index.IsEmpty());
   8156 }
   8157 
   8158 
   8159 THREADED_TEST(ErrorConstruction) {
   8160   LocalContext context;
   8161   v8::HandleScope scope(context->GetIsolate());
   8162 
   8163   v8::Handle<String> foo = v8_str("foo");
   8164   v8::Handle<String> message = v8_str("message");
   8165   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
   8166   CHECK(range_error->IsObject());
   8167   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
   8168   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
   8169   CHECK(reference_error->IsObject());
   8170   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
   8171   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
   8172   CHECK(syntax_error->IsObject());
   8173   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
   8174   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
   8175   CHECK(type_error->IsObject());
   8176   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
   8177   v8::Handle<Value> error = v8::Exception::Error(foo);
   8178   CHECK(error->IsObject());
   8179   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
   8180 }
   8181 
   8182 
   8183 static void YGetter(Local<String> name,
   8184                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   8185   ApiTestFuzzer::Fuzz();
   8186   info.GetReturnValue().Set(v8_num(10));
   8187 }
   8188 
   8189 
   8190 static void YSetter(Local<String> name,
   8191                     Local<Value> value,
   8192                     const v8::PropertyCallbackInfo<void>& info) {
   8193   Local<Object> this_obj = Local<Object>::Cast(info.This());
   8194   if (this_obj->Has(name)) this_obj->Delete(name);
   8195   this_obj->Set(name, value);
   8196 }
   8197 
   8198 
   8199 THREADED_TEST(DeleteAccessor) {
   8200   v8::Isolate* isolate = CcTest::isolate();
   8201   v8::HandleScope scope(isolate);
   8202   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
   8203   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
   8204   LocalContext context;
   8205   v8::Handle<v8::Object> holder = obj->NewInstance();
   8206   context->Global()->Set(v8_str("holder"), holder);
   8207   v8::Handle<Value> result = CompileRun(
   8208       "holder.y = 11; holder.y = 12; holder.y");
   8209   CHECK_EQ(12, result->Uint32Value());
   8210 }
   8211 
   8212 
   8213 THREADED_TEST(TypeSwitch) {
   8214   v8::Isolate* isolate = CcTest::isolate();
   8215   v8::HandleScope scope(isolate);
   8216   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
   8217   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
   8218   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
   8219   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
   8220   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
   8221   LocalContext context;
   8222   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
   8223   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
   8224   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
   8225   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
   8226   for (int i = 0; i < 10; i++) {
   8227     CHECK_EQ(0, type_switch->match(obj0));
   8228     CHECK_EQ(1, type_switch->match(obj1));
   8229     CHECK_EQ(2, type_switch->match(obj2));
   8230     CHECK_EQ(3, type_switch->match(obj3));
   8231     CHECK_EQ(3, type_switch->match(obj3));
   8232     CHECK_EQ(2, type_switch->match(obj2));
   8233     CHECK_EQ(1, type_switch->match(obj1));
   8234     CHECK_EQ(0, type_switch->match(obj0));
   8235   }
   8236 }
   8237 
   8238 
   8239 static int trouble_nesting = 0;
   8240 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   8241   ApiTestFuzzer::Fuzz();
   8242   trouble_nesting++;
   8243 
   8244   // Call a JS function that throws an uncaught exception.
   8245   Local<v8::Object> arg_this =
   8246       args.GetIsolate()->GetCurrentContext()->Global();
   8247   Local<Value> trouble_callee = (trouble_nesting == 3) ?
   8248     arg_this->Get(v8_str("trouble_callee")) :
   8249     arg_this->Get(v8_str("trouble_caller"));
   8250   CHECK(trouble_callee->IsFunction());
   8251   args.GetReturnValue().Set(
   8252       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
   8253 }
   8254 
   8255 
   8256 static int report_count = 0;
   8257 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
   8258                                              v8::Handle<Value>) {
   8259   report_count++;
   8260 }
   8261 
   8262 
   8263 // Counts uncaught exceptions, but other tests running in parallel
   8264 // also have uncaught exceptions.
   8265 TEST(ApiUncaughtException) {
   8266   report_count = 0;
   8267   LocalContext env;
   8268   v8::Isolate* isolate = env->GetIsolate();
   8269   v8::HandleScope scope(isolate);
   8270   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
   8271 
   8272   Local<v8::FunctionTemplate> fun =
   8273       v8::FunctionTemplate::New(isolate, TroubleCallback);
   8274   v8::Local<v8::Object> global = env->Global();
   8275   global->Set(v8_str("trouble"), fun->GetFunction());
   8276 
   8277   CompileRun(
   8278       "function trouble_callee() {"
   8279       "  var x = null;"
   8280       "  return x.foo;"
   8281       "};"
   8282       "function trouble_caller() {"
   8283       "  trouble();"
   8284       "};");
   8285   Local<Value> trouble = global->Get(v8_str("trouble"));
   8286   CHECK(trouble->IsFunction());
   8287   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
   8288   CHECK(trouble_callee->IsFunction());
   8289   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
   8290   CHECK(trouble_caller->IsFunction());
   8291   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
   8292   CHECK_EQ(1, report_count);
   8293   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
   8294 }
   8295 
   8296 static const char* script_resource_name = "ExceptionInNativeScript.js";
   8297 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
   8298                                                 v8::Handle<Value>) {
   8299   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
   8300   CHECK(!name_val.IsEmpty() && name_val->IsString());
   8301   v8::String::Utf8Value name(message->GetScriptResourceName());
   8302   CHECK_EQ(script_resource_name, *name);
   8303   CHECK_EQ(3, message->GetLineNumber());
   8304   v8::String::Utf8Value source_line(message->GetSourceLine());
   8305   CHECK_EQ("  new o.foo();", *source_line);
   8306 }
   8307 
   8308 
   8309 TEST(ExceptionInNativeScript) {
   8310   LocalContext env;
   8311   v8::Isolate* isolate = env->GetIsolate();
   8312   v8::HandleScope scope(isolate);
   8313   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
   8314 
   8315   Local<v8::FunctionTemplate> fun =
   8316       v8::FunctionTemplate::New(isolate, TroubleCallback);
   8317   v8::Local<v8::Object> global = env->Global();
   8318   global->Set(v8_str("trouble"), fun->GetFunction());
   8319 
   8320   CompileRunWithOrigin(
   8321       "function trouble() {\n"
   8322       "  var o = {};\n"
   8323       "  new o.foo();\n"
   8324       "};",
   8325       script_resource_name);
   8326   Local<Value> trouble = global->Get(v8_str("trouble"));
   8327   CHECK(trouble->IsFunction());
   8328   Function::Cast(*trouble)->Call(global, 0, NULL);
   8329   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
   8330 }
   8331 
   8332 
   8333 TEST(CompilationErrorUsingTryCatchHandler) {
   8334   LocalContext env;
   8335   v8::HandleScope scope(env->GetIsolate());
   8336   v8::TryCatch try_catch;
   8337   v8_compile("This doesn't &*&@#$&*^ compile.");
   8338   CHECK_NE(NULL, *try_catch.Exception());
   8339   CHECK(try_catch.HasCaught());
   8340 }
   8341 
   8342 
   8343 TEST(TryCatchFinallyUsingTryCatchHandler) {
   8344   LocalContext env;
   8345   v8::HandleScope scope(env->GetIsolate());
   8346   v8::TryCatch try_catch;
   8347   CompileRun("try { throw ''; } catch (e) {}");
   8348   CHECK(!try_catch.HasCaught());
   8349   CompileRun("try { throw ''; } finally {}");
   8350   CHECK(try_catch.HasCaught());
   8351   try_catch.Reset();
   8352   CompileRun(
   8353       "(function() {"
   8354       "try { throw ''; } finally { return; }"
   8355       "})()");
   8356   CHECK(!try_catch.HasCaught());
   8357   CompileRun(
   8358       "(function()"
   8359       "  { try { throw ''; } finally { throw 0; }"
   8360       "})()");
   8361   CHECK(try_catch.HasCaught());
   8362 }
   8363 
   8364 
   8365 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   8366   v8::HandleScope scope(args.GetIsolate());
   8367   CompileRun(args[0]->ToString());
   8368 }
   8369 
   8370 
   8371 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
   8372   v8::Isolate* isolate = CcTest::isolate();
   8373   v8::HandleScope scope(isolate);
   8374   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   8375   templ->Set(v8_str("CEvaluate"),
   8376              v8::FunctionTemplate::New(isolate, CEvaluate));
   8377   LocalContext context(0, templ);
   8378   v8::TryCatch try_catch;
   8379   CompileRun("try {"
   8380              "  CEvaluate('throw 1;');"
   8381              "} finally {"
   8382              "}");
   8383   CHECK(try_catch.HasCaught());
   8384   CHECK(!try_catch.Message().IsEmpty());
   8385   String::Utf8Value exception_value(try_catch.Exception());
   8386   CHECK_EQ(*exception_value, "1");
   8387   try_catch.Reset();
   8388   CompileRun("try {"
   8389              "  CEvaluate('throw 1;');"
   8390              "} finally {"
   8391              "  throw 2;"
   8392              "}");
   8393   CHECK(try_catch.HasCaught());
   8394   CHECK(!try_catch.Message().IsEmpty());
   8395   String::Utf8Value finally_exception_value(try_catch.Exception());
   8396   CHECK_EQ(*finally_exception_value, "2");
   8397 }
   8398 
   8399 
   8400 // For use within the TestSecurityHandler() test.
   8401 static bool g_security_callback_result = false;
   8402 static bool NamedSecurityTestCallback(Local<v8::Object> global,
   8403                                       Local<Value> name,
   8404                                       v8::AccessType type,
   8405                                       Local<Value> data) {
   8406   printf("a\n");
   8407   // Always allow read access.
   8408   if (type == v8::ACCESS_GET)
   8409     return true;
   8410 
   8411   // Sometimes allow other access.
   8412   return g_security_callback_result;
   8413 }
   8414 
   8415 
   8416 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
   8417                                         uint32_t key,
   8418                                         v8::AccessType type,
   8419                                         Local<Value> data) {
   8420   printf("b\n");
   8421   // Always allow read access.
   8422   if (type == v8::ACCESS_GET)
   8423     return true;
   8424 
   8425   // Sometimes allow other access.
   8426   return g_security_callback_result;
   8427 }
   8428 
   8429 
   8430 // SecurityHandler can't be run twice
   8431 TEST(SecurityHandler) {
   8432   v8::Isolate* isolate = CcTest::isolate();
   8433   v8::HandleScope scope0(isolate);
   8434   v8::Handle<v8::ObjectTemplate> global_template =
   8435       v8::ObjectTemplate::New(isolate);
   8436   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
   8437                                            IndexedSecurityTestCallback);
   8438   // Create an environment
   8439   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
   8440   context0->Enter();
   8441 
   8442   v8::Handle<v8::Object> global0 = context0->Global();
   8443   v8::Handle<Script> script0 = v8_compile("foo = 111");
   8444   script0->Run();
   8445   global0->Set(v8_str("0"), v8_num(999));
   8446   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
   8447   CHECK_EQ(111, foo0->Int32Value());
   8448   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
   8449   CHECK_EQ(999, z0->Int32Value());
   8450 
   8451   // Create another environment, should fail security checks.
   8452   v8::HandleScope scope1(isolate);
   8453 
   8454   v8::Handle<Context> context1 =
   8455     Context::New(isolate, NULL, global_template);
   8456   context1->Enter();
   8457 
   8458   v8::Handle<v8::Object> global1 = context1->Global();
   8459   global1->Set(v8_str("othercontext"), global0);
   8460   // This set will fail the security check.
   8461   v8::Handle<Script> script1 =
   8462     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
   8463   script1->Run();
   8464   // This read will pass the security check.
   8465   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
   8466   CHECK_EQ(111, foo1->Int32Value());
   8467   // This read will pass the security check.
   8468   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
   8469   CHECK_EQ(999, z1->Int32Value());
   8470 
   8471   // Create another environment, should pass security checks.
   8472   { g_security_callback_result = true;  // allow security handler to pass.
   8473     v8::HandleScope scope2(isolate);
   8474     LocalContext context2;
   8475     v8::Handle<v8::Object> global2 = context2->Global();
   8476     global2->Set(v8_str("othercontext"), global0);
   8477     v8::Handle<Script> script2 =
   8478         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
   8479     script2->Run();
   8480     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
   8481     CHECK_EQ(333, foo2->Int32Value());
   8482     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
   8483     CHECK_EQ(888, z2->Int32Value());
   8484   }
   8485 
   8486   context1->Exit();
   8487   context0->Exit();
   8488 }
   8489 
   8490 
   8491 THREADED_TEST(SecurityChecks) {
   8492   LocalContext env1;
   8493   v8::HandleScope handle_scope(env1->GetIsolate());
   8494   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
   8495 
   8496   Local<Value> foo = v8_str("foo");
   8497   Local<Value> bar = v8_str("bar");
   8498 
   8499   // Set to the same domain.
   8500   env1->SetSecurityToken(foo);
   8501 
   8502   // Create a function in env1.
   8503   CompileRun("spy=function(){return spy;}");
   8504   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
   8505   CHECK(spy->IsFunction());
   8506 
   8507   // Create another function accessing global objects.
   8508   CompileRun("spy2=function(){return new this.Array();}");
   8509   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
   8510   CHECK(spy2->IsFunction());
   8511 
   8512   // Switch to env2 in the same domain and invoke spy on env2.
   8513   {
   8514     env2->SetSecurityToken(foo);
   8515     // Enter env2
   8516     Context::Scope scope_env2(env2);
   8517     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
   8518     CHECK(result->IsFunction());
   8519   }
   8520 
   8521   {
   8522     env2->SetSecurityToken(bar);
   8523     Context::Scope scope_env2(env2);
   8524 
   8525     // Call cross_domain_call, it should throw an exception
   8526     v8::TryCatch try_catch;
   8527     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
   8528     CHECK(try_catch.HasCaught());
   8529   }
   8530 }
   8531 
   8532 
   8533 // Regression test case for issue 1183439.
   8534 THREADED_TEST(SecurityChecksForPrototypeChain) {
   8535   LocalContext current;
   8536   v8::HandleScope scope(current->GetIsolate());
   8537   v8::Handle<Context> other = Context::New(current->GetIsolate());
   8538 
   8539   // Change context to be able to get to the Object function in the
   8540   // other context without hitting the security checks.
   8541   v8::Local<Value> other_object;
   8542   { Context::Scope scope(other);
   8543     other_object = other->Global()->Get(v8_str("Object"));
   8544     other->Global()->Set(v8_num(42), v8_num(87));
   8545   }
   8546 
   8547   current->Global()->Set(v8_str("other"), other->Global());
   8548   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
   8549 
   8550   // Make sure the security check fails here and we get an undefined
   8551   // result instead of getting the Object function. Repeat in a loop
   8552   // to make sure to exercise the IC code.
   8553   v8::Local<Script> access_other0 = v8_compile("other.Object");
   8554   v8::Local<Script> access_other1 = v8_compile("other[42]");
   8555   for (int i = 0; i < 5; i++) {
   8556     CHECK(!access_other0->Run()->Equals(other_object));
   8557     CHECK(access_other0->Run()->IsUndefined());
   8558     CHECK(!access_other1->Run()->Equals(v8_num(87)));
   8559     CHECK(access_other1->Run()->IsUndefined());
   8560   }
   8561 
   8562   // Create an object that has 'other' in its prototype chain and make
   8563   // sure we cannot access the Object function indirectly through
   8564   // that. Repeat in a loop to make sure to exercise the IC code.
   8565   v8_compile("function F() { };"
   8566              "F.prototype = other;"
   8567              "var f = new F();")->Run();
   8568   v8::Local<Script> access_f0 = v8_compile("f.Object");
   8569   v8::Local<Script> access_f1 = v8_compile("f[42]");
   8570   for (int j = 0; j < 5; j++) {
   8571     CHECK(!access_f0->Run()->Equals(other_object));
   8572     CHECK(access_f0->Run()->IsUndefined());
   8573     CHECK(!access_f1->Run()->Equals(v8_num(87)));
   8574     CHECK(access_f1->Run()->IsUndefined());
   8575   }
   8576 
   8577   // Now it gets hairy: Set the prototype for the other global object
   8578   // to be the current global object. The prototype chain for 'f' now
   8579   // goes through 'other' but ends up in the current global object.
   8580   { Context::Scope scope(other);
   8581     other->Global()->Set(v8_str("__proto__"), current->Global());
   8582   }
   8583   // Set a named and an index property on the current global
   8584   // object. To force the lookup to go through the other global object,
   8585   // the properties must not exist in the other global object.
   8586   current->Global()->Set(v8_str("foo"), v8_num(100));
   8587   current->Global()->Set(v8_num(99), v8_num(101));
   8588   // Try to read the properties from f and make sure that the access
   8589   // gets stopped by the security checks on the other global object.
   8590   Local<Script> access_f2 = v8_compile("f.foo");
   8591   Local<Script> access_f3 = v8_compile("f[99]");
   8592   for (int k = 0; k < 5; k++) {
   8593     CHECK(!access_f2->Run()->Equals(v8_num(100)));
   8594     CHECK(access_f2->Run()->IsUndefined());
   8595     CHECK(!access_f3->Run()->Equals(v8_num(101)));
   8596     CHECK(access_f3->Run()->IsUndefined());
   8597   }
   8598 }
   8599 
   8600 
   8601 static bool named_security_check_with_gc_called;
   8602 
   8603 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
   8604                                         Local<Value> name,
   8605                                         v8::AccessType type,
   8606                                         Local<Value> data) {
   8607   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   8608   named_security_check_with_gc_called = true;
   8609   return true;
   8610 }
   8611 
   8612 
   8613 static bool indexed_security_check_with_gc_called;
   8614 
   8615 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
   8616                                               uint32_t key,
   8617                                               v8::AccessType type,
   8618                                               Local<Value> data) {
   8619   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   8620   indexed_security_check_with_gc_called = true;
   8621   return true;
   8622 }
   8623 
   8624 
   8625 TEST(SecurityTestGCAllowed) {
   8626   v8::Isolate* isolate = CcTest::isolate();
   8627   v8::HandleScope handle_scope(isolate);
   8628   v8::Handle<v8::ObjectTemplate> object_template =
   8629       v8::ObjectTemplate::New(isolate);
   8630   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
   8631                                            IndexedSecurityTestCallbackWithGC);
   8632 
   8633   v8::Handle<Context> context = Context::New(isolate);
   8634   v8::Context::Scope context_scope(context);
   8635 
   8636   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
   8637 
   8638   named_security_check_with_gc_called = false;
   8639   CompileRun("obj.foo = new String(1001);");
   8640   CHECK(named_security_check_with_gc_called);
   8641 
   8642   indexed_security_check_with_gc_called = false;
   8643   CompileRun("obj[0] = new String(1002);");
   8644   CHECK(indexed_security_check_with_gc_called);
   8645 
   8646   named_security_check_with_gc_called = false;
   8647   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
   8648   CHECK(named_security_check_with_gc_called);
   8649 
   8650   indexed_security_check_with_gc_called = false;
   8651   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
   8652   CHECK(indexed_security_check_with_gc_called);
   8653 }
   8654 
   8655 
   8656 THREADED_TEST(CrossDomainDelete) {
   8657   LocalContext env1;
   8658   v8::HandleScope handle_scope(env1->GetIsolate());
   8659   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
   8660 
   8661   Local<Value> foo = v8_str("foo");
   8662   Local<Value> bar = v8_str("bar");
   8663 
   8664   // Set to the same domain.
   8665   env1->SetSecurityToken(foo);
   8666   env2->SetSecurityToken(foo);
   8667 
   8668   env1->Global()->Set(v8_str("prop"), v8_num(3));
   8669   env2->Global()->Set(v8_str("env1"), env1->Global());
   8670 
   8671   // Change env2 to a different domain and delete env1.prop.
   8672   env2->SetSecurityToken(bar);
   8673   {
   8674     Context::Scope scope_env2(env2);
   8675     Local<Value> result =
   8676         CompileRun("delete env1.prop");
   8677     CHECK(result->IsFalse());
   8678   }
   8679 
   8680   // Check that env1.prop still exists.
   8681   Local<Value> v = env1->Global()->Get(v8_str("prop"));
   8682   CHECK(v->IsNumber());
   8683   CHECK_EQ(3, v->Int32Value());
   8684 }
   8685 
   8686 
   8687 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
   8688   LocalContext env1;
   8689   v8::HandleScope handle_scope(env1->GetIsolate());
   8690   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
   8691 
   8692   Local<Value> foo = v8_str("foo");
   8693   Local<Value> bar = v8_str("bar");
   8694 
   8695   // Set to the same domain.
   8696   env1->SetSecurityToken(foo);
   8697   env2->SetSecurityToken(foo);
   8698 
   8699   env1->Global()->Set(v8_str("prop"), v8_num(3));
   8700   env2->Global()->Set(v8_str("env1"), env1->Global());
   8701 
   8702   // env1.prop is enumerable in env2.
   8703   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
   8704   {
   8705     Context::Scope scope_env2(env2);
   8706     Local<Value> result = CompileRun(test);
   8707     CHECK(result->IsTrue());
   8708   }
   8709 
   8710   // Change env2 to a different domain and test again.
   8711   env2->SetSecurityToken(bar);
   8712   {
   8713     Context::Scope scope_env2(env2);
   8714     Local<Value> result = CompileRun(test);
   8715     CHECK(result->IsFalse());
   8716   }
   8717 }
   8718 
   8719 
   8720 THREADED_TEST(CrossDomainForIn) {
   8721   LocalContext env1;
   8722   v8::HandleScope handle_scope(env1->GetIsolate());
   8723   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
   8724 
   8725   Local<Value> foo = v8_str("foo");
   8726   Local<Value> bar = v8_str("bar");
   8727 
   8728   // Set to the same domain.
   8729   env1->SetSecurityToken(foo);
   8730   env2->SetSecurityToken(foo);
   8731 
   8732   env1->Global()->Set(v8_str("prop"), v8_num(3));
   8733   env2->Global()->Set(v8_str("env1"), env1->Global());
   8734 
   8735   // Change env2 to a different domain and set env1's global object
   8736   // as the __proto__ of an object in env2 and enumerate properties
   8737   // in for-in. It shouldn't enumerate properties on env1's global
   8738   // object.
   8739   env2->SetSecurityToken(bar);
   8740   {
   8741     Context::Scope scope_env2(env2);
   8742     Local<Value> result =
   8743         CompileRun("(function(){var obj = {'__proto__':env1};"
   8744                    "for (var p in obj)"
   8745                    "   if (p == 'prop') return false;"
   8746                    "return true;})()");
   8747     CHECK(result->IsTrue());
   8748   }
   8749 }
   8750 
   8751 
   8752 TEST(ContextDetachGlobal) {
   8753   LocalContext env1;
   8754   v8::HandleScope handle_scope(env1->GetIsolate());
   8755   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
   8756 
   8757   Local<v8::Object> global1 = env1->Global();
   8758 
   8759   Local<Value> foo = v8_str("foo");
   8760 
   8761   // Set to the same domain.
   8762   env1->SetSecurityToken(foo);
   8763   env2->SetSecurityToken(foo);
   8764 
   8765   // Enter env2
   8766   env2->Enter();
   8767 
   8768   // Create a function in env2 and add a reference to it in env1.
   8769   Local<v8::Object> global2 = env2->Global();
   8770   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
   8771   CompileRun("function getProp() {return prop;}");
   8772 
   8773   env1->Global()->Set(v8_str("getProp"),
   8774                       global2->Get(v8_str("getProp")));
   8775 
   8776   // Detach env2's global, and reuse the global object of env2
   8777   env2->Exit();
   8778   env2->DetachGlobal();
   8779 
   8780   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
   8781                                           0,
   8782                                           v8::Handle<v8::ObjectTemplate>(),
   8783                                           global2);
   8784   env3->SetSecurityToken(v8_str("bar"));
   8785   env3->Enter();
   8786 
   8787   Local<v8::Object> global3 = env3->Global();
   8788   CHECK_EQ(global2, global3);
   8789   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
   8790   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
   8791   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
   8792   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
   8793   env3->Exit();
   8794 
   8795   // Call getProp in env1, and it should return the value 1
   8796   {
   8797     Local<Value> get_prop = global1->Get(v8_str("getProp"));
   8798     CHECK(get_prop->IsFunction());
   8799     v8::TryCatch try_catch;
   8800     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
   8801     CHECK(!try_catch.HasCaught());
   8802     CHECK_EQ(1, r->Int32Value());
   8803   }
   8804 
   8805   // Check that env3 is not accessible from env1
   8806   {
   8807     Local<Value> r = global3->Get(v8_str("prop2"));
   8808     CHECK(r->IsUndefined());
   8809   }
   8810 }
   8811 
   8812 
   8813 TEST(DetachGlobal) {
   8814   LocalContext env1;
   8815   v8::HandleScope scope(env1->GetIsolate());
   8816 
   8817   // Create second environment.
   8818   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
   8819 
   8820   Local<Value> foo = v8_str("foo");
   8821 
   8822   // Set same security token for env1 and env2.
   8823   env1->SetSecurityToken(foo);
   8824   env2->SetSecurityToken(foo);
   8825 
   8826   // Create a property on the global object in env2.
   8827   {
   8828     v8::Context::Scope scope(env2);
   8829     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
   8830   }
   8831 
   8832   // Create a reference to env2 global from env1 global.
   8833   env1->Global()->Set(v8_str("other"), env2->Global());
   8834 
   8835   // Check that we have access to other.p in env2 from env1.
   8836   Local<Value> result = CompileRun("other.p");
   8837   CHECK(result->IsInt32());
   8838   CHECK_EQ(42, result->Int32Value());
   8839 
   8840   // Hold on to global from env2 and detach global from env2.
   8841   Local<v8::Object> global2 = env2->Global();
   8842   env2->DetachGlobal();
   8843 
   8844   // Check that the global has been detached. No other.p property can
   8845   // be found.
   8846   result = CompileRun("other.p");
   8847   CHECK(result->IsUndefined());
   8848 
   8849   // Reuse global2 for env3.
   8850   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
   8851                                           0,
   8852                                           v8::Handle<v8::ObjectTemplate>(),
   8853                                           global2);
   8854   CHECK_EQ(global2, env3->Global());
   8855 
   8856   // Start by using the same security token for env3 as for env1 and env2.
   8857   env3->SetSecurityToken(foo);
   8858 
   8859   // Create a property on the global object in env3.
   8860   {
   8861     v8::Context::Scope scope(env3);
   8862     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
   8863   }
   8864 
   8865   // Check that other.p is now the property in env3 and that we have access.
   8866   result = CompileRun("other.p");
   8867   CHECK(result->IsInt32());
   8868   CHECK_EQ(24, result->Int32Value());
   8869 
   8870   // Change security token for env3 to something different from env1 and env2.
   8871   env3->SetSecurityToken(v8_str("bar"));
   8872 
   8873   // Check that we do not have access to other.p in env1. |other| is now
   8874   // the global object for env3 which has a different security token,
   8875   // so access should be blocked.
   8876   result = CompileRun("other.p");
   8877   CHECK(result->IsUndefined());
   8878 }
   8879 
   8880 
   8881 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
   8882   info.GetReturnValue().Set(
   8883       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
   8884 }
   8885 
   8886 
   8887 TEST(DetachedAccesses) {
   8888   LocalContext env1;
   8889   v8::HandleScope scope(env1->GetIsolate());
   8890 
   8891   // Create second environment.
   8892   Local<ObjectTemplate> inner_global_template =
   8893       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
   8894   inner_global_template ->SetAccessorProperty(
   8895       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
   8896   v8::Local<Context> env2 =
   8897       Context::New(env1->GetIsolate(), NULL, inner_global_template);
   8898 
   8899   Local<Value> foo = v8_str("foo");
   8900 
   8901   // Set same security token for env1 and env2.
   8902   env1->SetSecurityToken(foo);
   8903   env2->SetSecurityToken(foo);
   8904 
   8905   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
   8906 
   8907   {
   8908     v8::Context::Scope scope(env2);
   8909     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
   8910     CompileRun(
   8911         "function bound_x() { return x; }"
   8912         "function get_x()   { return this.x; }"
   8913         "function get_x_w() { return (function() {return this.x;})(); }");
   8914     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
   8915     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
   8916     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
   8917     env1->Global()->Set(
   8918         v8_str("this_x"),
   8919         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
   8920   }
   8921 
   8922   Local<Object> env2_global = env2->Global();
   8923   env2_global->TurnOnAccessCheck();
   8924   env2->DetachGlobal();
   8925 
   8926   Local<Value> result;
   8927   result = CompileRun("bound_x()");
   8928   CHECK_EQ(v8_str("env2_x"), result);
   8929   result = CompileRun("get_x()");
   8930   CHECK(result->IsUndefined());
   8931   result = CompileRun("get_x_w()");
   8932   CHECK(result->IsUndefined());
   8933   result = CompileRun("this_x()");
   8934   CHECK_EQ(v8_str("env2_x"), result);
   8935 
   8936   // Reattach env2's proxy
   8937   env2 = Context::New(env1->GetIsolate(),
   8938                       0,
   8939                       v8::Handle<v8::ObjectTemplate>(),
   8940                       env2_global);
   8941   env2->SetSecurityToken(foo);
   8942   {
   8943     v8::Context::Scope scope(env2);
   8944     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
   8945     env2->Global()->Set(v8_str("env1"), env1->Global());
   8946     result = CompileRun(
   8947         "results = [];"
   8948         "for (var i = 0; i < 4; i++ ) {"
   8949         "  results.push(env1.bound_x());"
   8950         "  results.push(env1.get_x());"
   8951         "  results.push(env1.get_x_w());"
   8952         "  results.push(env1.this_x());"
   8953         "}"
   8954         "results");
   8955     Local<v8::Array> results = Local<v8::Array>::Cast(result);
   8956     CHECK_EQ(16, results->Length());
   8957     for (int i = 0; i < 16; i += 4) {
   8958       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
   8959       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
   8960       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
   8961       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
   8962     }
   8963   }
   8964 
   8965   result = CompileRun(
   8966       "results = [];"
   8967       "for (var i = 0; i < 4; i++ ) {"
   8968       "  results.push(bound_x());"
   8969       "  results.push(get_x());"
   8970       "  results.push(get_x_w());"
   8971       "  results.push(this_x());"
   8972       "}"
   8973       "results");
   8974   Local<v8::Array> results = Local<v8::Array>::Cast(result);
   8975   CHECK_EQ(16, results->Length());
   8976   for (int i = 0; i < 16; i += 4) {
   8977     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
   8978     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
   8979     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
   8980     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
   8981   }
   8982 
   8983   result = CompileRun(
   8984       "results = [];"
   8985       "for (var i = 0; i < 4; i++ ) {"
   8986       "  results.push(this.bound_x());"
   8987       "  results.push(this.get_x());"
   8988       "  results.push(this.get_x_w());"
   8989       "  results.push(this.this_x());"
   8990       "}"
   8991       "results");
   8992   results = Local<v8::Array>::Cast(result);
   8993   CHECK_EQ(16, results->Length());
   8994   for (int i = 0; i < 16; i += 4) {
   8995     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
   8996     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
   8997     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
   8998     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
   8999   }
   9000 }
   9001 
   9002 
   9003 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
   9004 static bool NamedAccessBlocker(Local<v8::Object> global,
   9005                                Local<Value> name,
   9006                                v8::AccessType type,
   9007                                Local<Value> data) {
   9008   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
   9009       allowed_access_type[type];
   9010 }
   9011 
   9012 
   9013 static bool IndexedAccessBlocker(Local<v8::Object> global,
   9014                                  uint32_t key,
   9015                                  v8::AccessType type,
   9016                                  Local<Value> data) {
   9017   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
   9018       allowed_access_type[type];
   9019 }
   9020 
   9021 
   9022 static int g_echo_value_1 = -1;
   9023 static int g_echo_value_2 = -1;
   9024 
   9025 
   9026 static void EchoGetter(
   9027     Local<String> name,
   9028     const v8::PropertyCallbackInfo<v8::Value>& info) {
   9029   info.GetReturnValue().Set(v8_num(g_echo_value_1));
   9030 }
   9031 
   9032 
   9033 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
   9034   info.GetReturnValue().Set(v8_num(g_echo_value_2));
   9035 }
   9036 
   9037 
   9038 static void EchoSetter(Local<String> name,
   9039                        Local<Value> value,
   9040                        const v8::PropertyCallbackInfo<void>&) {
   9041   if (value->IsNumber())
   9042     g_echo_value_1 = value->Int32Value();
   9043 }
   9044 
   9045 
   9046 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
   9047   v8::Handle<v8::Value> value = info[0];
   9048   if (value->IsNumber())
   9049     g_echo_value_2 = value->Int32Value();
   9050 }
   9051 
   9052 
   9053 static void UnreachableGetter(
   9054     Local<String> name,
   9055     const v8::PropertyCallbackInfo<v8::Value>& info) {
   9056   CHECK(false);  // This function should not be called..
   9057 }
   9058 
   9059 
   9060 static void UnreachableSetter(Local<String>,
   9061                               Local<Value>,
   9062                               const v8::PropertyCallbackInfo<void>&) {
   9063   CHECK(false);  // This function should nto be called.
   9064 }
   9065 
   9066 
   9067 static void UnreachableFunction(
   9068     const v8::FunctionCallbackInfo<v8::Value>& info) {
   9069   CHECK(false);  // This function should not be called..
   9070 }
   9071 
   9072 
   9073 TEST(AccessControl) {
   9074   v8::Isolate* isolate = CcTest::isolate();
   9075   v8::HandleScope handle_scope(isolate);
   9076   v8::Handle<v8::ObjectTemplate> global_template =
   9077       v8::ObjectTemplate::New(isolate);
   9078 
   9079   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
   9080                                            IndexedAccessBlocker);
   9081 
   9082   // Add an accessor accessible by cross-domain JS code.
   9083   global_template->SetAccessor(
   9084       v8_str("accessible_prop"),
   9085       EchoGetter, EchoSetter,
   9086       v8::Handle<Value>(),
   9087       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
   9088 
   9089 
   9090   global_template->SetAccessorProperty(
   9091       v8_str("accessible_js_prop"),
   9092       v8::FunctionTemplate::New(isolate, EchoGetter),
   9093       v8::FunctionTemplate::New(isolate, EchoSetter),
   9094       v8::None,
   9095       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
   9096 
   9097   // Add an accessor that is not accessible by cross-domain JS code.
   9098   global_template->SetAccessor(v8_str("blocked_prop"),
   9099                                UnreachableGetter, UnreachableSetter,
   9100                                v8::Handle<Value>(),
   9101                                v8::DEFAULT);
   9102 
   9103   global_template->SetAccessorProperty(
   9104       v8_str("blocked_js_prop"),
   9105       v8::FunctionTemplate::New(isolate, UnreachableFunction),
   9106       v8::FunctionTemplate::New(isolate, UnreachableFunction),
   9107       v8::None,
   9108       v8::DEFAULT);
   9109 
   9110   // Create an environment
   9111   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
   9112   context0->Enter();
   9113 
   9114   v8::Handle<v8::Object> global0 = context0->Global();
   9115 
   9116   // Define a property with JS getter and setter.
   9117   CompileRun(
   9118       "function getter() { return 'getter'; };\n"
   9119       "function setter() { return 'setter'; }\n"
   9120       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
   9121 
   9122   Local<Value> getter = global0->Get(v8_str("getter"));
   9123   Local<Value> setter = global0->Get(v8_str("setter"));
   9124 
   9125   // And define normal element.
   9126   global0->Set(239, v8_str("239"));
   9127 
   9128   // Define an element with JS getter and setter.
   9129   CompileRun(
   9130       "function el_getter() { return 'el_getter'; };\n"
   9131       "function el_setter() { return 'el_setter'; };\n"
   9132       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
   9133 
   9134   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
   9135   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
   9136 
   9137   v8::HandleScope scope1(isolate);
   9138 
   9139   v8::Local<Context> context1 = Context::New(isolate);
   9140   context1->Enter();
   9141 
   9142   v8::Handle<v8::Object> global1 = context1->Global();
   9143   global1->Set(v8_str("other"), global0);
   9144 
   9145   // Access blocked property.
   9146   CompileRun("other.blocked_prop = 1");
   9147 
   9148   ExpectUndefined("other.blocked_prop");
   9149   ExpectUndefined(
   9150       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
   9151   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
   9152 
   9153   // Enable ACCESS_HAS
   9154   allowed_access_type[v8::ACCESS_HAS] = true;
   9155   ExpectUndefined("other.blocked_prop");
   9156   // ... and now we can get the descriptor...
   9157   ExpectUndefined(
   9158       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
   9159   // ... and enumerate the property.
   9160   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
   9161   allowed_access_type[v8::ACCESS_HAS] = false;
   9162 
   9163   // Access blocked element.
   9164   CompileRun("other[239] = 1");
   9165 
   9166   ExpectUndefined("other[239]");
   9167   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
   9168   ExpectFalse("propertyIsEnumerable.call(other, '239')");
   9169 
   9170   // Enable ACCESS_HAS
   9171   allowed_access_type[v8::ACCESS_HAS] = true;
   9172   ExpectUndefined("other[239]");
   9173   // ... and now we can get the descriptor...
   9174   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
   9175   // ... and enumerate the property.
   9176   ExpectTrue("propertyIsEnumerable.call(other, '239')");
   9177   allowed_access_type[v8::ACCESS_HAS] = false;
   9178 
   9179   // Access a property with JS accessor.
   9180   CompileRun("other.js_accessor_p = 2");
   9181 
   9182   ExpectUndefined("other.js_accessor_p");
   9183   ExpectUndefined(
   9184       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
   9185 
   9186   // Enable ACCESS_HAS.
   9187   allowed_access_type[v8::ACCESS_HAS] = true;
   9188   ExpectUndefined("other.js_accessor_p");
   9189   ExpectUndefined(
   9190       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
   9191   ExpectUndefined(
   9192       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
   9193   ExpectUndefined(
   9194       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   9195   allowed_access_type[v8::ACCESS_HAS] = false;
   9196 
   9197   // Enable both ACCESS_HAS and ACCESS_GET.
   9198   allowed_access_type[v8::ACCESS_HAS] = true;
   9199   allowed_access_type[v8::ACCESS_GET] = true;
   9200 
   9201   ExpectString("other.js_accessor_p", "getter");
   9202   ExpectObject(
   9203       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
   9204   ExpectUndefined(
   9205       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
   9206   ExpectUndefined(
   9207       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   9208 
   9209   allowed_access_type[v8::ACCESS_GET] = false;
   9210   allowed_access_type[v8::ACCESS_HAS] = false;
   9211 
   9212   // Enable both ACCESS_HAS and ACCESS_SET.
   9213   allowed_access_type[v8::ACCESS_HAS] = true;
   9214   allowed_access_type[v8::ACCESS_SET] = true;
   9215 
   9216   ExpectUndefined("other.js_accessor_p");
   9217   ExpectUndefined(
   9218       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
   9219   ExpectObject(
   9220       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
   9221   ExpectUndefined(
   9222       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   9223 
   9224   allowed_access_type[v8::ACCESS_SET] = false;
   9225   allowed_access_type[v8::ACCESS_HAS] = false;
   9226 
   9227   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
   9228   allowed_access_type[v8::ACCESS_HAS] = true;
   9229   allowed_access_type[v8::ACCESS_GET] = true;
   9230   allowed_access_type[v8::ACCESS_SET] = true;
   9231 
   9232   ExpectString("other.js_accessor_p", "getter");
   9233   ExpectObject(
   9234       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
   9235   ExpectObject(
   9236       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
   9237   ExpectUndefined(
   9238       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
   9239 
   9240   allowed_access_type[v8::ACCESS_SET] = false;
   9241   allowed_access_type[v8::ACCESS_GET] = false;
   9242   allowed_access_type[v8::ACCESS_HAS] = false;
   9243 
   9244   // Access an element with JS accessor.
   9245   CompileRun("other[42] = 2");
   9246 
   9247   ExpectUndefined("other[42]");
   9248   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
   9249 
   9250   // Enable ACCESS_HAS.
   9251   allowed_access_type[v8::ACCESS_HAS] = true;
   9252   ExpectUndefined("other[42]");
   9253   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
   9254   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
   9255   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   9256   allowed_access_type[v8::ACCESS_HAS] = false;
   9257 
   9258   // Enable both ACCESS_HAS and ACCESS_GET.
   9259   allowed_access_type[v8::ACCESS_HAS] = true;
   9260   allowed_access_type[v8::ACCESS_GET] = true;
   9261 
   9262   ExpectString("other[42]", "el_getter");
   9263   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
   9264   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
   9265   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   9266 
   9267   allowed_access_type[v8::ACCESS_GET] = false;
   9268   allowed_access_type[v8::ACCESS_HAS] = false;
   9269 
   9270   // Enable both ACCESS_HAS and ACCESS_SET.
   9271   allowed_access_type[v8::ACCESS_HAS] = true;
   9272   allowed_access_type[v8::ACCESS_SET] = true;
   9273 
   9274   ExpectUndefined("other[42]");
   9275   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
   9276   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
   9277   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   9278 
   9279   allowed_access_type[v8::ACCESS_SET] = false;
   9280   allowed_access_type[v8::ACCESS_HAS] = false;
   9281 
   9282   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
   9283   allowed_access_type[v8::ACCESS_HAS] = true;
   9284   allowed_access_type[v8::ACCESS_GET] = true;
   9285   allowed_access_type[v8::ACCESS_SET] = true;
   9286 
   9287   ExpectString("other[42]", "el_getter");
   9288   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
   9289   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
   9290   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
   9291 
   9292   allowed_access_type[v8::ACCESS_SET] = false;
   9293   allowed_access_type[v8::ACCESS_GET] = false;
   9294   allowed_access_type[v8::ACCESS_HAS] = false;
   9295 
   9296   v8::Handle<Value> value;
   9297 
   9298   // Access accessible property
   9299   value = CompileRun("other.accessible_prop = 3");
   9300   CHECK(value->IsNumber());
   9301   CHECK_EQ(3, value->Int32Value());
   9302   CHECK_EQ(3, g_echo_value_1);
   9303 
   9304   // Access accessible js property
   9305   value = CompileRun("other.accessible_js_prop = 3");
   9306   CHECK(value->IsNumber());
   9307   CHECK_EQ(3, value->Int32Value());
   9308   CHECK_EQ(3, g_echo_value_2);
   9309 
   9310   value = CompileRun("other.accessible_prop");
   9311   CHECK(value->IsNumber());
   9312   CHECK_EQ(3, value->Int32Value());
   9313 
   9314   value = CompileRun("other.accessible_js_prop");
   9315   CHECK(value->IsNumber());
   9316   CHECK_EQ(3, value->Int32Value());
   9317 
   9318   value = CompileRun(
   9319       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
   9320   CHECK(value->IsNumber());
   9321   CHECK_EQ(3, value->Int32Value());
   9322 
   9323   value = CompileRun(
   9324       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
   9325   CHECK(value->IsNumber());
   9326   CHECK_EQ(3, value->Int32Value());
   9327 
   9328   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
   9329   CHECK(value->IsTrue());
   9330 
   9331   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
   9332   CHECK(value->IsTrue());
   9333 
   9334   // Enumeration doesn't enumerate accessors from inaccessible objects in
   9335   // the prototype chain even if the accessors are in themselves accessible.
   9336   value =
   9337       CompileRun("(function(){var obj = {'__proto__':other};"
   9338                  "for (var p in obj)"
   9339                  "   if (p == 'accessible_prop' ||"
   9340                  "       p == 'accessible_js_prop' ||"
   9341                  "       p == 'blocked_js_prop' ||"
   9342                  "       p == 'blocked_js_prop') {"
   9343                  "     return false;"
   9344                  "   }"
   9345                  "return true;})()");
   9346   CHECK(value->IsTrue());
   9347 
   9348   context1->Exit();
   9349   context0->Exit();
   9350 }
   9351 
   9352 
   9353 TEST(AccessControlES5) {
   9354   v8::Isolate* isolate = CcTest::isolate();
   9355   v8::HandleScope handle_scope(isolate);
   9356   v8::Handle<v8::ObjectTemplate> global_template =
   9357       v8::ObjectTemplate::New(isolate);
   9358 
   9359   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
   9360                                            IndexedAccessBlocker);
   9361 
   9362   // Add accessible accessor.
   9363   global_template->SetAccessor(
   9364       v8_str("accessible_prop"),
   9365       EchoGetter, EchoSetter,
   9366       v8::Handle<Value>(),
   9367       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
   9368 
   9369 
   9370   // Add an accessor that is not accessible by cross-domain JS code.
   9371   global_template->SetAccessor(v8_str("blocked_prop"),
   9372                                UnreachableGetter, UnreachableSetter,
   9373                                v8::Handle<Value>(),
   9374                                v8::DEFAULT);
   9375 
   9376   // Create an environment
   9377   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
   9378   context0->Enter();
   9379 
   9380   v8::Handle<v8::Object> global0 = context0->Global();
   9381 
   9382   v8::Local<Context> context1 = Context::New(isolate);
   9383   context1->Enter();
   9384   v8::Handle<v8::Object> global1 = context1->Global();
   9385   global1->Set(v8_str("other"), global0);
   9386 
   9387   // Regression test for issue 1154.
   9388   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
   9389 
   9390   ExpectUndefined("other.blocked_prop");
   9391 
   9392   // Regression test for issue 1027.
   9393   CompileRun("Object.defineProperty(\n"
   9394              "  other, 'blocked_prop', {configurable: false})");
   9395   ExpectUndefined("other.blocked_prop");
   9396   ExpectUndefined(
   9397       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
   9398 
   9399   // Regression test for issue 1171.
   9400   ExpectTrue("Object.isExtensible(other)");
   9401   CompileRun("Object.preventExtensions(other)");
   9402   ExpectTrue("Object.isExtensible(other)");
   9403 
   9404   // Object.seal and Object.freeze.
   9405   CompileRun("Object.freeze(other)");
   9406   ExpectTrue("Object.isExtensible(other)");
   9407 
   9408   CompileRun("Object.seal(other)");
   9409   ExpectTrue("Object.isExtensible(other)");
   9410 
   9411   // Regression test for issue 1250.
   9412   // Make sure that we can set the accessible accessors value using normal
   9413   // assignment.
   9414   CompileRun("other.accessible_prop = 42");
   9415   CHECK_EQ(42, g_echo_value_1);
   9416 
   9417   v8::Handle<Value> value;
   9418   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
   9419   value = CompileRun("other.accessible_prop == 42");
   9420   CHECK(value->IsTrue());
   9421 }
   9422 
   9423 
   9424 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
   9425                                             Local<Value> name,
   9426                                             v8::AccessType type,
   9427                                             Local<Value> data) {
   9428   return false;
   9429 }
   9430 
   9431 
   9432 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
   9433                                               uint32_t key,
   9434                                               v8::AccessType type,
   9435                                               Local<Value> data) {
   9436   return false;
   9437 }
   9438 
   9439 
   9440 THREADED_TEST(AccessControlGetOwnPropertyNames) {
   9441   v8::Isolate* isolate = CcTest::isolate();
   9442   v8::HandleScope handle_scope(isolate);
   9443   v8::Handle<v8::ObjectTemplate> obj_template =
   9444       v8::ObjectTemplate::New(isolate);
   9445 
   9446   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
   9447   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
   9448                                         GetOwnPropertyNamesIndexedBlocker);
   9449 
   9450   // Create an environment
   9451   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
   9452   context0->Enter();
   9453 
   9454   v8::Handle<v8::Object> global0 = context0->Global();
   9455 
   9456   v8::HandleScope scope1(CcTest::isolate());
   9457 
   9458   v8::Local<Context> context1 = Context::New(isolate);
   9459   context1->Enter();
   9460 
   9461   v8::Handle<v8::Object> global1 = context1->Global();
   9462   global1->Set(v8_str("other"), global0);
   9463   global1->Set(v8_str("object"), obj_template->NewInstance());
   9464 
   9465   v8::Handle<Value> value;
   9466 
   9467   // Attempt to get the property names of the other global object and
   9468   // of an object that requires access checks.  Accessing the other
   9469   // global object should be blocked by access checks on the global
   9470   // proxy object.  Accessing the object that requires access checks
   9471   // is blocked by the access checks on the object itself.
   9472   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
   9473   CHECK(value->IsTrue());
   9474 
   9475   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
   9476   CHECK(value->IsTrue());
   9477 
   9478   context1->Exit();
   9479   context0->Exit();
   9480 }
   9481 
   9482 
   9483 static void IndexedPropertyEnumerator(
   9484     const v8::PropertyCallbackInfo<v8::Array>& info) {
   9485   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   9486   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
   9487   result->Set(1, v8::Object::New(info.GetIsolate()));
   9488   info.GetReturnValue().Set(result);
   9489 }
   9490 
   9491 
   9492 static void NamedPropertyEnumerator(
   9493     const v8::PropertyCallbackInfo<v8::Array>& info) {
   9494   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   9495   result->Set(0, v8_str("x"));
   9496   result->Set(1, v8::Object::New(info.GetIsolate()));
   9497   info.GetReturnValue().Set(result);
   9498 }
   9499 
   9500 
   9501 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
   9502   v8::Isolate* isolate = CcTest::isolate();
   9503   v8::HandleScope handle_scope(isolate);
   9504   v8::Handle<v8::ObjectTemplate> obj_template =
   9505       v8::ObjectTemplate::New(isolate);
   9506 
   9507   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
   9508   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
   9509   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
   9510                                           IndexedPropertyEnumerator);
   9511   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
   9512                                         NamedPropertyEnumerator);
   9513 
   9514   LocalContext context;
   9515   v8::Handle<v8::Object> global = context->Global();
   9516   global->Set(v8_str("object"), obj_template->NewInstance());
   9517 
   9518   v8::Handle<v8::Value> result =
   9519       CompileRun("Object.getOwnPropertyNames(object)");
   9520   CHECK(result->IsArray());
   9521   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
   9522   CHECK_EQ(3, result_array->Length());
   9523   CHECK(result_array->Get(0)->IsString());
   9524   CHECK(result_array->Get(1)->IsString());
   9525   CHECK(result_array->Get(2)->IsString());
   9526   CHECK_EQ(v8_str("7"), result_array->Get(0));
   9527   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
   9528   CHECK_EQ(v8_str("x"), result_array->Get(2));
   9529 }
   9530 
   9531 
   9532 static void ConstTenGetter(Local<String> name,
   9533                            const v8::PropertyCallbackInfo<v8::Value>& info) {
   9534   info.GetReturnValue().Set(v8_num(10));
   9535 }
   9536 
   9537 
   9538 THREADED_TEST(CrossDomainAccessors) {
   9539   v8::Isolate* isolate = CcTest::isolate();
   9540   v8::HandleScope handle_scope(isolate);
   9541 
   9542   v8::Handle<v8::FunctionTemplate> func_template =
   9543       v8::FunctionTemplate::New(isolate);
   9544 
   9545   v8::Handle<v8::ObjectTemplate> global_template =
   9546       func_template->InstanceTemplate();
   9547 
   9548   v8::Handle<v8::ObjectTemplate> proto_template =
   9549       func_template->PrototypeTemplate();
   9550 
   9551   // Add an accessor to proto that's accessible by cross-domain JS code.
   9552   proto_template->SetAccessor(v8_str("accessible"),
   9553                               ConstTenGetter, 0,
   9554                               v8::Handle<Value>(),
   9555                               v8::ALL_CAN_READ);
   9556 
   9557   // Add an accessor that is not accessible by cross-domain JS code.
   9558   global_template->SetAccessor(v8_str("unreachable"),
   9559                                UnreachableGetter, 0,
   9560                                v8::Handle<Value>(),
   9561                                v8::DEFAULT);
   9562 
   9563   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
   9564   context0->Enter();
   9565 
   9566   Local<v8::Object> global = context0->Global();
   9567   // Add a normal property that shadows 'accessible'
   9568   global->Set(v8_str("accessible"), v8_num(11));
   9569 
   9570   // Enter a new context.
   9571   v8::HandleScope scope1(CcTest::isolate());
   9572   v8::Local<Context> context1 = Context::New(isolate);
   9573   context1->Enter();
   9574 
   9575   v8::Handle<v8::Object> global1 = context1->Global();
   9576   global1->Set(v8_str("other"), global);
   9577 
   9578   // Should return 10, instead of 11
   9579   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
   9580   CHECK(value->IsNumber());
   9581   CHECK_EQ(10, value->Int32Value());
   9582 
   9583   value = v8_compile("other.unreachable")->Run();
   9584   CHECK(value->IsUndefined());
   9585 
   9586   context1->Exit();
   9587   context0->Exit();
   9588 }
   9589 
   9590 
   9591 static int named_access_count = 0;
   9592 static int indexed_access_count = 0;
   9593 
   9594 static bool NamedAccessCounter(Local<v8::Object> global,
   9595                                Local<Value> name,
   9596                                v8::AccessType type,
   9597                                Local<Value> data) {
   9598   named_access_count++;
   9599   return true;
   9600 }
   9601 
   9602 
   9603 static bool IndexedAccessCounter(Local<v8::Object> global,
   9604                                  uint32_t key,
   9605                                  v8::AccessType type,
   9606                                  Local<Value> data) {
   9607   indexed_access_count++;
   9608   return true;
   9609 }
   9610 
   9611 
   9612 // This one is too easily disturbed by other tests.
   9613 TEST(AccessControlIC) {
   9614   named_access_count = 0;
   9615   indexed_access_count = 0;
   9616 
   9617   v8::Isolate* isolate = CcTest::isolate();
   9618   v8::HandleScope handle_scope(isolate);
   9619 
   9620   // Create an environment.
   9621   v8::Local<Context> context0 = Context::New(isolate);
   9622   context0->Enter();
   9623 
   9624   // Create an object that requires access-check functions to be
   9625   // called for cross-domain access.
   9626   v8::Handle<v8::ObjectTemplate> object_template =
   9627       v8::ObjectTemplate::New(isolate);
   9628   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
   9629                                            IndexedAccessCounter);
   9630   Local<v8::Object> object = object_template->NewInstance();
   9631 
   9632   v8::HandleScope scope1(isolate);
   9633 
   9634   // Create another environment.
   9635   v8::Local<Context> context1 = Context::New(isolate);
   9636   context1->Enter();
   9637 
   9638   // Make easy access to the object from the other environment.
   9639   v8::Handle<v8::Object> global1 = context1->Global();
   9640   global1->Set(v8_str("obj"), object);
   9641 
   9642   v8::Handle<Value> value;
   9643 
   9644   // Check that the named access-control function is called every time.
   9645   CompileRun("function testProp(obj) {"
   9646              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
   9647              "  for (var j = 0; j < 10; j++) obj.prop;"
   9648              "  return obj.prop"
   9649              "}");
   9650   value = CompileRun("testProp(obj)");
   9651   CHECK(value->IsNumber());
   9652   CHECK_EQ(1, value->Int32Value());
   9653   CHECK_EQ(21, named_access_count);
   9654 
   9655   // Check that the named access-control function is called every time.
   9656   CompileRun("var p = 'prop';"
   9657              "function testKeyed(obj) {"
   9658              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
   9659              "  for (var j = 0; j < 10; j++) obj[p];"
   9660              "  return obj[p];"
   9661              "}");
   9662   // Use obj which requires access checks.  No inline caching is used
   9663   // in that case.
   9664   value = CompileRun("testKeyed(obj)");
   9665   CHECK(value->IsNumber());
   9666   CHECK_EQ(1, value->Int32Value());
   9667   CHECK_EQ(42, named_access_count);
   9668   // Force the inline caches into generic state and try again.
   9669   CompileRun("testKeyed({ a: 0 })");
   9670   CompileRun("testKeyed({ b: 0 })");
   9671   value = CompileRun("testKeyed(obj)");
   9672   CHECK(value->IsNumber());
   9673   CHECK_EQ(1, value->Int32Value());
   9674   CHECK_EQ(63, named_access_count);
   9675 
   9676   // Check that the indexed access-control function is called every time.
   9677   CompileRun("function testIndexed(obj) {"
   9678              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
   9679              "  for (var j = 0; j < 10; j++) obj[0];"
   9680              "  return obj[0]"
   9681              "}");
   9682   value = CompileRun("testIndexed(obj)");
   9683   CHECK(value->IsNumber());
   9684   CHECK_EQ(1, value->Int32Value());
   9685   CHECK_EQ(21, indexed_access_count);
   9686   // Force the inline caches into generic state.
   9687   CompileRun("testIndexed(new Array(1))");
   9688   // Test that the indexed access check is called.
   9689   value = CompileRun("testIndexed(obj)");
   9690   CHECK(value->IsNumber());
   9691   CHECK_EQ(1, value->Int32Value());
   9692   CHECK_EQ(42, indexed_access_count);
   9693 
   9694   // Check that the named access check is called when invoking
   9695   // functions on an object that requires access checks.
   9696   CompileRun("obj.f = function() {}");
   9697   CompileRun("function testCallNormal(obj) {"
   9698              "  for (var i = 0; i < 10; i++) obj.f();"
   9699              "}");
   9700   CompileRun("testCallNormal(obj)");
   9701   CHECK_EQ(74, named_access_count);
   9702 
   9703   // Force obj into slow case.
   9704   value = CompileRun("delete obj.prop");
   9705   CHECK(value->BooleanValue());
   9706   // Force inline caches into dictionary probing mode.
   9707   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
   9708   // Test that the named access check is called.
   9709   value = CompileRun("testProp(obj);");
   9710   CHECK(value->IsNumber());
   9711   CHECK_EQ(1, value->Int32Value());
   9712   CHECK_EQ(96, named_access_count);
   9713 
   9714   // Force the call inline cache into dictionary probing mode.
   9715   CompileRun("o.f = function() {}; testCallNormal(o)");
   9716   // Test that the named access check is still called for each
   9717   // invocation of the function.
   9718   value = CompileRun("testCallNormal(obj)");
   9719   CHECK_EQ(106, named_access_count);
   9720 
   9721   context1->Exit();
   9722   context0->Exit();
   9723 }
   9724 
   9725 
   9726 static bool NamedAccessFlatten(Local<v8::Object> global,
   9727                                Local<Value> name,
   9728                                v8::AccessType type,
   9729                                Local<Value> data) {
   9730   char buf[100];
   9731   int len;
   9732 
   9733   CHECK(name->IsString());
   9734 
   9735   memset(buf, 0x1, sizeof(buf));
   9736   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
   9737   CHECK_EQ(4, len);
   9738 
   9739   uint16_t buf2[100];
   9740 
   9741   memset(buf, 0x1, sizeof(buf));
   9742   len = name.As<String>()->Write(buf2);
   9743   CHECK_EQ(4, len);
   9744 
   9745   return true;
   9746 }
   9747 
   9748 
   9749 static bool IndexedAccessFlatten(Local<v8::Object> global,
   9750                                  uint32_t key,
   9751                                  v8::AccessType type,
   9752                                  Local<Value> data) {
   9753   return true;
   9754 }
   9755 
   9756 
   9757 // Regression test.  In access checks, operations that may cause
   9758 // garbage collection are not allowed.  It used to be the case that
   9759 // using the Write operation on a string could cause a garbage
   9760 // collection due to flattening of the string.  This is no longer the
   9761 // case.
   9762 THREADED_TEST(AccessControlFlatten) {
   9763   named_access_count = 0;
   9764   indexed_access_count = 0;
   9765 
   9766   v8::Isolate* isolate = CcTest::isolate();
   9767   v8::HandleScope handle_scope(isolate);
   9768 
   9769   // Create an environment.
   9770   v8::Local<Context> context0 = Context::New(isolate);
   9771   context0->Enter();
   9772 
   9773   // Create an object that requires access-check functions to be
   9774   // called for cross-domain access.
   9775   v8::Handle<v8::ObjectTemplate> object_template =
   9776       v8::ObjectTemplate::New(isolate);
   9777   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
   9778                                            IndexedAccessFlatten);
   9779   Local<v8::Object> object = object_template->NewInstance();
   9780 
   9781   v8::HandleScope scope1(isolate);
   9782 
   9783   // Create another environment.
   9784   v8::Local<Context> context1 = Context::New(isolate);
   9785   context1->Enter();
   9786 
   9787   // Make easy access to the object from the other environment.
   9788   v8::Handle<v8::Object> global1 = context1->Global();
   9789   global1->Set(v8_str("obj"), object);
   9790 
   9791   v8::Handle<Value> value;
   9792 
   9793   value = v8_compile("var p = 'as' + 'df';")->Run();
   9794   value = v8_compile("obj[p];")->Run();
   9795 
   9796   context1->Exit();
   9797   context0->Exit();
   9798 }
   9799 
   9800 
   9801 static void AccessControlNamedGetter(
   9802     Local<String>,
   9803     const v8::PropertyCallbackInfo<v8::Value>& info) {
   9804   info.GetReturnValue().Set(42);
   9805 }
   9806 
   9807 
   9808 static void AccessControlNamedSetter(
   9809     Local<String>,
   9810     Local<Value> value,
   9811     const v8::PropertyCallbackInfo<v8::Value>& info) {
   9812   info.GetReturnValue().Set(value);
   9813 }
   9814 
   9815 
   9816 static void AccessControlIndexedGetter(
   9817       uint32_t index,
   9818       const v8::PropertyCallbackInfo<v8::Value>& info) {
   9819   info.GetReturnValue().Set(v8_num(42));
   9820 }
   9821 
   9822 
   9823 static void AccessControlIndexedSetter(
   9824     uint32_t,
   9825     Local<Value> value,
   9826     const v8::PropertyCallbackInfo<v8::Value>& info) {
   9827   info.GetReturnValue().Set(value);
   9828 }
   9829 
   9830 
   9831 THREADED_TEST(AccessControlInterceptorIC) {
   9832   named_access_count = 0;
   9833   indexed_access_count = 0;
   9834 
   9835   v8::Isolate* isolate = CcTest::isolate();
   9836   v8::HandleScope handle_scope(isolate);
   9837 
   9838   // Create an environment.
   9839   v8::Local<Context> context0 = Context::New(isolate);
   9840   context0->Enter();
   9841 
   9842   // Create an object that requires access-check functions to be
   9843   // called for cross-domain access.  The object also has interceptors
   9844   // interceptor.
   9845   v8::Handle<v8::ObjectTemplate> object_template =
   9846       v8::ObjectTemplate::New(isolate);
   9847   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
   9848                                            IndexedAccessCounter);
   9849   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
   9850                                            AccessControlNamedSetter);
   9851   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
   9852                                              AccessControlIndexedSetter);
   9853   Local<v8::Object> object = object_template->NewInstance();
   9854 
   9855   v8::HandleScope scope1(isolate);
   9856 
   9857   // Create another environment.
   9858   v8::Local<Context> context1 = Context::New(isolate);
   9859   context1->Enter();
   9860 
   9861   // Make easy access to the object from the other environment.
   9862   v8::Handle<v8::Object> global1 = context1->Global();
   9863   global1->Set(v8_str("obj"), object);
   9864 
   9865   v8::Handle<Value> value;
   9866 
   9867   // Check that the named access-control function is called every time
   9868   // eventhough there is an interceptor on the object.
   9869   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
   9870   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
   9871                      "obj.x")->Run();
   9872   CHECK(value->IsNumber());
   9873   CHECK_EQ(42, value->Int32Value());
   9874   CHECK_EQ(21, named_access_count);
   9875 
   9876   value = v8_compile("var p = 'x';")->Run();
   9877   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
   9878   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
   9879                      "obj[p]")->Run();
   9880   CHECK(value->IsNumber());
   9881   CHECK_EQ(42, value->Int32Value());
   9882   CHECK_EQ(42, named_access_count);
   9883 
   9884   // Check that the indexed access-control function is called every
   9885   // time eventhough there is an interceptor on the object.
   9886   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
   9887   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
   9888                      "obj[0]")->Run();
   9889   CHECK(value->IsNumber());
   9890   CHECK_EQ(42, value->Int32Value());
   9891   CHECK_EQ(21, indexed_access_count);
   9892 
   9893   context1->Exit();
   9894   context0->Exit();
   9895 }
   9896 
   9897 
   9898 THREADED_TEST(Version) {
   9899   v8::V8::GetVersion();
   9900 }
   9901 
   9902 
   9903 static void InstanceFunctionCallback(
   9904     const v8::FunctionCallbackInfo<v8::Value>& args) {
   9905   ApiTestFuzzer::Fuzz();
   9906   args.GetReturnValue().Set(v8_num(12));
   9907 }
   9908 
   9909 
   9910 THREADED_TEST(InstanceProperties) {
   9911   LocalContext context;
   9912   v8::Isolate* isolate = context->GetIsolate();
   9913   v8::HandleScope handle_scope(isolate);
   9914 
   9915   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   9916   Local<ObjectTemplate> instance = t->InstanceTemplate();
   9917 
   9918   instance->Set(v8_str("x"), v8_num(42));
   9919   instance->Set(v8_str("f"),
   9920                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
   9921 
   9922   Local<Value> o = t->GetFunction()->NewInstance();
   9923 
   9924   context->Global()->Set(v8_str("i"), o);
   9925   Local<Value> value = CompileRun("i.x");
   9926   CHECK_EQ(42, value->Int32Value());
   9927 
   9928   value = CompileRun("i.f()");
   9929   CHECK_EQ(12, value->Int32Value());
   9930 }
   9931 
   9932 
   9933 static void GlobalObjectInstancePropertiesGet(
   9934     Local<String> key,
   9935     const v8::PropertyCallbackInfo<v8::Value>&) {
   9936   ApiTestFuzzer::Fuzz();
   9937 }
   9938 
   9939 
   9940 THREADED_TEST(GlobalObjectInstanceProperties) {
   9941   v8::Isolate* isolate = CcTest::isolate();
   9942   v8::HandleScope handle_scope(isolate);
   9943 
   9944   Local<Value> global_object;
   9945 
   9946   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   9947   t->InstanceTemplate()->SetNamedPropertyHandler(
   9948       GlobalObjectInstancePropertiesGet);
   9949   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   9950   instance_template->Set(v8_str("x"), v8_num(42));
   9951   instance_template->Set(v8_str("f"),
   9952                          v8::FunctionTemplate::New(isolate,
   9953                                                    InstanceFunctionCallback));
   9954 
   9955   // The script to check how Crankshaft compiles missing global function
   9956   // invocations.  function g is not defined and should throw on call.
   9957   const char* script =
   9958       "function wrapper(call) {"
   9959       "  var x = 0, y = 1;"
   9960       "  for (var i = 0; i < 1000; i++) {"
   9961       "    x += i * 100;"
   9962       "    y += i * 100;"
   9963       "  }"
   9964       "  if (call) g();"
   9965       "}"
   9966       "for (var i = 0; i < 17; i++) wrapper(false);"
   9967       "var thrown = 0;"
   9968       "try { wrapper(true); } catch (e) { thrown = 1; };"
   9969       "thrown";
   9970 
   9971   {
   9972     LocalContext env(NULL, instance_template);
   9973     // Hold on to the global object so it can be used again in another
   9974     // environment initialization.
   9975     global_object = env->Global();
   9976 
   9977     Local<Value> value = CompileRun("x");
   9978     CHECK_EQ(42, value->Int32Value());
   9979     value = CompileRun("f()");
   9980     CHECK_EQ(12, value->Int32Value());
   9981     value = CompileRun(script);
   9982     CHECK_EQ(1, value->Int32Value());
   9983   }
   9984 
   9985   {
   9986     // Create new environment reusing the global object.
   9987     LocalContext env(NULL, instance_template, global_object);
   9988     Local<Value> value = CompileRun("x");
   9989     CHECK_EQ(42, value->Int32Value());
   9990     value = CompileRun("f()");
   9991     CHECK_EQ(12, value->Int32Value());
   9992     value = CompileRun(script);
   9993     CHECK_EQ(1, value->Int32Value());
   9994   }
   9995 }
   9996 
   9997 
   9998 THREADED_TEST(CallKnownGlobalReceiver) {
   9999   v8::Isolate* isolate = CcTest::isolate();
   10000   v8::HandleScope handle_scope(isolate);
   10001 
   10002   Local<Value> global_object;
   10003 
   10004   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   10005   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   10006 
   10007   // The script to check that we leave global object not
   10008   // global object proxy on stack when we deoptimize from inside
   10009   // arguments evaluation.
   10010   // To provoke error we need to both force deoptimization
   10011   // from arguments evaluation and to force CallIC to take
   10012   // CallIC_Miss code path that can't cope with global proxy.
   10013   const char* script =
   10014       "function bar(x, y) { try { } finally { } }"
   10015       "function baz(x) { try { } finally { } }"
   10016       "function bom(x) { try { } finally { } }"
   10017       "function foo(x) { bar([x], bom(2)); }"
   10018       "for (var i = 0; i < 10000; i++) foo(1);"
   10019       "foo";
   10020 
   10021   Local<Value> foo;
   10022   {
   10023     LocalContext env(NULL, instance_template);
   10024     // Hold on to the global object so it can be used again in another
   10025     // environment initialization.
   10026     global_object = env->Global();
   10027     foo = CompileRun(script);
   10028   }
   10029 
   10030   {
   10031     // Create new environment reusing the global object.
   10032     LocalContext env(NULL, instance_template, global_object);
   10033     env->Global()->Set(v8_str("foo"), foo);
   10034     CompileRun("foo()");
   10035   }
   10036 }
   10037 
   10038 
   10039 static void ShadowFunctionCallback(
   10040     const v8::FunctionCallbackInfo<v8::Value>& args) {
   10041   ApiTestFuzzer::Fuzz();
   10042   args.GetReturnValue().Set(v8_num(42));
   10043 }
   10044 
   10045 
   10046 static int shadow_y;
   10047 static int shadow_y_setter_call_count;
   10048 static int shadow_y_getter_call_count;
   10049 
   10050 
   10051 static void ShadowYSetter(Local<String>,
   10052                           Local<Value>,
   10053                           const v8::PropertyCallbackInfo<void>&) {
   10054   shadow_y_setter_call_count++;
   10055   shadow_y = 42;
   10056 }
   10057 
   10058 
   10059 static void ShadowYGetter(Local<String> name,
   10060                           const v8::PropertyCallbackInfo<v8::Value>& info) {
   10061   ApiTestFuzzer::Fuzz();
   10062   shadow_y_getter_call_count++;
   10063   info.GetReturnValue().Set(v8_num(shadow_y));
   10064 }
   10065 
   10066 
   10067 static void ShadowIndexedGet(uint32_t index,
   10068                              const v8::PropertyCallbackInfo<v8::Value>&) {
   10069 }
   10070 
   10071 
   10072 static void ShadowNamedGet(Local<String> key,
   10073                            const v8::PropertyCallbackInfo<v8::Value>&) {
   10074 }
   10075 
   10076 
   10077 THREADED_TEST(ShadowObject) {
   10078   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
   10079   v8::Isolate* isolate = CcTest::isolate();
   10080   v8::HandleScope handle_scope(isolate);
   10081 
   10082   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
   10083   LocalContext context(NULL, global_template);
   10084 
   10085   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   10086   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
   10087   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
   10088   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   10089   Local<ObjectTemplate> instance = t->InstanceTemplate();
   10090 
   10091   proto->Set(v8_str("f"),
   10092              v8::FunctionTemplate::New(isolate,
   10093                                        ShadowFunctionCallback,
   10094                                        Local<Value>()));
   10095   proto->Set(v8_str("x"), v8_num(12));
   10096 
   10097   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
   10098 
   10099   Local<Value> o = t->GetFunction()->NewInstance();
   10100   context->Global()->Set(v8_str("__proto__"), o);
   10101 
   10102   Local<Value> value =
   10103       CompileRun("this.propertyIsEnumerable(0)");
   10104   CHECK(value->IsBoolean());
   10105   CHECK(!value->BooleanValue());
   10106 
   10107   value = CompileRun("x");
   10108   CHECK_EQ(12, value->Int32Value());
   10109 
   10110   value = CompileRun("f()");
   10111   CHECK_EQ(42, value->Int32Value());
   10112 
   10113   CompileRun("y = 43");
   10114   CHECK_EQ(1, shadow_y_setter_call_count);
   10115   value = CompileRun("y");
   10116   CHECK_EQ(1, shadow_y_getter_call_count);
   10117   CHECK_EQ(42, value->Int32Value());
   10118 }
   10119 
   10120 
   10121 THREADED_TEST(HiddenPrototype) {
   10122   LocalContext context;
   10123   v8::Isolate* isolate = context->GetIsolate();
   10124   v8::HandleScope handle_scope(isolate);
   10125 
   10126   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
   10127   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   10128   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
   10129   t1->SetHiddenPrototype(true);
   10130   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
   10131   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
   10132   t2->SetHiddenPrototype(true);
   10133   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
   10134   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
   10135   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
   10136 
   10137   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
   10138   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   10139   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   10140   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   10141 
   10142   // Setting the prototype on an object skips hidden prototypes.
   10143   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10144   o0->Set(v8_str("__proto__"), o1);
   10145   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10146   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   10147   o0->Set(v8_str("__proto__"), o2);
   10148   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10149   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   10150   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   10151   o0->Set(v8_str("__proto__"), o3);
   10152   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10153   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   10154   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   10155   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
   10156 
   10157   // Getting the prototype of o0 should get the first visible one
   10158   // which is o3.  Therefore, z should not be defined on the prototype
   10159   // object.
   10160   Local<Value> proto = o0->Get(v8_str("__proto__"));
   10161   CHECK(proto->IsObject());
   10162   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
   10163 }
   10164 
   10165 
   10166 THREADED_TEST(HiddenPrototypeSet) {
   10167   LocalContext context;
   10168   v8::Isolate* isolate = context->GetIsolate();
   10169   v8::HandleScope handle_scope(isolate);
   10170 
   10171   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
   10172   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
   10173   ht->SetHiddenPrototype(true);
   10174   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
   10175   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   10176 
   10177   Local<v8::Object> o = ot->GetFunction()->NewInstance();
   10178   Local<v8::Object> h = ht->GetFunction()->NewInstance();
   10179   Local<v8::Object> p = pt->GetFunction()->NewInstance();
   10180   o->Set(v8_str("__proto__"), h);
   10181   h->Set(v8_str("__proto__"), p);
   10182 
   10183   // Setting a property that exists on the hidden prototype goes there.
   10184   o->Set(v8_str("x"), v8_num(7));
   10185   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
   10186   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
   10187   CHECK(p->Get(v8_str("x"))->IsUndefined());
   10188 
   10189   // Setting a new property should not be forwarded to the hidden prototype.
   10190   o->Set(v8_str("y"), v8_num(6));
   10191   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
   10192   CHECK(h->Get(v8_str("y"))->IsUndefined());
   10193   CHECK(p->Get(v8_str("y"))->IsUndefined());
   10194 
   10195   // Setting a property that only exists on a prototype of the hidden prototype
   10196   // is treated normally again.
   10197   p->Set(v8_str("z"), v8_num(8));
   10198   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
   10199   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
   10200   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
   10201   o->Set(v8_str("z"), v8_num(9));
   10202   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
   10203   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
   10204   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
   10205 }
   10206 
   10207 
   10208 // Regression test for issue 2457.
   10209 THREADED_TEST(HiddenPrototypeIdentityHash) {
   10210   LocalContext context;
   10211   v8::HandleScope handle_scope(context->GetIsolate());
   10212 
   10213   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
   10214   t->SetHiddenPrototype(true);
   10215   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
   10216   Handle<Object> p = t->GetFunction()->NewInstance();
   10217   Handle<Object> o = Object::New(context->GetIsolate());
   10218   o->SetPrototype(p);
   10219 
   10220   int hash = o->GetIdentityHash();
   10221   USE(hash);
   10222   o->Set(v8_str("foo"), v8_num(42));
   10223   ASSERT_EQ(hash, o->GetIdentityHash());
   10224 }
   10225 
   10226 
   10227 THREADED_TEST(SetPrototype) {
   10228   LocalContext context;
   10229   v8::Isolate* isolate = context->GetIsolate();
   10230   v8::HandleScope handle_scope(isolate);
   10231 
   10232   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
   10233   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
   10234   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
   10235   t1->SetHiddenPrototype(true);
   10236   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
   10237   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
   10238   t2->SetHiddenPrototype(true);
   10239   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
   10240   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
   10241   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
   10242 
   10243   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
   10244   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   10245   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   10246   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   10247 
   10248   // Setting the prototype on an object does not skip hidden prototypes.
   10249   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10250   CHECK(o0->SetPrototype(o1));
   10251   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10252   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   10253   CHECK(o1->SetPrototype(o2));
   10254   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10255   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   10256   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   10257   CHECK(o2->SetPrototype(o3));
   10258   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
   10259   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
   10260   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
   10261   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
   10262 
   10263   // Getting the prototype of o0 should get the first visible one
   10264   // which is o3.  Therefore, z should not be defined on the prototype
   10265   // object.
   10266   Local<Value> proto = o0->Get(v8_str("__proto__"));
   10267   CHECK(proto->IsObject());
   10268   CHECK_EQ(proto.As<v8::Object>(), o3);
   10269 
   10270   // However, Object::GetPrototype ignores hidden prototype.
   10271   Local<Value> proto0 = o0->GetPrototype();
   10272   CHECK(proto0->IsObject());
   10273   CHECK_EQ(proto0.As<v8::Object>(), o1);
   10274 
   10275   Local<Value> proto1 = o1->GetPrototype();
   10276   CHECK(proto1->IsObject());
   10277   CHECK_EQ(proto1.As<v8::Object>(), o2);
   10278 
   10279   Local<Value> proto2 = o2->GetPrototype();
   10280   CHECK(proto2->IsObject());
   10281   CHECK_EQ(proto2.As<v8::Object>(), o3);
   10282 }
   10283 
   10284 
   10285 // Getting property names of an object with a prototype chain that
   10286 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
   10287 // crash the runtime.
   10288 THREADED_TEST(Regress91517) {
   10289   i::FLAG_allow_natives_syntax = true;
   10290   LocalContext context;
   10291   v8::Isolate* isolate = context->GetIsolate();
   10292   v8::HandleScope handle_scope(isolate);
   10293 
   10294   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
   10295   t1->SetHiddenPrototype(true);
   10296   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
   10297   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
   10298   t2->SetHiddenPrototype(true);
   10299   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
   10300   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
   10301   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
   10302   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
   10303   t3->SetHiddenPrototype(true);
   10304   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
   10305   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
   10306   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
   10307 
   10308   // Force dictionary-based properties.
   10309   i::ScopedVector<char> name_buf(1024);
   10310   for (int i = 1; i <= 1000; i++) {
   10311     i::SNPrintF(name_buf, "sdf%d", i);
   10312     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
   10313   }
   10314 
   10315   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   10316   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   10317   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
   10318   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
   10319 
   10320   // Create prototype chain of hidden prototypes.
   10321   CHECK(o4->SetPrototype(o3));
   10322   CHECK(o3->SetPrototype(o2));
   10323   CHECK(o2->SetPrototype(o1));
   10324 
   10325   // Call the runtime version of GetOwnPropertyNames() on the natively
   10326   // created object through JavaScript.
   10327   context->Global()->Set(v8_str("obj"), o4);
   10328   // PROPERTY_ATTRIBUTES_NONE = 0
   10329   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
   10330 
   10331   ExpectInt32("names.length", 1006);
   10332   ExpectTrue("names.indexOf(\"baz\") >= 0");
   10333   ExpectTrue("names.indexOf(\"boo\") >= 0");
   10334   ExpectTrue("names.indexOf(\"foo\") >= 0");
   10335   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
   10336   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
   10337   ExpectFalse("names[1005] == undefined");
   10338 }
   10339 
   10340 
   10341 // Getting property names of an object with a hidden and inherited
   10342 // prototype should not duplicate the accessor properties inherited.
   10343 THREADED_TEST(Regress269562) {
   10344   i::FLAG_allow_natives_syntax = true;
   10345   LocalContext context;
   10346   v8::HandleScope handle_scope(context->GetIsolate());
   10347 
   10348   Local<v8::FunctionTemplate> t1 =
   10349       v8::FunctionTemplate::New(context->GetIsolate());
   10350   t1->SetHiddenPrototype(true);
   10351 
   10352   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
   10353   i1->SetAccessor(v8_str("foo"),
   10354                   SimpleAccessorGetter, SimpleAccessorSetter);
   10355   i1->SetAccessor(v8_str("bar"),
   10356                   SimpleAccessorGetter, SimpleAccessorSetter);
   10357   i1->SetAccessor(v8_str("baz"),
   10358                   SimpleAccessorGetter, SimpleAccessorSetter);
   10359   i1->Set(v8_str("n1"), v8_num(1));
   10360   i1->Set(v8_str("n2"), v8_num(2));
   10361 
   10362   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
   10363   Local<v8::FunctionTemplate> t2 =
   10364       v8::FunctionTemplate::New(context->GetIsolate());
   10365   t2->SetHiddenPrototype(true);
   10366 
   10367   // Inherit from t1 and mark prototype as hidden.
   10368   t2->Inherit(t1);
   10369   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
   10370 
   10371   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
   10372   CHECK(o2->SetPrototype(o1));
   10373 
   10374   v8::Local<v8::Symbol> sym =
   10375       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
   10376   o1->Set(sym, v8_num(3));
   10377   o1->SetHiddenValue(
   10378       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
   10379 
   10380   // Call the runtime version of GetOwnPropertyNames() on
   10381   // the natively created object through JavaScript.
   10382   context->Global()->Set(v8_str("obj"), o2);
   10383   context->Global()->Set(v8_str("sym"), sym);
   10384   // PROPERTY_ATTRIBUTES_NONE = 0
   10385   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
   10386 
   10387   ExpectInt32("names.length", 7);
   10388   ExpectTrue("names.indexOf(\"foo\") >= 0");
   10389   ExpectTrue("names.indexOf(\"bar\") >= 0");
   10390   ExpectTrue("names.indexOf(\"baz\") >= 0");
   10391   ExpectTrue("names.indexOf(\"n1\") >= 0");
   10392   ExpectTrue("names.indexOf(\"n2\") >= 0");
   10393   ExpectTrue("names.indexOf(sym) >= 0");
   10394   ExpectTrue("names.indexOf(\"mine\") >= 0");
   10395 }
   10396 
   10397 
   10398 THREADED_TEST(FunctionReadOnlyPrototype) {
   10399   LocalContext context;
   10400   v8::Isolate* isolate = context->GetIsolate();
   10401   v8::HandleScope handle_scope(isolate);
   10402 
   10403   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
   10404   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
   10405   t1->ReadOnlyPrototype();
   10406   context->Global()->Set(v8_str("func1"), t1->GetFunction());
   10407   // Configured value of ReadOnly flag.
   10408   CHECK(CompileRun(
   10409       "(function() {"
   10410       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
   10411       "  return (descriptor['writable'] == false);"
   10412       "})()")->BooleanValue());
   10413   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
   10414   CHECK_EQ(42,
   10415            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
   10416 
   10417   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
   10418   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
   10419   context->Global()->Set(v8_str("func2"), t2->GetFunction());
   10420   // Default value of ReadOnly flag.
   10421   CHECK(CompileRun(
   10422       "(function() {"
   10423       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
   10424       "  return (descriptor['writable'] == true);"
   10425       "})()")->BooleanValue());
   10426   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
   10427 }
   10428 
   10429 
   10430 THREADED_TEST(SetPrototypeThrows) {
   10431   LocalContext context;
   10432   v8::Isolate* isolate = context->GetIsolate();
   10433   v8::HandleScope handle_scope(isolate);
   10434 
   10435   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   10436 
   10437   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
   10438   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
   10439 
   10440   CHECK(o0->SetPrototype(o1));
   10441   // If setting the prototype leads to the cycle, SetPrototype should
   10442   // return false and keep VM in sane state.
   10443   v8::TryCatch try_catch;
   10444   CHECK(!o1->SetPrototype(o0));
   10445   CHECK(!try_catch.HasCaught());
   10446   ASSERT(!CcTest::i_isolate()->has_pending_exception());
   10447 
   10448   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
   10449 }
   10450 
   10451 
   10452 THREADED_TEST(FunctionRemovePrototype) {
   10453   LocalContext context;
   10454   v8::Isolate* isolate = context->GetIsolate();
   10455   v8::HandleScope handle_scope(isolate);
   10456 
   10457   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
   10458   t1->RemovePrototype();
   10459   Local<v8::Function> fun = t1->GetFunction();
   10460   context->Global()->Set(v8_str("fun"), fun);
   10461   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
   10462 
   10463   v8::TryCatch try_catch;
   10464   CompileRun("new fun()");
   10465   CHECK(try_catch.HasCaught());
   10466 
   10467   try_catch.Reset();
   10468   fun->NewInstance();
   10469   CHECK(try_catch.HasCaught());
   10470 }
   10471 
   10472 
   10473 THREADED_TEST(GetterSetterExceptions) {
   10474   LocalContext context;
   10475   v8::Isolate* isolate = context->GetIsolate();
   10476   v8::HandleScope handle_scope(isolate);
   10477   CompileRun(
   10478     "function Foo() { };"
   10479     "function Throw() { throw 5; };"
   10480     "var x = { };"
   10481     "x.__defineSetter__('set', Throw);"
   10482     "x.__defineGetter__('get', Throw);");
   10483   Local<v8::Object> x =
   10484       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
   10485   v8::TryCatch try_catch;
   10486   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
   10487   x->Get(v8_str("get"));
   10488   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
   10489   x->Get(v8_str("get"));
   10490   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
   10491   x->Get(v8_str("get"));
   10492   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
   10493   x->Get(v8_str("get"));
   10494 }
   10495 
   10496 
   10497 THREADED_TEST(Constructor) {
   10498   LocalContext context;
   10499   v8::Isolate* isolate = context->GetIsolate();
   10500   v8::HandleScope handle_scope(isolate);
   10501   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   10502   templ->SetClassName(v8_str("Fun"));
   10503   Local<Function> cons = templ->GetFunction();
   10504   context->Global()->Set(v8_str("Fun"), cons);
   10505   Local<v8::Object> inst = cons->NewInstance();
   10506   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
   10507   CHECK(obj->IsJSObject());
   10508   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
   10509   CHECK(value->BooleanValue());
   10510 }
   10511 
   10512 
   10513 static void ConstructorCallback(
   10514     const v8::FunctionCallbackInfo<v8::Value>& args) {
   10515   ApiTestFuzzer::Fuzz();
   10516   Local<Object> This;
   10517 
   10518   if (args.IsConstructCall()) {
   10519     Local<Object> Holder = args.Holder();
   10520     This = Object::New(args.GetIsolate());
   10521     Local<Value> proto = Holder->GetPrototype();
   10522     if (proto->IsObject()) {
   10523       This->SetPrototype(proto);
   10524     }
   10525   } else {
   10526     This = args.This();
   10527   }
   10528 
   10529   This->Set(v8_str("a"), args[0]);
   10530   args.GetReturnValue().Set(This);
   10531 }
   10532 
   10533 
   10534 static void FakeConstructorCallback(
   10535     const v8::FunctionCallbackInfo<v8::Value>& args) {
   10536   ApiTestFuzzer::Fuzz();
   10537   args.GetReturnValue().Set(args[0]);
   10538 }
   10539 
   10540 
   10541 THREADED_TEST(ConstructorForObject) {
   10542   LocalContext context;
   10543   v8::Isolate* isolate = context->GetIsolate();
   10544   v8::HandleScope handle_scope(isolate);
   10545 
   10546   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
   10547     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
   10548     Local<Object> instance = instance_template->NewInstance();
   10549     context->Global()->Set(v8_str("obj"), instance);
   10550     v8::TryCatch try_catch;
   10551     Local<Value> value;
   10552     CHECK(!try_catch.HasCaught());
   10553 
   10554     // Call the Object's constructor with a 32-bit signed integer.
   10555     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
   10556     CHECK(!try_catch.HasCaught());
   10557     CHECK(value->IsInt32());
   10558     CHECK_EQ(28, value->Int32Value());
   10559 
   10560     Local<Value> args1[] = { v8_num(28) };
   10561     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
   10562     CHECK(value_obj1->IsObject());
   10563     Local<Object> object1 = Local<Object>::Cast(value_obj1);
   10564     value = object1->Get(v8_str("a"));
   10565     CHECK(value->IsInt32());
   10566     CHECK(!try_catch.HasCaught());
   10567     CHECK_EQ(28, value->Int32Value());
   10568 
   10569     // Call the Object's constructor with a String.
   10570     value = CompileRun(
   10571         "(function() { var o = new obj('tipli'); return o.a; })()");
   10572     CHECK(!try_catch.HasCaught());
   10573     CHECK(value->IsString());
   10574     String::Utf8Value string_value1(value->ToString());
   10575     CHECK_EQ("tipli", *string_value1);
   10576 
   10577     Local<Value> args2[] = { v8_str("tipli") };
   10578     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
   10579     CHECK(value_obj2->IsObject());
   10580     Local<Object> object2 = Local<Object>::Cast(value_obj2);
   10581     value = object2->Get(v8_str("a"));
   10582     CHECK(!try_catch.HasCaught());
   10583     CHECK(value->IsString());
   10584     String::Utf8Value string_value2(value->ToString());
   10585     CHECK_EQ("tipli", *string_value2);
   10586 
   10587     // Call the Object's constructor with a Boolean.
   10588     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
   10589     CHECK(!try_catch.HasCaught());
   10590     CHECK(value->IsBoolean());
   10591     CHECK_EQ(true, value->BooleanValue());
   10592 
   10593     Handle<Value> args3[] = { v8::True(isolate) };
   10594     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
   10595     CHECK(value_obj3->IsObject());
   10596     Local<Object> object3 = Local<Object>::Cast(value_obj3);
   10597     value = object3->Get(v8_str("a"));
   10598     CHECK(!try_catch.HasCaught());
   10599     CHECK(value->IsBoolean());
   10600     CHECK_EQ(true, value->BooleanValue());
   10601 
   10602     // Call the Object's constructor with undefined.
   10603     Handle<Value> args4[] = { v8::Undefined(isolate) };
   10604     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
   10605     CHECK(value_obj4->IsObject());
   10606     Local<Object> object4 = Local<Object>::Cast(value_obj4);
   10607     value = object4->Get(v8_str("a"));
   10608     CHECK(!try_catch.HasCaught());
   10609     CHECK(value->IsUndefined());
   10610 
   10611     // Call the Object's constructor with null.
   10612     Handle<Value> args5[] = { v8::Null(isolate) };
   10613     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
   10614     CHECK(value_obj5->IsObject());
   10615     Local<Object> object5 = Local<Object>::Cast(value_obj5);
   10616     value = object5->Get(v8_str("a"));
   10617     CHECK(!try_catch.HasCaught());
   10618     CHECK(value->IsNull());
   10619   }
   10620 
   10621   // Check exception handling when there is no constructor set for the Object.
   10622   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
   10623     Local<Object> instance = instance_template->NewInstance();
   10624     context->Global()->Set(v8_str("obj2"), instance);
   10625     v8::TryCatch try_catch;
   10626     Local<Value> value;
   10627     CHECK(!try_catch.HasCaught());
   10628 
   10629     value = CompileRun("new obj2(28)");
   10630     CHECK(try_catch.HasCaught());
   10631     String::Utf8Value exception_value1(try_catch.Exception());
   10632     CHECK_EQ("TypeError: object is not a function", *exception_value1);
   10633     try_catch.Reset();
   10634 
   10635     Local<Value> args[] = { v8_num(29) };
   10636     value = instance->CallAsConstructor(1, args);
   10637     CHECK(try_catch.HasCaught());
   10638     String::Utf8Value exception_value2(try_catch.Exception());
   10639     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
   10640     try_catch.Reset();
   10641   }
   10642 
   10643   // Check the case when constructor throws exception.
   10644   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
   10645     instance_template->SetCallAsFunctionHandler(ThrowValue);
   10646     Local<Object> instance = instance_template->NewInstance();
   10647     context->Global()->Set(v8_str("obj3"), instance);
   10648     v8::TryCatch try_catch;
   10649     Local<Value> value;
   10650     CHECK(!try_catch.HasCaught());
   10651 
   10652     value = CompileRun("new obj3(22)");
   10653     CHECK(try_catch.HasCaught());
   10654     String::Utf8Value exception_value1(try_catch.Exception());
   10655     CHECK_EQ("22", *exception_value1);
   10656     try_catch.Reset();
   10657 
   10658     Local<Value> args[] = { v8_num(23) };
   10659     value = instance->CallAsConstructor(1, args);
   10660     CHECK(try_catch.HasCaught());
   10661     String::Utf8Value exception_value2(try_catch.Exception());
   10662     CHECK_EQ("23", *exception_value2);
   10663     try_catch.Reset();
   10664   }
   10665 
   10666   // Check whether constructor returns with an object or non-object.
   10667   { Local<FunctionTemplate> function_template =
   10668         FunctionTemplate::New(isolate, FakeConstructorCallback);
   10669     Local<Function> function = function_template->GetFunction();
   10670     Local<Object> instance1 = function;
   10671     context->Global()->Set(v8_str("obj4"), instance1);
   10672     v8::TryCatch try_catch;
   10673     Local<Value> value;
   10674     CHECK(!try_catch.HasCaught());
   10675 
   10676     CHECK(instance1->IsObject());
   10677     CHECK(instance1->IsFunction());
   10678 
   10679     value = CompileRun("new obj4(28)");
   10680     CHECK(!try_catch.HasCaught());
   10681     CHECK(value->IsObject());
   10682 
   10683     Local<Value> args1[] = { v8_num(28) };
   10684     value = instance1->CallAsConstructor(1, args1);
   10685     CHECK(!try_catch.HasCaught());
   10686     CHECK(value->IsObject());
   10687 
   10688     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
   10689     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
   10690     Local<Object> instance2 = instance_template->NewInstance();
   10691     context->Global()->Set(v8_str("obj5"), instance2);
   10692     CHECK(!try_catch.HasCaught());
   10693 
   10694     CHECK(instance2->IsObject());
   10695     CHECK(!instance2->IsFunction());
   10696 
   10697     value = CompileRun("new obj5(28)");
   10698     CHECK(!try_catch.HasCaught());
   10699     CHECK(!value->IsObject());
   10700 
   10701     Local<Value> args2[] = { v8_num(28) };
   10702     value = instance2->CallAsConstructor(1, args2);
   10703     CHECK(!try_catch.HasCaught());
   10704     CHECK(!value->IsObject());
   10705   }
   10706 }
   10707 
   10708 
   10709 THREADED_TEST(FunctionDescriptorException) {
   10710   LocalContext context;
   10711   v8::Isolate* isolate = context->GetIsolate();
   10712   v8::HandleScope handle_scope(isolate);
   10713   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   10714   templ->SetClassName(v8_str("Fun"));
   10715   Local<Function> cons = templ->GetFunction();
   10716   context->Global()->Set(v8_str("Fun"), cons);
   10717   Local<Value> value = CompileRun(
   10718     "function test() {"
   10719     "  try {"
   10720     "    (new Fun()).blah()"
   10721     "  } catch (e) {"
   10722     "    var str = String(e);"
   10723     // "    if (str.indexOf('TypeError') == -1) return 1;"
   10724     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
   10725     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
   10726     "    return 0;"
   10727     "  }"
   10728     "  return 4;"
   10729     "}"
   10730     "test();");
   10731   CHECK_EQ(0, value->Int32Value());
   10732 }
   10733 
   10734 
   10735 THREADED_TEST(EvalAliasedDynamic) {
   10736   LocalContext current;
   10737   v8::HandleScope scope(current->GetIsolate());
   10738 
   10739   // Tests where aliased eval can only be resolved dynamically.
   10740   Local<Script> script = v8_compile(
   10741       "function f(x) { "
   10742       "  var foo = 2;"
   10743       "  with (x) { return eval('foo'); }"
   10744       "}"
   10745       "foo = 0;"
   10746       "result1 = f(new Object());"
   10747       "result2 = f(this);"
   10748       "var x = new Object();"
   10749       "x.eval = function(x) { return 1; };"
   10750       "result3 = f(x);");
   10751   script->Run();
   10752   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
   10753   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
   10754   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
   10755 
   10756   v8::TryCatch try_catch;
   10757   script = v8_compile(
   10758       "function f(x) { "
   10759       "  var bar = 2;"
   10760       "  with (x) { return eval('bar'); }"
   10761       "}"
   10762       "result4 = f(this)");
   10763   script->Run();
   10764   CHECK(!try_catch.HasCaught());
   10765   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
   10766 
   10767   try_catch.Reset();
   10768 }
   10769 
   10770 
   10771 THREADED_TEST(CrossEval) {
   10772   v8::HandleScope scope(CcTest::isolate());
   10773   LocalContext other;
   10774   LocalContext current;
   10775 
   10776   Local<String> token = v8_str("<security token>");
   10777   other->SetSecurityToken(token);
   10778   current->SetSecurityToken(token);
   10779 
   10780   // Set up reference from current to other.
   10781   current->Global()->Set(v8_str("other"), other->Global());
   10782 
   10783   // Check that new variables are introduced in other context.
   10784   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
   10785   script->Run();
   10786   Local<Value> foo = other->Global()->Get(v8_str("foo"));
   10787   CHECK_EQ(1234, foo->Int32Value());
   10788   CHECK(!current->Global()->Has(v8_str("foo")));
   10789 
   10790   // Check that writing to non-existing properties introduces them in
   10791   // the other context.
   10792   script = v8_compile("other.eval('na = 1234')");
   10793   script->Run();
   10794   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
   10795   CHECK(!current->Global()->Has(v8_str("na")));
   10796 
   10797   // Check that global variables in current context are not visible in other
   10798   // context.
   10799   v8::TryCatch try_catch;
   10800   script = v8_compile("var bar = 42; other.eval('bar');");
   10801   Local<Value> result = script->Run();
   10802   CHECK(try_catch.HasCaught());
   10803   try_catch.Reset();
   10804 
   10805   // Check that local variables in current context are not visible in other
   10806   // context.
   10807   script = v8_compile(
   10808       "(function() { "
   10809       "  var baz = 87;"
   10810       "  return other.eval('baz');"
   10811       "})();");
   10812   result = script->Run();
   10813   CHECK(try_catch.HasCaught());
   10814   try_catch.Reset();
   10815 
   10816   // Check that global variables in the other environment are visible
   10817   // when evaluting code.
   10818   other->Global()->Set(v8_str("bis"), v8_num(1234));
   10819   script = v8_compile("other.eval('bis')");
   10820   CHECK_EQ(1234, script->Run()->Int32Value());
   10821   CHECK(!try_catch.HasCaught());
   10822 
   10823   // Check that the 'this' pointer points to the global object evaluating
   10824   // code.
   10825   other->Global()->Set(v8_str("t"), other->Global());
   10826   script = v8_compile("other.eval('this == t')");
   10827   result = script->Run();
   10828   CHECK(result->IsTrue());
   10829   CHECK(!try_catch.HasCaught());
   10830 
   10831   // Check that variables introduced in with-statement are not visible in
   10832   // other context.
   10833   script = v8_compile("with({x:2}){other.eval('x')}");
   10834   result = script->Run();
   10835   CHECK(try_catch.HasCaught());
   10836   try_catch.Reset();
   10837 
   10838   // Check that you cannot use 'eval.call' with another object than the
   10839   // current global object.
   10840   script = v8_compile("other.y = 1; eval.call(other, 'y')");
   10841   result = script->Run();
   10842   CHECK(try_catch.HasCaught());
   10843 }
   10844 
   10845 
   10846 // Test that calling eval in a context which has been detached from
   10847 // its global throws an exception.  This behavior is consistent with
   10848 // other JavaScript implementations.
   10849 THREADED_TEST(EvalInDetachedGlobal) {
   10850   v8::Isolate* isolate = CcTest::isolate();
   10851   v8::HandleScope scope(isolate);
   10852 
   10853   v8::Local<Context> context0 = Context::New(isolate);
   10854   v8::Local<Context> context1 = Context::New(isolate);
   10855 
   10856   // Set up function in context0 that uses eval from context0.
   10857   context0->Enter();
   10858   v8::Handle<v8::Value> fun =
   10859       CompileRun("var x = 42;"
   10860                  "(function() {"
   10861                  "  var e = eval;"
   10862                  "  return function(s) { return e(s); }"
   10863                  "})()");
   10864   context0->Exit();
   10865 
   10866   // Put the function into context1 and call it before and after
   10867   // detaching the global.  Before detaching, the call succeeds and
   10868   // after detaching and exception is thrown.
   10869   context1->Enter();
   10870   context1->Global()->Set(v8_str("fun"), fun);
   10871   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
   10872   CHECK_EQ(42, x_value->Int32Value());
   10873   context0->DetachGlobal();
   10874   v8::TryCatch catcher;
   10875   x_value = CompileRun("fun('x')");
   10876   CHECK(x_value.IsEmpty());
   10877   CHECK(catcher.HasCaught());
   10878   context1->Exit();
   10879 }
   10880 
   10881 
   10882 THREADED_TEST(CrossLazyLoad) {
   10883   v8::HandleScope scope(CcTest::isolate());
   10884   LocalContext other;
   10885   LocalContext current;
   10886 
   10887   Local<String> token = v8_str("<security token>");
   10888   other->SetSecurityToken(token);
   10889   current->SetSecurityToken(token);
   10890 
   10891   // Set up reference from current to other.
   10892   current->Global()->Set(v8_str("other"), other->Global());
   10893 
   10894   // Trigger lazy loading in other context.
   10895   Local<Script> script = v8_compile("other.eval('new Date(42)')");
   10896   Local<Value> value = script->Run();
   10897   CHECK_EQ(42.0, value->NumberValue());
   10898 }
   10899 
   10900 
   10901 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
   10902   ApiTestFuzzer::Fuzz();
   10903   if (args.IsConstructCall()) {
   10904     if (args[0]->IsInt32()) {
   10905       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
   10906       return;
   10907     }
   10908   }
   10909 
   10910   args.GetReturnValue().Set(args[0]);
   10911 }
   10912 
   10913 
   10914 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
   10915   args.GetReturnValue().Set(args.This());
   10916 }
   10917 
   10918 
   10919 // Test that a call handler can be set for objects which will allow
   10920 // non-function objects created through the API to be called as
   10921 // functions.
   10922 THREADED_TEST(CallAsFunction) {
   10923   LocalContext context;
   10924   v8::Isolate* isolate = context->GetIsolate();
   10925   v8::HandleScope scope(isolate);
   10926 
   10927   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   10928     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   10929     instance_template->SetCallAsFunctionHandler(call_as_function);
   10930     Local<v8::Object> instance = t->GetFunction()->NewInstance();
   10931     context->Global()->Set(v8_str("obj"), instance);
   10932     v8::TryCatch try_catch;
   10933     Local<Value> value;
   10934     CHECK(!try_catch.HasCaught());
   10935 
   10936     value = CompileRun("obj(42)");
   10937     CHECK(!try_catch.HasCaught());
   10938     CHECK_EQ(42, value->Int32Value());
   10939 
   10940     value = CompileRun("(function(o){return o(49)})(obj)");
   10941     CHECK(!try_catch.HasCaught());
   10942     CHECK_EQ(49, value->Int32Value());
   10943 
   10944     // test special case of call as function
   10945     value = CompileRun("[obj]['0'](45)");
   10946     CHECK(!try_catch.HasCaught());
   10947     CHECK_EQ(45, value->Int32Value());
   10948 
   10949     value = CompileRun("obj.call = Function.prototype.call;"
   10950                        "obj.call(null, 87)");
   10951     CHECK(!try_catch.HasCaught());
   10952     CHECK_EQ(87, value->Int32Value());
   10953 
   10954     // Regression tests for bug #1116356: Calling call through call/apply
   10955     // must work for non-function receivers.
   10956     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
   10957     value = CompileRun(apply_99);
   10958     CHECK(!try_catch.HasCaught());
   10959     CHECK_EQ(99, value->Int32Value());
   10960 
   10961     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
   10962     value = CompileRun(call_17);
   10963     CHECK(!try_catch.HasCaught());
   10964     CHECK_EQ(17, value->Int32Value());
   10965 
   10966     // Check that the call-as-function handler can be called through
   10967     // new.
   10968     value = CompileRun("new obj(43)");
   10969     CHECK(!try_catch.HasCaught());
   10970     CHECK_EQ(-43, value->Int32Value());
   10971 
   10972     // Check that the call-as-function handler can be called through
   10973     // the API.
   10974     v8::Handle<Value> args[] = { v8_num(28) };
   10975     value = instance->CallAsFunction(instance, 1, args);
   10976     CHECK(!try_catch.HasCaught());
   10977     CHECK_EQ(28, value->Int32Value());
   10978   }
   10979 
   10980   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   10981     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
   10982     USE(instance_template);
   10983     Local<v8::Object> instance = t->GetFunction()->NewInstance();
   10984     context->Global()->Set(v8_str("obj2"), instance);
   10985     v8::TryCatch try_catch;
   10986     Local<Value> value;
   10987     CHECK(!try_catch.HasCaught());
   10988 
   10989     // Call an object without call-as-function handler through the JS
   10990     value = CompileRun("obj2(28)");
   10991     CHECK(value.IsEmpty());
   10992     CHECK(try_catch.HasCaught());
   10993     String::Utf8Value exception_value1(try_catch.Exception());
   10994     // TODO(verwaest): Better message
   10995     CHECK_EQ("TypeError: object is not a function",
   10996              *exception_value1);
   10997     try_catch.Reset();
   10998 
   10999     // Call an object without call-as-function handler through the API
   11000     value = CompileRun("obj2(28)");
   11001     v8::Handle<Value> args[] = { v8_num(28) };
   11002     value = instance->CallAsFunction(instance, 1, args);
   11003     CHECK(value.IsEmpty());
   11004     CHECK(try_catch.HasCaught());
   11005     String::Utf8Value exception_value2(try_catch.Exception());
   11006     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
   11007     try_catch.Reset();
   11008   }
   11009 
   11010   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   11011     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   11012     instance_template->SetCallAsFunctionHandler(ThrowValue);
   11013     Local<v8::Object> instance = t->GetFunction()->NewInstance();
   11014     context->Global()->Set(v8_str("obj3"), instance);
   11015     v8::TryCatch try_catch;
   11016     Local<Value> value;
   11017     CHECK(!try_catch.HasCaught());
   11018 
   11019     // Catch the exception which is thrown by call-as-function handler
   11020     value = CompileRun("obj3(22)");
   11021     CHECK(try_catch.HasCaught());
   11022     String::Utf8Value exception_value1(try_catch.Exception());
   11023     CHECK_EQ("22", *exception_value1);
   11024     try_catch.Reset();
   11025 
   11026     v8::Handle<Value> args[] = { v8_num(23) };
   11027     value = instance->CallAsFunction(instance, 1, args);
   11028     CHECK(try_catch.HasCaught());
   11029     String::Utf8Value exception_value2(try_catch.Exception());
   11030     CHECK_EQ("23", *exception_value2);
   11031     try_catch.Reset();
   11032   }
   11033 
   11034   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
   11035     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   11036     instance_template->SetCallAsFunctionHandler(ReturnThis);
   11037     Local<v8::Object> instance = t->GetFunction()->NewInstance();
   11038 
   11039     Local<v8::Value> a1 =
   11040         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
   11041     CHECK(a1->StrictEquals(instance));
   11042     Local<v8::Value> a2 =
   11043         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
   11044     CHECK(a2->StrictEquals(instance));
   11045     Local<v8::Value> a3 =
   11046         instance->CallAsFunction(v8_num(42), 0, NULL);
   11047     CHECK(a3->StrictEquals(instance));
   11048     Local<v8::Value> a4 =
   11049         instance->CallAsFunction(v8_str("hello"), 0, NULL);
   11050     CHECK(a4->StrictEquals(instance));
   11051     Local<v8::Value> a5 =
   11052         instance->CallAsFunction(v8::True(isolate), 0, NULL);
   11053     CHECK(a5->StrictEquals(instance));
   11054   }
   11055 
   11056   { CompileRun(
   11057       "function ReturnThisSloppy() {"
   11058       "  return this;"
   11059       "}"
   11060       "function ReturnThisStrict() {"
   11061       "  'use strict';"
   11062       "  return this;"
   11063       "}");
   11064     Local<Function> ReturnThisSloppy =
   11065         Local<Function>::Cast(
   11066             context->Global()->Get(v8_str("ReturnThisSloppy")));
   11067     Local<Function> ReturnThisStrict =
   11068         Local<Function>::Cast(
   11069             context->Global()->Get(v8_str("ReturnThisStrict")));
   11070 
   11071     Local<v8::Value> a1 =
   11072         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
   11073     CHECK(a1->StrictEquals(context->Global()));
   11074     Local<v8::Value> a2 =
   11075         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
   11076     CHECK(a2->StrictEquals(context->Global()));
   11077     Local<v8::Value> a3 =
   11078         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
   11079     CHECK(a3->IsNumberObject());
   11080     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
   11081     Local<v8::Value> a4 =
   11082         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
   11083     CHECK(a4->IsStringObject());
   11084     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
   11085     Local<v8::Value> a5 =
   11086         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
   11087     CHECK(a5->IsBooleanObject());
   11088     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
   11089 
   11090     Local<v8::Value> a6 =
   11091         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
   11092     CHECK(a6->IsUndefined());
   11093     Local<v8::Value> a7 =
   11094         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
   11095     CHECK(a7->IsNull());
   11096     Local<v8::Value> a8 =
   11097         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
   11098     CHECK(a8->StrictEquals(v8_num(42)));
   11099     Local<v8::Value> a9 =
   11100         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
   11101     CHECK(a9->StrictEquals(v8_str("hello")));
   11102     Local<v8::Value> a10 =
   11103         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
   11104     CHECK(a10->StrictEquals(v8::True(isolate)));
   11105   }
   11106 }
   11107 
   11108 
   11109 // Check whether a non-function object is callable.
   11110 THREADED_TEST(CallableObject) {
   11111   LocalContext context;
   11112   v8::Isolate* isolate = context->GetIsolate();
   11113   v8::HandleScope scope(isolate);
   11114 
   11115   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
   11116     instance_template->SetCallAsFunctionHandler(call_as_function);
   11117     Local<Object> instance = instance_template->NewInstance();
   11118     v8::TryCatch try_catch;
   11119 
   11120     CHECK(instance->IsCallable());
   11121     CHECK(!try_catch.HasCaught());
   11122   }
   11123 
   11124   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
   11125     Local<Object> instance = instance_template->NewInstance();
   11126     v8::TryCatch try_catch;
   11127 
   11128     CHECK(!instance->IsCallable());
   11129     CHECK(!try_catch.HasCaught());
   11130   }
   11131 
   11132   { Local<FunctionTemplate> function_template =
   11133         FunctionTemplate::New(isolate, call_as_function);
   11134     Local<Function> function = function_template->GetFunction();
   11135     Local<Object> instance = function;
   11136     v8::TryCatch try_catch;
   11137 
   11138     CHECK(instance->IsCallable());
   11139     CHECK(!try_catch.HasCaught());
   11140   }
   11141 
   11142   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
   11143     Local<Function> function = function_template->GetFunction();
   11144     Local<Object> instance = function;
   11145     v8::TryCatch try_catch;
   11146 
   11147     CHECK(instance->IsCallable());
   11148     CHECK(!try_catch.HasCaught());
   11149   }
   11150 }
   11151 
   11152 
   11153 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
   11154   v8::HandleScope scope(isolate);
   11155   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
   11156   for (int i = 0; i < iterations; i++) {
   11157     Local<v8::Number> n(v8::Integer::New(isolate, 42));
   11158   }
   11159   return Recurse(isolate, depth - 1, iterations);
   11160 }
   11161 
   11162 
   11163 THREADED_TEST(HandleIteration) {
   11164   static const int kIterations = 500;
   11165   static const int kNesting = 200;
   11166   LocalContext context;
   11167   v8::Isolate* isolate = context->GetIsolate();
   11168   v8::HandleScope scope0(isolate);
   11169   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
   11170   {
   11171     v8::HandleScope scope1(isolate);
   11172     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
   11173     for (int i = 0; i < kIterations; i++) {
   11174       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
   11175       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
   11176     }
   11177 
   11178     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
   11179     {
   11180       v8::HandleScope scope2(CcTest::isolate());
   11181       for (int j = 0; j < kIterations; j++) {
   11182         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
   11183         CHECK_EQ(j + 1 + kIterations,
   11184                  v8::HandleScope::NumberOfHandles(isolate));
   11185       }
   11186     }
   11187     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
   11188   }
   11189   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
   11190   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
   11191 }
   11192 
   11193 
   11194 static void InterceptorHasOwnPropertyGetter(
   11195     Local<String> name,
   11196     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11197   ApiTestFuzzer::Fuzz();
   11198 }
   11199 
   11200 
   11201 THREADED_TEST(InterceptorHasOwnProperty) {
   11202   LocalContext context;
   11203   v8::Isolate* isolate = context->GetIsolate();
   11204   v8::HandleScope scope(isolate);
   11205   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   11206   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   11207   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
   11208   Local<Function> function = fun_templ->GetFunction();
   11209   context->Global()->Set(v8_str("constructor"), function);
   11210   v8::Handle<Value> value = CompileRun(
   11211       "var o = new constructor();"
   11212       "o.hasOwnProperty('ostehaps');");
   11213   CHECK_EQ(false, value->BooleanValue());
   11214   value = CompileRun(
   11215       "o.ostehaps = 42;"
   11216       "o.hasOwnProperty('ostehaps');");
   11217   CHECK_EQ(true, value->BooleanValue());
   11218   value = CompileRun(
   11219       "var p = new constructor();"
   11220       "p.hasOwnProperty('ostehaps');");
   11221   CHECK_EQ(false, value->BooleanValue());
   11222 }
   11223 
   11224 
   11225 static void InterceptorHasOwnPropertyGetterGC(
   11226     Local<String> name,
   11227     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11228   ApiTestFuzzer::Fuzz();
   11229   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   11230 }
   11231 
   11232 
   11233 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
   11234   LocalContext context;
   11235   v8::Isolate* isolate = context->GetIsolate();
   11236   v8::HandleScope scope(isolate);
   11237   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   11238   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
   11239   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
   11240   Local<Function> function = fun_templ->GetFunction();
   11241   context->Global()->Set(v8_str("constructor"), function);
   11242   // Let's first make some stuff so we can be sure to get a good GC.
   11243   CompileRun(
   11244       "function makestr(size) {"
   11245       "  switch (size) {"
   11246       "    case 1: return 'f';"
   11247       "    case 2: return 'fo';"
   11248       "    case 3: return 'foo';"
   11249       "  }"
   11250       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
   11251       "}"
   11252       "var x = makestr(12345);"
   11253       "x = makestr(31415);"
   11254       "x = makestr(23456);");
   11255   v8::Handle<Value> value = CompileRun(
   11256       "var o = new constructor();"
   11257       "o.__proto__ = new String(x);"
   11258       "o.hasOwnProperty('ostehaps');");
   11259   CHECK_EQ(false, value->BooleanValue());
   11260 }
   11261 
   11262 
   11263 typedef void (*NamedPropertyGetter)(
   11264     Local<String> property,
   11265     const v8::PropertyCallbackInfo<v8::Value>& info);
   11266 
   11267 
   11268 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
   11269                                    const char* source,
   11270                                    int expected) {
   11271   v8::Isolate* isolate = CcTest::isolate();
   11272   v8::HandleScope scope(isolate);
   11273   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11274   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
   11275   LocalContext context;
   11276   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11277   v8::Handle<Value> value = CompileRun(source);
   11278   CHECK_EQ(expected, value->Int32Value());
   11279 }
   11280 
   11281 
   11282 static void InterceptorLoadICGetter(
   11283     Local<String> name,
   11284     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11285   ApiTestFuzzer::Fuzz();
   11286   v8::Isolate* isolate = CcTest::isolate();
   11287   CHECK_EQ(isolate, info.GetIsolate());
   11288   CHECK_EQ(v8_str("data"), info.Data());
   11289   CHECK_EQ(v8_str("x"), name);
   11290   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
   11291 }
   11292 
   11293 
   11294 // This test should hit the load IC for the interceptor case.
   11295 THREADED_TEST(InterceptorLoadIC) {
   11296   CheckInterceptorLoadIC(InterceptorLoadICGetter,
   11297     "var result = 0;"
   11298     "for (var i = 0; i < 1000; i++) {"
   11299     "  result = o.x;"
   11300     "}",
   11301     42);
   11302 }
   11303 
   11304 
   11305 // Below go several tests which verify that JITing for various
   11306 // configurations of interceptor and explicit fields works fine
   11307 // (those cases are special cased to get better performance).
   11308 
   11309 static void InterceptorLoadXICGetter(
   11310     Local<String> name,
   11311     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11312   ApiTestFuzzer::Fuzz();
   11313   info.GetReturnValue().Set(
   11314       v8_str("x")->Equals(name) ?
   11315           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
   11316           v8::Handle<v8::Value>());
   11317 }
   11318 
   11319 
   11320 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
   11321   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11322     "var result = 0;"
   11323     "o.y = 239;"
   11324     "for (var i = 0; i < 1000; i++) {"
   11325     "  result = o.y;"
   11326     "}",
   11327     239);
   11328 }
   11329 
   11330 
   11331 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
   11332   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11333     "var result = 0;"
   11334     "o.__proto__ = { 'y': 239 };"
   11335     "for (var i = 0; i < 1000; i++) {"
   11336     "  result = o.y + o.x;"
   11337     "}",
   11338     239 + 42);
   11339 }
   11340 
   11341 
   11342 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
   11343   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11344     "var result = 0;"
   11345     "o.__proto__.y = 239;"
   11346     "for (var i = 0; i < 1000; i++) {"
   11347     "  result = o.y + o.x;"
   11348     "}",
   11349     239 + 42);
   11350 }
   11351 
   11352 
   11353 THREADED_TEST(InterceptorLoadICUndefined) {
   11354   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11355     "var result = 0;"
   11356     "for (var i = 0; i < 1000; i++) {"
   11357     "  result = (o.y == undefined) ? 239 : 42;"
   11358     "}",
   11359     239);
   11360 }
   11361 
   11362 
   11363 THREADED_TEST(InterceptorLoadICWithOverride) {
   11364   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11365     "fst = new Object();  fst.__proto__ = o;"
   11366     "snd = new Object();  snd.__proto__ = fst;"
   11367     "var result1 = 0;"
   11368     "for (var i = 0; i < 1000;  i++) {"
   11369     "  result1 = snd.x;"
   11370     "}"
   11371     "fst.x = 239;"
   11372     "var result = 0;"
   11373     "for (var i = 0; i < 1000; i++) {"
   11374     "  result = snd.x;"
   11375     "}"
   11376     "result + result1",
   11377     239 + 42);
   11378 }
   11379 
   11380 
   11381 // Test the case when we stored field into
   11382 // a stub, but interceptor produced value on its own.
   11383 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
   11384   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11385     "proto = new Object();"
   11386     "o.__proto__ = proto;"
   11387     "proto.x = 239;"
   11388     "for (var i = 0; i < 1000; i++) {"
   11389     "  o.x;"
   11390     // Now it should be ICed and keep a reference to x defined on proto
   11391     "}"
   11392     "var result = 0;"
   11393     "for (var i = 0; i < 1000; i++) {"
   11394     "  result += o.x;"
   11395     "}"
   11396     "result;",
   11397     42 * 1000);
   11398 }
   11399 
   11400 
   11401 // Test the case when we stored field into
   11402 // a stub, but it got invalidated later on.
   11403 THREADED_TEST(InterceptorLoadICInvalidatedField) {
   11404   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11405     "proto1 = new Object();"
   11406     "proto2 = new Object();"
   11407     "o.__proto__ = proto1;"
   11408     "proto1.__proto__ = proto2;"
   11409     "proto2.y = 239;"
   11410     "for (var i = 0; i < 1000; i++) {"
   11411     "  o.y;"
   11412     // Now it should be ICed and keep a reference to y defined on proto2
   11413     "}"
   11414     "proto1.y = 42;"
   11415     "var result = 0;"
   11416     "for (var i = 0; i < 1000; i++) {"
   11417     "  result += o.y;"
   11418     "}"
   11419     "result;",
   11420     42 * 1000);
   11421 }
   11422 
   11423 
   11424 static int interceptor_load_not_handled_calls = 0;
   11425 static void InterceptorLoadNotHandled(
   11426     Local<String> name,
   11427     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11428   ++interceptor_load_not_handled_calls;
   11429 }
   11430 
   11431 
   11432 // Test how post-interceptor lookups are done in the non-cacheable
   11433 // case: the interceptor should not be invoked during this lookup.
   11434 THREADED_TEST(InterceptorLoadICPostInterceptor) {
   11435   interceptor_load_not_handled_calls = 0;
   11436   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
   11437     "receiver = new Object();"
   11438     "receiver.__proto__ = o;"
   11439     "proto = new Object();"
   11440     "/* Make proto a slow-case object. */"
   11441     "for (var i = 0; i < 1000; i++) {"
   11442     "  proto[\"xxxxxxxx\" + i] = [];"
   11443     "}"
   11444     "proto.x = 17;"
   11445     "o.__proto__ = proto;"
   11446     "var result = 0;"
   11447     "for (var i = 0; i < 1000; i++) {"
   11448     "  result += receiver.x;"
   11449     "}"
   11450     "result;",
   11451     17 * 1000);
   11452   CHECK_EQ(1000, interceptor_load_not_handled_calls);
   11453 }
   11454 
   11455 
   11456 // Test the case when we stored field into
   11457 // a stub, but it got invalidated later on due to override on
   11458 // global object which is between interceptor and fields' holders.
   11459 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
   11460   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
   11461     "o.__proto__ = this;"  // set a global to be a proto of o.
   11462     "this.__proto__.y = 239;"
   11463     "for (var i = 0; i < 10; i++) {"
   11464     "  if (o.y != 239) throw 'oops: ' + o.y;"
   11465     // Now it should be ICed and keep a reference to y defined on field_holder.
   11466     "}"
   11467     "this.y = 42;"  // Assign on a global.
   11468     "var result = 0;"
   11469     "for (var i = 0; i < 10; i++) {"
   11470     "  result += o.y;"
   11471     "}"
   11472     "result;",
   11473     42 * 10);
   11474 }
   11475 
   11476 
   11477 static void SetOnThis(Local<String> name,
   11478                       Local<Value> value,
   11479                       const v8::PropertyCallbackInfo<void>& info) {
   11480   Local<Object>::Cast(info.This())->ForceSet(name, value);
   11481 }
   11482 
   11483 
   11484 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
   11485   v8::Isolate* isolate = CcTest::isolate();
   11486   v8::HandleScope scope(isolate);
   11487   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11488   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11489   templ->SetAccessor(v8_str("y"), Return239Callback);
   11490   LocalContext context;
   11491   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11492 
   11493   // Check the case when receiver and interceptor's holder
   11494   // are the same objects.
   11495   v8::Handle<Value> value = CompileRun(
   11496       "var result = 0;"
   11497       "for (var i = 0; i < 7; i++) {"
   11498       "  result = o.y;"
   11499       "}");
   11500   CHECK_EQ(239, value->Int32Value());
   11501 
   11502   // Check the case when interceptor's holder is in proto chain
   11503   // of receiver.
   11504   value = CompileRun(
   11505       "r = { __proto__: o };"
   11506       "var result = 0;"
   11507       "for (var i = 0; i < 7; i++) {"
   11508       "  result = r.y;"
   11509       "}");
   11510   CHECK_EQ(239, value->Int32Value());
   11511 }
   11512 
   11513 
   11514 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
   11515   v8::Isolate* isolate = CcTest::isolate();
   11516   v8::HandleScope scope(isolate);
   11517   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   11518   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11519   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   11520   templ_p->SetAccessor(v8_str("y"), Return239Callback);
   11521 
   11522   LocalContext context;
   11523   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   11524   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   11525 
   11526   // Check the case when receiver and interceptor's holder
   11527   // are the same objects.
   11528   v8::Handle<Value> value = CompileRun(
   11529       "o.__proto__ = p;"
   11530       "var result = 0;"
   11531       "for (var i = 0; i < 7; i++) {"
   11532       "  result = o.x + o.y;"
   11533       "}");
   11534   CHECK_EQ(239 + 42, value->Int32Value());
   11535 
   11536   // Check the case when interceptor's holder is in proto chain
   11537   // of receiver.
   11538   value = CompileRun(
   11539       "r = { __proto__: o };"
   11540       "var result = 0;"
   11541       "for (var i = 0; i < 7; i++) {"
   11542       "  result = r.x + r.y;"
   11543       "}");
   11544   CHECK_EQ(239 + 42, value->Int32Value());
   11545 }
   11546 
   11547 
   11548 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
   11549   v8::Isolate* isolate = CcTest::isolate();
   11550   v8::HandleScope scope(isolate);
   11551   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11552   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11553   templ->SetAccessor(v8_str("y"), Return239Callback);
   11554 
   11555   LocalContext context;
   11556   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11557 
   11558   v8::Handle<Value> value = CompileRun(
   11559     "fst = new Object();  fst.__proto__ = o;"
   11560     "snd = new Object();  snd.__proto__ = fst;"
   11561     "var result1 = 0;"
   11562     "for (var i = 0; i < 7;  i++) {"
   11563     "  result1 = snd.x;"
   11564     "}"
   11565     "fst.x = 239;"
   11566     "var result = 0;"
   11567     "for (var i = 0; i < 7; i++) {"
   11568     "  result = snd.x;"
   11569     "}"
   11570     "result + result1");
   11571   CHECK_EQ(239 + 42, value->Int32Value());
   11572 }
   11573 
   11574 
   11575 // Test the case when we stored callback into
   11576 // a stub, but interceptor produced value on its own.
   11577 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
   11578   v8::Isolate* isolate = CcTest::isolate();
   11579   v8::HandleScope scope(isolate);
   11580   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   11581   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11582   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   11583   templ_p->SetAccessor(v8_str("y"), Return239Callback);
   11584 
   11585   LocalContext context;
   11586   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   11587   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   11588 
   11589   v8::Handle<Value> value = CompileRun(
   11590     "o.__proto__ = p;"
   11591     "for (var i = 0; i < 7; i++) {"
   11592     "  o.x;"
   11593     // Now it should be ICed and keep a reference to x defined on p
   11594     "}"
   11595     "var result = 0;"
   11596     "for (var i = 0; i < 7; i++) {"
   11597     "  result += o.x;"
   11598     "}"
   11599     "result");
   11600   CHECK_EQ(42 * 7, value->Int32Value());
   11601 }
   11602 
   11603 
   11604 // Test the case when we stored callback into
   11605 // a stub, but it got invalidated later on.
   11606 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
   11607   v8::Isolate* isolate = CcTest::isolate();
   11608   v8::HandleScope scope(isolate);
   11609   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   11610   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11611   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   11612   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
   11613 
   11614   LocalContext context;
   11615   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   11616   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   11617 
   11618   v8::Handle<Value> value = CompileRun(
   11619     "inbetween = new Object();"
   11620     "o.__proto__ = inbetween;"
   11621     "inbetween.__proto__ = p;"
   11622     "for (var i = 0; i < 10; i++) {"
   11623     "  o.y;"
   11624     // Now it should be ICed and keep a reference to y defined on p
   11625     "}"
   11626     "inbetween.y = 42;"
   11627     "var result = 0;"
   11628     "for (var i = 0; i < 10; i++) {"
   11629     "  result += o.y;"
   11630     "}"
   11631     "result");
   11632   CHECK_EQ(42 * 10, value->Int32Value());
   11633 }
   11634 
   11635 
   11636 // Test the case when we stored callback into
   11637 // a stub, but it got invalidated later on due to override on
   11638 // global object which is between interceptor and callbacks' holders.
   11639 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
   11640   v8::Isolate* isolate = CcTest::isolate();
   11641   v8::HandleScope scope(isolate);
   11642   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   11643   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11644   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   11645   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
   11646 
   11647   LocalContext context;
   11648   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   11649   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
   11650 
   11651   v8::Handle<Value> value = CompileRun(
   11652     "o.__proto__ = this;"
   11653     "this.__proto__ = p;"
   11654     "for (var i = 0; i < 10; i++) {"
   11655     "  if (o.y != 239) throw 'oops: ' + o.y;"
   11656     // Now it should be ICed and keep a reference to y defined on p
   11657     "}"
   11658     "this.y = 42;"
   11659     "var result = 0;"
   11660     "for (var i = 0; i < 10; i++) {"
   11661     "  result += o.y;"
   11662     "}"
   11663     "result");
   11664   CHECK_EQ(42 * 10, value->Int32Value());
   11665 }
   11666 
   11667 
   11668 static void InterceptorLoadICGetter0(
   11669     Local<String> name,
   11670     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11671   ApiTestFuzzer::Fuzz();
   11672   CHECK(v8_str("x")->Equals(name));
   11673   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
   11674 }
   11675 
   11676 
   11677 THREADED_TEST(InterceptorReturningZero) {
   11678   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
   11679      "o.x == undefined ? 1 : 0",
   11680      0);
   11681 }
   11682 
   11683 
   11684 static void InterceptorStoreICSetter(
   11685     Local<String> key,
   11686     Local<Value> value,
   11687     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11688   CHECK(v8_str("x")->Equals(key));
   11689   CHECK_EQ(42, value->Int32Value());
   11690   info.GetReturnValue().Set(value);
   11691 }
   11692 
   11693 
   11694 // This test should hit the store IC for the interceptor case.
   11695 THREADED_TEST(InterceptorStoreIC) {
   11696   v8::Isolate* isolate = CcTest::isolate();
   11697   v8::HandleScope scope(isolate);
   11698   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11699   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
   11700                                  InterceptorStoreICSetter,
   11701                                  0, 0, 0, v8_str("data"));
   11702   LocalContext context;
   11703   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11704   CompileRun(
   11705       "for (var i = 0; i < 1000; i++) {"
   11706       "  o.x = 42;"
   11707       "}");
   11708 }
   11709 
   11710 
   11711 THREADED_TEST(InterceptorStoreICWithNoSetter) {
   11712   v8::Isolate* isolate = CcTest::isolate();
   11713   v8::HandleScope scope(isolate);
   11714   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11715   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   11716   LocalContext context;
   11717   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11718   v8::Handle<Value> value = CompileRun(
   11719     "for (var i = 0; i < 1000; i++) {"
   11720     "  o.y = 239;"
   11721     "}"
   11722     "42 + o.y");
   11723   CHECK_EQ(239 + 42, value->Int32Value());
   11724 }
   11725 
   11726 
   11727 
   11728 
   11729 v8::Handle<Value> call_ic_function;
   11730 v8::Handle<Value> call_ic_function2;
   11731 v8::Handle<Value> call_ic_function3;
   11732 
   11733 static void InterceptorCallICGetter(
   11734     Local<String> name,
   11735     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11736   ApiTestFuzzer::Fuzz();
   11737   CHECK(v8_str("x")->Equals(name));
   11738   info.GetReturnValue().Set(call_ic_function);
   11739 }
   11740 
   11741 
   11742 // This test should hit the call IC for the interceptor case.
   11743 THREADED_TEST(InterceptorCallIC) {
   11744   v8::Isolate* isolate = CcTest::isolate();
   11745   v8::HandleScope scope(isolate);
   11746   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11747   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
   11748   LocalContext context;
   11749   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11750   call_ic_function =
   11751       v8_compile("function f(x) { return x + 1; }; f")->Run();
   11752   v8::Handle<Value> value = CompileRun(
   11753     "var result = 0;"
   11754     "for (var i = 0; i < 1000; i++) {"
   11755     "  result = o.x(41);"
   11756     "}");
   11757   CHECK_EQ(42, value->Int32Value());
   11758 }
   11759 
   11760 
   11761 // This test checks that if interceptor doesn't provide
   11762 // a value, we can fetch regular value.
   11763 THREADED_TEST(InterceptorCallICSeesOthers) {
   11764   v8::Isolate* isolate = CcTest::isolate();
   11765   v8::HandleScope scope(isolate);
   11766   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11767   templ->SetNamedPropertyHandler(NoBlockGetterX);
   11768   LocalContext context;
   11769   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11770   v8::Handle<Value> value = CompileRun(
   11771     "o.x = function f(x) { return x + 1; };"
   11772     "var result = 0;"
   11773     "for (var i = 0; i < 7; i++) {"
   11774     "  result = o.x(41);"
   11775     "}");
   11776   CHECK_EQ(42, value->Int32Value());
   11777 }
   11778 
   11779 
   11780 static v8::Handle<Value> call_ic_function4;
   11781 static void InterceptorCallICGetter4(
   11782     Local<String> name,
   11783     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11784   ApiTestFuzzer::Fuzz();
   11785   CHECK(v8_str("x")->Equals(name));
   11786   info.GetReturnValue().Set(call_ic_function4);
   11787 }
   11788 
   11789 
   11790 // This test checks that if interceptor provides a function,
   11791 // even if we cached shadowed variant, interceptor's function
   11792 // is invoked
   11793 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
   11794   v8::Isolate* isolate = CcTest::isolate();
   11795   v8::HandleScope scope(isolate);
   11796   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11797   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
   11798   LocalContext context;
   11799   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11800   call_ic_function4 =
   11801       v8_compile("function f(x) { return x - 1; }; f")->Run();
   11802   v8::Handle<Value> value = CompileRun(
   11803     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
   11804     "var result = 0;"
   11805     "for (var i = 0; i < 1000; i++) {"
   11806     "  result = o.x(42);"
   11807     "}");
   11808   CHECK_EQ(41, value->Int32Value());
   11809 }
   11810 
   11811 
   11812 // Test the case when we stored cacheable lookup into
   11813 // a stub, but it got invalidated later on
   11814 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
   11815   v8::Isolate* isolate = CcTest::isolate();
   11816   v8::HandleScope scope(isolate);
   11817   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11818   templ->SetNamedPropertyHandler(NoBlockGetterX);
   11819   LocalContext context;
   11820   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11821   v8::Handle<Value> value = CompileRun(
   11822     "proto1 = new Object();"
   11823     "proto2 = new Object();"
   11824     "o.__proto__ = proto1;"
   11825     "proto1.__proto__ = proto2;"
   11826     "proto2.y = function(x) { return x + 1; };"
   11827     // Invoke it many times to compile a stub
   11828     "for (var i = 0; i < 7; i++) {"
   11829     "  o.y(42);"
   11830     "}"
   11831     "proto1.y = function(x) { return x - 1; };"
   11832     "var result = 0;"
   11833     "for (var i = 0; i < 7; i++) {"
   11834     "  result += o.y(42);"
   11835     "}");
   11836   CHECK_EQ(41 * 7, value->Int32Value());
   11837 }
   11838 
   11839 
   11840 // This test checks that if interceptor doesn't provide a function,
   11841 // cached constant function is used
   11842 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
   11843   v8::Isolate* isolate = CcTest::isolate();
   11844   v8::HandleScope scope(isolate);
   11845   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11846   templ->SetNamedPropertyHandler(NoBlockGetterX);
   11847   LocalContext context;
   11848   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11849   v8::Handle<Value> value = CompileRun(
   11850     "function inc(x) { return x + 1; };"
   11851     "inc(1);"
   11852     "o.x = inc;"
   11853     "var result = 0;"
   11854     "for (var i = 0; i < 1000; i++) {"
   11855     "  result = o.x(42);"
   11856     "}");
   11857   CHECK_EQ(43, value->Int32Value());
   11858 }
   11859 
   11860 
   11861 static v8::Handle<Value> call_ic_function5;
   11862 static void InterceptorCallICGetter5(
   11863     Local<String> name,
   11864     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11865   ApiTestFuzzer::Fuzz();
   11866   if (v8_str("x")->Equals(name))
   11867     info.GetReturnValue().Set(call_ic_function5);
   11868 }
   11869 
   11870 
   11871 // This test checks that if interceptor provides a function,
   11872 // even if we cached constant function, interceptor's function
   11873 // is invoked
   11874 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
   11875   v8::Isolate* isolate = CcTest::isolate();
   11876   v8::HandleScope scope(isolate);
   11877   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11878   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
   11879   LocalContext context;
   11880   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11881   call_ic_function5 =
   11882       v8_compile("function f(x) { return x - 1; }; f")->Run();
   11883   v8::Handle<Value> value = CompileRun(
   11884     "function inc(x) { return x + 1; };"
   11885     "inc(1);"
   11886     "o.x = inc;"
   11887     "var result = 0;"
   11888     "for (var i = 0; i < 1000; i++) {"
   11889     "  result = o.x(42);"
   11890     "}");
   11891   CHECK_EQ(41, value->Int32Value());
   11892 }
   11893 
   11894 
   11895 static v8::Handle<Value> call_ic_function6;
   11896 static void InterceptorCallICGetter6(
   11897     Local<String> name,
   11898     const v8::PropertyCallbackInfo<v8::Value>& info) {
   11899   ApiTestFuzzer::Fuzz();
   11900   if (v8_str("x")->Equals(name))
   11901     info.GetReturnValue().Set(call_ic_function6);
   11902 }
   11903 
   11904 
   11905 // Same test as above, except the code is wrapped in a function
   11906 // to test the optimized compiler.
   11907 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
   11908   i::FLAG_allow_natives_syntax = true;
   11909   v8::Isolate* isolate = CcTest::isolate();
   11910   v8::HandleScope scope(isolate);
   11911   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11912   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
   11913   LocalContext context;
   11914   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11915   call_ic_function6 =
   11916       v8_compile("function f(x) { return x - 1; }; f")->Run();
   11917   v8::Handle<Value> value = CompileRun(
   11918     "function inc(x) { return x + 1; };"
   11919     "inc(1);"
   11920     "o.x = inc;"
   11921     "function test() {"
   11922     "  var result = 0;"
   11923     "  for (var i = 0; i < 1000; i++) {"
   11924     "    result = o.x(42);"
   11925     "  }"
   11926     "  return result;"
   11927     "};"
   11928     "test();"
   11929     "test();"
   11930     "test();"
   11931     "%OptimizeFunctionOnNextCall(test);"
   11932     "test()");
   11933   CHECK_EQ(41, value->Int32Value());
   11934 }
   11935 
   11936 
   11937 // Test the case when we stored constant function into
   11938 // a stub, but it got invalidated later on
   11939 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
   11940   v8::Isolate* isolate = CcTest::isolate();
   11941   v8::HandleScope scope(isolate);
   11942   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11943   templ->SetNamedPropertyHandler(NoBlockGetterX);
   11944   LocalContext context;
   11945   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11946   v8::Handle<Value> value = CompileRun(
   11947     "function inc(x) { return x + 1; };"
   11948     "inc(1);"
   11949     "proto1 = new Object();"
   11950     "proto2 = new Object();"
   11951     "o.__proto__ = proto1;"
   11952     "proto1.__proto__ = proto2;"
   11953     "proto2.y = inc;"
   11954     // Invoke it many times to compile a stub
   11955     "for (var i = 0; i < 7; i++) {"
   11956     "  o.y(42);"
   11957     "}"
   11958     "proto1.y = function(x) { return x - 1; };"
   11959     "var result = 0;"
   11960     "for (var i = 0; i < 7; i++) {"
   11961     "  result += o.y(42);"
   11962     "}");
   11963   CHECK_EQ(41 * 7, value->Int32Value());
   11964 }
   11965 
   11966 
   11967 // Test the case when we stored constant function into
   11968 // a stub, but it got invalidated later on due to override on
   11969 // global object which is between interceptor and constant function' holders.
   11970 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
   11971   v8::Isolate* isolate = CcTest::isolate();
   11972   v8::HandleScope scope(isolate);
   11973   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   11974   templ->SetNamedPropertyHandler(NoBlockGetterX);
   11975   LocalContext context;
   11976   context->Global()->Set(v8_str("o"), templ->NewInstance());
   11977   v8::Handle<Value> value = CompileRun(
   11978     "function inc(x) { return x + 1; };"
   11979     "inc(1);"
   11980     "o.__proto__ = this;"
   11981     "this.__proto__.y = inc;"
   11982     // Invoke it many times to compile a stub
   11983     "for (var i = 0; i < 7; i++) {"
   11984     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
   11985     "}"
   11986     "this.y = function(x) { return x - 1; };"
   11987     "var result = 0;"
   11988     "for (var i = 0; i < 7; i++) {"
   11989     "  result += o.y(42);"
   11990     "}");
   11991   CHECK_EQ(41 * 7, value->Int32Value());
   11992 }
   11993 
   11994 
   11995 // Test the case when actual function to call sits on global object.
   11996 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
   11997   v8::Isolate* isolate = CcTest::isolate();
   11998   v8::HandleScope scope(isolate);
   11999   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   12000   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
   12001 
   12002   LocalContext context;
   12003   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   12004 
   12005   v8::Handle<Value> value = CompileRun(
   12006     "try {"
   12007     "  o.__proto__ = this;"
   12008     "  for (var i = 0; i < 10; i++) {"
   12009     "    var v = o.parseFloat('239');"
   12010     "    if (v != 239) throw v;"
   12011       // Now it should be ICed and keep a reference to parseFloat.
   12012     "  }"
   12013     "  var result = 0;"
   12014     "  for (var i = 0; i < 10; i++) {"
   12015     "    result += o.parseFloat('239');"
   12016     "  }"
   12017     "  result"
   12018     "} catch(e) {"
   12019     "  e"
   12020     "};");
   12021   CHECK_EQ(239 * 10, value->Int32Value());
   12022 }
   12023 
   12024 static void InterceptorCallICFastApi(
   12025     Local<String> name,
   12026     const v8::PropertyCallbackInfo<v8::Value>& info) {
   12027   ApiTestFuzzer::Fuzz();
   12028   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
   12029   int* call_count =
   12030       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
   12031   ++(*call_count);
   12032   if ((*call_count) % 20 == 0) {
   12033     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   12034   }
   12035 }
   12036 
   12037 static void FastApiCallback_TrivialSignature(
   12038     const v8::FunctionCallbackInfo<v8::Value>& args) {
   12039   ApiTestFuzzer::Fuzz();
   12040   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
   12041   v8::Isolate* isolate = CcTest::isolate();
   12042   CHECK_EQ(isolate, args.GetIsolate());
   12043   CHECK_EQ(args.This(), args.Holder());
   12044   CHECK(args.Data()->Equals(v8_str("method_data")));
   12045   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
   12046 }
   12047 
   12048 static void FastApiCallback_SimpleSignature(
   12049     const v8::FunctionCallbackInfo<v8::Value>& args) {
   12050   ApiTestFuzzer::Fuzz();
   12051   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
   12052   v8::Isolate* isolate = CcTest::isolate();
   12053   CHECK_EQ(isolate, args.GetIsolate());
   12054   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
   12055   CHECK(args.Data()->Equals(v8_str("method_data")));
   12056   // Note, we're using HasRealNamedProperty instead of Has to avoid
   12057   // invoking the interceptor again.
   12058   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
   12059   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
   12060 }
   12061 
   12062 
   12063 // Helper to maximize the odds of object moving.
   12064 static void GenerateSomeGarbage() {
   12065   CompileRun(
   12066       "var garbage;"
   12067       "for (var i = 0; i < 1000; i++) {"
   12068       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
   12069       "}"
   12070       "garbage = undefined;");
   12071 }
   12072 
   12073 
   12074 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   12075   static int count = 0;
   12076   if (count++ % 3 == 0) {
   12077     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   12078         // This should move the stub
   12079     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
   12080   }
   12081 }
   12082 
   12083 
   12084 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
   12085   LocalContext context;
   12086   v8::Isolate* isolate = context->GetIsolate();
   12087   v8::HandleScope scope(isolate);
   12088   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
   12089       v8::ObjectTemplate::New(isolate);
   12090   nativeobject_templ->Set(isolate, "callback",
   12091                           v8::FunctionTemplate::New(isolate,
   12092                                                     DirectApiCallback));
   12093   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
   12094   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
   12095   // call the api function multiple times to ensure direct call stub creation.
   12096   CompileRun(
   12097         "function f() {"
   12098         "  for (var i = 1; i <= 30; i++) {"
   12099         "    nativeobject.callback();"
   12100         "  }"
   12101         "}"
   12102         "f();");
   12103 }
   12104 
   12105 
   12106 void ThrowingDirectApiCallback(
   12107     const v8::FunctionCallbackInfo<v8::Value>& args) {
   12108   args.GetIsolate()->ThrowException(v8_str("g"));
   12109 }
   12110 
   12111 
   12112 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
   12113   LocalContext context;
   12114   v8::Isolate* isolate = context->GetIsolate();
   12115   v8::HandleScope scope(isolate);
   12116   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
   12117       v8::ObjectTemplate::New(isolate);
   12118   nativeobject_templ->Set(isolate, "callback",
   12119                           v8::FunctionTemplate::New(isolate,
   12120                                                     ThrowingDirectApiCallback));
   12121   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
   12122   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
   12123   // call the api function multiple times to ensure direct call stub creation.
   12124   v8::Handle<Value> result = CompileRun(
   12125       "var result = '';"
   12126       "function f() {"
   12127       "  for (var i = 1; i <= 5; i++) {"
   12128       "    try { nativeobject.callback(); } catch (e) { result += e; }"
   12129       "  }"
   12130       "}"
   12131       "f(); result;");
   12132   CHECK_EQ(v8_str("ggggg"), result);
   12133 }
   12134 
   12135 
   12136 static Handle<Value> DoDirectGetter() {
   12137   if (++p_getter_count % 3 == 0) {
   12138     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   12139     GenerateSomeGarbage();
   12140   }
   12141   return v8_str("Direct Getter Result");
   12142 }
   12143 
   12144 static void DirectGetterCallback(
   12145     Local<String> name,
   12146     const v8::PropertyCallbackInfo<v8::Value>& info) {
   12147   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
   12148   info.GetReturnValue().Set(DoDirectGetter());
   12149 }
   12150 
   12151 
   12152 template<typename Accessor>
   12153 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
   12154   LocalContext context;
   12155   v8::Isolate* isolate = context->GetIsolate();
   12156   v8::HandleScope scope(isolate);
   12157   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
   12158   obj->SetAccessor(v8_str("p1"), accessor);
   12159   context->Global()->Set(v8_str("o1"), obj->NewInstance());
   12160   p_getter_count = 0;
   12161   v8::Handle<v8::Value> result = CompileRun(
   12162       "function f() {"
   12163       "  for (var i = 0; i < 30; i++) o1.p1;"
   12164       "  return o1.p1"
   12165       "}"
   12166       "f();");
   12167   CHECK_EQ(v8_str("Direct Getter Result"), result);
   12168   CHECK_EQ(31, p_getter_count);
   12169 }
   12170 
   12171 
   12172 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
   12173   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
   12174 }
   12175 
   12176 
   12177 void ThrowingDirectGetterCallback(
   12178     Local<String> name,
   12179     const v8::PropertyCallbackInfo<v8::Value>& info) {
   12180   info.GetIsolate()->ThrowException(v8_str("g"));
   12181 }
   12182 
   12183 
   12184 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
   12185   LocalContext context;
   12186   v8::Isolate* isolate = context->GetIsolate();
   12187   v8::HandleScope scope(isolate);
   12188   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
   12189   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
   12190   context->Global()->Set(v8_str("o1"), obj->NewInstance());
   12191   v8::Handle<Value> result = CompileRun(
   12192       "var result = '';"
   12193       "for (var i = 0; i < 5; i++) {"
   12194       "    try { o1.p1; } catch (e) { result += e; }"
   12195       "}"
   12196       "result;");
   12197   CHECK_EQ(v8_str("ggggg"), result);
   12198 }
   12199 
   12200 
   12201 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
   12202   int interceptor_call_count = 0;
   12203   v8::Isolate* isolate = CcTest::isolate();
   12204   v8::HandleScope scope(isolate);
   12205   v8::Handle<v8::FunctionTemplate> fun_templ =
   12206       v8::FunctionTemplate::New(isolate);
   12207   v8::Handle<v8::FunctionTemplate> method_templ =
   12208       v8::FunctionTemplate::New(isolate,
   12209                                 FastApiCallback_TrivialSignature,
   12210                                 v8_str("method_data"),
   12211                                 v8::Handle<v8::Signature>());
   12212   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12213   proto_templ->Set(v8_str("method"), method_templ);
   12214   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   12215   templ->SetNamedPropertyHandler(
   12216       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
   12217       v8::External::New(isolate, &interceptor_call_count));
   12218   LocalContext context;
   12219   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12220   GenerateSomeGarbage();
   12221   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12222   CompileRun(
   12223       "var result = 0;"
   12224       "for (var i = 0; i < 100; i++) {"
   12225       "  result = o.method(41);"
   12226       "}");
   12227   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   12228   CHECK_EQ(100, interceptor_call_count);
   12229 }
   12230 
   12231 
   12232 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
   12233   int interceptor_call_count = 0;
   12234   v8::Isolate* isolate = CcTest::isolate();
   12235   v8::HandleScope scope(isolate);
   12236   v8::Handle<v8::FunctionTemplate> fun_templ =
   12237       v8::FunctionTemplate::New(isolate);
   12238   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12239       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12240       v8::Signature::New(isolate, fun_templ));
   12241   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12242   proto_templ->Set(v8_str("method"), method_templ);
   12243   fun_templ->SetHiddenPrototype(true);
   12244   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   12245   templ->SetNamedPropertyHandler(
   12246       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
   12247       v8::External::New(isolate, &interceptor_call_count));
   12248   LocalContext context;
   12249   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12250   GenerateSomeGarbage();
   12251   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12252   CompileRun(
   12253       "o.foo = 17;"
   12254       "var receiver = {};"
   12255       "receiver.__proto__ = o;"
   12256       "var result = 0;"
   12257       "for (var i = 0; i < 100; i++) {"
   12258       "  result = receiver.method(41);"
   12259       "}");
   12260   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   12261   CHECK_EQ(100, interceptor_call_count);
   12262 }
   12263 
   12264 
   12265 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
   12266   int interceptor_call_count = 0;
   12267   v8::Isolate* isolate = CcTest::isolate();
   12268   v8::HandleScope scope(isolate);
   12269   v8::Handle<v8::FunctionTemplate> fun_templ =
   12270       v8::FunctionTemplate::New(isolate);
   12271   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12272       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12273       v8::Signature::New(isolate, fun_templ));
   12274   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12275   proto_templ->Set(v8_str("method"), method_templ);
   12276   fun_templ->SetHiddenPrototype(true);
   12277   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   12278   templ->SetNamedPropertyHandler(
   12279       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
   12280       v8::External::New(isolate, &interceptor_call_count));
   12281   LocalContext context;
   12282   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12283   GenerateSomeGarbage();
   12284   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12285   CompileRun(
   12286       "o.foo = 17;"
   12287       "var receiver = {};"
   12288       "receiver.__proto__ = o;"
   12289       "var result = 0;"
   12290       "var saved_result = 0;"
   12291       "for (var i = 0; i < 100; i++) {"
   12292       "  result = receiver.method(41);"
   12293       "  if (i == 50) {"
   12294       "    saved_result = result;"
   12295       "    receiver = {method: function(x) { return x - 1 }};"
   12296       "  }"
   12297       "}");
   12298   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
   12299   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12300   CHECK_GE(interceptor_call_count, 50);
   12301 }
   12302 
   12303 
   12304 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
   12305   int interceptor_call_count = 0;
   12306   v8::Isolate* isolate = CcTest::isolate();
   12307   v8::HandleScope scope(isolate);
   12308   v8::Handle<v8::FunctionTemplate> fun_templ =
   12309       v8::FunctionTemplate::New(isolate);
   12310   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12311       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12312       v8::Signature::New(isolate, fun_templ));
   12313   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12314   proto_templ->Set(v8_str("method"), method_templ);
   12315   fun_templ->SetHiddenPrototype(true);
   12316   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   12317   templ->SetNamedPropertyHandler(
   12318       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
   12319       v8::External::New(isolate, &interceptor_call_count));
   12320   LocalContext context;
   12321   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12322   GenerateSomeGarbage();
   12323   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12324   CompileRun(
   12325       "o.foo = 17;"
   12326       "var receiver = {};"
   12327       "receiver.__proto__ = o;"
   12328       "var result = 0;"
   12329       "var saved_result = 0;"
   12330       "for (var i = 0; i < 100; i++) {"
   12331       "  result = receiver.method(41);"
   12332       "  if (i == 50) {"
   12333       "    saved_result = result;"
   12334       "    o.method = function(x) { return x - 1 };"
   12335       "  }"
   12336       "}");
   12337   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
   12338   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12339   CHECK_GE(interceptor_call_count, 50);
   12340 }
   12341 
   12342 
   12343 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
   12344   int interceptor_call_count = 0;
   12345   v8::Isolate* isolate = CcTest::isolate();
   12346   v8::HandleScope scope(isolate);
   12347   v8::Handle<v8::FunctionTemplate> fun_templ =
   12348       v8::FunctionTemplate::New(isolate);
   12349   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12350       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12351       v8::Signature::New(isolate, fun_templ));
   12352   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12353   proto_templ->Set(v8_str("method"), method_templ);
   12354   fun_templ->SetHiddenPrototype(true);
   12355   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   12356   templ->SetNamedPropertyHandler(
   12357       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
   12358       v8::External::New(isolate, &interceptor_call_count));
   12359   LocalContext context;
   12360   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12361   GenerateSomeGarbage();
   12362   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12363   v8::TryCatch try_catch;
   12364   CompileRun(
   12365       "o.foo = 17;"
   12366       "var receiver = {};"
   12367       "receiver.__proto__ = o;"
   12368       "var result = 0;"
   12369       "var saved_result = 0;"
   12370       "for (var i = 0; i < 100; i++) {"
   12371       "  result = receiver.method(41);"
   12372       "  if (i == 50) {"
   12373       "    saved_result = result;"
   12374       "    receiver = 333;"
   12375       "  }"
   12376       "}");
   12377   CHECK(try_catch.HasCaught());
   12378   // TODO(verwaest): Adjust message.
   12379   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
   12380            try_catch.Exception()->ToString());
   12381   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12382   CHECK_GE(interceptor_call_count, 50);
   12383 }
   12384 
   12385 
   12386 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
   12387   int interceptor_call_count = 0;
   12388   v8::Isolate* isolate = CcTest::isolate();
   12389   v8::HandleScope scope(isolate);
   12390   v8::Handle<v8::FunctionTemplate> fun_templ =
   12391       v8::FunctionTemplate::New(isolate);
   12392   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12393       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12394       v8::Signature::New(isolate, fun_templ));
   12395   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12396   proto_templ->Set(v8_str("method"), method_templ);
   12397   fun_templ->SetHiddenPrototype(true);
   12398   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   12399   templ->SetNamedPropertyHandler(
   12400       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
   12401       v8::External::New(isolate, &interceptor_call_count));
   12402   LocalContext context;
   12403   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12404   GenerateSomeGarbage();
   12405   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12406   v8::TryCatch try_catch;
   12407   CompileRun(
   12408       "o.foo = 17;"
   12409       "var receiver = {};"
   12410       "receiver.__proto__ = o;"
   12411       "var result = 0;"
   12412       "var saved_result = 0;"
   12413       "for (var i = 0; i < 100; i++) {"
   12414       "  result = receiver.method(41);"
   12415       "  if (i == 50) {"
   12416       "    saved_result = result;"
   12417       "    receiver = {method: receiver.method};"
   12418       "  }"
   12419       "}");
   12420   CHECK(try_catch.HasCaught());
   12421   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
   12422            try_catch.Exception()->ToString());
   12423   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12424   CHECK_GE(interceptor_call_count, 50);
   12425 }
   12426 
   12427 
   12428 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
   12429   v8::Isolate* isolate = CcTest::isolate();
   12430   v8::HandleScope scope(isolate);
   12431   v8::Handle<v8::FunctionTemplate> fun_templ =
   12432       v8::FunctionTemplate::New(isolate);
   12433   v8::Handle<v8::FunctionTemplate> method_templ =
   12434       v8::FunctionTemplate::New(isolate,
   12435                                 FastApiCallback_TrivialSignature,
   12436                                 v8_str("method_data"),
   12437                                 v8::Handle<v8::Signature>());
   12438   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12439   proto_templ->Set(v8_str("method"), method_templ);
   12440   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   12441   USE(templ);
   12442   LocalContext context;
   12443   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12444   GenerateSomeGarbage();
   12445   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12446   CompileRun(
   12447       "var result = 0;"
   12448       "for (var i = 0; i < 100; i++) {"
   12449       "  result = o.method(41);"
   12450       "}");
   12451 
   12452   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   12453 }
   12454 
   12455 
   12456 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
   12457   v8::Isolate* isolate = CcTest::isolate();
   12458   v8::HandleScope scope(isolate);
   12459   v8::Handle<v8::FunctionTemplate> fun_templ =
   12460       v8::FunctionTemplate::New(isolate);
   12461   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12462       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12463       v8::Signature::New(isolate, fun_templ));
   12464   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12465   proto_templ->Set(v8_str("method"), method_templ);
   12466   fun_templ->SetHiddenPrototype(true);
   12467   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   12468   CHECK(!templ.IsEmpty());
   12469   LocalContext context;
   12470   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12471   GenerateSomeGarbage();
   12472   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12473   CompileRun(
   12474       "o.foo = 17;"
   12475       "var receiver = {};"
   12476       "receiver.__proto__ = o;"
   12477       "var result = 0;"
   12478       "for (var i = 0; i < 100; i++) {"
   12479       "  result = receiver.method(41);"
   12480       "}");
   12481 
   12482   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
   12483 }
   12484 
   12485 
   12486 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
   12487   v8::Isolate* isolate = CcTest::isolate();
   12488   v8::HandleScope scope(isolate);
   12489   v8::Handle<v8::FunctionTemplate> fun_templ =
   12490       v8::FunctionTemplate::New(isolate);
   12491   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12492       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12493       v8::Signature::New(isolate, fun_templ));
   12494   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12495   proto_templ->Set(v8_str("method"), method_templ);
   12496   fun_templ->SetHiddenPrototype(true);
   12497   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   12498   CHECK(!templ.IsEmpty());
   12499   LocalContext context;
   12500   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12501   GenerateSomeGarbage();
   12502   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12503   CompileRun(
   12504       "o.foo = 17;"
   12505       "var receiver = {};"
   12506       "receiver.__proto__ = o;"
   12507       "var result = 0;"
   12508       "var saved_result = 0;"
   12509       "for (var i = 0; i < 100; i++) {"
   12510       "  result = receiver.method(41);"
   12511       "  if (i == 50) {"
   12512       "    saved_result = result;"
   12513       "    receiver = {method: function(x) { return x - 1 }};"
   12514       "  }"
   12515       "}");
   12516   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
   12517   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12518 }
   12519 
   12520 
   12521 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
   12522   v8::Isolate* isolate = CcTest::isolate();
   12523   v8::HandleScope scope(isolate);
   12524   v8::Handle<v8::FunctionTemplate> fun_templ =
   12525       v8::FunctionTemplate::New(isolate);
   12526   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12527       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12528       v8::Signature::New(isolate, fun_templ));
   12529   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12530   proto_templ->Set(v8_str("method"), method_templ);
   12531   fun_templ->SetHiddenPrototype(true);
   12532   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   12533   CHECK(!templ.IsEmpty());
   12534   LocalContext context;
   12535   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12536   GenerateSomeGarbage();
   12537   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12538   v8::TryCatch try_catch;
   12539   CompileRun(
   12540       "o.foo = 17;"
   12541       "var receiver = {};"
   12542       "receiver.__proto__ = o;"
   12543       "var result = 0;"
   12544       "var saved_result = 0;"
   12545       "for (var i = 0; i < 100; i++) {"
   12546       "  result = receiver.method(41);"
   12547       "  if (i == 50) {"
   12548       "    saved_result = result;"
   12549       "    receiver = 333;"
   12550       "  }"
   12551       "}");
   12552   CHECK(try_catch.HasCaught());
   12553   // TODO(verwaest): Adjust message.
   12554   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
   12555            try_catch.Exception()->ToString());
   12556   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12557 }
   12558 
   12559 
   12560 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
   12561   v8::Isolate* isolate = CcTest::isolate();
   12562   v8::HandleScope scope(isolate);
   12563   v8::Handle<v8::FunctionTemplate> fun_templ =
   12564       v8::FunctionTemplate::New(isolate);
   12565   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
   12566       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
   12567       v8::Signature::New(isolate, fun_templ));
   12568   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   12569   proto_templ->Set(v8_str("method"), method_templ);
   12570   fun_templ->SetHiddenPrototype(true);
   12571   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   12572   CHECK(!templ.IsEmpty());
   12573   LocalContext context;
   12574   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   12575   GenerateSomeGarbage();
   12576   context->Global()->Set(v8_str("o"), fun->NewInstance());
   12577   v8::TryCatch try_catch;
   12578   CompileRun(
   12579       "o.foo = 17;"
   12580       "var receiver = {};"
   12581       "receiver.__proto__ = o;"
   12582       "var result = 0;"
   12583       "var saved_result = 0;"
   12584       "for (var i = 0; i < 100; i++) {"
   12585       "  result = receiver.method(41);"
   12586       "  if (i == 50) {"
   12587       "    saved_result = result;"
   12588       "    receiver = Object.create(receiver);"
   12589       "  }"
   12590       "}");
   12591   CHECK(try_catch.HasCaught());
   12592   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
   12593            try_catch.Exception()->ToString());
   12594   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12595 }
   12596 
   12597 
   12598 v8::Handle<Value> keyed_call_ic_function;
   12599 
   12600 static void InterceptorKeyedCallICGetter(
   12601     Local<String> name,
   12602     const v8::PropertyCallbackInfo<v8::Value>& info) {
   12603   ApiTestFuzzer::Fuzz();
   12604   if (v8_str("x")->Equals(name)) {
   12605     info.GetReturnValue().Set(keyed_call_ic_function);
   12606   }
   12607 }
   12608 
   12609 
   12610 // Test the case when we stored cacheable lookup into
   12611 // a stub, but the function name changed (to another cacheable function).
   12612 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
   12613   v8::Isolate* isolate = CcTest::isolate();
   12614   v8::HandleScope scope(isolate);
   12615   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12616   templ->SetNamedPropertyHandler(NoBlockGetterX);
   12617   LocalContext context;
   12618   context->Global()->Set(v8_str("o"), templ->NewInstance());
   12619   CompileRun(
   12620     "proto = new Object();"
   12621     "proto.y = function(x) { return x + 1; };"
   12622     "proto.z = function(x) { return x - 1; };"
   12623     "o.__proto__ = proto;"
   12624     "var result = 0;"
   12625     "var method = 'y';"
   12626     "for (var i = 0; i < 10; i++) {"
   12627     "  if (i == 5) { method = 'z'; };"
   12628     "  result += o[method](41);"
   12629     "}");
   12630   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
   12631 }
   12632 
   12633 
   12634 // Test the case when we stored cacheable lookup into
   12635 // a stub, but the function name changed (and the new function is present
   12636 // both before and after the interceptor in the prototype chain).
   12637 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
   12638   v8::Isolate* isolate = CcTest::isolate();
   12639   v8::HandleScope scope(isolate);
   12640   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12641   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
   12642   LocalContext context;
   12643   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
   12644   keyed_call_ic_function =
   12645       v8_compile("function f(x) { return x - 1; }; f")->Run();
   12646   CompileRun(
   12647     "o = new Object();"
   12648     "proto2 = new Object();"
   12649     "o.y = function(x) { return x + 1; };"
   12650     "proto2.y = function(x) { return x + 2; };"
   12651     "o.__proto__ = proto1;"
   12652     "proto1.__proto__ = proto2;"
   12653     "var result = 0;"
   12654     "var method = 'x';"
   12655     "for (var i = 0; i < 10; i++) {"
   12656     "  if (i == 5) { method = 'y'; };"
   12657     "  result += o[method](41);"
   12658     "}");
   12659   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
   12660 }
   12661 
   12662 
   12663 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
   12664 // on the global object.
   12665 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
   12666   v8::Isolate* isolate = CcTest::isolate();
   12667   v8::HandleScope scope(isolate);
   12668   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12669   templ->SetNamedPropertyHandler(NoBlockGetterX);
   12670   LocalContext context;
   12671   context->Global()->Set(v8_str("o"), templ->NewInstance());
   12672   CompileRun(
   12673     "function inc(x) { return x + 1; };"
   12674     "inc(1);"
   12675     "function dec(x) { return x - 1; };"
   12676     "dec(1);"
   12677     "o.__proto__ = this;"
   12678     "this.__proto__.x = inc;"
   12679     "this.__proto__.y = dec;"
   12680     "var result = 0;"
   12681     "var method = 'x';"
   12682     "for (var i = 0; i < 10; i++) {"
   12683     "  if (i == 5) { method = 'y'; };"
   12684     "  result += o[method](41);"
   12685     "}");
   12686   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
   12687 }
   12688 
   12689 
   12690 // Test the case when actual function to call sits on global object.
   12691 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
   12692   v8::Isolate* isolate = CcTest::isolate();
   12693   v8::HandleScope scope(isolate);
   12694   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   12695   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
   12696   LocalContext context;
   12697   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   12698 
   12699   CompileRun(
   12700     "function len(x) { return x.length; };"
   12701     "o.__proto__ = this;"
   12702     "var m = 'parseFloat';"
   12703     "var result = 0;"
   12704     "for (var i = 0; i < 10; i++) {"
   12705     "  if (i == 5) {"
   12706     "    m = 'len';"
   12707     "    saved_result = result;"
   12708     "  };"
   12709     "  result = o[m]('239');"
   12710     "}");
   12711   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
   12712   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   12713 }
   12714 
   12715 
   12716 // Test the map transition before the interceptor.
   12717 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
   12718   v8::Isolate* isolate = CcTest::isolate();
   12719   v8::HandleScope scope(isolate);
   12720   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   12721   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
   12722   LocalContext context;
   12723   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
   12724 
   12725   CompileRun(
   12726     "var o = new Object();"
   12727     "o.__proto__ = proto;"
   12728     "o.method = function(x) { return x + 1; };"
   12729     "var m = 'method';"
   12730     "var result = 0;"
   12731     "for (var i = 0; i < 10; i++) {"
   12732     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
   12733     "  result += o[m](41);"
   12734     "}");
   12735   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
   12736 }
   12737 
   12738 
   12739 // Test the map transition after the interceptor.
   12740 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
   12741   v8::Isolate* isolate = CcTest::isolate();
   12742   v8::HandleScope scope(isolate);
   12743   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
   12744   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
   12745   LocalContext context;
   12746   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
   12747 
   12748   CompileRun(
   12749     "var proto = new Object();"
   12750     "o.__proto__ = proto;"
   12751     "proto.method = function(x) { return x + 1; };"
   12752     "var m = 'method';"
   12753     "var result = 0;"
   12754     "for (var i = 0; i < 10; i++) {"
   12755     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
   12756     "  result += o[m](41);"
   12757     "}");
   12758   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
   12759 }
   12760 
   12761 
   12762 static int interceptor_call_count = 0;
   12763 
   12764 static void InterceptorICRefErrorGetter(
   12765     Local<String> name,
   12766     const v8::PropertyCallbackInfo<v8::Value>& info) {
   12767   ApiTestFuzzer::Fuzz();
   12768   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
   12769     info.GetReturnValue().Set(call_ic_function2);
   12770   }
   12771 }
   12772 
   12773 
   12774 // This test should hit load and call ICs for the interceptor case.
   12775 // Once in a while, the interceptor will reply that a property was not
   12776 // found in which case we should get a reference error.
   12777 THREADED_TEST(InterceptorICReferenceErrors) {
   12778   v8::Isolate* isolate = CcTest::isolate();
   12779   v8::HandleScope scope(isolate);
   12780   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12781   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
   12782   LocalContext context(0, templ, v8::Handle<Value>());
   12783   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
   12784   v8::Handle<Value> value = CompileRun(
   12785     "function f() {"
   12786     "  for (var i = 0; i < 1000; i++) {"
   12787     "    try { x; } catch(e) { return true; }"
   12788     "  }"
   12789     "  return false;"
   12790     "};"
   12791     "f();");
   12792   CHECK_EQ(true, value->BooleanValue());
   12793   interceptor_call_count = 0;
   12794   value = CompileRun(
   12795     "function g() {"
   12796     "  for (var i = 0; i < 1000; i++) {"
   12797     "    try { x(42); } catch(e) { return true; }"
   12798     "  }"
   12799     "  return false;"
   12800     "};"
   12801     "g();");
   12802   CHECK_EQ(true, value->BooleanValue());
   12803 }
   12804 
   12805 
   12806 static int interceptor_ic_exception_get_count = 0;
   12807 
   12808 static void InterceptorICExceptionGetter(
   12809     Local<String> name,
   12810     const v8::PropertyCallbackInfo<v8::Value>& info) {
   12811   ApiTestFuzzer::Fuzz();
   12812   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
   12813     info.GetReturnValue().Set(call_ic_function3);
   12814   }
   12815   if (interceptor_ic_exception_get_count == 20) {
   12816     info.GetIsolate()->ThrowException(v8_num(42));
   12817     return;
   12818   }
   12819 }
   12820 
   12821 
   12822 // Test interceptor load/call IC where the interceptor throws an
   12823 // exception once in a while.
   12824 THREADED_TEST(InterceptorICGetterExceptions) {
   12825   interceptor_ic_exception_get_count = 0;
   12826   v8::Isolate* isolate = CcTest::isolate();
   12827   v8::HandleScope scope(isolate);
   12828   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12829   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
   12830   LocalContext context(0, templ, v8::Handle<Value>());
   12831   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
   12832   v8::Handle<Value> value = CompileRun(
   12833     "function f() {"
   12834     "  for (var i = 0; i < 100; i++) {"
   12835     "    try { x; } catch(e) { return true; }"
   12836     "  }"
   12837     "  return false;"
   12838     "};"
   12839     "f();");
   12840   CHECK_EQ(true, value->BooleanValue());
   12841   interceptor_ic_exception_get_count = 0;
   12842   value = CompileRun(
   12843     "function f() {"
   12844     "  for (var i = 0; i < 100; i++) {"
   12845     "    try { x(42); } catch(e) { return true; }"
   12846     "  }"
   12847     "  return false;"
   12848     "};"
   12849     "f();");
   12850   CHECK_EQ(true, value->BooleanValue());
   12851 }
   12852 
   12853 
   12854 static int interceptor_ic_exception_set_count = 0;
   12855 
   12856 static void InterceptorICExceptionSetter(
   12857       Local<String> key,
   12858       Local<Value> value,
   12859       const v8::PropertyCallbackInfo<v8::Value>& info) {
   12860   ApiTestFuzzer::Fuzz();
   12861   if (++interceptor_ic_exception_set_count > 20) {
   12862     info.GetIsolate()->ThrowException(v8_num(42));
   12863   }
   12864 }
   12865 
   12866 
   12867 // Test interceptor store IC where the interceptor throws an exception
   12868 // once in a while.
   12869 THREADED_TEST(InterceptorICSetterExceptions) {
   12870   interceptor_ic_exception_set_count = 0;
   12871   v8::Isolate* isolate = CcTest::isolate();
   12872   v8::HandleScope scope(isolate);
   12873   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12874   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
   12875   LocalContext context(0, templ, v8::Handle<Value>());
   12876   v8::Handle<Value> value = CompileRun(
   12877     "function f() {"
   12878     "  for (var i = 0; i < 100; i++) {"
   12879     "    try { x = 42; } catch(e) { return true; }"
   12880     "  }"
   12881     "  return false;"
   12882     "};"
   12883     "f();");
   12884   CHECK_EQ(true, value->BooleanValue());
   12885 }
   12886 
   12887 
   12888 // Test that we ignore null interceptors.
   12889 THREADED_TEST(NullNamedInterceptor) {
   12890   v8::Isolate* isolate = CcTest::isolate();
   12891   v8::HandleScope scope(isolate);
   12892   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12893   templ->SetNamedPropertyHandler(
   12894       static_cast<v8::NamedPropertyGetterCallback>(0));
   12895   LocalContext context;
   12896   templ->Set(CcTest::isolate(), "x", v8_num(42));
   12897   v8::Handle<v8::Object> obj = templ->NewInstance();
   12898   context->Global()->Set(v8_str("obj"), obj);
   12899   v8::Handle<Value> value = CompileRun("obj.x");
   12900   CHECK(value->IsInt32());
   12901   CHECK_EQ(42, value->Int32Value());
   12902 }
   12903 
   12904 
   12905 // Test that we ignore null interceptors.
   12906 THREADED_TEST(NullIndexedInterceptor) {
   12907   v8::Isolate* isolate = CcTest::isolate();
   12908   v8::HandleScope scope(isolate);
   12909   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
   12910   templ->SetIndexedPropertyHandler(
   12911       static_cast<v8::IndexedPropertyGetterCallback>(0));
   12912   LocalContext context;
   12913   templ->Set(CcTest::isolate(), "42", v8_num(42));
   12914   v8::Handle<v8::Object> obj = templ->NewInstance();
   12915   context->Global()->Set(v8_str("obj"), obj);
   12916   v8::Handle<Value> value = CompileRun("obj[42]");
   12917   CHECK(value->IsInt32());
   12918   CHECK_EQ(42, value->Int32Value());
   12919 }
   12920 
   12921 
   12922 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
   12923   v8::Isolate* isolate = CcTest::isolate();
   12924   v8::HandleScope scope(isolate);
   12925   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   12926   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
   12927   LocalContext env;
   12928   env->Global()->Set(v8_str("obj"),
   12929                      templ->GetFunction()->NewInstance());
   12930   ExpectTrue("obj.x === 42");
   12931   ExpectTrue("!obj.propertyIsEnumerable('x')");
   12932 }
   12933 
   12934 
   12935 static void ThrowingGetter(Local<String> name,
   12936                            const v8::PropertyCallbackInfo<v8::Value>& info) {
   12937   ApiTestFuzzer::Fuzz();
   12938   info.GetIsolate()->ThrowException(Handle<Value>());
   12939   info.GetReturnValue().SetUndefined();
   12940 }
   12941 
   12942 
   12943 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
   12944   LocalContext context;
   12945   HandleScope scope(context->GetIsolate());
   12946 
   12947   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
   12948   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
   12949   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
   12950 
   12951   Local<Object> instance = templ->GetFunction()->NewInstance();
   12952 
   12953   Local<Object> another = Object::New(context->GetIsolate());
   12954   another->SetPrototype(instance);
   12955 
   12956   Local<Object> with_js_getter = CompileRun(
   12957       "o = {};\n"
   12958       "o.__defineGetter__('f', function() { throw undefined; });\n"
   12959       "o\n").As<Object>();
   12960   CHECK(!with_js_getter.IsEmpty());
   12961 
   12962   TryCatch try_catch;
   12963 
   12964   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
   12965   CHECK(try_catch.HasCaught());
   12966   try_catch.Reset();
   12967   CHECK(result.IsEmpty());
   12968 
   12969   result = another->GetRealNamedProperty(v8_str("f"));
   12970   CHECK(try_catch.HasCaught());
   12971   try_catch.Reset();
   12972   CHECK(result.IsEmpty());
   12973 
   12974   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
   12975   CHECK(try_catch.HasCaught());
   12976   try_catch.Reset();
   12977   CHECK(result.IsEmpty());
   12978 
   12979   result = another->Get(v8_str("f"));
   12980   CHECK(try_catch.HasCaught());
   12981   try_catch.Reset();
   12982   CHECK(result.IsEmpty());
   12983 
   12984   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
   12985   CHECK(try_catch.HasCaught());
   12986   try_catch.Reset();
   12987   CHECK(result.IsEmpty());
   12988 
   12989   result = with_js_getter->Get(v8_str("f"));
   12990   CHECK(try_catch.HasCaught());
   12991   try_catch.Reset();
   12992   CHECK(result.IsEmpty());
   12993 }
   12994 
   12995 
   12996 static void ThrowingCallbackWithTryCatch(
   12997     const v8::FunctionCallbackInfo<v8::Value>& args) {
   12998   TryCatch try_catch;
   12999   // Verboseness is important: it triggers message delivery which can call into
   13000   // external code.
   13001   try_catch.SetVerbose(true);
   13002   CompileRun("throw 'from JS';");
   13003   CHECK(try_catch.HasCaught());
   13004   CHECK(!CcTest::i_isolate()->has_pending_exception());
   13005   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
   13006 }
   13007 
   13008 
   13009 static int call_depth;
   13010 
   13011 
   13012 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
   13013   TryCatch try_catch;
   13014 }
   13015 
   13016 
   13017 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
   13018   if (--call_depth) CompileRun("throw 'ThrowInJS';");
   13019 }
   13020 
   13021 
   13022 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
   13023   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
   13024 }
   13025 
   13026 
   13027 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
   13028   Handle<String> errorMessageString = message->Get();
   13029   CHECK(!errorMessageString.IsEmpty());
   13030   message->GetStackTrace();
   13031   message->GetScriptResourceName();
   13032 }
   13033 
   13034 
   13035 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
   13036   LocalContext context;
   13037   v8::Isolate* isolate = context->GetIsolate();
   13038   HandleScope scope(isolate);
   13039 
   13040   Local<Function> func =
   13041       FunctionTemplate::New(isolate,
   13042                             ThrowingCallbackWithTryCatch)->GetFunction();
   13043   context->Global()->Set(v8_str("func"), func);
   13044 
   13045   MessageCallback callbacks[] =
   13046       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
   13047   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
   13048     MessageCallback callback = callbacks[i];
   13049     if (callback != NULL) {
   13050       V8::AddMessageListener(callback);
   13051     }
   13052     // Some small number to control number of times message handler should
   13053     // throw an exception.
   13054     call_depth = 5;
   13055     ExpectFalse(
   13056         "var thrown = false;\n"
   13057         "try { func(); } catch(e) { thrown = true; }\n"
   13058         "thrown\n");
   13059     if (callback != NULL) {
   13060       V8::RemoveMessageListeners(callback);
   13061     }
   13062   }
   13063 }
   13064 
   13065 
   13066 static void ParentGetter(Local<String> name,
   13067                          const v8::PropertyCallbackInfo<v8::Value>& info) {
   13068   ApiTestFuzzer::Fuzz();
   13069   info.GetReturnValue().Set(v8_num(1));
   13070 }
   13071 
   13072 
   13073 static void ChildGetter(Local<String> name,
   13074                         const v8::PropertyCallbackInfo<v8::Value>& info) {
   13075   ApiTestFuzzer::Fuzz();
   13076   info.GetReturnValue().Set(v8_num(42));
   13077 }
   13078 
   13079 
   13080 THREADED_TEST(Overriding) {
   13081   LocalContext context;
   13082   v8::Isolate* isolate = context->GetIsolate();
   13083   v8::HandleScope scope(isolate);
   13084 
   13085   // Parent template.
   13086   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
   13087   Local<ObjectTemplate> parent_instance_templ =
   13088       parent_templ->InstanceTemplate();
   13089   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
   13090 
   13091   // Template that inherits from the parent template.
   13092   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
   13093   Local<ObjectTemplate> child_instance_templ =
   13094       child_templ->InstanceTemplate();
   13095   child_templ->Inherit(parent_templ);
   13096   // Override 'f'.  The child version of 'f' should get called for child
   13097   // instances.
   13098   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
   13099   // Add 'g' twice.  The 'g' added last should get called for instances.
   13100   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
   13101   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
   13102 
   13103   // Add 'h' as an accessor to the proto template with ReadOnly attributes
   13104   // so 'h' can be shadowed on the instance object.
   13105   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
   13106   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
   13107       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
   13108 
   13109   // Add 'i' as an accessor to the instance template with ReadOnly attributes
   13110   // but the attribute does not have effect because it is duplicated with
   13111   // NULL setter.
   13112   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
   13113       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
   13114 
   13115 
   13116 
   13117   // Instantiate the child template.
   13118   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
   13119 
   13120   // Check that the child function overrides the parent one.
   13121   context->Global()->Set(v8_str("o"), instance);
   13122   Local<Value> value = v8_compile("o.f")->Run();
   13123   // Check that the 'g' that was added last is hit.
   13124   CHECK_EQ(42, value->Int32Value());
   13125   value = v8_compile("o.g")->Run();
   13126   CHECK_EQ(42, value->Int32Value());
   13127 
   13128   // Check that 'h' cannot be shadowed.
   13129   value = v8_compile("o.h = 3; o.h")->Run();
   13130   CHECK_EQ(1, value->Int32Value());
   13131 
   13132   // Check that 'i' cannot be shadowed or changed.
   13133   value = v8_compile("o.i = 3; o.i")->Run();
   13134   CHECK_EQ(42, value->Int32Value());
   13135 }
   13136 
   13137 
   13138 static void IsConstructHandler(
   13139     const v8::FunctionCallbackInfo<v8::Value>& args) {
   13140   ApiTestFuzzer::Fuzz();
   13141   args.GetReturnValue().Set(args.IsConstructCall());
   13142 }
   13143 
   13144 
   13145 THREADED_TEST(IsConstructCall) {
   13146   v8::Isolate* isolate = CcTest::isolate();
   13147   v8::HandleScope scope(isolate);
   13148 
   13149   // Function template with call handler.
   13150   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   13151   templ->SetCallHandler(IsConstructHandler);
   13152 
   13153   LocalContext context;
   13154 
   13155   context->Global()->Set(v8_str("f"), templ->GetFunction());
   13156   Local<Value> value = v8_compile("f()")->Run();
   13157   CHECK(!value->BooleanValue());
   13158   value = v8_compile("new f()")->Run();
   13159   CHECK(value->BooleanValue());
   13160 }
   13161 
   13162 
   13163 THREADED_TEST(ObjectProtoToString) {
   13164   v8::Isolate* isolate = CcTest::isolate();
   13165   v8::HandleScope scope(isolate);
   13166   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
   13167   templ->SetClassName(v8_str("MyClass"));
   13168 
   13169   LocalContext context;
   13170 
   13171   Local<String> customized_tostring = v8_str("customized toString");
   13172 
   13173   // Replace Object.prototype.toString
   13174   v8_compile("Object.prototype.toString = function() {"
   13175                   "  return 'customized toString';"
   13176                   "}")->Run();
   13177 
   13178   // Normal ToString call should call replaced Object.prototype.toString
   13179   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
   13180   Local<String> value = instance->ToString();
   13181   CHECK(value->IsString() && value->Equals(customized_tostring));
   13182 
   13183   // ObjectProtoToString should not call replace toString function.
   13184   value = instance->ObjectProtoToString();
   13185   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
   13186 
   13187   // Check global
   13188   value = context->Global()->ObjectProtoToString();
   13189   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
   13190 
   13191   // Check ordinary object
   13192   Local<Value> object = v8_compile("new Object()")->Run();
   13193   value = object.As<v8::Object>()->ObjectProtoToString();
   13194   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
   13195 }
   13196 
   13197 
   13198 THREADED_TEST(ObjectGetConstructorName) {
   13199   LocalContext context;
   13200   v8::HandleScope scope(context->GetIsolate());
   13201   v8_compile("function Parent() {};"
   13202              "function Child() {};"
   13203              "Child.prototype = new Parent();"
   13204              "var outer = { inner: function() { } };"
   13205              "var p = new Parent();"
   13206              "var c = new Child();"
   13207              "var x = new outer.inner();")->Run();
   13208 
   13209   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
   13210   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
   13211       v8_str("Parent")));
   13212 
   13213   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
   13214   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
   13215       v8_str("Child")));
   13216 
   13217   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
   13218   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
   13219       v8_str("outer.inner")));
   13220 }
   13221 
   13222 
   13223 bool ApiTestFuzzer::fuzzing_ = false;
   13224 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
   13225 int ApiTestFuzzer::active_tests_;
   13226 int ApiTestFuzzer::tests_being_run_;
   13227 int ApiTestFuzzer::current_;
   13228 
   13229 
   13230 // We are in a callback and want to switch to another thread (if we
   13231 // are currently running the thread fuzzing test).
   13232 void ApiTestFuzzer::Fuzz() {
   13233   if (!fuzzing_) return;
   13234   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
   13235   test->ContextSwitch();
   13236 }
   13237 
   13238 
   13239 // Let the next thread go.  Since it is also waiting on the V8 lock it may
   13240 // not start immediately.
   13241 bool ApiTestFuzzer::NextThread() {
   13242   int test_position = GetNextTestNumber();
   13243   const char* test_name = RegisterThreadedTest::nth(current_)->name();
   13244   if (test_position == current_) {
   13245     if (kLogThreading)
   13246       printf("Stay with %s\n", test_name);
   13247     return false;
   13248   }
   13249   if (kLogThreading) {
   13250     printf("Switch from %s to %s\n",
   13251            test_name,
   13252            RegisterThreadedTest::nth(test_position)->name());
   13253   }
   13254   current_ = test_position;
   13255   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
   13256   return true;
   13257 }
   13258 
   13259 
   13260 void ApiTestFuzzer::Run() {
   13261   // When it is our turn...
   13262   gate_.Wait();
   13263   {
   13264     // ... get the V8 lock and start running the test.
   13265     v8::Locker locker(CcTest::isolate());
   13266     CallTest();
   13267   }
   13268   // This test finished.
   13269   active_ = false;
   13270   active_tests_--;
   13271   // If it was the last then signal that fact.
   13272   if (active_tests_ == 0) {
   13273     all_tests_done_.Signal();
   13274   } else {
   13275     // Otherwise select a new test and start that.
   13276     NextThread();
   13277   }
   13278 }
   13279 
   13280 
   13281 static unsigned linear_congruential_generator;
   13282 
   13283 
   13284 void ApiTestFuzzer::SetUp(PartOfTest part) {
   13285   linear_congruential_generator = i::FLAG_testing_prng_seed;
   13286   fuzzing_ = true;
   13287   int count = RegisterThreadedTest::count();
   13288   int start =  count * part / (LAST_PART + 1);
   13289   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
   13290   active_tests_ = tests_being_run_ = end - start + 1;
   13291   for (int i = 0; i < tests_being_run_; i++) {
   13292     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
   13293   }
   13294   for (int i = 0; i < active_tests_; i++) {
   13295     RegisterThreadedTest::nth(i)->fuzzer_->Start();
   13296   }
   13297 }
   13298 
   13299 
   13300 static void CallTestNumber(int test_number) {
   13301   (RegisterThreadedTest::nth(test_number)->callback())();
   13302 }
   13303 
   13304 
   13305 void ApiTestFuzzer::RunAllTests() {
   13306   // Set off the first test.
   13307   current_ = -1;
   13308   NextThread();
   13309   // Wait till they are all done.
   13310   all_tests_done_.Wait();
   13311 }
   13312 
   13313 
   13314 int ApiTestFuzzer::GetNextTestNumber() {
   13315   int next_test;
   13316   do {
   13317     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
   13318     linear_congruential_generator *= 1664525u;
   13319     linear_congruential_generator += 1013904223u;
   13320   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
   13321   return next_test;
   13322 }
   13323 
   13324 
   13325 void ApiTestFuzzer::ContextSwitch() {
   13326   // If the new thread is the same as the current thread there is nothing to do.
   13327   if (NextThread()) {
   13328     // Now it can start.
   13329     v8::Unlocker unlocker(CcTest::isolate());
   13330     // Wait till someone starts us again.
   13331     gate_.Wait();
   13332     // And we're off.
   13333   }
   13334 }
   13335 
   13336 
   13337 void ApiTestFuzzer::TearDown() {
   13338   fuzzing_ = false;
   13339   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
   13340     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
   13341     if (fuzzer != NULL) fuzzer->Join();
   13342   }
   13343 }
   13344 
   13345 
   13346 // Lets not be needlessly self-referential.
   13347 TEST(Threading1) {
   13348   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
   13349   ApiTestFuzzer::RunAllTests();
   13350   ApiTestFuzzer::TearDown();
   13351 }
   13352 
   13353 
   13354 TEST(Threading2) {
   13355   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
   13356   ApiTestFuzzer::RunAllTests();
   13357   ApiTestFuzzer::TearDown();
   13358 }
   13359 
   13360 
   13361 TEST(Threading3) {
   13362   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
   13363   ApiTestFuzzer::RunAllTests();
   13364   ApiTestFuzzer::TearDown();
   13365 }
   13366 
   13367 
   13368 TEST(Threading4) {
   13369   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
   13370   ApiTestFuzzer::RunAllTests();
   13371   ApiTestFuzzer::TearDown();
   13372 }
   13373 
   13374 
   13375 void ApiTestFuzzer::CallTest() {
   13376   v8::Isolate::Scope scope(CcTest::isolate());
   13377   if (kLogThreading)
   13378     printf("Start test %d\n", test_number_);
   13379   CallTestNumber(test_number_);
   13380   if (kLogThreading)
   13381     printf("End test %d\n", test_number_);
   13382 }
   13383 
   13384 
   13385 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
   13386   v8::Isolate* isolate = args.GetIsolate();
   13387   CHECK(v8::Locker::IsLocked(isolate));
   13388   ApiTestFuzzer::Fuzz();
   13389   v8::Unlocker unlocker(isolate);
   13390   const char* code = "throw 7;";
   13391   {
   13392     v8::Locker nested_locker(isolate);
   13393     v8::HandleScope scope(isolate);
   13394     v8::Handle<Value> exception;
   13395     { v8::TryCatch try_catch;
   13396       v8::Handle<Value> value = CompileRun(code);
   13397       CHECK(value.IsEmpty());
   13398       CHECK(try_catch.HasCaught());
   13399       // Make sure to wrap the exception in a new handle because
   13400       // the handle returned from the TryCatch is destroyed
   13401       // when the TryCatch is destroyed.
   13402       exception = Local<Value>::New(isolate, try_catch.Exception());
   13403     }
   13404     args.GetIsolate()->ThrowException(exception);
   13405   }
   13406 }
   13407 
   13408 
   13409 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
   13410   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
   13411   ApiTestFuzzer::Fuzz();
   13412   v8::Unlocker unlocker(CcTest::isolate());
   13413   const char* code = "throw 7;";
   13414   {
   13415     v8::Locker nested_locker(CcTest::isolate());
   13416     v8::HandleScope scope(args.GetIsolate());
   13417     v8::Handle<Value> value = CompileRun(code);
   13418     CHECK(value.IsEmpty());
   13419     args.GetReturnValue().Set(v8_str("foo"));
   13420   }
   13421 }
   13422 
   13423 
   13424 // These are locking tests that don't need to be run again
   13425 // as part of the locking aggregation tests.
   13426 TEST(NestedLockers) {
   13427   v8::Isolate* isolate = CcTest::isolate();
   13428   v8::Locker locker(isolate);
   13429   CHECK(v8::Locker::IsLocked(isolate));
   13430   LocalContext env;
   13431   v8::HandleScope scope(env->GetIsolate());
   13432   Local<v8::FunctionTemplate> fun_templ =
   13433       v8::FunctionTemplate::New(isolate, ThrowInJS);
   13434   Local<Function> fun = fun_templ->GetFunction();
   13435   env->Global()->Set(v8_str("throw_in_js"), fun);
   13436   Local<Script> script = v8_compile("(function () {"
   13437                                     "  try {"
   13438                                     "    throw_in_js();"
   13439                                     "    return 42;"
   13440                                     "  } catch (e) {"
   13441                                     "    return e * 13;"
   13442                                     "  }"
   13443                                     "})();");
   13444   CHECK_EQ(91, script->Run()->Int32Value());
   13445 }
   13446 
   13447 
   13448 // These are locking tests that don't need to be run again
   13449 // as part of the locking aggregation tests.
   13450 TEST(NestedLockersNoTryCatch) {
   13451   v8::Locker locker(CcTest::isolate());
   13452   LocalContext env;
   13453   v8::HandleScope scope(env->GetIsolate());
   13454   Local<v8::FunctionTemplate> fun_templ =
   13455       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
   13456   Local<Function> fun = fun_templ->GetFunction();
   13457   env->Global()->Set(v8_str("throw_in_js"), fun);
   13458   Local<Script> script = v8_compile("(function () {"
   13459                                     "  try {"
   13460                                     "    throw_in_js();"
   13461                                     "    return 42;"
   13462                                     "  } catch (e) {"
   13463                                     "    return e * 13;"
   13464                                     "  }"
   13465                                     "})();");
   13466   CHECK_EQ(91, script->Run()->Int32Value());
   13467 }
   13468 
   13469 
   13470 THREADED_TEST(RecursiveLocking) {
   13471   v8::Locker locker(CcTest::isolate());
   13472   {
   13473     v8::Locker locker2(CcTest::isolate());
   13474     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
   13475   }
   13476 }
   13477 
   13478 
   13479 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
   13480   ApiTestFuzzer::Fuzz();
   13481   v8::Unlocker unlocker(CcTest::isolate());
   13482 }
   13483 
   13484 
   13485 THREADED_TEST(LockUnlockLock) {
   13486   {
   13487     v8::Locker locker(CcTest::isolate());
   13488     v8::HandleScope scope(CcTest::isolate());
   13489     LocalContext env;
   13490     Local<v8::FunctionTemplate> fun_templ =
   13491         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
   13492     Local<Function> fun = fun_templ->GetFunction();
   13493     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
   13494     Local<Script> script = v8_compile("(function () {"
   13495                                       "  unlock_for_a_moment();"
   13496                                       "  return 42;"
   13497                                       "})();");
   13498     CHECK_EQ(42, script->Run()->Int32Value());
   13499   }
   13500   {
   13501     v8::Locker locker(CcTest::isolate());
   13502     v8::HandleScope scope(CcTest::isolate());
   13503     LocalContext env;
   13504     Local<v8::FunctionTemplate> fun_templ =
   13505         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
   13506     Local<Function> fun = fun_templ->GetFunction();
   13507     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
   13508     Local<Script> script = v8_compile("(function () {"
   13509                                       "  unlock_for_a_moment();"
   13510                                       "  return 42;"
   13511                                       "})();");
   13512     CHECK_EQ(42, script->Run()->Int32Value());
   13513   }
   13514 }
   13515 
   13516 
   13517 static int GetGlobalObjectsCount() {
   13518   int count = 0;
   13519   i::HeapIterator it(CcTest::heap());
   13520   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
   13521     if (object->IsJSGlobalObject()) count++;
   13522   return count;
   13523 }
   13524 
   13525 
   13526 static void CheckSurvivingGlobalObjectsCount(int expected) {
   13527   // We need to collect all garbage twice to be sure that everything
   13528   // has been collected.  This is because inline caches are cleared in
   13529   // the first garbage collection but some of the maps have already
   13530   // been marked at that point.  Therefore some of the maps are not
   13531   // collected until the second garbage collection.
   13532   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   13533   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
   13534   int count = GetGlobalObjectsCount();
   13535 #ifdef DEBUG
   13536   if (count != expected) CcTest::heap()->TracePathToGlobal();
   13537 #endif
   13538   CHECK_EQ(expected, count);
   13539 }
   13540 
   13541 
   13542 TEST(DontLeakGlobalObjects) {
   13543   // Regression test for issues 1139850 and 1174891.
   13544 
   13545   i::FLAG_expose_gc = true;
   13546   v8::V8::Initialize();
   13547 
   13548   for (int i = 0; i < 5; i++) {
   13549     { v8::HandleScope scope(CcTest::isolate());
   13550       LocalContext context;
   13551     }
   13552     v8::V8::ContextDisposedNotification();
   13553     CheckSurvivingGlobalObjectsCount(0);
   13554 
   13555     { v8::HandleScope scope(CcTest::isolate());
   13556       LocalContext context;
   13557       v8_compile("Date")->Run();
   13558     }
   13559     v8::V8::ContextDisposedNotification();
   13560     CheckSurvivingGlobalObjectsCount(0);
   13561 
   13562     { v8::HandleScope scope(CcTest::isolate());
   13563       LocalContext context;
   13564       v8_compile("/aaa/")->Run();
   13565     }
   13566     v8::V8::ContextDisposedNotification();
   13567     CheckSurvivingGlobalObjectsCount(0);
   13568 
   13569     { v8::HandleScope scope(CcTest::isolate());
   13570       const char* extension_list[] = { "v8/gc" };
   13571       v8::ExtensionConfiguration extensions(1, extension_list);
   13572       LocalContext context(&extensions);
   13573       v8_compile("gc();")->Run();
   13574     }
   13575     v8::V8::ContextDisposedNotification();
   13576     CheckSurvivingGlobalObjectsCount(0);
   13577   }
   13578 }
   13579 
   13580 
   13581 TEST(CopyablePersistent) {
   13582   LocalContext context;
   13583   v8::Isolate* isolate = context->GetIsolate();
   13584   i::GlobalHandles* globals =
   13585       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
   13586   int initial_handles = globals->global_handles_count();
   13587   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
   13588       CopyableObject;
   13589   {
   13590     CopyableObject handle1;
   13591     {
   13592       v8::HandleScope scope(isolate);
   13593       handle1.Reset(isolate, v8::Object::New(isolate));
   13594     }
   13595     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
   13596     CopyableObject  handle2;
   13597     handle2 = handle1;
   13598     CHECK(handle1 == handle2);
   13599     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
   13600     CopyableObject handle3(handle2);
   13601     CHECK(handle1 == handle3);
   13602     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
   13603   }
   13604   // Verify autodispose
   13605   CHECK_EQ(initial_handles, globals->global_handles_count());
   13606 }
   13607 
   13608 
   13609 static void WeakApiCallback(
   13610     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
   13611   Local<Value> value = data.GetValue()->Get(v8_str("key"));
   13612   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
   13613   data.GetParameter()->Reset();
   13614   delete data.GetParameter();
   13615 }
   13616 
   13617 
   13618 TEST(WeakCallbackApi) {
   13619   LocalContext context;
   13620   v8::Isolate* isolate = context->GetIsolate();
   13621   i::GlobalHandles* globals =
   13622       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
   13623   int initial_handles = globals->global_handles_count();
   13624   {
   13625     v8::HandleScope scope(isolate);
   13626     v8::Local<v8::Object> obj = v8::Object::New(isolate);
   13627     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
   13628     v8::Persistent<v8::Object>* handle =
   13629         new v8::Persistent<v8::Object>(isolate, obj);
   13630     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
   13631                                                              WeakApiCallback);
   13632   }
   13633   reinterpret_cast<i::Isolate*>(isolate)->heap()->
   13634       CollectAllGarbage(i::Heap::kNoGCFlags);
   13635   // Verify disposed.
   13636   CHECK_EQ(initial_handles, globals->global_handles_count());
   13637 }
   13638 
   13639 
   13640 v8::Persistent<v8::Object> some_object;
   13641 v8::Persistent<v8::Object> bad_handle;
   13642 
   13643 void NewPersistentHandleCallback(
   13644     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
   13645   v8::HandleScope scope(data.GetIsolate());
   13646   bad_handle.Reset(data.GetIsolate(), some_object);
   13647   data.GetParameter()->Reset();
   13648 }
   13649 
   13650 
   13651 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
   13652   LocalContext context;
   13653   v8::Isolate* isolate = context->GetIsolate();
   13654 
   13655   v8::Persistent<v8::Object> handle1, handle2;
   13656   {
   13657     v8::HandleScope scope(isolate);
   13658     some_object.Reset(isolate, v8::Object::New(isolate));
   13659     handle1.Reset(isolate, v8::Object::New(isolate));
   13660     handle2.Reset(isolate, v8::Object::New(isolate));
   13661   }
   13662   // Note: order is implementation dependent alas: currently
   13663   // global handle nodes are processed by PostGarbageCollectionProcessing
   13664   // in reverse allocation order, so if second allocated handle is deleted,
   13665   // weak callback of the first handle would be able to 'reallocate' it.
   13666   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
   13667   handle2.Reset();
   13668   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   13669 }
   13670 
   13671 
   13672 v8::Persistent<v8::Object> to_be_disposed;
   13673 
   13674 void DisposeAndForceGcCallback(
   13675     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
   13676   to_be_disposed.Reset();
   13677   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   13678   data.GetParameter()->Reset();
   13679 }
   13680 
   13681 
   13682 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
   13683   LocalContext context;
   13684   v8::Isolate* isolate = context->GetIsolate();
   13685 
   13686   v8::Persistent<v8::Object> handle1, handle2;
   13687   {
   13688     v8::HandleScope scope(isolate);
   13689     handle1.Reset(isolate, v8::Object::New(isolate));
   13690     handle2.Reset(isolate, v8::Object::New(isolate));
   13691   }
   13692   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
   13693   to_be_disposed.Reset(isolate, handle2);
   13694   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   13695 }
   13696 
   13697 void DisposingCallback(
   13698     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
   13699   data.GetParameter()->Reset();
   13700 }
   13701 
   13702 void HandleCreatingCallback(
   13703     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
   13704   v8::HandleScope scope(data.GetIsolate());
   13705   v8::Persistent<v8::Object>(data.GetIsolate(),
   13706                              v8::Object::New(data.GetIsolate()));
   13707   data.GetParameter()->Reset();
   13708 }
   13709 
   13710 
   13711 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
   13712   LocalContext context;
   13713   v8::Isolate* isolate = context->GetIsolate();
   13714 
   13715   v8::Persistent<v8::Object> handle1, handle2, handle3;
   13716   {
   13717     v8::HandleScope scope(isolate);
   13718     handle3.Reset(isolate, v8::Object::New(isolate));
   13719     handle2.Reset(isolate, v8::Object::New(isolate));
   13720     handle1.Reset(isolate, v8::Object::New(isolate));
   13721   }
   13722   handle2.SetWeak(&handle2, DisposingCallback);
   13723   handle3.SetWeak(&handle3, HandleCreatingCallback);
   13724   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
   13725 }
   13726 
   13727 
   13728 THREADED_TEST(CheckForCrossContextObjectLiterals) {
   13729   v8::V8::Initialize();
   13730 
   13731   const int nof = 2;
   13732   const char* sources[nof] = {
   13733     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
   13734     "Object()"
   13735   };
   13736 
   13737   for (int i = 0; i < nof; i++) {
   13738     const char* source = sources[i];
   13739     { v8::HandleScope scope(CcTest::isolate());
   13740       LocalContext context;
   13741       CompileRun(source);
   13742     }
   13743     { v8::HandleScope scope(CcTest::isolate());
   13744       LocalContext context;
   13745       CompileRun(source);
   13746     }
   13747   }
   13748 }
   13749 
   13750 
   13751 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
   13752   v8::EscapableHandleScope inner(env->GetIsolate());
   13753   env->Enter();
   13754   v8::Local<Value> three = v8_num(3);
   13755   v8::Local<Value> value = inner.Escape(three);
   13756   env->Exit();
   13757   return value;
   13758 }
   13759 
   13760 
   13761 THREADED_TEST(NestedHandleScopeAndContexts) {
   13762   v8::Isolate* isolate = CcTest::isolate();
   13763   v8::HandleScope outer(isolate);
   13764   v8::Local<Context> env = Context::New(isolate);
   13765   env->Enter();
   13766   v8::Handle<Value> value = NestedScope(env);
   13767   v8::Handle<String> str(value->ToString());
   13768   CHECK(!str.IsEmpty());
   13769   env->Exit();
   13770 }
   13771 
   13772 
   13773 static bool MatchPointers(void* key1, void* key2) {
   13774   return key1 == key2;
   13775 }
   13776 
   13777 
   13778 struct SymbolInfo {
   13779   size_t id;
   13780   size_t size;
   13781   std::string name;
   13782 };
   13783 
   13784 
   13785 class SetFunctionEntryHookTest {
   13786  public:
   13787   SetFunctionEntryHookTest() {
   13788     CHECK(instance_ == NULL);
   13789     instance_ = this;
   13790   }
   13791   ~SetFunctionEntryHookTest() {
   13792     CHECK(instance_ == this);
   13793     instance_ = NULL;
   13794   }
   13795   void Reset() {
   13796     symbols_.clear();
   13797     symbol_locations_.clear();
   13798     invocations_.clear();
   13799   }
   13800   void RunTest();
   13801   void OnJitEvent(const v8::JitCodeEvent* event);
   13802   static void JitEvent(const v8::JitCodeEvent* event) {
   13803     CHECK(instance_ != NULL);
   13804     instance_->OnJitEvent(event);
   13805   }
   13806 
   13807   void OnEntryHook(uintptr_t function,
   13808                    uintptr_t return_addr_location);
   13809   static void EntryHook(uintptr_t function,
   13810                         uintptr_t return_addr_location) {
   13811     CHECK(instance_ != NULL);
   13812     instance_->OnEntryHook(function, return_addr_location);
   13813   }
   13814 
   13815   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   13816     CHECK(instance_ != NULL);
   13817     args.GetReturnValue().Set(v8_num(42));
   13818   }
   13819   void RunLoopInNewEnv(v8::Isolate* isolate);
   13820 
   13821   // Records addr as location of symbol.
   13822   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
   13823 
   13824   // Finds the symbol containing addr
   13825   SymbolInfo* FindSymbolForAddr(i::Address addr);
   13826   // Returns the number of invocations where the caller name contains
   13827   // \p caller_name and the function name contains \p function_name.
   13828   int CountInvocations(const char* caller_name,
   13829                        const char* function_name);
   13830 
   13831   i::Handle<i::JSFunction> foo_func_;
   13832   i::Handle<i::JSFunction> bar_func_;
   13833 
   13834   typedef std::map<size_t, SymbolInfo> SymbolMap;
   13835   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
   13836   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
   13837   SymbolMap symbols_;
   13838   SymbolLocationMap symbol_locations_;
   13839   InvocationMap invocations_;
   13840 
   13841   static SetFunctionEntryHookTest* instance_;
   13842 };
   13843 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
   13844 
   13845 
   13846 // Returns true if addr is in the range [start, start+len).
   13847 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
   13848   if (start <= addr && start + len > addr)
   13849     return true;
   13850 
   13851   return false;
   13852 }
   13853 
   13854 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
   13855                                               SymbolInfo* symbol) {
   13856   // Insert the symbol at the new location.
   13857   SymbolLocationMap::iterator it =
   13858       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
   13859   // Now erase symbols to the left and right that overlap this one.
   13860   while (it != symbol_locations_.begin()) {
   13861     SymbolLocationMap::iterator left = it;
   13862     --left;
   13863     if (!Overlaps(left->first, left->second->size, addr))
   13864       break;
   13865     symbol_locations_.erase(left);
   13866   }
   13867 
   13868   // Now erase symbols to the left and right that overlap this one.
   13869   while (true) {
   13870     SymbolLocationMap::iterator right = it;
   13871     ++right;
   13872     if (right == symbol_locations_.end())
   13873         break;
   13874     if (!Overlaps(addr, symbol->size, right->first))
   13875       break;
   13876     symbol_locations_.erase(right);
   13877   }
   13878 }
   13879 
   13880 
   13881 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
   13882   switch (event->type) {
   13883     case v8::JitCodeEvent::CODE_ADDED: {
   13884         CHECK(event->code_start != NULL);
   13885         CHECK_NE(0, static_cast<int>(event->code_len));
   13886         CHECK(event->name.str != NULL);
   13887         size_t symbol_id = symbols_.size();
   13888 
   13889         // Record the new symbol.
   13890         SymbolInfo& info = symbols_[symbol_id];
   13891         info.id = symbol_id;
   13892         info.size = event->code_len;
   13893         info.name.assign(event->name.str, event->name.str + event->name.len);
   13894 
   13895         // And record it's location.
   13896         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
   13897       }
   13898       break;
   13899 
   13900     case v8::JitCodeEvent::CODE_MOVED: {
   13901         // We would like to never see code move that we haven't seen before,
   13902         // but the code creation event does not happen until the line endings
   13903         // have been calculated (this is so that we can report the line in the
   13904         // script at which the function source is found, see
   13905         // Compiler::RecordFunctionCompilation) and the line endings
   13906         // calculations can cause a GC, which can move the newly created code
   13907         // before its existence can be logged.
   13908         SymbolLocationMap::iterator it(
   13909             symbol_locations_.find(
   13910                 reinterpret_cast<i::Address>(event->code_start)));
   13911         if (it != symbol_locations_.end()) {
   13912           // Found a symbol at this location, move it.
   13913           SymbolInfo* info = it->second;
   13914           symbol_locations_.erase(it);
   13915           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
   13916                          info);
   13917         }
   13918       }
   13919     default:
   13920       break;
   13921   }
   13922 }
   13923 
   13924 void SetFunctionEntryHookTest::OnEntryHook(
   13925     uintptr_t function, uintptr_t return_addr_location) {
   13926   // Get the function's code object.
   13927   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
   13928       reinterpret_cast<i::Address>(function));
   13929   CHECK(function_code != NULL);
   13930 
   13931   // Then try and look up the caller's code object.
   13932   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
   13933 
   13934   // Count the invocation.
   13935   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
   13936   SymbolInfo* function_symbol =
   13937       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
   13938   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
   13939 
   13940   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
   13941     // Check that we have a symbol for the "bar" function at the right location.
   13942     SymbolLocationMap::iterator it(
   13943         symbol_locations_.find(function_code->instruction_start()));
   13944     CHECK(it != symbol_locations_.end());
   13945   }
   13946 
   13947   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
   13948     // Check that we have a symbol for "foo" at the right location.
   13949     SymbolLocationMap::iterator it(
   13950         symbol_locations_.find(function_code->instruction_start()));
   13951     CHECK(it != symbol_locations_.end());
   13952   }
   13953 }
   13954 
   13955 
   13956 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
   13957   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
   13958   // Do we have a direct hit on a symbol?
   13959   if (it != symbol_locations_.end()) {
   13960     if (it->first == addr)
   13961       return it->second;
   13962   }
   13963 
   13964   // If not a direct hit, it'll have to be the previous symbol.
   13965   if (it == symbol_locations_.begin())
   13966     return NULL;
   13967 
   13968   --it;
   13969   size_t offs = addr - it->first;
   13970   if (offs < it->second->size)
   13971     return it->second;
   13972 
   13973   return NULL;
   13974 }
   13975 
   13976 
   13977 int SetFunctionEntryHookTest::CountInvocations(
   13978     const char* caller_name, const char* function_name) {
   13979   InvocationMap::iterator it(invocations_.begin());
   13980   int invocations = 0;
   13981   for (; it != invocations_.end(); ++it) {
   13982     SymbolInfo* caller = it->first.first;
   13983     SymbolInfo* function = it->first.second;
   13984 
   13985     // Filter out non-matching functions.
   13986     if (function_name != NULL) {
   13987       if (function->name.find(function_name) == std::string::npos)
   13988         continue;
   13989     }
   13990 
   13991     // Filter out non-matching callers.
   13992     if (caller_name != NULL) {
   13993       if (caller == NULL)
   13994         continue;
   13995       if (caller->name.find(caller_name) == std::string::npos)
   13996         continue;
   13997     }
   13998 
   13999     // It matches add the invocation count to the tally.
   14000     invocations += it->second;
   14001   }
   14002 
   14003   return invocations;
   14004 }
   14005 
   14006 
   14007 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
   14008   v8::HandleScope outer(isolate);
   14009   v8::Local<Context> env = Context::New(isolate);
   14010   env->Enter();
   14011 
   14012   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
   14013   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
   14014   env->Global()->Set(v8_str("obj"), t->NewInstance());
   14015 
   14016   const char* script =
   14017       "function bar() {\n"
   14018       "  var sum = 0;\n"
   14019       "  for (i = 0; i < 100; ++i)\n"
   14020       "    sum = foo(i);\n"
   14021       "  return sum;\n"
   14022       "}\n"
   14023       "function foo(i) { return i * i; }\n"
   14024       "// Invoke on the runtime function.\n"
   14025       "obj.asdf()";
   14026   CompileRun(script);
   14027   bar_func_ = i::Handle<i::JSFunction>::cast(
   14028           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
   14029   ASSERT(!bar_func_.is_null());
   14030 
   14031   foo_func_ =
   14032       i::Handle<i::JSFunction>::cast(
   14033            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
   14034   ASSERT(!foo_func_.is_null());
   14035 
   14036   v8::Handle<v8::Value> value = CompileRun("bar();");
   14037   CHECK(value->IsNumber());
   14038   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
   14039 
   14040   // Test the optimized codegen path.
   14041   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
   14042                      "bar();");
   14043   CHECK(value->IsNumber());
   14044   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
   14045 
   14046   env->Exit();
   14047 }
   14048 
   14049 
   14050 void SetFunctionEntryHookTest::RunTest() {
   14051   // Work in a new isolate throughout.
   14052   v8::Isolate* isolate = v8::Isolate::New();
   14053 
   14054   // Test setting the entry hook on the new isolate.
   14055   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
   14056 
   14057   // Replacing the hook, once set should fail.
   14058   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
   14059 
   14060   {
   14061     v8::Isolate::Scope scope(isolate);
   14062 
   14063     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
   14064 
   14065     RunLoopInNewEnv(isolate);
   14066 
   14067     // Check the exepected invocation counts.
   14068     CHECK_EQ(2, CountInvocations(NULL, "bar"));
   14069     CHECK_EQ(200, CountInvocations("bar", "foo"));
   14070     CHECK_EQ(200, CountInvocations(NULL, "foo"));
   14071 
   14072     // Verify that we have an entry hook on some specific stubs.
   14073     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
   14074     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
   14075     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
   14076   }
   14077   isolate->Dispose();
   14078 
   14079   Reset();
   14080 
   14081   // Make sure a second isolate is unaffected by the previous entry hook.
   14082   isolate = v8::Isolate::New();
   14083   {
   14084     v8::Isolate::Scope scope(isolate);
   14085 
   14086     // Reset the entry count to zero and set the entry hook.
   14087     RunLoopInNewEnv(isolate);
   14088 
   14089     // We should record no invocations in this isolate.
   14090     CHECK_EQ(0, static_cast<int>(invocations_.size()));
   14091   }
   14092   // Since the isolate has been used, we shouldn't be able to set an entry
   14093   // hook anymore.
   14094   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
   14095 
   14096   isolate->Dispose();
   14097 }
   14098 
   14099 
   14100 TEST(SetFunctionEntryHook) {
   14101   // FunctionEntryHook does not work well with experimental natives.
   14102   // Experimental natives are compiled during snapshot deserialization.
   14103   // This test breaks because InstallGetter (function from snapshot that
   14104   // only gets called from experimental natives) is compiled with entry hooks.
   14105   i::FLAG_allow_natives_syntax = true;
   14106   i::FLAG_use_inlining = false;
   14107 
   14108   SetFunctionEntryHookTest test;
   14109   test.RunTest();
   14110 }
   14111 
   14112 
   14113 static i::HashMap* code_map = NULL;
   14114 static i::HashMap* jitcode_line_info = NULL;
   14115 static int saw_bar = 0;
   14116 static int move_events = 0;
   14117 
   14118 
   14119 static bool FunctionNameIs(const char* expected,
   14120                            const v8::JitCodeEvent* event) {
   14121   // Log lines for functions are of the general form:
   14122   // "LazyCompile:<type><function_name>", where the type is one of
   14123   // "*", "~" or "".
   14124   static const char kPreamble[] = "LazyCompile:";
   14125   static size_t kPreambleLen = sizeof(kPreamble) - 1;
   14126 
   14127   if (event->name.len < sizeof(kPreamble) - 1 ||
   14128       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
   14129     return false;
   14130   }
   14131 
   14132   const char* tail = event->name.str + kPreambleLen;
   14133   size_t tail_len = event->name.len - kPreambleLen;
   14134   size_t expected_len = strlen(expected);
   14135   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
   14136     --tail_len;
   14137     ++tail;
   14138   }
   14139 
   14140   // Check for tails like 'bar :1'.
   14141   if (tail_len > expected_len + 2 &&
   14142       tail[expected_len] == ' ' &&
   14143       tail[expected_len + 1] == ':' &&
   14144       tail[expected_len + 2] &&
   14145       !strncmp(tail, expected, expected_len)) {
   14146     return true;
   14147   }
   14148 
   14149   if (tail_len != expected_len)
   14150     return false;
   14151 
   14152   return strncmp(tail, expected, expected_len) == 0;
   14153 }
   14154 
   14155 
   14156 static void event_handler(const v8::JitCodeEvent* event) {
   14157   CHECK(event != NULL);
   14158   CHECK(code_map != NULL);
   14159   CHECK(jitcode_line_info != NULL);
   14160 
   14161   class DummyJitCodeLineInfo {
   14162   };
   14163 
   14164   switch (event->type) {
   14165     case v8::JitCodeEvent::CODE_ADDED: {
   14166         CHECK(event->code_start != NULL);
   14167         CHECK_NE(0, static_cast<int>(event->code_len));
   14168         CHECK(event->name.str != NULL);
   14169         i::HashMap::Entry* entry =
   14170             code_map->Lookup(event->code_start,
   14171                              i::ComputePointerHash(event->code_start),
   14172                              true);
   14173         entry->value = reinterpret_cast<void*>(event->code_len);
   14174 
   14175         if (FunctionNameIs("bar", event)) {
   14176           ++saw_bar;
   14177         }
   14178       }
   14179       break;
   14180 
   14181     case v8::JitCodeEvent::CODE_MOVED: {
   14182         uint32_t hash = i::ComputePointerHash(event->code_start);
   14183         // We would like to never see code move that we haven't seen before,
   14184         // but the code creation event does not happen until the line endings
   14185         // have been calculated (this is so that we can report the line in the
   14186         // script at which the function source is found, see
   14187         // Compiler::RecordFunctionCompilation) and the line endings
   14188         // calculations can cause a GC, which can move the newly created code
   14189         // before its existence can be logged.
   14190         i::HashMap::Entry* entry =
   14191             code_map->Lookup(event->code_start, hash, false);
   14192         if (entry != NULL) {
   14193           ++move_events;
   14194 
   14195           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
   14196           code_map->Remove(event->code_start, hash);
   14197 
   14198           entry = code_map->Lookup(event->new_code_start,
   14199                                    i::ComputePointerHash(event->new_code_start),
   14200                                    true);
   14201           CHECK(entry != NULL);
   14202           entry->value = reinterpret_cast<void*>(event->code_len);
   14203         }
   14204       }
   14205       break;
   14206 
   14207     case v8::JitCodeEvent::CODE_REMOVED:
   14208       // Object/code removal events are currently not dispatched from the GC.
   14209       CHECK(false);
   14210       break;
   14211 
   14212     // For CODE_START_LINE_INFO_RECORDING event, we will create one
   14213     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
   14214     // record it in jitcode_line_info.
   14215     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
   14216         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
   14217         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
   14218         temp_event->user_data = line_info;
   14219         i::HashMap::Entry* entry =
   14220             jitcode_line_info->Lookup(line_info,
   14221                                       i::ComputePointerHash(line_info),
   14222                                       true);
   14223         entry->value = reinterpret_cast<void*>(line_info);
   14224       }
   14225       break;
   14226     // For these two events, we will check whether the event->user_data
   14227     // data structure is created before during CODE_START_LINE_INFO_RECORDING
   14228     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
   14229     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
   14230         CHECK(event->user_data != NULL);
   14231         uint32_t hash = i::ComputePointerHash(event->user_data);
   14232         i::HashMap::Entry* entry =
   14233             jitcode_line_info->Lookup(event->user_data, hash, false);
   14234         CHECK(entry != NULL);
   14235         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
   14236       }
   14237       break;
   14238 
   14239     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
   14240         CHECK(event->user_data != NULL);
   14241         uint32_t hash = i::ComputePointerHash(event->user_data);
   14242         i::HashMap::Entry* entry =
   14243             jitcode_line_info->Lookup(event->user_data, hash, false);
   14244         CHECK(entry != NULL);
   14245       }
   14246       break;
   14247 
   14248     default:
   14249       // Impossible event.
   14250       CHECK(false);
   14251       break;
   14252   }
   14253 }
   14254 
   14255 
   14256 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
   14257   i::FLAG_stress_compaction = true;
   14258   i::FLAG_incremental_marking = false;
   14259   if (i::FLAG_never_compact) return;
   14260   const char* script =
   14261     "function bar() {"
   14262     "  var sum = 0;"
   14263     "  for (i = 0; i < 100; ++i)"
   14264     "    sum = foo(i);"
   14265     "  return sum;"
   14266     "}"
   14267     "function foo(i) { return i * i; };"
   14268     "bar();";
   14269 
   14270   // Run this test in a new isolate to make sure we don't
   14271   // have remnants of state from other code.
   14272   v8::Isolate* isolate = v8::Isolate::New();
   14273   isolate->Enter();
   14274   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   14275   i::Heap* heap = i_isolate->heap();
   14276 
   14277   {
   14278     v8::HandleScope scope(isolate);
   14279     i::HashMap code(MatchPointers);
   14280     code_map = &code;
   14281 
   14282     i::HashMap lineinfo(MatchPointers);
   14283     jitcode_line_info = &lineinfo;
   14284 
   14285     saw_bar = 0;
   14286     move_events = 0;
   14287 
   14288     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
   14289 
   14290     // Generate new code objects sparsely distributed across several
   14291     // different fragmented code-space pages.
   14292     const int kIterations = 10;
   14293     for (int i = 0; i < kIterations; ++i) {
   14294       LocalContext env(isolate);
   14295       i::AlwaysAllocateScope always_allocate(i_isolate);
   14296       SimulateFullSpace(heap->code_space());
   14297       CompileRun(script);
   14298 
   14299       // Keep a strong reference to the code object in the handle scope.
   14300       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
   14301           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
   14302       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
   14303           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
   14304 
   14305       // Clear the compilation cache to get more wastage.
   14306       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
   14307     }
   14308 
   14309     // Force code movement.
   14310     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
   14311 
   14312     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
   14313 
   14314     CHECK_LE(kIterations, saw_bar);
   14315     CHECK_LT(0, move_events);
   14316 
   14317     code_map = NULL;
   14318     jitcode_line_info = NULL;
   14319   }
   14320 
   14321   isolate->Exit();
   14322   isolate->Dispose();
   14323 
   14324   // Do this in a new isolate.
   14325   isolate = v8::Isolate::New();
   14326   isolate->Enter();
   14327 
   14328   // Verify that we get callbacks for existing code objects when we
   14329   // request enumeration of existing code.
   14330   {
   14331     v8::HandleScope scope(isolate);
   14332     LocalContext env(isolate);
   14333     CompileRun(script);
   14334 
   14335     // Now get code through initial iteration.
   14336     i::HashMap code(MatchPointers);
   14337     code_map = &code;
   14338 
   14339     i::HashMap lineinfo(MatchPointers);
   14340     jitcode_line_info = &lineinfo;
   14341 
   14342     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
   14343     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
   14344 
   14345     jitcode_line_info = NULL;
   14346     // We expect that we got some events. Note that if we could get code removal
   14347     // notifications, we could compare two collections, one created by listening
   14348     // from the time of creation of an isolate, and the other by subscribing
   14349     // with EnumExisting.
   14350     CHECK_LT(0, code.occupancy());
   14351 
   14352     code_map = NULL;
   14353   }
   14354 
   14355   isolate->Exit();
   14356   isolate->Dispose();
   14357 }
   14358 
   14359 
   14360 THREADED_TEST(ExternalAllocatedMemory) {
   14361   v8::Isolate* isolate = CcTest::isolate();
   14362   v8::HandleScope outer(isolate);
   14363   v8::Local<Context> env(Context::New(isolate));
   14364   CHECK(!env.IsEmpty());
   14365   const int64_t kSize = 1024*1024;
   14366   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
   14367   CHECK_EQ(baseline + kSize,
   14368            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
   14369   CHECK_EQ(baseline,
   14370            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
   14371 }
   14372 
   14373 
   14374 // Regression test for issue 54, object templates with internal fields
   14375 // but no accessors or interceptors did not get their internal field
   14376 // count set on instances.
   14377 THREADED_TEST(Regress54) {
   14378   LocalContext context;
   14379   v8::Isolate* isolate = context->GetIsolate();
   14380   v8::HandleScope outer(isolate);
   14381   static v8::Persistent<v8::ObjectTemplate> templ;
   14382   if (templ.IsEmpty()) {
   14383     v8::EscapableHandleScope inner(isolate);
   14384     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
   14385     local->SetInternalFieldCount(1);
   14386     templ.Reset(isolate, inner.Escape(local));
   14387   }
   14388   v8::Handle<v8::Object> result =
   14389       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
   14390   CHECK_EQ(1, result->InternalFieldCount());
   14391 }
   14392 
   14393 
   14394 // If part of the threaded tests, this test makes ThreadingTest fail
   14395 // on mac.
   14396 TEST(CatchStackOverflow) {
   14397   LocalContext context;
   14398   v8::HandleScope scope(context->GetIsolate());
   14399   v8::TryCatch try_catch;
   14400   v8::Handle<v8::Value> result = CompileRun(
   14401     "function f() {"
   14402     "  return f();"
   14403     "}"
   14404     ""
   14405     "f();");
   14406   CHECK(result.IsEmpty());
   14407 }
   14408 
   14409 
   14410 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
   14411                                     const char* resource_name,
   14412                                     int line_offset) {
   14413   v8::HandleScope scope(CcTest::isolate());
   14414   v8::TryCatch try_catch;
   14415   v8::Handle<v8::Value> result = script->Run();
   14416   CHECK(result.IsEmpty());
   14417   CHECK(try_catch.HasCaught());
   14418   v8::Handle<v8::Message> message = try_catch.Message();
   14419   CHECK(!message.IsEmpty());
   14420   CHECK_EQ(10 + line_offset, message->GetLineNumber());
   14421   CHECK_EQ(91, message->GetStartPosition());
   14422   CHECK_EQ(92, message->GetEndPosition());
   14423   CHECK_EQ(2, message->GetStartColumn());
   14424   CHECK_EQ(3, message->GetEndColumn());
   14425   v8::String::Utf8Value line(message->GetSourceLine());
   14426   CHECK_EQ("  throw 'nirk';", *line);
   14427   v8::String::Utf8Value name(message->GetScriptResourceName());
   14428   CHECK_EQ(resource_name, *name);
   14429 }
   14430 
   14431 
   14432 THREADED_TEST(TryCatchSourceInfo) {
   14433   LocalContext context;
   14434   v8::HandleScope scope(context->GetIsolate());
   14435   v8::Local<v8::String> source = v8_str(
   14436       "function Foo() {\n"
   14437       "  return Bar();\n"
   14438       "}\n"
   14439       "\n"
   14440       "function Bar() {\n"
   14441       "  return Baz();\n"
   14442       "}\n"
   14443       "\n"
   14444       "function Baz() {\n"
   14445       "  throw 'nirk';\n"
   14446       "}\n"
   14447       "\n"
   14448       "Foo();\n");
   14449 
   14450   const char* resource_name;
   14451   v8::Handle<v8::Script> script;
   14452   resource_name = "test.js";
   14453   script = CompileWithOrigin(source, resource_name);
   14454   CheckTryCatchSourceInfo(script, resource_name, 0);
   14455 
   14456   resource_name = "test1.js";
   14457   v8::ScriptOrigin origin1(
   14458       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
   14459   script = v8::Script::Compile(source, &origin1);
   14460   CheckTryCatchSourceInfo(script, resource_name, 0);
   14461 
   14462   resource_name = "test2.js";
   14463   v8::ScriptOrigin origin2(
   14464       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
   14465       v8::Integer::New(context->GetIsolate(), 7));
   14466   script = v8::Script::Compile(source, &origin2);
   14467   CheckTryCatchSourceInfo(script, resource_name, 7);
   14468 }
   14469 
   14470 
   14471 THREADED_TEST(CompilationCache) {
   14472   LocalContext context;
   14473   v8::HandleScope scope(context->GetIsolate());
   14474   v8::Handle<v8::String> source0 =
   14475       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
   14476   v8::Handle<v8::String> source1 =
   14477       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
   14478   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
   14479   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
   14480   v8::Handle<v8::Script> script2 =
   14481       v8::Script::Compile(source0);  // different origin
   14482   CHECK_EQ(1234, script0->Run()->Int32Value());
   14483   CHECK_EQ(1234, script1->Run()->Int32Value());
   14484   CHECK_EQ(1234, script2->Run()->Int32Value());
   14485 }
   14486 
   14487 
   14488 static void FunctionNameCallback(
   14489     const v8::FunctionCallbackInfo<v8::Value>& args) {
   14490   ApiTestFuzzer::Fuzz();
   14491   args.GetReturnValue().Set(v8_num(42));
   14492 }
   14493 
   14494 
   14495 THREADED_TEST(CallbackFunctionName) {
   14496   LocalContext context;
   14497   v8::Isolate* isolate = context->GetIsolate();
   14498   v8::HandleScope scope(isolate);
   14499   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
   14500   t->Set(v8_str("asdf"),
   14501          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
   14502   context->Global()->Set(v8_str("obj"), t->NewInstance());
   14503   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
   14504   CHECK(value->IsString());
   14505   v8::String::Utf8Value name(value);
   14506   CHECK_EQ("asdf", *name);
   14507 }
   14508 
   14509 
   14510 THREADED_TEST(DateAccess) {
   14511   LocalContext context;
   14512   v8::HandleScope scope(context->GetIsolate());
   14513   v8::Handle<v8::Value> date =
   14514       v8::Date::New(context->GetIsolate(), 1224744689038.0);
   14515   CHECK(date->IsDate());
   14516   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
   14517 }
   14518 
   14519 
   14520 void CheckProperties(v8::Isolate* isolate,
   14521                      v8::Handle<v8::Value> val,
   14522                      int elmc,
   14523                      const char* elmv[]) {
   14524   v8::Handle<v8::Object> obj = val.As<v8::Object>();
   14525   v8::Handle<v8::Array> props = obj->GetPropertyNames();
   14526   CHECK_EQ(elmc, props->Length());
   14527   for (int i = 0; i < elmc; i++) {
   14528     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
   14529     CHECK_EQ(elmv[i], *elm);
   14530   }
   14531 }
   14532 
   14533 
   14534 void CheckOwnProperties(v8::Isolate* isolate,
   14535                         v8::Handle<v8::Value> val,
   14536                         int elmc,
   14537                         const char* elmv[]) {
   14538   v8::Handle<v8::Object> obj = val.As<v8::Object>();
   14539   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
   14540   CHECK_EQ(elmc, props->Length());
   14541   for (int i = 0; i < elmc; i++) {
   14542     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
   14543     CHECK_EQ(elmv[i], *elm);
   14544   }
   14545 }
   14546 
   14547 
   14548 THREADED_TEST(PropertyEnumeration) {
   14549   LocalContext context;
   14550   v8::Isolate* isolate = context->GetIsolate();
   14551   v8::HandleScope scope(isolate);
   14552   v8::Handle<v8::Value> obj = CompileRun(
   14553       "var result = [];"
   14554       "result[0] = {};"
   14555       "result[1] = {a: 1, b: 2};"
   14556       "result[2] = [1, 2, 3];"
   14557       "var proto = {x: 1, y: 2, z: 3};"
   14558       "var x = { __proto__: proto, w: 0, z: 1 };"
   14559       "result[3] = x;"
   14560       "result;");
   14561   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
   14562   CHECK_EQ(4, elms->Length());
   14563   int elmc0 = 0;
   14564   const char** elmv0 = NULL;
   14565   CheckProperties(
   14566       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
   14567   CheckOwnProperties(
   14568       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
   14569   int elmc1 = 2;
   14570   const char* elmv1[] = {"a", "b"};
   14571   CheckProperties(
   14572       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
   14573   CheckOwnProperties(
   14574       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
   14575   int elmc2 = 3;
   14576   const char* elmv2[] = {"0", "1", "2"};
   14577   CheckProperties(
   14578       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
   14579   CheckOwnProperties(
   14580       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
   14581   int elmc3 = 4;
   14582   const char* elmv3[] = {"w", "z", "x", "y"};
   14583   CheckProperties(
   14584       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
   14585   int elmc4 = 2;
   14586   const char* elmv4[] = {"w", "z"};
   14587   CheckOwnProperties(
   14588       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
   14589 }
   14590 
   14591 
   14592 THREADED_TEST(PropertyEnumeration2) {
   14593   LocalContext context;
   14594   v8::Isolate* isolate = context->GetIsolate();
   14595   v8::HandleScope scope(isolate);
   14596   v8::Handle<v8::Value> obj = CompileRun(
   14597       "var result = [];"
   14598       "result[0] = {};"
   14599       "result[1] = {a: 1, b: 2};"
   14600       "result[2] = [1, 2, 3];"
   14601       "var proto = {x: 1, y: 2, z: 3};"
   14602       "var x = { __proto__: proto, w: 0, z: 1 };"
   14603       "result[3] = x;"
   14604       "result;");
   14605   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
   14606   CHECK_EQ(4, elms->Length());
   14607   int elmc0 = 0;
   14608   const char** elmv0 = NULL;
   14609   CheckProperties(isolate,
   14610                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
   14611 
   14612   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
   14613   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
   14614   CHECK_EQ(0, props->Length());
   14615   for (uint32_t i = 0; i < props->Length(); i++) {
   14616     printf("p[%d]\n", i);
   14617   }
   14618 }
   14619 
   14620 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
   14621                                   Local<Value> name,
   14622                                   v8::AccessType type,
   14623                                   Local<Value> data) {
   14624   return type != v8::ACCESS_SET;
   14625 }
   14626 
   14627 
   14628 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
   14629                                     uint32_t key,
   14630                                     v8::AccessType type,
   14631                                     Local<Value> data) {
   14632   return type != v8::ACCESS_SET;
   14633 }
   14634 
   14635 
   14636 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
   14637   LocalContext context;
   14638   v8::Isolate* isolate = context->GetIsolate();
   14639   v8::HandleScope scope(isolate);
   14640   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   14641   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
   14642                                  IndexedSetAccessBlocker);
   14643   templ->Set(v8_str("x"), v8::True(isolate));
   14644   Local<v8::Object> instance = templ->NewInstance();
   14645   context->Global()->Set(v8_str("obj"), instance);
   14646   Local<Value> value = CompileRun("obj.x");
   14647   CHECK(value->BooleanValue());
   14648 }
   14649 
   14650 
   14651 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
   14652                                   Local<Value> name,
   14653                                   v8::AccessType type,
   14654                                   Local<Value> data) {
   14655   return false;
   14656 }
   14657 
   14658 
   14659 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
   14660                                     uint32_t key,
   14661                                     v8::AccessType type,
   14662                                     Local<Value> data) {
   14663   return false;
   14664 }
   14665 
   14666 
   14667 
   14668 THREADED_TEST(AccessChecksReenabledCorrectly) {
   14669   LocalContext context;
   14670   v8::Isolate* isolate = context->GetIsolate();
   14671   v8::HandleScope scope(isolate);
   14672   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   14673   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
   14674                                  IndexedGetAccessBlocker);
   14675   templ->Set(v8_str("a"), v8_str("a"));
   14676   // Add more than 8 (see kMaxFastProperties) properties
   14677   // so that the constructor will force copying map.
   14678   // Cannot sprintf, gcc complains unsafety.
   14679   char buf[4];
   14680   for (char i = '0'; i <= '9' ; i++) {
   14681     buf[0] = i;
   14682     for (char j = '0'; j <= '9'; j++) {
   14683       buf[1] = j;
   14684       for (char k = '0'; k <= '9'; k++) {
   14685         buf[2] = k;
   14686         buf[3] = 0;
   14687         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
   14688       }
   14689     }
   14690   }
   14691 
   14692   Local<v8::Object> instance_1 = templ->NewInstance();
   14693   context->Global()->Set(v8_str("obj_1"), instance_1);
   14694 
   14695   Local<Value> value_1 = CompileRun("obj_1.a");
   14696   CHECK(value_1->IsUndefined());
   14697 
   14698   Local<v8::Object> instance_2 = templ->NewInstance();
   14699   context->Global()->Set(v8_str("obj_2"), instance_2);
   14700 
   14701   Local<Value> value_2 = CompileRun("obj_2.a");
   14702   CHECK(value_2->IsUndefined());
   14703 }
   14704 
   14705 
   14706 // This tests that access check information remains on the global
   14707 // object template when creating contexts.
   14708 THREADED_TEST(AccessControlRepeatedContextCreation) {
   14709   v8::Isolate* isolate = CcTest::isolate();
   14710   v8::HandleScope handle_scope(isolate);
   14711   v8::Handle<v8::ObjectTemplate> global_template =
   14712       v8::ObjectTemplate::New(isolate);
   14713   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
   14714                                            IndexedSetAccessBlocker);
   14715   i::Handle<i::ObjectTemplateInfo> internal_template =
   14716       v8::Utils::OpenHandle(*global_template);
   14717   CHECK(!internal_template->constructor()->IsUndefined());
   14718   i::Handle<i::FunctionTemplateInfo> constructor(
   14719       i::FunctionTemplateInfo::cast(internal_template->constructor()));
   14720   CHECK(!constructor->access_check_info()->IsUndefined());
   14721   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
   14722   CHECK(!context0.IsEmpty());
   14723   CHECK(!constructor->access_check_info()->IsUndefined());
   14724 }
   14725 
   14726 
   14727 THREADED_TEST(TurnOnAccessCheck) {
   14728   v8::Isolate* isolate = CcTest::isolate();
   14729   v8::HandleScope handle_scope(isolate);
   14730 
   14731   // Create an environment with access check to the global object disabled by
   14732   // default.
   14733   v8::Handle<v8::ObjectTemplate> global_template =
   14734       v8::ObjectTemplate::New(isolate);
   14735   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
   14736                                            IndexedGetAccessBlocker,
   14737                                            v8::Handle<v8::Value>(),
   14738                                            false);
   14739   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
   14740   Context::Scope context_scope(context);
   14741 
   14742   // Set up a property and a number of functions.
   14743   context->Global()->Set(v8_str("a"), v8_num(1));
   14744   CompileRun("function f1() {return a;}"
   14745              "function f2() {return a;}"
   14746              "function g1() {return h();}"
   14747              "function g2() {return h();}"
   14748              "function h() {return 1;}");
   14749   Local<Function> f1 =
   14750       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
   14751   Local<Function> f2 =
   14752       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
   14753   Local<Function> g1 =
   14754       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
   14755   Local<Function> g2 =
   14756       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
   14757   Local<Function> h =
   14758       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
   14759 
   14760   // Get the global object.
   14761   v8::Handle<v8::Object> global = context->Global();
   14762 
   14763   // Call f1 one time and f2 a number of times. This will ensure that f1 still
   14764   // uses the runtime system to retreive property a whereas f2 uses global load
   14765   // inline cache.
   14766   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
   14767   for (int i = 0; i < 4; i++) {
   14768     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
   14769   }
   14770 
   14771   // Same for g1 and g2.
   14772   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
   14773   for (int i = 0; i < 4; i++) {
   14774     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
   14775   }
   14776 
   14777   // Detach the global and turn on access check.
   14778   Local<Object> hidden_global = Local<Object>::Cast(
   14779       context->Global()->GetPrototype());
   14780   context->DetachGlobal();
   14781   hidden_global->TurnOnAccessCheck();
   14782 
   14783   // Failing access check to property get results in undefined.
   14784   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
   14785   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
   14786 
   14787   // Failing access check to function call results in exception.
   14788   CHECK(g1->Call(global, 0, NULL).IsEmpty());
   14789   CHECK(g2->Call(global, 0, NULL).IsEmpty());
   14790 
   14791   // No failing access check when just returning a constant.
   14792   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
   14793 }
   14794 
   14795 
   14796 static const char* kPropertyA = "a";
   14797 static const char* kPropertyH = "h";
   14798 
   14799 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
   14800                                        Local<Value> name,
   14801                                        v8::AccessType type,
   14802                                        Local<Value> data) {
   14803   if (!name->IsString()) return false;
   14804   i::Handle<i::String> name_handle =
   14805       v8::Utils::OpenHandle(String::Cast(*name));
   14806   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
   14807       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
   14808 }
   14809 
   14810 
   14811 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
   14812   v8::Isolate* isolate = CcTest::isolate();
   14813   v8::HandleScope handle_scope(isolate);
   14814 
   14815   // Create an environment with access check to the global object disabled by
   14816   // default. When the registered access checker will block access to properties
   14817   // a and h.
   14818   v8::Handle<v8::ObjectTemplate> global_template =
   14819      v8::ObjectTemplate::New(isolate);
   14820   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
   14821                                            IndexedGetAccessBlocker,
   14822                                            v8::Handle<v8::Value>(),
   14823                                            false);
   14824   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
   14825   Context::Scope context_scope(context);
   14826 
   14827   // Set up a property and a number of functions.
   14828   context->Global()->Set(v8_str("a"), v8_num(1));
   14829   static const char* source = "function f1() {return a;}"
   14830                               "function f2() {return a;}"
   14831                               "function g1() {return h();}"
   14832                               "function g2() {return h();}"
   14833                               "function h() {return 1;}";
   14834 
   14835   CompileRun(source);
   14836   Local<Function> f1;
   14837   Local<Function> f2;
   14838   Local<Function> g1;
   14839   Local<Function> g2;
   14840   Local<Function> h;
   14841   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
   14842   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
   14843   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
   14844   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
   14845   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
   14846 
   14847   // Get the global object.
   14848   v8::Handle<v8::Object> global = context->Global();
   14849 
   14850   // Call f1 one time and f2 a number of times. This will ensure that f1 still
   14851   // uses the runtime system to retreive property a whereas f2 uses global load
   14852   // inline cache.
   14853   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
   14854   for (int i = 0; i < 4; i++) {
   14855     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
   14856   }
   14857 
   14858   // Same for g1 and g2.
   14859   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
   14860   for (int i = 0; i < 4; i++) {
   14861     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
   14862   }
   14863 
   14864   // Detach the global and turn on access check now blocking access to property
   14865   // a and function h.
   14866   Local<Object> hidden_global = Local<Object>::Cast(
   14867       context->Global()->GetPrototype());
   14868   context->DetachGlobal();
   14869   hidden_global->TurnOnAccessCheck();
   14870 
   14871   // Failing access check to property get results in undefined.
   14872   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
   14873   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
   14874 
   14875   // Failing access check to function call results in exception.
   14876   CHECK(g1->Call(global, 0, NULL).IsEmpty());
   14877   CHECK(g2->Call(global, 0, NULL).IsEmpty());
   14878 
   14879   // No failing access check when just returning a constant.
   14880   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
   14881 
   14882   // Now compile the source again. And get the newly compiled functions, except
   14883   // for h for which access is blocked.
   14884   CompileRun(source);
   14885   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
   14886   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
   14887   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
   14888   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
   14889   CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
   14890 
   14891   // Failing access check to property get results in undefined.
   14892   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
   14893   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
   14894 
   14895   // Failing access check to function call results in exception.
   14896   CHECK(g1->Call(global, 0, NULL).IsEmpty());
   14897   CHECK(g2->Call(global, 0, NULL).IsEmpty());
   14898 }
   14899 
   14900 
   14901 // Tests that ScriptData can be serialized and deserialized.
   14902 TEST(PreCompileSerialization) {
   14903   v8::V8::Initialize();
   14904   LocalContext env;
   14905   v8::Isolate* isolate = env->GetIsolate();
   14906   HandleScope handle_scope(isolate);
   14907 
   14908   i::FLAG_min_preparse_length = 0;
   14909   const char* script = "function foo(a) { return a+1; }";
   14910   v8::ScriptCompiler::Source source(v8_str(script));
   14911   v8::ScriptCompiler::Compile(isolate, &source,
   14912                               v8::ScriptCompiler::kProduceDataToCache);
   14913   // Serialize.
   14914   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
   14915   char* serialized_data = i::NewArray<char>(cd->length);
   14916   i::MemCopy(serialized_data, cd->data, cd->length);
   14917 
   14918   // Deserialize.
   14919   i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
   14920 
   14921   // Verify that the original is the same as the deserialized.
   14922   CHECK_EQ(cd->length, deserialized->Length());
   14923   CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
   14924 
   14925   delete deserialized;
   14926   i::DeleteArray(serialized_data);
   14927 }
   14928 
   14929 
   14930 // Attempts to deserialize bad data.
   14931 TEST(PreCompileDeserializationError) {
   14932   v8::V8::Initialize();
   14933   const char* data = "DONT CARE";
   14934   int invalid_size = 3;
   14935   i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
   14936   CHECK_EQ(NULL, sd);
   14937 }
   14938 
   14939 
   14940 TEST(CompileWithInvalidCachedData) {
   14941   v8::V8::Initialize();
   14942   v8::Isolate* isolate = CcTest::isolate();
   14943   LocalContext context;
   14944   v8::HandleScope scope(context->GetIsolate());
   14945   i::FLAG_min_preparse_length = 0;
   14946 
   14947   const char* script = "function foo(){ return 5;}\n"
   14948       "function bar(){ return 6 + 7;}  foo();";
   14949   v8::ScriptCompiler::Source source(v8_str(script));
   14950   v8::ScriptCompiler::Compile(isolate, &source,
   14951                               v8::ScriptCompiler::kProduceDataToCache);
   14952   // source owns its cached data. Create a ScriptData based on it. The user
   14953   // never needs to create ScriptDatas any more; we only need it here because we
   14954   // want to modify the data before passing it back.
   14955   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
   14956   // ScriptData does not take ownership of the buffers passed to it.
   14957   i::ScriptData* sd =
   14958       i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
   14959   CHECK(!sd->HasError());
   14960   // ScriptData private implementation details
   14961   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
   14962   const int kFunctionEntrySize = i::FunctionEntry::kSize;
   14963   const int kFunctionEntryStartOffset = 0;
   14964   const int kFunctionEntryEndOffset = 1;
   14965   unsigned* sd_data =
   14966       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
   14967 
   14968   // Overwrite function bar's end position with 0.
   14969   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
   14970   v8::TryCatch try_catch;
   14971 
   14972   // Make the script slightly different so that we don't hit the compilation
   14973   // cache. Don't change the lenghts of tokens.
   14974   const char* script2 = "function foo(){ return 6;}\n"
   14975       "function bar(){ return 6 + 7;}  foo();";
   14976   v8::ScriptCompiler::Source source2(
   14977       v8_str(script2),
   14978       // CachedData doesn't take ownership of the buffers, Source takes
   14979       // ownership of CachedData.
   14980       new v8::ScriptCompiler::CachedData(
   14981           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
   14982   Local<v8::UnboundScript> compiled_script =
   14983       v8::ScriptCompiler::CompileUnbound(isolate, &source2);
   14984 
   14985   CHECK(try_catch.HasCaught());
   14986   {
   14987     String::Utf8Value exception_value(try_catch.Message()->Get());
   14988     CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
   14989              *exception_value);
   14990   }
   14991 
   14992   try_catch.Reset();
   14993   delete sd;
   14994 
   14995   // Overwrite function bar's start position with 200. The function entry will
   14996   // not be found when searching for it by position, and the compilation fails.
   14997 
   14998   // ScriptData does not take ownership of the buffers passed to it.
   14999   sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
   15000   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
   15001   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
   15002       200;
   15003   const char* script3 = "function foo(){ return 7;}\n"
   15004       "function bar(){ return 6 + 7;}  foo();";
   15005   v8::ScriptCompiler::Source source3(
   15006       v8_str(script3),
   15007       new v8::ScriptCompiler::CachedData(
   15008           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
   15009   compiled_script =
   15010       v8::ScriptCompiler::CompileUnbound(isolate, &source3);
   15011   CHECK(try_catch.HasCaught());
   15012   {
   15013     String::Utf8Value exception_value(try_catch.Message()->Get());
   15014     CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
   15015              *exception_value);
   15016   }
   15017   CHECK(compiled_script.IsEmpty());
   15018   try_catch.Reset();
   15019   delete sd;
   15020 
   15021   // Try passing in cached data which is obviously invalid (wrong length).
   15022   sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
   15023   const char* script4 =
   15024       "function foo(){ return 8;}\n"
   15025       "function bar(){ return 6 + 7;}  foo();";
   15026   v8::ScriptCompiler::Source source4(
   15027       v8_str(script4),
   15028       new v8::ScriptCompiler::CachedData(
   15029           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
   15030   compiled_script =
   15031       v8::ScriptCompiler::CompileUnbound(isolate, &source4);
   15032   CHECK(try_catch.HasCaught());
   15033   {
   15034     String::Utf8Value exception_value(try_catch.Message()->Get());
   15035     CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
   15036              *exception_value);
   15037   }
   15038   CHECK(compiled_script.IsEmpty());
   15039   delete sd;
   15040 }
   15041 
   15042 
   15043 // This tests that we do not allow dictionary load/call inline caches
   15044 // to use functions that have not yet been compiled.  The potential
   15045 // problem of loading a function that has not yet been compiled can
   15046 // arise because we share code between contexts via the compilation
   15047 // cache.
   15048 THREADED_TEST(DictionaryICLoadedFunction) {
   15049   v8::HandleScope scope(CcTest::isolate());
   15050   // Test LoadIC.
   15051   for (int i = 0; i < 2; i++) {
   15052     LocalContext context;
   15053     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
   15054     context->Global()->Delete(v8_str("tmp"));
   15055     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
   15056   }
   15057   // Test CallIC.
   15058   for (int i = 0; i < 2; i++) {
   15059     LocalContext context;
   15060     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
   15061     context->Global()->Delete(v8_str("tmp"));
   15062     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
   15063   }
   15064 }
   15065 
   15066 
   15067 // Test that cross-context new calls use the context of the callee to
   15068 // create the new JavaScript object.
   15069 THREADED_TEST(CrossContextNew) {
   15070   v8::Isolate* isolate = CcTest::isolate();
   15071   v8::HandleScope scope(isolate);
   15072   v8::Local<Context> context0 = Context::New(isolate);
   15073   v8::Local<Context> context1 = Context::New(isolate);
   15074 
   15075   // Allow cross-domain access.
   15076   Local<String> token = v8_str("<security token>");
   15077   context0->SetSecurityToken(token);
   15078   context1->SetSecurityToken(token);
   15079 
   15080   // Set an 'x' property on the Object prototype and define a
   15081   // constructor function in context0.
   15082   context0->Enter();
   15083   CompileRun("Object.prototype.x = 42; function C() {};");
   15084   context0->Exit();
   15085 
   15086   // Call the constructor function from context0 and check that the
   15087   // result has the 'x' property.
   15088   context1->Enter();
   15089   context1->Global()->Set(v8_str("other"), context0->Global());
   15090   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
   15091   CHECK(value->IsInt32());
   15092   CHECK_EQ(42, value->Int32Value());
   15093   context1->Exit();
   15094 }
   15095 
   15096 
   15097 // Verify that we can clone an object
   15098 TEST(ObjectClone) {
   15099   LocalContext env;
   15100   v8::Isolate* isolate = env->GetIsolate();
   15101   v8::HandleScope scope(isolate);
   15102 
   15103   const char* sample =
   15104     "var rv = {};"      \
   15105     "rv.alpha = 'hello';" \
   15106     "rv.beta = 123;"     \
   15107     "rv;";
   15108 
   15109   // Create an object, verify basics.
   15110   Local<Value> val = CompileRun(sample);
   15111   CHECK(val->IsObject());
   15112   Local<v8::Object> obj = val.As<v8::Object>();
   15113   obj->Set(v8_str("gamma"), v8_str("cloneme"));
   15114 
   15115   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
   15116   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
   15117   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
   15118 
   15119   // Clone it.
   15120   Local<v8::Object> clone = obj->Clone();
   15121   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
   15122   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
   15123   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
   15124 
   15125   // Set a property on the clone, verify each object.
   15126   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
   15127   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
   15128   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
   15129 }
   15130 
   15131 
   15132 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
   15133  public:
   15134   explicit AsciiVectorResource(i::Vector<const char> vector)
   15135       : data_(vector) {}
   15136   virtual ~AsciiVectorResource() {}
   15137   virtual size_t length() const { return data_.length(); }
   15138   virtual const char* data() const { return data_.start(); }
   15139  private:
   15140   i::Vector<const char> data_;
   15141 };
   15142 
   15143 
   15144 class UC16VectorResource : public v8::String::ExternalStringResource {
   15145  public:
   15146   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
   15147       : data_(vector) {}
   15148   virtual ~UC16VectorResource() {}
   15149   virtual size_t length() const { return data_.length(); }
   15150   virtual const i::uc16* data() const { return data_.start(); }
   15151  private:
   15152   i::Vector<const i::uc16> data_;
   15153 };
   15154 
   15155 
   15156 static void MorphAString(i::String* string,
   15157                          AsciiVectorResource* ascii_resource,
   15158                          UC16VectorResource* uc16_resource) {
   15159   CHECK(i::StringShape(string).IsExternal());
   15160   if (string->IsOneByteRepresentation()) {
   15161     // Check old map is not internalized or long.
   15162     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
   15163     // Morph external string to be TwoByte string.
   15164     string->set_map(CcTest::heap()->external_string_map());
   15165     i::ExternalTwoByteString* morphed =
   15166          i::ExternalTwoByteString::cast(string);
   15167     morphed->set_resource(uc16_resource);
   15168   } else {
   15169     // Check old map is not internalized or long.
   15170     CHECK(string->map() == CcTest::heap()->external_string_map());
   15171     // Morph external string to be ASCII string.
   15172     string->set_map(CcTest::heap()->external_ascii_string_map());
   15173     i::ExternalAsciiString* morphed =
   15174          i::ExternalAsciiString::cast(string);
   15175     morphed->set_resource(ascii_resource);
   15176   }
   15177 }
   15178 
   15179 
   15180 // Test that we can still flatten a string if the components it is built up
   15181 // from have been turned into 16 bit strings in the mean time.
   15182 THREADED_TEST(MorphCompositeStringTest) {
   15183   char utf_buffer[129];
   15184   const char* c_string = "Now is the time for all good men"
   15185                          " to come to the aid of the party";
   15186   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
   15187   {
   15188     LocalContext env;
   15189     i::Factory* factory = CcTest::i_isolate()->factory();
   15190     v8::HandleScope scope(env->GetIsolate());
   15191     AsciiVectorResource ascii_resource(
   15192         i::Vector<const char>(c_string, i::StrLength(c_string)));
   15193     UC16VectorResource uc16_resource(
   15194         i::Vector<const uint16_t>(two_byte_string,
   15195                                   i::StrLength(c_string)));
   15196 
   15197     Local<String> lhs(v8::Utils::ToLocal(
   15198         factory->NewExternalStringFromAscii(&ascii_resource)
   15199             .ToHandleChecked()));
   15200     Local<String> rhs(v8::Utils::ToLocal(
   15201         factory->NewExternalStringFromAscii(&ascii_resource)
   15202             .ToHandleChecked()));
   15203 
   15204     env->Global()->Set(v8_str("lhs"), lhs);
   15205     env->Global()->Set(v8_str("rhs"), rhs);
   15206 
   15207     CompileRun(
   15208         "var cons = lhs + rhs;"
   15209         "var slice = lhs.substring(1, lhs.length - 1);"
   15210         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
   15211 
   15212     CHECK(lhs->IsOneByte());
   15213     CHECK(rhs->IsOneByte());
   15214 
   15215     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
   15216     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
   15217 
   15218     // This should UTF-8 without flattening, since everything is ASCII.
   15219     Handle<String> cons = v8_compile("cons")->Run().As<String>();
   15220     CHECK_EQ(128, cons->Utf8Length());
   15221     int nchars = -1;
   15222     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
   15223     CHECK_EQ(128, nchars);
   15224     CHECK_EQ(0, strcmp(
   15225         utf_buffer,
   15226         "Now is the time for all good men to come to the aid of the party"
   15227         "Now is the time for all good men to come to the aid of the party"));
   15228 
   15229     // Now do some stuff to make sure the strings are flattened, etc.
   15230     CompileRun(
   15231         "/[^a-z]/.test(cons);"
   15232         "/[^a-z]/.test(slice);"
   15233         "/[^a-z]/.test(slice_on_cons);");
   15234     const char* expected_cons =
   15235         "Now is the time for all good men to come to the aid of the party"
   15236         "Now is the time for all good men to come to the aid of the party";
   15237     const char* expected_slice =
   15238         "ow is the time for all good men to come to the aid of the part";
   15239     const char* expected_slice_on_cons =
   15240         "ow is the time for all good men to come to the aid of the party"
   15241         "Now is the time for all good men to come to the aid of the part";
   15242     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
   15243              env->Global()->Get(v8_str("cons")));
   15244     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
   15245              env->Global()->Get(v8_str("slice")));
   15246     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
   15247              env->Global()->Get(v8_str("slice_on_cons")));
   15248   }
   15249   i::DeleteArray(two_byte_string);
   15250 }
   15251 
   15252 
   15253 TEST(CompileExternalTwoByteSource) {
   15254   LocalContext context;
   15255   v8::HandleScope scope(context->GetIsolate());
   15256 
   15257   // This is a very short list of sources, which currently is to check for a
   15258   // regression caused by r2703.
   15259   const char* ascii_sources[] = {
   15260     "0.5",
   15261     "-0.5",   // This mainly testes PushBack in the Scanner.
   15262     "--0.5",  // This mainly testes PushBack in the Scanner.
   15263     NULL
   15264   };
   15265 
   15266   // Compile the sources as external two byte strings.
   15267   for (int i = 0; ascii_sources[i] != NULL; i++) {
   15268     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
   15269     TestResource* uc16_resource = new TestResource(two_byte_string);
   15270     v8::Local<v8::String> source =
   15271         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
   15272     v8::Script::Compile(source);
   15273   }
   15274 }
   15275 
   15276 
   15277 #ifndef V8_INTERPRETED_REGEXP
   15278 
   15279 struct RegExpInterruptionData {
   15280   int loop_count;
   15281   UC16VectorResource* string_resource;
   15282   v8::Persistent<v8::String> string;
   15283 } regexp_interruption_data;
   15284 
   15285 
   15286 class RegExpInterruptionThread : public i::Thread {
   15287  public:
   15288   explicit RegExpInterruptionThread(v8::Isolate* isolate)
   15289       : Thread("TimeoutThread"), isolate_(isolate) {}
   15290 
   15291   virtual void Run() {
   15292     for (regexp_interruption_data.loop_count = 0;
   15293          regexp_interruption_data.loop_count < 7;
   15294          regexp_interruption_data.loop_count++) {
   15295       i::OS::Sleep(50);  // Wait a bit before requesting GC.
   15296       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
   15297     }
   15298     i::OS::Sleep(50);  // Wait a bit before terminating.
   15299     v8::V8::TerminateExecution(isolate_);
   15300   }
   15301 
   15302  private:
   15303   v8::Isolate* isolate_;
   15304 };
   15305 
   15306 
   15307 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
   15308   if (regexp_interruption_data.loop_count != 2) return;
   15309   v8::HandleScope scope(CcTest::isolate());
   15310   v8::Local<v8::String> string = v8::Local<v8::String>::New(
   15311       CcTest::isolate(), regexp_interruption_data.string);
   15312   string->MakeExternal(regexp_interruption_data.string_resource);
   15313 }
   15314 
   15315 
   15316 // Test that RegExp execution can be interrupted.  Specifically, we test
   15317 // * interrupting with GC
   15318 // * turn the subject string from one-byte internal to two-byte external string
   15319 // * force termination
   15320 TEST(RegExpInterruption) {
   15321   v8::HandleScope scope(CcTest::isolate());
   15322   LocalContext env;
   15323 
   15324   RegExpInterruptionThread timeout_thread(CcTest::isolate());
   15325 
   15326   v8::V8::AddGCPrologueCallback(RunBeforeGC);
   15327   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
   15328   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
   15329   v8::Local<v8::String> string = v8_str(ascii_content);
   15330 
   15331   CcTest::global()->Set(v8_str("a"), string);
   15332   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
   15333   regexp_interruption_data.string_resource = new UC16VectorResource(
   15334       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
   15335 
   15336   v8::TryCatch try_catch;
   15337   timeout_thread.Start();
   15338 
   15339   CompileRun("/((a*)*)*b/.exec(a)");
   15340   CHECK(try_catch.HasTerminated());
   15341 
   15342   timeout_thread.Join();
   15343 
   15344   regexp_interruption_data.string.Reset();
   15345   i::DeleteArray(uc16_content);
   15346 }
   15347 
   15348 #endif  // V8_INTERPRETED_REGEXP
   15349 
   15350 
   15351 // Test that we cannot set a property on the global object if there
   15352 // is a read-only property in the prototype chain.
   15353 TEST(ReadOnlyPropertyInGlobalProto) {
   15354   v8::Isolate* isolate = CcTest::isolate();
   15355   v8::HandleScope scope(isolate);
   15356   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
   15357   LocalContext context(0, templ);
   15358   v8::Handle<v8::Object> global = context->Global();
   15359   v8::Handle<v8::Object> global_proto =
   15360       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
   15361   global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
   15362   global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
   15363   // Check without 'eval' or 'with'.
   15364   v8::Handle<v8::Value> res =
   15365       CompileRun("function f() { x = 42; return x; }; f()");
   15366   CHECK_EQ(v8::Integer::New(isolate, 0), res);
   15367   // Check with 'eval'.
   15368   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
   15369   CHECK_EQ(v8::Integer::New(isolate, 0), res);
   15370   // Check with 'with'.
   15371   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
   15372   CHECK_EQ(v8::Integer::New(isolate, 0), res);
   15373 }
   15374 
   15375 static int force_set_set_count = 0;
   15376 static int force_set_get_count = 0;
   15377 bool pass_on_get = false;
   15378 
   15379 static void ForceSetGetter(v8::Local<v8::String> name,
   15380                            const v8::PropertyCallbackInfo<v8::Value>& info) {
   15381   force_set_get_count++;
   15382   if (pass_on_get) {
   15383     return;
   15384   }
   15385   info.GetReturnValue().Set(3);
   15386 }
   15387 
   15388 static void ForceSetSetter(v8::Local<v8::String> name,
   15389                            v8::Local<v8::Value> value,
   15390                            const v8::PropertyCallbackInfo<void>& info) {
   15391   force_set_set_count++;
   15392 }
   15393 
   15394 static void ForceSetInterceptSetter(
   15395     v8::Local<v8::String> name,
   15396     v8::Local<v8::Value> value,
   15397     const v8::PropertyCallbackInfo<v8::Value>& info) {
   15398   force_set_set_count++;
   15399   info.GetReturnValue().SetUndefined();
   15400 }
   15401 
   15402 
   15403 TEST(ForceSet) {
   15404   force_set_get_count = 0;
   15405   force_set_set_count = 0;
   15406   pass_on_get = false;
   15407 
   15408   v8::Isolate* isolate = CcTest::isolate();
   15409   v8::HandleScope scope(isolate);
   15410   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
   15411   v8::Handle<v8::String> access_property =
   15412       v8::String::NewFromUtf8(isolate, "a");
   15413   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
   15414   LocalContext context(NULL, templ);
   15415   v8::Handle<v8::Object> global = context->Global();
   15416 
   15417   // Ordinary properties
   15418   v8::Handle<v8::String> simple_property =
   15419       v8::String::NewFromUtf8(isolate, "p");
   15420   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
   15421   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   15422   // This should fail because the property is read-only
   15423   global->Set(simple_property, v8::Int32::New(isolate, 5));
   15424   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   15425   // This should succeed even though the property is read-only
   15426   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
   15427   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
   15428 
   15429   // Accessors
   15430   CHECK_EQ(0, force_set_set_count);
   15431   CHECK_EQ(0, force_set_get_count);
   15432   CHECK_EQ(3, global->Get(access_property)->Int32Value());
   15433   // CHECK_EQ the property shouldn't override it, just call the setter
   15434   // which in this case does nothing.
   15435   global->Set(access_property, v8::Int32::New(isolate, 7));
   15436   CHECK_EQ(3, global->Get(access_property)->Int32Value());
   15437   CHECK_EQ(1, force_set_set_count);
   15438   CHECK_EQ(2, force_set_get_count);
   15439   // Forcing the property to be set should override the accessor without
   15440   // calling it
   15441   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
   15442   CHECK_EQ(8, global->Get(access_property)->Int32Value());
   15443   CHECK_EQ(1, force_set_set_count);
   15444   CHECK_EQ(2, force_set_get_count);
   15445 }
   15446 
   15447 
   15448 TEST(ForceSetWithInterceptor) {
   15449   force_set_get_count = 0;
   15450   force_set_set_count = 0;
   15451   pass_on_get = false;
   15452 
   15453   v8::Isolate* isolate = CcTest::isolate();
   15454   v8::HandleScope scope(isolate);
   15455   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
   15456   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
   15457   LocalContext context(NULL, templ);
   15458   v8::Handle<v8::Object> global = context->Global();
   15459 
   15460   v8::Handle<v8::String> some_property =
   15461       v8::String::NewFromUtf8(isolate, "a");
   15462   CHECK_EQ(0, force_set_set_count);
   15463   CHECK_EQ(0, force_set_get_count);
   15464   CHECK_EQ(3, global->Get(some_property)->Int32Value());
   15465   // Setting the property shouldn't override it, just call the setter
   15466   // which in this case does nothing.
   15467   global->Set(some_property, v8::Int32::New(isolate, 7));
   15468   CHECK_EQ(3, global->Get(some_property)->Int32Value());
   15469   CHECK_EQ(1, force_set_set_count);
   15470   CHECK_EQ(2, force_set_get_count);
   15471   // Getting the property when the interceptor returns an empty handle
   15472   // should yield undefined, since the property isn't present on the
   15473   // object itself yet.
   15474   pass_on_get = true;
   15475   CHECK(global->Get(some_property)->IsUndefined());
   15476   CHECK_EQ(1, force_set_set_count);
   15477   CHECK_EQ(3, force_set_get_count);
   15478   // Forcing the property to be set should cause the value to be
   15479   // set locally without calling the interceptor.
   15480   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
   15481   CHECK_EQ(8, global->Get(some_property)->Int32Value());
   15482   CHECK_EQ(1, force_set_set_count);
   15483   CHECK_EQ(4, force_set_get_count);
   15484   // Reenabling the interceptor should cause it to take precedence over
   15485   // the property
   15486   pass_on_get = false;
   15487   CHECK_EQ(3, global->Get(some_property)->Int32Value());
   15488   CHECK_EQ(1, force_set_set_count);
   15489   CHECK_EQ(5, force_set_get_count);
   15490   // The interceptor should also work for other properties
   15491   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
   15492                   ->Int32Value());
   15493   CHECK_EQ(1, force_set_set_count);
   15494   CHECK_EQ(6, force_set_get_count);
   15495 }
   15496 
   15497 
   15498 THREADED_TEST(ForceDelete) {
   15499   v8::Isolate* isolate = CcTest::isolate();
   15500   v8::HandleScope scope(isolate);
   15501   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
   15502   LocalContext context(NULL, templ);
   15503   v8::Handle<v8::Object> global = context->Global();
   15504 
   15505   // Ordinary properties
   15506   v8::Handle<v8::String> simple_property =
   15507       v8::String::NewFromUtf8(isolate, "p");
   15508   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
   15509   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   15510   // This should fail because the property is dont-delete.
   15511   CHECK(!global->Delete(simple_property));
   15512   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
   15513   // This should succeed even though the property is dont-delete.
   15514   CHECK(global->ForceDelete(simple_property));
   15515   CHECK(global->Get(simple_property)->IsUndefined());
   15516 }
   15517 
   15518 
   15519 static int force_delete_interceptor_count = 0;
   15520 static bool pass_on_delete = false;
   15521 
   15522 
   15523 static void ForceDeleteDeleter(
   15524     v8::Local<v8::String> name,
   15525     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   15526   force_delete_interceptor_count++;
   15527   if (pass_on_delete) return;
   15528   info.GetReturnValue().Set(true);
   15529 }
   15530 
   15531 
   15532 THREADED_TEST(ForceDeleteWithInterceptor) {
   15533   force_delete_interceptor_count = 0;
   15534   pass_on_delete = false;
   15535 
   15536   v8::Isolate* isolate = CcTest::isolate();
   15537   v8::HandleScope scope(isolate);
   15538   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
   15539   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
   15540   LocalContext context(NULL, templ);
   15541   v8::Handle<v8::Object> global = context->Global();
   15542 
   15543   v8::Handle<v8::String> some_property =
   15544       v8::String::NewFromUtf8(isolate, "a");
   15545   global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
   15546 
   15547   // Deleting a property should get intercepted and nothing should
   15548   // happen.
   15549   CHECK_EQ(0, force_delete_interceptor_count);
   15550   CHECK(global->Delete(some_property));
   15551   CHECK_EQ(1, force_delete_interceptor_count);
   15552   CHECK_EQ(42, global->Get(some_property)->Int32Value());
   15553   // Deleting the property when the interceptor returns an empty
   15554   // handle should not delete the property since it is DontDelete.
   15555   pass_on_delete = true;
   15556   CHECK(!global->Delete(some_property));
   15557   CHECK_EQ(2, force_delete_interceptor_count);
   15558   CHECK_EQ(42, global->Get(some_property)->Int32Value());
   15559   // Forcing the property to be deleted should delete the value
   15560   // without calling the interceptor.
   15561   CHECK(global->ForceDelete(some_property));
   15562   CHECK(global->Get(some_property)->IsUndefined());
   15563   CHECK_EQ(2, force_delete_interceptor_count);
   15564 }
   15565 
   15566 
   15567 // Make sure that forcing a delete invalidates any IC stubs, so we
   15568 // don't read the hole value.
   15569 THREADED_TEST(ForceDeleteIC) {
   15570   LocalContext context;
   15571   v8::HandleScope scope(context->GetIsolate());
   15572   // Create a DontDelete variable on the global object.
   15573   CompileRun("this.__proto__ = { foo: 'horse' };"
   15574              "var foo = 'fish';"
   15575              "function f() { return foo.length; }");
   15576   // Initialize the IC for foo in f.
   15577   CompileRun("for (var i = 0; i < 4; i++) f();");
   15578   // Make sure the value of foo is correct before the deletion.
   15579   CHECK_EQ(4, CompileRun("f()")->Int32Value());
   15580   // Force the deletion of foo.
   15581   CHECK(context->Global()->ForceDelete(v8_str("foo")));
   15582   // Make sure the value for foo is read from the prototype, and that
   15583   // we don't get in trouble with reading the deleted cell value
   15584   // sentinel.
   15585   CHECK_EQ(5, CompileRun("f()")->Int32Value());
   15586 }
   15587 
   15588 
   15589 TEST(InlinedFunctionAcrossContexts) {
   15590   i::FLAG_allow_natives_syntax = true;
   15591   v8::Isolate* isolate = CcTest::isolate();
   15592   v8::HandleScope outer_scope(isolate);
   15593   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
   15594   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
   15595   ctx1->Enter();
   15596 
   15597   {
   15598     v8::HandleScope inner_scope(CcTest::isolate());
   15599     CompileRun("var G = 42; function foo() { return G; }");
   15600     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
   15601     ctx2->Enter();
   15602     ctx2->Global()->Set(v8_str("o"), foo);
   15603     v8::Local<v8::Value> res = CompileRun(
   15604         "function f() { return o(); }"
   15605         "for (var i = 0; i < 10; ++i) f();"
   15606         "%OptimizeFunctionOnNextCall(f);"
   15607         "f();");
   15608     CHECK_EQ(42, res->Int32Value());
   15609     ctx2->Exit();
   15610     v8::Handle<v8::String> G_property =
   15611         v8::String::NewFromUtf8(CcTest::isolate(), "G");
   15612     CHECK(ctx1->Global()->ForceDelete(G_property));
   15613     ctx2->Enter();
   15614     ExpectString(
   15615         "(function() {"
   15616         "  try {"
   15617         "    return f();"
   15618         "  } catch(e) {"
   15619         "    return e.toString();"
   15620         "  }"
   15621         " })()",
   15622         "ReferenceError: G is not defined");
   15623     ctx2->Exit();
   15624     ctx1->Exit();
   15625   }
   15626 }
   15627 
   15628 
   15629 static v8::Local<Context> calling_context0;
   15630 static v8::Local<Context> calling_context1;
   15631 static v8::Local<Context> calling_context2;
   15632 
   15633 
   15634 // Check that the call to the callback is initiated in
   15635 // calling_context2, the directly calling context is calling_context1
   15636 // and the callback itself is in calling_context0.
   15637 static void GetCallingContextCallback(
   15638     const v8::FunctionCallbackInfo<v8::Value>& args) {
   15639   ApiTestFuzzer::Fuzz();
   15640   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
   15641   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
   15642   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
   15643   args.GetReturnValue().Set(42);
   15644 }
   15645 
   15646 
   15647 THREADED_TEST(GetCurrentContextWhenNotInContext) {
   15648   i::Isolate* isolate = CcTest::i_isolate();
   15649   CHECK(isolate != NULL);
   15650   CHECK(isolate->context() == NULL);
   15651   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
   15652   v8::HandleScope scope(v8_isolate);
   15653   // The following should not crash, but return an empty handle.
   15654   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
   15655   CHECK(current.IsEmpty());
   15656 }
   15657 
   15658 
   15659 THREADED_TEST(GetCallingContext) {
   15660   v8::Isolate* isolate = CcTest::isolate();
   15661   v8::HandleScope scope(isolate);
   15662 
   15663   Local<Context> calling_context0(Context::New(isolate));
   15664   Local<Context> calling_context1(Context::New(isolate));
   15665   Local<Context> calling_context2(Context::New(isolate));
   15666   ::calling_context0 = calling_context0;
   15667   ::calling_context1 = calling_context1;
   15668   ::calling_context2 = calling_context2;
   15669 
   15670   // Allow cross-domain access.
   15671   Local<String> token = v8_str("<security token>");
   15672   calling_context0->SetSecurityToken(token);
   15673   calling_context1->SetSecurityToken(token);
   15674   calling_context2->SetSecurityToken(token);
   15675 
   15676   // Create an object with a C++ callback in context0.
   15677   calling_context0->Enter();
   15678   Local<v8::FunctionTemplate> callback_templ =
   15679       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
   15680   calling_context0->Global()->Set(v8_str("callback"),
   15681                                   callback_templ->GetFunction());
   15682   calling_context0->Exit();
   15683 
   15684   // Expose context0 in context1 and set up a function that calls the
   15685   // callback function.
   15686   calling_context1->Enter();
   15687   calling_context1->Global()->Set(v8_str("context0"),
   15688                                   calling_context0->Global());
   15689   CompileRun("function f() { context0.callback() }");
   15690   calling_context1->Exit();
   15691 
   15692   // Expose context1 in context2 and call the callback function in
   15693   // context0 indirectly through f in context1.
   15694   calling_context2->Enter();
   15695   calling_context2->Global()->Set(v8_str("context1"),
   15696                                   calling_context1->Global());
   15697   CompileRun("context1.f()");
   15698   calling_context2->Exit();
   15699   ::calling_context0.Clear();
   15700   ::calling_context1.Clear();
   15701   ::calling_context2.Clear();
   15702 }
   15703 
   15704 
   15705 // Check that a variable declaration with no explicit initialization
   15706 // value does shadow an existing property in the prototype chain.
   15707 THREADED_TEST(InitGlobalVarInProtoChain) {
   15708   LocalContext context;
   15709   v8::HandleScope scope(context->GetIsolate());
   15710   // Introduce a variable in the prototype chain.
   15711   CompileRun("__proto__.x = 42");
   15712   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
   15713   CHECK(!result->IsUndefined());
   15714   CHECK_EQ(43, result->Int32Value());
   15715 }
   15716 
   15717 
   15718 // Regression test for issue 398.
   15719 // If a function is added to an object, creating a constant function
   15720 // field, and the result is cloned, replacing the constant function on the
   15721 // original should not affect the clone.
   15722 // See http://code.google.com/p/v8/issues/detail?id=398
   15723 THREADED_TEST(ReplaceConstantFunction) {
   15724   LocalContext context;
   15725   v8::Isolate* isolate = context->GetIsolate();
   15726   v8::HandleScope scope(isolate);
   15727   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   15728   v8::Handle<v8::FunctionTemplate> func_templ =
   15729       v8::FunctionTemplate::New(isolate);
   15730   v8::Handle<v8::String> foo_string =
   15731       v8::String::NewFromUtf8(isolate, "foo");
   15732   obj->Set(foo_string, func_templ->GetFunction());
   15733   v8::Handle<v8::Object> obj_clone = obj->Clone();
   15734   obj_clone->Set(foo_string,
   15735                  v8::String::NewFromUtf8(isolate, "Hello"));
   15736   CHECK(!obj->Get(foo_string)->IsUndefined());
   15737 }
   15738 
   15739 
   15740 static void CheckElementValue(i::Isolate* isolate,
   15741                               int expected,
   15742                               i::Handle<i::Object> obj,
   15743                               int offset) {
   15744   i::Object* element =
   15745       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
   15746   CHECK_EQ(expected, i::Smi::cast(element)->value());
   15747 }
   15748 
   15749 
   15750 THREADED_TEST(PixelArray) {
   15751   LocalContext context;
   15752   i::Isolate* isolate = CcTest::i_isolate();
   15753   i::Factory* factory = isolate->factory();
   15754   v8::HandleScope scope(context->GetIsolate());
   15755   const int kElementCount = 260;
   15756   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
   15757   i::Handle<i::ExternalUint8ClampedArray> pixels =
   15758       i::Handle<i::ExternalUint8ClampedArray>::cast(
   15759           factory->NewExternalArray(kElementCount,
   15760                                     v8::kExternalUint8ClampedArray,
   15761                                     pixel_data));
   15762   // Force GC to trigger verification.
   15763   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   15764   for (int i = 0; i < kElementCount; i++) {
   15765     pixels->set(i, i % 256);
   15766   }
   15767   // Force GC to trigger verification.
   15768   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   15769   for (int i = 0; i < kElementCount; i++) {
   15770     CHECK_EQ(i % 256, pixels->get_scalar(i));
   15771     CHECK_EQ(i % 256, pixel_data[i]);
   15772   }
   15773 
   15774   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
   15775   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
   15776   // Set the elements to be the pixels.
   15777   // jsobj->set_elements(*pixels);
   15778   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
   15779   CheckElementValue(isolate, 1, jsobj, 1);
   15780   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
   15781   context->Global()->Set(v8_str("pixels"), obj);
   15782   v8::Handle<v8::Value> result = CompileRun("pixels.field");
   15783   CHECK_EQ(1503, result->Int32Value());
   15784   result = CompileRun("pixels[1]");
   15785   CHECK_EQ(1, result->Int32Value());
   15786 
   15787   result = CompileRun("var sum = 0;"
   15788                       "for (var i = 0; i < 8; i++) {"
   15789                       "  sum += pixels[i] = pixels[i] = -i;"
   15790                       "}"
   15791                       "sum;");
   15792   CHECK_EQ(-28, result->Int32Value());
   15793 
   15794   result = CompileRun("var sum = 0;"
   15795                       "for (var i = 0; i < 8; i++) {"
   15796                       "  sum += pixels[i] = pixels[i] = 0;"
   15797                       "}"
   15798                       "sum;");
   15799   CHECK_EQ(0, result->Int32Value());
   15800 
   15801   result = CompileRun("var sum = 0;"
   15802                       "for (var i = 0; i < 8; i++) {"
   15803                       "  sum += pixels[i] = pixels[i] = 255;"
   15804                       "}"
   15805                       "sum;");
   15806   CHECK_EQ(8 * 255, result->Int32Value());
   15807 
   15808   result = CompileRun("var sum = 0;"
   15809                       "for (var i = 0; i < 8; i++) {"
   15810                       "  sum += pixels[i] = pixels[i] = 256 + i;"
   15811                       "}"
   15812                       "sum;");
   15813   CHECK_EQ(2076, result->Int32Value());
   15814 
   15815   result = CompileRun("var sum = 0;"
   15816                       "for (var i = 0; i < 8; i++) {"
   15817                       "  sum += pixels[i] = pixels[i] = i;"
   15818                       "}"
   15819                       "sum;");
   15820   CHECK_EQ(28, result->Int32Value());
   15821 
   15822   result = CompileRun("var sum = 0;"
   15823                       "for (var i = 0; i < 8; i++) {"
   15824                       "  sum += pixels[i];"
   15825                       "}"
   15826                       "sum;");
   15827   CHECK_EQ(28, result->Int32Value());
   15828 
   15829   i::Handle<i::Smi> value(i::Smi::FromInt(2),
   15830                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
   15831   i::Handle<i::Object> no_failure;
   15832   no_failure = i::JSObject::SetElement(
   15833       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
   15834   ASSERT(!no_failure.is_null());
   15835   USE(no_failure);
   15836   CheckElementValue(isolate, 2, jsobj, 1);
   15837   *value.location() = i::Smi::FromInt(256);
   15838   no_failure = i::JSObject::SetElement(
   15839       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
   15840   ASSERT(!no_failure.is_null());
   15841   USE(no_failure);
   15842   CheckElementValue(isolate, 255, jsobj, 1);
   15843   *value.location() = i::Smi::FromInt(-1);
   15844   no_failure = i::JSObject::SetElement(
   15845       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
   15846   ASSERT(!no_failure.is_null());
   15847   USE(no_failure);
   15848   CheckElementValue(isolate, 0, jsobj, 1);
   15849 
   15850   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15851                       "  pixels[i] = (i * 65) - 109;"
   15852                       "}"
   15853                       "pixels[1] + pixels[6];");
   15854   CHECK_EQ(255, result->Int32Value());
   15855   CheckElementValue(isolate, 0, jsobj, 0);
   15856   CheckElementValue(isolate, 0, jsobj, 1);
   15857   CheckElementValue(isolate, 21, jsobj, 2);
   15858   CheckElementValue(isolate, 86, jsobj, 3);
   15859   CheckElementValue(isolate, 151, jsobj, 4);
   15860   CheckElementValue(isolate, 216, jsobj, 5);
   15861   CheckElementValue(isolate, 255, jsobj, 6);
   15862   CheckElementValue(isolate, 255, jsobj, 7);
   15863   result = CompileRun("var sum = 0;"
   15864                       "for (var i = 0; i < 8; i++) {"
   15865                       "  sum += pixels[i];"
   15866                       "}"
   15867                       "sum;");
   15868   CHECK_EQ(984, result->Int32Value());
   15869 
   15870   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15871                       "  pixels[i] = (i * 1.1);"
   15872                       "}"
   15873                       "pixels[1] + pixels[6];");
   15874   CHECK_EQ(8, result->Int32Value());
   15875   CheckElementValue(isolate, 0, jsobj, 0);
   15876   CheckElementValue(isolate, 1, jsobj, 1);
   15877   CheckElementValue(isolate, 2, jsobj, 2);
   15878   CheckElementValue(isolate, 3, jsobj, 3);
   15879   CheckElementValue(isolate, 4, jsobj, 4);
   15880   CheckElementValue(isolate, 6, jsobj, 5);
   15881   CheckElementValue(isolate, 7, jsobj, 6);
   15882   CheckElementValue(isolate, 8, jsobj, 7);
   15883 
   15884   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15885                       "  pixels[7] = undefined;"
   15886                       "}"
   15887                       "pixels[7];");
   15888   CHECK_EQ(0, result->Int32Value());
   15889   CheckElementValue(isolate, 0, jsobj, 7);
   15890 
   15891   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15892                       "  pixels[6] = '2.3';"
   15893                       "}"
   15894                       "pixels[6];");
   15895   CHECK_EQ(2, result->Int32Value());
   15896   CheckElementValue(isolate, 2, jsobj, 6);
   15897 
   15898   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15899                       "  pixels[5] = NaN;"
   15900                       "}"
   15901                       "pixels[5];");
   15902   CHECK_EQ(0, result->Int32Value());
   15903   CheckElementValue(isolate, 0, jsobj, 5);
   15904 
   15905   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15906                       "  pixels[8] = Infinity;"
   15907                       "}"
   15908                       "pixels[8];");
   15909   CHECK_EQ(255, result->Int32Value());
   15910   CheckElementValue(isolate, 255, jsobj, 8);
   15911 
   15912   result = CompileRun("for (var i = 0; i < 8; i++) {"
   15913                       "  pixels[9] = -Infinity;"
   15914                       "}"
   15915                       "pixels[9];");
   15916   CHECK_EQ(0, result->Int32Value());
   15917   CheckElementValue(isolate, 0, jsobj, 9);
   15918 
   15919   result = CompileRun("pixels[3] = 33;"
   15920                       "delete pixels[3];"
   15921                       "pixels[3];");
   15922   CHECK_EQ(33, result->Int32Value());
   15923 
   15924   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
   15925                       "pixels[2] = 12; pixels[3] = 13;"
   15926                       "pixels.__defineGetter__('2',"
   15927                       "function() { return 120; });"
   15928                       "pixels[2];");
   15929   CHECK_EQ(12, result->Int32Value());
   15930 
   15931   result = CompileRun("var js_array = new Array(40);"
   15932                       "js_array[0] = 77;"
   15933                       "js_array;");
   15934   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   15935 
   15936   result = CompileRun("pixels[1] = 23;"
   15937                       "pixels.__proto__ = [];"
   15938                       "js_array.__proto__ = pixels;"
   15939                       "js_array.concat(pixels);");
   15940   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   15941   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
   15942 
   15943   result = CompileRun("pixels[1] = 23;");
   15944   CHECK_EQ(23, result->Int32Value());
   15945 
   15946   // Test for index greater than 255.  Regression test for:
   15947   // http://code.google.com/p/chromium/issues/detail?id=26337.
   15948   result = CompileRun("pixels[256] = 255;");
   15949   CHECK_EQ(255, result->Int32Value());
   15950   result = CompileRun("var i = 0;"
   15951                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
   15952                       "i");
   15953   CHECK_EQ(255, result->Int32Value());
   15954 
   15955   // Make sure that pixel array ICs recognize when a non-pixel array
   15956   // is passed to it.
   15957   result = CompileRun("function pa_load(p) {"
   15958                       "  var sum = 0;"
   15959                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
   15960                       "  return sum;"
   15961                       "}"
   15962                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
   15963                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
   15964                       "just_ints = new Object();"
   15965                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
   15966                       "for (var i = 0; i < 10; ++i) {"
   15967                       "  result = pa_load(just_ints);"
   15968                       "}"
   15969                       "result");
   15970   CHECK_EQ(32640, result->Int32Value());
   15971 
   15972   // Make sure that pixel array ICs recognize out-of-bound accesses.
   15973   result = CompileRun("function pa_load(p, start) {"
   15974                       "  var sum = 0;"
   15975                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
   15976                       "  return sum;"
   15977                       "}"
   15978                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
   15979                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
   15980                       "for (var i = 0; i < 10; ++i) {"
   15981                       "  result = pa_load(pixels,-10);"
   15982                       "}"
   15983                       "result");
   15984   CHECK_EQ(0, result->Int32Value());
   15985 
   15986   // Make sure that generic ICs properly handles a pixel array.
   15987   result = CompileRun("function pa_load(p) {"
   15988                       "  var sum = 0;"
   15989                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
   15990                       "  return sum;"
   15991                       "}"
   15992                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
   15993                       "just_ints = new Object();"
   15994                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
   15995                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
   15996                       "for (var i = 0; i < 10; ++i) {"
   15997                       "  result = pa_load(pixels);"
   15998                       "}"
   15999                       "result");
   16000   CHECK_EQ(32640, result->Int32Value());
   16001 
   16002   // Make sure that generic load ICs recognize out-of-bound accesses in
   16003   // pixel arrays.
   16004   result = CompileRun("function pa_load(p, start) {"
   16005                       "  var sum = 0;"
   16006                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
   16007                       "  return sum;"
   16008                       "}"
   16009                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
   16010                       "just_ints = new Object();"
   16011                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
   16012                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
   16013                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
   16014                       "for (var i = 0; i < 10; ++i) {"
   16015                       "  result = pa_load(pixels,-10);"
   16016                       "}"
   16017                       "result");
   16018   CHECK_EQ(0, result->Int32Value());
   16019 
   16020   // Make sure that generic ICs properly handles other types than pixel
   16021   // arrays (that the inlined fast pixel array test leaves the right information
   16022   // in the right registers).
   16023   result = CompileRun("function pa_load(p) {"
   16024                       "  var sum = 0;"
   16025                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
   16026                       "  return sum;"
   16027                       "}"
   16028                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
   16029                       "just_ints = new Object();"
   16030                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
   16031                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
   16032                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
   16033                       "sparse_array = new Object();"
   16034                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
   16035                       "sparse_array[1000000] = 3;"
   16036                       "for (var i = 0; i < 10; ++i) {"
   16037                       "  result = pa_load(sparse_array);"
   16038                       "}"
   16039                       "result");
   16040   CHECK_EQ(32640, result->Int32Value());
   16041 
   16042   // Make sure that pixel array store ICs clamp values correctly.
   16043   result = CompileRun("function pa_store(p) {"
   16044                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
   16045                       "}"
   16046                       "pa_store(pixels);"
   16047                       "var sum = 0;"
   16048                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
   16049                       "sum");
   16050   CHECK_EQ(48896, result->Int32Value());
   16051 
   16052   // Make sure that pixel array stores correctly handle accesses outside
   16053   // of the pixel array..
   16054   result = CompileRun("function pa_store(p,start) {"
   16055                       "  for (var j = 0; j < 256; j++) {"
   16056                       "    p[j+start] = j * 2;"
   16057                       "  }"
   16058                       "}"
   16059                       "pa_store(pixels,0);"
   16060                       "pa_store(pixels,-128);"
   16061                       "var sum = 0;"
   16062                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
   16063                       "sum");
   16064   CHECK_EQ(65280, result->Int32Value());
   16065 
   16066   // Make sure that the generic store stub correctly handle accesses outside
   16067   // of the pixel array..
   16068   result = CompileRun("function pa_store(p,start) {"
   16069                       "  for (var j = 0; j < 256; j++) {"
   16070                       "    p[j+start] = j * 2;"
   16071                       "  }"
   16072                       "}"
   16073                       "pa_store(pixels,0);"
   16074                       "just_ints = new Object();"
   16075                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
   16076                       "pa_store(just_ints, 0);"
   16077                       "pa_store(pixels,-128);"
   16078                       "var sum = 0;"
   16079                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
   16080                       "sum");
   16081   CHECK_EQ(65280, result->Int32Value());
   16082 
   16083   // Make sure that the generic keyed store stub clamps pixel array values
   16084   // correctly.
   16085   result = CompileRun("function pa_store(p) {"
   16086                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
   16087                       "}"
   16088                       "pa_store(pixels);"
   16089                       "just_ints = new Object();"
   16090                       "pa_store(just_ints);"
   16091                       "pa_store(pixels);"
   16092                       "var sum = 0;"
   16093                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
   16094                       "sum");
   16095   CHECK_EQ(48896, result->Int32Value());
   16096 
   16097   // Make sure that pixel array loads are optimized by crankshaft.
   16098   result = CompileRun("function pa_load(p) {"
   16099                       "  var sum = 0;"
   16100                       "  for (var i=0; i<256; ++i) {"
   16101                       "    sum += p[i];"
   16102                       "  }"
   16103                       "  return sum; "
   16104                       "}"
   16105                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
   16106                       "for (var i = 0; i < 5000; ++i) {"
   16107                       "  result = pa_load(pixels);"
   16108                       "}"
   16109                       "result");
   16110   CHECK_EQ(32640, result->Int32Value());
   16111 
   16112   // Make sure that pixel array stores are optimized by crankshaft.
   16113   result = CompileRun("function pa_init(p) {"
   16114                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
   16115                       "}"
   16116                       "function pa_load(p) {"
   16117                       "  var sum = 0;"
   16118                       "  for (var i=0; i<256; ++i) {"
   16119                       "    sum += p[i];"
   16120                       "  }"
   16121                       "  return sum; "
   16122                       "}"
   16123                       "for (var i = 0; i < 5000; ++i) {"
   16124                       "  pa_init(pixels);"
   16125                       "}"
   16126                       "result = pa_load(pixels);"
   16127                       "result");
   16128   CHECK_EQ(32640, result->Int32Value());
   16129 
   16130   free(pixel_data);
   16131 }
   16132 
   16133 
   16134 THREADED_TEST(PixelArrayInfo) {
   16135   LocalContext context;
   16136   v8::HandleScope scope(context->GetIsolate());
   16137   for (int size = 0; size < 100; size += 10) {
   16138     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
   16139     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
   16140     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
   16141     CHECK(obj->HasIndexedPropertiesInPixelData());
   16142     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
   16143     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
   16144     free(pixel_data);
   16145   }
   16146 }
   16147 
   16148 
   16149 static void NotHandledIndexedPropertyGetter(
   16150     uint32_t index,
   16151     const v8::PropertyCallbackInfo<v8::Value>& info) {
   16152   ApiTestFuzzer::Fuzz();
   16153 }
   16154 
   16155 
   16156 static void NotHandledIndexedPropertySetter(
   16157     uint32_t index,
   16158     Local<Value> value,
   16159     const v8::PropertyCallbackInfo<v8::Value>& info) {
   16160   ApiTestFuzzer::Fuzz();
   16161 }
   16162 
   16163 
   16164 THREADED_TEST(PixelArrayWithInterceptor) {
   16165   LocalContext context;
   16166   i::Factory* factory = CcTest::i_isolate()->factory();
   16167   v8::Isolate* isolate = context->GetIsolate();
   16168   v8::HandleScope scope(isolate);
   16169   const int kElementCount = 260;
   16170   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
   16171   i::Handle<i::ExternalUint8ClampedArray> pixels =
   16172       i::Handle<i::ExternalUint8ClampedArray>::cast(
   16173           factory->NewExternalArray(kElementCount,
   16174                                     v8::kExternalUint8ClampedArray,
   16175                                     pixel_data));
   16176   for (int i = 0; i < kElementCount; i++) {
   16177     pixels->set(i, i % 256);
   16178   }
   16179   v8::Handle<v8::ObjectTemplate> templ =
   16180       v8::ObjectTemplate::New(context->GetIsolate());
   16181   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
   16182                                    NotHandledIndexedPropertySetter);
   16183   v8::Handle<v8::Object> obj = templ->NewInstance();
   16184   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
   16185   context->Global()->Set(v8_str("pixels"), obj);
   16186   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
   16187   CHECK_EQ(1, result->Int32Value());
   16188   result = CompileRun("var sum = 0;"
   16189                       "for (var i = 0; i < 8; i++) {"
   16190                       "  sum += pixels[i] = pixels[i] = -i;"
   16191                       "}"
   16192                       "sum;");
   16193   CHECK_EQ(-28, result->Int32Value());
   16194   result = CompileRun("pixels.hasOwnProperty('1')");
   16195   CHECK(result->BooleanValue());
   16196   free(pixel_data);
   16197 }
   16198 
   16199 
   16200 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
   16201   switch (array_type) {
   16202     case v8::kExternalInt8Array:
   16203     case v8::kExternalUint8Array:
   16204     case v8::kExternalUint8ClampedArray:
   16205       return 1;
   16206       break;
   16207     case v8::kExternalInt16Array:
   16208     case v8::kExternalUint16Array:
   16209       return 2;
   16210       break;
   16211     case v8::kExternalInt32Array:
   16212     case v8::kExternalUint32Array:
   16213     case v8::kExternalFloat32Array:
   16214       return 4;
   16215       break;
   16216     case v8::kExternalFloat64Array:
   16217       return 8;
   16218       break;
   16219     default:
   16220       UNREACHABLE();
   16221       return -1;
   16222   }
   16223   UNREACHABLE();
   16224   return -1;
   16225 }
   16226 
   16227 
   16228 template <class ExternalArrayClass, class ElementType>
   16229 static void ObjectWithExternalArrayTestHelper(
   16230     Handle<Context> context,
   16231     v8::Handle<Object> obj,
   16232     int element_count,
   16233     v8::ExternalArrayType array_type,
   16234     int64_t low, int64_t high) {
   16235   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
   16236   i::Isolate* isolate = jsobj->GetIsolate();
   16237   obj->Set(v8_str("field"),
   16238            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
   16239   context->Global()->Set(v8_str("ext_array"), obj);
   16240   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
   16241   CHECK_EQ(1503, result->Int32Value());
   16242   result = CompileRun("ext_array[1]");
   16243   CHECK_EQ(1, result->Int32Value());
   16244 
   16245   // Check assigned smis
   16246   result = CompileRun("for (var i = 0; i < 8; i++) {"
   16247                       "  ext_array[i] = i;"
   16248                       "}"
   16249                       "var sum = 0;"
   16250                       "for (var i = 0; i < 8; i++) {"
   16251                       "  sum += ext_array[i];"
   16252                       "}"
   16253                       "sum;");
   16254 
   16255   CHECK_EQ(28, result->Int32Value());
   16256   // Check pass through of assigned smis
   16257   result = CompileRun("var sum = 0;"
   16258                       "for (var i = 0; i < 8; i++) {"
   16259                       "  sum += ext_array[i] = ext_array[i] = -i;"
   16260                       "}"
   16261                       "sum;");
   16262   CHECK_EQ(-28, result->Int32Value());
   16263 
   16264 
   16265   // Check assigned smis in reverse order
   16266   result = CompileRun("for (var i = 8; --i >= 0; ) {"
   16267                       "  ext_array[i] = i;"
   16268                       "}"
   16269                       "var sum = 0;"
   16270                       "for (var i = 0; i < 8; i++) {"
   16271                       "  sum += ext_array[i];"
   16272                       "}"
   16273                       "sum;");
   16274   CHECK_EQ(28, result->Int32Value());
   16275 
   16276   // Check pass through of assigned HeapNumbers
   16277   result = CompileRun("var sum = 0;"
   16278                       "for (var i = 0; i < 16; i+=2) {"
   16279                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
   16280                       "}"
   16281                       "sum;");
   16282   CHECK_EQ(-28, result->Int32Value());
   16283 
   16284   // Check assigned HeapNumbers
   16285   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
   16286                       "  ext_array[i] = (i * 0.5);"
   16287                       "}"
   16288                       "var sum = 0;"
   16289                       "for (var i = 0; i < 16; i+=2) {"
   16290                       "  sum += ext_array[i];"
   16291                       "}"
   16292                       "sum;");
   16293   CHECK_EQ(28, result->Int32Value());
   16294 
   16295   // Check assigned HeapNumbers in reverse order
   16296   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
   16297                       "  ext_array[i] = (i * 0.5);"
   16298                       "}"
   16299                       "var sum = 0;"
   16300                       "for (var i = 0; i < 16; i+=2) {"
   16301                       "  sum += ext_array[i];"
   16302                       "}"
   16303                       "sum;");
   16304   CHECK_EQ(28, result->Int32Value());
   16305 
   16306   i::ScopedVector<char> test_buf(1024);
   16307 
   16308   // Check legal boundary conditions.
   16309   // The repeated loads and stores ensure the ICs are exercised.
   16310   const char* boundary_program =
   16311       "var res = 0;"
   16312       "for (var i = 0; i < 16; i++) {"
   16313       "  ext_array[i] = %lld;"
   16314       "  if (i > 8) {"
   16315       "    res = ext_array[i];"
   16316       "  }"
   16317       "}"
   16318       "res;";
   16319   i::SNPrintF(test_buf,
   16320               boundary_program,
   16321               low);
   16322   result = CompileRun(test_buf.start());
   16323   CHECK_EQ(low, result->IntegerValue());
   16324 
   16325   i::SNPrintF(test_buf,
   16326               boundary_program,
   16327               high);
   16328   result = CompileRun(test_buf.start());
   16329   CHECK_EQ(high, result->IntegerValue());
   16330 
   16331   // Check misprediction of type in IC.
   16332   result = CompileRun("var tmp_array = ext_array;"
   16333                       "var sum = 0;"
   16334                       "for (var i = 0; i < 8; i++) {"
   16335                       "  tmp_array[i] = i;"
   16336                       "  sum += tmp_array[i];"
   16337                       "  if (i == 4) {"
   16338                       "    tmp_array = {};"
   16339                       "  }"
   16340                       "}"
   16341                       "sum;");
   16342   // Force GC to trigger verification.
   16343   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   16344   CHECK_EQ(28, result->Int32Value());
   16345 
   16346   // Make sure out-of-range loads do not throw.
   16347   i::SNPrintF(test_buf,
   16348               "var caught_exception = false;"
   16349               "try {"
   16350               "  ext_array[%d];"
   16351               "} catch (e) {"
   16352               "  caught_exception = true;"
   16353               "}"
   16354               "caught_exception;",
   16355               element_count);
   16356   result = CompileRun(test_buf.start());
   16357   CHECK_EQ(false, result->BooleanValue());
   16358 
   16359   // Make sure out-of-range stores do not throw.
   16360   i::SNPrintF(test_buf,
   16361               "var caught_exception = false;"
   16362               "try {"
   16363               "  ext_array[%d] = 1;"
   16364               "} catch (e) {"
   16365               "  caught_exception = true;"
   16366               "}"
   16367               "caught_exception;",
   16368               element_count);
   16369   result = CompileRun(test_buf.start());
   16370   CHECK_EQ(false, result->BooleanValue());
   16371 
   16372   // Check other boundary conditions, values and operations.
   16373   result = CompileRun("for (var i = 0; i < 8; i++) {"
   16374                       "  ext_array[7] = undefined;"
   16375                       "}"
   16376                       "ext_array[7];");
   16377   CHECK_EQ(0, result->Int32Value());
   16378   if (array_type == v8::kExternalFloat64Array ||
   16379       array_type == v8::kExternalFloat32Array) {
   16380     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
   16381              static_cast<int>(
   16382                  i::Object::GetElement(
   16383                      isolate, jsobj, 7).ToHandleChecked()->Number()));
   16384   } else {
   16385     CheckElementValue(isolate, 0, jsobj, 7);
   16386   }
   16387 
   16388   result = CompileRun("for (var i = 0; i < 8; i++) {"
   16389                       "  ext_array[6] = '2.3';"
   16390                       "}"
   16391                       "ext_array[6];");
   16392   CHECK_EQ(2, result->Int32Value());
   16393   CHECK_EQ(2,
   16394            static_cast<int>(
   16395                i::Object::GetElement(
   16396                    isolate, jsobj, 6).ToHandleChecked()->Number()));
   16397 
   16398   if (array_type != v8::kExternalFloat32Array &&
   16399       array_type != v8::kExternalFloat64Array) {
   16400     // Though the specification doesn't state it, be explicit about
   16401     // converting NaNs and +/-Infinity to zero.
   16402     result = CompileRun("for (var i = 0; i < 8; i++) {"
   16403                         "  ext_array[i] = 5;"
   16404                         "}"
   16405                         "for (var i = 0; i < 8; i++) {"
   16406                         "  ext_array[i] = NaN;"
   16407                         "}"
   16408                         "ext_array[5];");
   16409     CHECK_EQ(0, result->Int32Value());
   16410     CheckElementValue(isolate, 0, jsobj, 5);
   16411 
   16412     result = CompileRun("for (var i = 0; i < 8; i++) {"
   16413                         "  ext_array[i] = 5;"
   16414                         "}"
   16415                         "for (var i = 0; i < 8; i++) {"
   16416                         "  ext_array[i] = Infinity;"
   16417                         "}"
   16418                         "ext_array[5];");
   16419     int expected_value =
   16420         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
   16421     CHECK_EQ(expected_value, result->Int32Value());
   16422     CheckElementValue(isolate, expected_value, jsobj, 5);
   16423 
   16424     result = CompileRun("for (var i = 0; i < 8; i++) {"
   16425                         "  ext_array[i] = 5;"
   16426                         "}"
   16427                         "for (var i = 0; i < 8; i++) {"
   16428                         "  ext_array[i] = -Infinity;"
   16429                         "}"
   16430                         "ext_array[5];");
   16431     CHECK_EQ(0, result->Int32Value());
   16432     CheckElementValue(isolate, 0, jsobj, 5);
   16433 
   16434     // Check truncation behavior of integral arrays.
   16435     const char* unsigned_data =
   16436         "var source_data = [0.6, 10.6];"
   16437         "var expected_results = [0, 10];";
   16438     const char* signed_data =
   16439         "var source_data = [0.6, 10.6, -0.6, -10.6];"
   16440         "var expected_results = [0, 10, 0, -10];";
   16441     const char* pixel_data =
   16442         "var source_data = [0.6, 10.6];"
   16443         "var expected_results = [1, 11];";
   16444     bool is_unsigned =
   16445         (array_type == v8::kExternalUint8Array ||
   16446          array_type == v8::kExternalUint16Array ||
   16447          array_type == v8::kExternalUint32Array);
   16448     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
   16449 
   16450     i::SNPrintF(test_buf,
   16451                 "%s"
   16452                 "var all_passed = true;"
   16453                 "for (var i = 0; i < source_data.length; i++) {"
   16454                 "  for (var j = 0; j < 8; j++) {"
   16455                 "    ext_array[j] = source_data[i];"
   16456                 "  }"
   16457                 "  all_passed = all_passed &&"
   16458                 "               (ext_array[5] == expected_results[i]);"
   16459                 "}"
   16460                 "all_passed;",
   16461                 (is_unsigned ?
   16462                      unsigned_data :
   16463                      (is_pixel_data ? pixel_data : signed_data)));
   16464     result = CompileRun(test_buf.start());
   16465     CHECK_EQ(true, result->BooleanValue());
   16466   }
   16467 
   16468   i::Handle<ExternalArrayClass> array(
   16469       ExternalArrayClass::cast(jsobj->elements()));
   16470   for (int i = 0; i < element_count; i++) {
   16471     array->set(i, static_cast<ElementType>(i));
   16472   }
   16473 
   16474   // Test complex assignments
   16475   result = CompileRun("function ee_op_test_complex_func(sum) {"
   16476                       " for (var i = 0; i < 40; ++i) {"
   16477                       "   sum += (ext_array[i] += 1);"
   16478                       "   sum += (ext_array[i] -= 1);"
   16479                       " } "
   16480                       " return sum;"
   16481                       "}"
   16482                       "sum=0;"
   16483                       "for (var i=0;i<10000;++i) {"
   16484                       "  sum=ee_op_test_complex_func(sum);"
   16485                       "}"
   16486                       "sum;");
   16487   CHECK_EQ(16000000, result->Int32Value());
   16488 
   16489   // Test count operations
   16490   result = CompileRun("function ee_op_test_count_func(sum) {"
   16491                       " for (var i = 0; i < 40; ++i) {"
   16492                       "   sum += (++ext_array[i]);"
   16493                       "   sum += (--ext_array[i]);"
   16494                       " } "
   16495                       " return sum;"
   16496                       "}"
   16497                       "sum=0;"
   16498                       "for (var i=0;i<10000;++i) {"
   16499                       "  sum=ee_op_test_count_func(sum);"
   16500                       "}"
   16501                       "sum;");
   16502   CHECK_EQ(16000000, result->Int32Value());
   16503 
   16504   result = CompileRun("ext_array[3] = 33;"
   16505                       "delete ext_array[3];"
   16506                       "ext_array[3];");
   16507   CHECK_EQ(33, result->Int32Value());
   16508 
   16509   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
   16510                       "ext_array[2] = 12; ext_array[3] = 13;"
   16511                       "ext_array.__defineGetter__('2',"
   16512                       "function() { return 120; });"
   16513                       "ext_array[2];");
   16514   CHECK_EQ(12, result->Int32Value());
   16515 
   16516   result = CompileRun("var js_array = new Array(40);"
   16517                       "js_array[0] = 77;"
   16518                       "js_array;");
   16519   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   16520 
   16521   result = CompileRun("ext_array[1] = 23;"
   16522                       "ext_array.__proto__ = [];"
   16523                       "js_array.__proto__ = ext_array;"
   16524                       "js_array.concat(ext_array);");
   16525   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
   16526   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
   16527 
   16528   result = CompileRun("ext_array[1] = 23;");
   16529   CHECK_EQ(23, result->Int32Value());
   16530 }
   16531 
   16532 
   16533 template <class FixedTypedArrayClass,
   16534           i::ElementsKind elements_kind,
   16535           class ElementType>
   16536 static void FixedTypedArrayTestHelper(
   16537     v8::ExternalArrayType array_type,
   16538     ElementType low,
   16539     ElementType high) {
   16540   i::FLAG_allow_natives_syntax = true;
   16541   LocalContext context;
   16542   i::Isolate* isolate = CcTest::i_isolate();
   16543   i::Factory* factory = isolate->factory();
   16544   v8::HandleScope scope(context->GetIsolate());
   16545   const int kElementCount = 260;
   16546   i::Handle<FixedTypedArrayClass> fixed_array =
   16547     i::Handle<FixedTypedArrayClass>::cast(
   16548         factory->NewFixedTypedArray(kElementCount, array_type));
   16549   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
   16550            fixed_array->map()->instance_type());
   16551   CHECK_EQ(kElementCount, fixed_array->length());
   16552   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   16553   for (int i = 0; i < kElementCount; i++) {
   16554     fixed_array->set(i, static_cast<ElementType>(i));
   16555   }
   16556   // Force GC to trigger verification.
   16557   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   16558   for (int i = 0; i < kElementCount; i++) {
   16559     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
   16560              static_cast<int64_t>(fixed_array->get_scalar(i)));
   16561   }
   16562   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
   16563   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
   16564   i::Handle<i::Map> fixed_array_map =
   16565       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
   16566   jsobj->set_map(*fixed_array_map);
   16567   jsobj->set_elements(*fixed_array);
   16568 
   16569   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
   16570       context.local(), obj, kElementCount, array_type,
   16571       static_cast<int64_t>(low),
   16572       static_cast<int64_t>(high));
   16573 }
   16574 
   16575 
   16576 THREADED_TEST(FixedUint8Array) {
   16577   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
   16578     v8::kExternalUint8Array,
   16579     0x0, 0xFF);
   16580 }
   16581 
   16582 
   16583 THREADED_TEST(FixedUint8ClampedArray) {
   16584   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
   16585                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
   16586     v8::kExternalUint8ClampedArray,
   16587     0x0, 0xFF);
   16588 }
   16589 
   16590 
   16591 THREADED_TEST(FixedInt8Array) {
   16592   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
   16593     v8::kExternalInt8Array,
   16594     -0x80, 0x7F);
   16595 }
   16596 
   16597 
   16598 THREADED_TEST(FixedUint16Array) {
   16599   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
   16600     v8::kExternalUint16Array,
   16601     0x0, 0xFFFF);
   16602 }
   16603 
   16604 
   16605 THREADED_TEST(FixedInt16Array) {
   16606   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
   16607     v8::kExternalInt16Array,
   16608     -0x8000, 0x7FFF);
   16609 }
   16610 
   16611 
   16612 THREADED_TEST(FixedUint32Array) {
   16613   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
   16614     v8::kExternalUint32Array,
   16615     0x0, UINT_MAX);
   16616 }
   16617 
   16618 
   16619 THREADED_TEST(FixedInt32Array) {
   16620   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
   16621     v8::kExternalInt32Array,
   16622     INT_MIN, INT_MAX);
   16623 }
   16624 
   16625 
   16626 THREADED_TEST(FixedFloat32Array) {
   16627   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
   16628     v8::kExternalFloat32Array,
   16629     -500, 500);
   16630 }
   16631 
   16632 
   16633 THREADED_TEST(FixedFloat64Array) {
   16634   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
   16635     v8::kExternalFloat64Array,
   16636     -500, 500);
   16637 }
   16638 
   16639 
   16640 template <class ExternalArrayClass, class ElementType>
   16641 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
   16642                                     int64_t low,
   16643                                     int64_t high) {
   16644   LocalContext context;
   16645   i::Isolate* isolate = CcTest::i_isolate();
   16646   i::Factory* factory = isolate->factory();
   16647   v8::HandleScope scope(context->GetIsolate());
   16648   const int kElementCount = 40;
   16649   int element_size = ExternalArrayElementSize(array_type);
   16650   ElementType* array_data =
   16651       static_cast<ElementType*>(malloc(kElementCount * element_size));
   16652   i::Handle<ExternalArrayClass> array =
   16653       i::Handle<ExternalArrayClass>::cast(
   16654           factory->NewExternalArray(kElementCount, array_type, array_data));
   16655   // Force GC to trigger verification.
   16656   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   16657   for (int i = 0; i < kElementCount; i++) {
   16658     array->set(i, static_cast<ElementType>(i));
   16659   }
   16660   // Force GC to trigger verification.
   16661   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   16662   for (int i = 0; i < kElementCount; i++) {
   16663     CHECK_EQ(static_cast<int64_t>(i),
   16664              static_cast<int64_t>(array->get_scalar(i)));
   16665     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
   16666   }
   16667 
   16668   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
   16669   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
   16670   // Set the elements to be the external array.
   16671   obj->SetIndexedPropertiesToExternalArrayData(array_data,
   16672                                                array_type,
   16673                                                kElementCount);
   16674   CHECK_EQ(1,
   16675            static_cast<int>(
   16676                i::Object::GetElement(
   16677                    isolate, jsobj, 1).ToHandleChecked()->Number()));
   16678 
   16679   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
   16680       context.local(), obj, kElementCount, array_type, low, high);
   16681 
   16682   v8::Handle<v8::Value> result;
   16683 
   16684   // Test more complex manipulations which cause eax to contain values
   16685   // that won't be completely overwritten by loads from the arrays.
   16686   // This catches bugs in the instructions used for the KeyedLoadIC
   16687   // for byte and word types.
   16688   {
   16689     const int kXSize = 300;
   16690     const int kYSize = 300;
   16691     const int kLargeElementCount = kXSize * kYSize * 4;
   16692     ElementType* large_array_data =
   16693         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
   16694     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
   16695     // Set the elements to be the external array.
   16696     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
   16697                                                        array_type,
   16698                                                        kLargeElementCount);
   16699     context->Global()->Set(v8_str("large_array"), large_obj);
   16700     // Initialize contents of a few rows.
   16701     for (int x = 0; x < 300; x++) {
   16702       int row = 0;
   16703       int offset = row * 300 * 4;
   16704       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
   16705       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
   16706       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
   16707       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
   16708       row = 150;
   16709       offset = row * 300 * 4;
   16710       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
   16711       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
   16712       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
   16713       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
   16714       row = 298;
   16715       offset = row * 300 * 4;
   16716       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
   16717       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
   16718       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
   16719       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
   16720     }
   16721     // The goal of the code below is to make "offset" large enough
   16722     // that the computation of the index (which goes into eax) has
   16723     // high bits set which will not be overwritten by a byte or short
   16724     // load.
   16725     result = CompileRun("var failed = false;"
   16726                         "var offset = 0;"
   16727                         "for (var i = 0; i < 300; i++) {"
   16728                         "  if (large_array[4 * i] != 127 ||"
   16729                         "      large_array[4 * i + 1] != 0 ||"
   16730                         "      large_array[4 * i + 2] != 0 ||"
   16731                         "      large_array[4 * i + 3] != 127) {"
   16732                         "    failed = true;"
   16733                         "  }"
   16734                         "}"
   16735                         "offset = 150 * 300 * 4;"
   16736                         "for (var i = 0; i < 300; i++) {"
   16737                         "  if (large_array[offset + 4 * i] != 127 ||"
   16738                         "      large_array[offset + 4 * i + 1] != 0 ||"
   16739                         "      large_array[offset + 4 * i + 2] != 0 ||"
   16740                         "      large_array[offset + 4 * i + 3] != 127) {"
   16741                         "    failed = true;"
   16742                         "  }"
   16743                         "}"
   16744                         "offset = 298 * 300 * 4;"
   16745                         "for (var i = 0; i < 300; i++) {"
   16746                         "  if (large_array[offset + 4 * i] != 127 ||"
   16747                         "      large_array[offset + 4 * i + 1] != 0 ||"
   16748                         "      large_array[offset + 4 * i + 2] != 0 ||"
   16749                         "      large_array[offset + 4 * i + 3] != 127) {"
   16750                         "    failed = true;"
   16751                         "  }"
   16752                         "}"
   16753                         "!failed;");
   16754     CHECK_EQ(true, result->BooleanValue());
   16755     free(large_array_data);
   16756   }
   16757 
   16758   // The "" property descriptor is overloaded to store information about
   16759   // the external array. Ensure that setting and accessing the "" property
   16760   // works (it should overwrite the information cached about the external
   16761   // array in the DescriptorArray) in various situations.
   16762   result = CompileRun("ext_array[''] = 23; ext_array['']");
   16763   CHECK_EQ(23, result->Int32Value());
   16764 
   16765   // Property "" set after the external array is associated with the object.
   16766   {
   16767     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
   16768     obj2->Set(v8_str("ee_test_field"),
   16769               v8::Int32::New(context->GetIsolate(), 256));
   16770     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
   16771     // Set the elements to be the external array.
   16772     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
   16773                                                   array_type,
   16774                                                   kElementCount);
   16775     context->Global()->Set(v8_str("ext_array"), obj2);
   16776     result = CompileRun("ext_array['']");
   16777     CHECK_EQ(1503, result->Int32Value());
   16778   }
   16779 
   16780   // Property "" set after the external array is associated with the object.
   16781   {
   16782     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
   16783     obj2->Set(v8_str("ee_test_field_2"),
   16784               v8::Int32::New(context->GetIsolate(), 256));
   16785     // Set the elements to be the external array.
   16786     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
   16787                                                   array_type,
   16788                                                   kElementCount);
   16789     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
   16790     context->Global()->Set(v8_str("ext_array"), obj2);
   16791     result = CompileRun("ext_array['']");
   16792     CHECK_EQ(1503, result->Int32Value());
   16793   }
   16794 
   16795   // Should reuse the map from previous test.
   16796   {
   16797     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
   16798     obj2->Set(v8_str("ee_test_field_2"),
   16799               v8::Int32::New(context->GetIsolate(), 256));
   16800     // Set the elements to be the external array. Should re-use the map
   16801     // from previous test.
   16802     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
   16803                                                   array_type,
   16804                                                   kElementCount);
   16805     context->Global()->Set(v8_str("ext_array"), obj2);
   16806     result = CompileRun("ext_array['']");
   16807   }
   16808 
   16809   // Property "" is a constant function that shouldn't not be interfered with
   16810   // when an external array is set.
   16811   {
   16812     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
   16813     // Start
   16814     obj2->Set(v8_str("ee_test_field3"),
   16815               v8::Int32::New(context->GetIsolate(), 256));
   16816 
   16817     // Add a constant function to an object.
   16818     context->Global()->Set(v8_str("ext_array"), obj2);
   16819     result = CompileRun("ext_array[''] = function() {return 1503;};"
   16820                         "ext_array['']();");
   16821 
   16822     // Add an external array transition to the same map that
   16823     // has the constant transition.
   16824     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
   16825     obj3->Set(v8_str("ee_test_field3"),
   16826               v8::Int32::New(context->GetIsolate(), 256));
   16827     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
   16828                                                   array_type,
   16829                                                   kElementCount);
   16830     context->Global()->Set(v8_str("ext_array"), obj3);
   16831   }
   16832 
   16833   // If a external array transition is in the map, it should get clobbered
   16834   // by a constant function.
   16835   {
   16836     // Add an external array transition.
   16837     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
   16838     obj3->Set(v8_str("ee_test_field4"),
   16839               v8::Int32::New(context->GetIsolate(), 256));
   16840     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
   16841                                                   array_type,
   16842                                                   kElementCount);
   16843 
   16844     // Add a constant function to the same map that just got an external array
   16845     // transition.
   16846     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
   16847     obj2->Set(v8_str("ee_test_field4"),
   16848               v8::Int32::New(context->GetIsolate(), 256));
   16849     context->Global()->Set(v8_str("ext_array"), obj2);
   16850     result = CompileRun("ext_array[''] = function() {return 1503;};"
   16851                         "ext_array['']();");
   16852   }
   16853 
   16854   free(array_data);
   16855 }
   16856 
   16857 
   16858 THREADED_TEST(ExternalInt8Array) {
   16859   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
   16860       v8::kExternalInt8Array,
   16861       -128,
   16862       127);
   16863 }
   16864 
   16865 
   16866 THREADED_TEST(ExternalUint8Array) {
   16867   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
   16868       v8::kExternalUint8Array,
   16869       0,
   16870       255);
   16871 }
   16872 
   16873 
   16874 THREADED_TEST(ExternalUint8ClampedArray) {
   16875   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
   16876       v8::kExternalUint8ClampedArray,
   16877       0,
   16878       255);
   16879 }
   16880 
   16881 
   16882 THREADED_TEST(ExternalInt16Array) {
   16883   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
   16884       v8::kExternalInt16Array,
   16885       -32768,
   16886       32767);
   16887 }
   16888 
   16889 
   16890 THREADED_TEST(ExternalUint16Array) {
   16891   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
   16892       v8::kExternalUint16Array,
   16893       0,
   16894       65535);
   16895 }
   16896 
   16897 
   16898 THREADED_TEST(ExternalInt32Array) {
   16899   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
   16900       v8::kExternalInt32Array,
   16901       INT_MIN,   // -2147483648
   16902       INT_MAX);  //  2147483647
   16903 }
   16904 
   16905 
   16906 THREADED_TEST(ExternalUint32Array) {
   16907   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
   16908       v8::kExternalUint32Array,
   16909       0,
   16910       UINT_MAX);  // 4294967295
   16911 }
   16912 
   16913 
   16914 THREADED_TEST(ExternalFloat32Array) {
   16915   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
   16916       v8::kExternalFloat32Array,
   16917       -500,
   16918       500);
   16919 }
   16920 
   16921 
   16922 THREADED_TEST(ExternalFloat64Array) {
   16923   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
   16924       v8::kExternalFloat64Array,
   16925       -500,
   16926       500);
   16927 }
   16928 
   16929 
   16930 THREADED_TEST(ExternalArrays) {
   16931   TestExternalInt8Array();
   16932   TestExternalUint8Array();
   16933   TestExternalInt16Array();
   16934   TestExternalUint16Array();
   16935   TestExternalInt32Array();
   16936   TestExternalUint32Array();
   16937   TestExternalFloat32Array();
   16938 }
   16939 
   16940 
   16941 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
   16942   LocalContext context;
   16943   v8::HandleScope scope(context->GetIsolate());
   16944   for (int size = 0; size < 100; size += 10) {
   16945     int element_size = ExternalArrayElementSize(array_type);
   16946     void* external_data = malloc(size * element_size);
   16947     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
   16948     obj->SetIndexedPropertiesToExternalArrayData(
   16949         external_data, array_type, size);
   16950     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
   16951     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
   16952     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
   16953     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
   16954     free(external_data);
   16955   }
   16956 }
   16957 
   16958 
   16959 THREADED_TEST(ExternalArrayInfo) {
   16960   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
   16961   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
   16962   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
   16963   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
   16964   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
   16965   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
   16966   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
   16967   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
   16968   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
   16969 }
   16970 
   16971 
   16972 void ExtArrayLimitsHelper(v8::Isolate* isolate,
   16973                           v8::ExternalArrayType array_type,
   16974                           int size) {
   16975   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
   16976   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   16977   last_location = last_message = NULL;
   16978   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
   16979   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
   16980   CHECK_NE(NULL, last_location);
   16981   CHECK_NE(NULL, last_message);
   16982 }
   16983 
   16984 
   16985 TEST(ExternalArrayLimits) {
   16986   LocalContext context;
   16987   v8::Isolate* isolate = context->GetIsolate();
   16988   v8::HandleScope scope(isolate);
   16989   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
   16990   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
   16991   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
   16992   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
   16993   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
   16994   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
   16995   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
   16996   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
   16997   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
   16998   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
   16999   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
   17000   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
   17001   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
   17002   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
   17003   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
   17004   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
   17005   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
   17006   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
   17007 }
   17008 
   17009 
   17010 template <typename ElementType, typename TypedArray,
   17011           class ExternalArrayClass>
   17012 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
   17013                           int64_t low, int64_t high) {
   17014   const int kElementCount = 50;
   17015 
   17016   i::ScopedVector<ElementType> backing_store(kElementCount+2);
   17017 
   17018   LocalContext env;
   17019   v8::Isolate* isolate = env->GetIsolate();
   17020   v8::HandleScope handle_scope(isolate);
   17021 
   17022   Local<v8::ArrayBuffer> ab =
   17023       v8::ArrayBuffer::New(isolate, backing_store.start(),
   17024                            (kElementCount + 2) * sizeof(ElementType));
   17025   Local<TypedArray> ta =
   17026       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
   17027   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
   17028   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
   17029   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
   17030   CHECK_EQ(kElementCount*sizeof(ElementType),
   17031            static_cast<int>(ta->ByteLength()));
   17032   CHECK_EQ(ab, ta->Buffer());
   17033 
   17034   ElementType* data = backing_store.start() + 2;
   17035   for (int i = 0; i < kElementCount; i++) {
   17036     data[i] = static_cast<ElementType>(i);
   17037   }
   17038 
   17039   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
   17040       env.local(), ta, kElementCount, array_type, low, high);
   17041 }
   17042 
   17043 
   17044 THREADED_TEST(Uint8Array) {
   17045   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
   17046       v8::kExternalUint8Array, 0, 0xFF);
   17047 }
   17048 
   17049 
   17050 THREADED_TEST(Int8Array) {
   17051   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
   17052       v8::kExternalInt8Array, -0x80, 0x7F);
   17053 }
   17054 
   17055 
   17056 THREADED_TEST(Uint16Array) {
   17057   TypedArrayTestHelper<uint16_t,
   17058                        v8::Uint16Array,
   17059                        i::ExternalUint16Array>(
   17060       v8::kExternalUint16Array, 0, 0xFFFF);
   17061 }
   17062 
   17063 
   17064 THREADED_TEST(Int16Array) {
   17065   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
   17066       v8::kExternalInt16Array, -0x8000, 0x7FFF);
   17067 }
   17068 
   17069 
   17070 THREADED_TEST(Uint32Array) {
   17071   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
   17072       v8::kExternalUint32Array, 0, UINT_MAX);
   17073 }
   17074 
   17075 
   17076 THREADED_TEST(Int32Array) {
   17077   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
   17078       v8::kExternalInt32Array, INT_MIN, INT_MAX);
   17079 }
   17080 
   17081 
   17082 THREADED_TEST(Float32Array) {
   17083   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
   17084       v8::kExternalFloat32Array, -500, 500);
   17085 }
   17086 
   17087 
   17088 THREADED_TEST(Float64Array) {
   17089   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
   17090       v8::kExternalFloat64Array, -500, 500);
   17091 }
   17092 
   17093 
   17094 THREADED_TEST(Uint8ClampedArray) {
   17095   TypedArrayTestHelper<uint8_t,
   17096                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
   17097       v8::kExternalUint8ClampedArray, 0, 0xFF);
   17098 }
   17099 
   17100 
   17101 THREADED_TEST(DataView) {
   17102   const int kSize = 50;
   17103 
   17104   i::ScopedVector<uint8_t> backing_store(kSize+2);
   17105 
   17106   LocalContext env;
   17107   v8::Isolate* isolate = env->GetIsolate();
   17108   v8::HandleScope handle_scope(isolate);
   17109 
   17110   Local<v8::ArrayBuffer> ab =
   17111       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
   17112   Local<v8::DataView> dv =
   17113       v8::DataView::New(ab, 2, kSize);
   17114   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
   17115   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
   17116   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
   17117   CHECK_EQ(ab, dv->Buffer());
   17118 }
   17119 
   17120 
   17121 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
   17122   THREADED_TEST(Is##View) {                                                   \
   17123     LocalContext env;                                                         \
   17124     v8::Isolate* isolate = env->GetIsolate();                                 \
   17125     v8::HandleScope handle_scope(isolate);                                    \
   17126                                                                               \
   17127     Handle<Value> result = CompileRun(                                        \
   17128         "var ab = new ArrayBuffer(128);"                                      \
   17129         "new " #View "(ab)");                                                 \
   17130     CHECK(result->IsArrayBufferView());                                       \
   17131     CHECK(result->Is##View());                                                \
   17132     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
   17133   }
   17134 
   17135 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
   17136 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
   17137 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
   17138 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
   17139 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
   17140 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
   17141 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
   17142 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
   17143 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
   17144 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
   17145 
   17146 #undef IS_ARRAY_BUFFER_VIEW_TEST
   17147 
   17148 
   17149 
   17150 THREADED_TEST(ScriptContextDependence) {
   17151   LocalContext c1;
   17152   v8::HandleScope scope(c1->GetIsolate());
   17153   const char *source = "foo";
   17154   v8::Handle<v8::Script> dep = v8_compile(source);
   17155   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
   17156       c1->GetIsolate(), source));
   17157   v8::Handle<v8::UnboundScript> indep =
   17158       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
   17159   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
   17160                     v8::Integer::New(c1->GetIsolate(), 100));
   17161   CHECK_EQ(dep->Run()->Int32Value(), 100);
   17162   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
   17163   LocalContext c2;
   17164   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
   17165                     v8::Integer::New(c2->GetIsolate(), 101));
   17166   CHECK_EQ(dep->Run()->Int32Value(), 100);
   17167   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
   17168 }
   17169 
   17170 
   17171 THREADED_TEST(StackTrace) {
   17172   LocalContext context;
   17173   v8::HandleScope scope(context->GetIsolate());
   17174   v8::TryCatch try_catch;
   17175   const char *source = "function foo() { FAIL.FAIL; }; foo();";
   17176   v8::Handle<v8::String> src =
   17177       v8::String::NewFromUtf8(context->GetIsolate(), source);
   17178   v8::Handle<v8::String> origin =
   17179       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
   17180   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
   17181   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
   17182       ->BindToCurrentContext()
   17183       ->Run();
   17184   CHECK(try_catch.HasCaught());
   17185   v8::String::Utf8Value stack(try_catch.StackTrace());
   17186   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
   17187 }
   17188 
   17189 
   17190 // Checks that a StackFrame has certain expected values.
   17191 void checkStackFrame(const char* expected_script_name,
   17192     const char* expected_func_name, int expected_line_number,
   17193     int expected_column, bool is_eval, bool is_constructor,
   17194     v8::Handle<v8::StackFrame> frame) {
   17195   v8::HandleScope scope(CcTest::isolate());
   17196   v8::String::Utf8Value func_name(frame->GetFunctionName());
   17197   v8::String::Utf8Value script_name(frame->GetScriptName());
   17198   if (*script_name == NULL) {
   17199     // The situation where there is no associated script, like for evals.
   17200     CHECK(expected_script_name == NULL);
   17201   } else {
   17202     CHECK(strstr(*script_name, expected_script_name) != NULL);
   17203   }
   17204   CHECK(strstr(*func_name, expected_func_name) != NULL);
   17205   CHECK_EQ(expected_line_number, frame->GetLineNumber());
   17206   CHECK_EQ(expected_column, frame->GetColumn());
   17207   CHECK_EQ(is_eval, frame->IsEval());
   17208   CHECK_EQ(is_constructor, frame->IsConstructor());
   17209 }
   17210 
   17211 
   17212 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
   17213   v8::HandleScope scope(args.GetIsolate());
   17214   const char* origin = "capture-stack-trace-test";
   17215   const int kOverviewTest = 1;
   17216   const int kDetailedTest = 2;
   17217 
   17218   ASSERT(args.Length() == 1);
   17219 
   17220   int testGroup = args[0]->Int32Value();
   17221   if (testGroup == kOverviewTest) {
   17222     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
   17223         args.GetIsolate(), 10, v8::StackTrace::kOverview);
   17224     CHECK_EQ(4, stackTrace->GetFrameCount());
   17225     checkStackFrame(origin, "bar", 2, 10, false, false,
   17226                     stackTrace->GetFrame(0));
   17227     checkStackFrame(origin, "foo", 6, 3, false, false,
   17228                     stackTrace->GetFrame(1));
   17229     // This is the source string inside the eval which has the call to foo.
   17230     checkStackFrame(NULL, "", 1, 5, false, false,
   17231                     stackTrace->GetFrame(2));
   17232     // The last frame is an anonymous function which has the initial eval call.
   17233     checkStackFrame(origin, "", 8, 7, false, false,
   17234                     stackTrace->GetFrame(3));
   17235 
   17236     CHECK(stackTrace->AsArray()->IsArray());
   17237   } else if (testGroup == kDetailedTest) {
   17238     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
   17239         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
   17240     CHECK_EQ(4, stackTrace->GetFrameCount());
   17241     checkStackFrame(origin, "bat", 4, 22, false, false,
   17242                     stackTrace->GetFrame(0));
   17243     checkStackFrame(origin, "baz", 8, 3, false, true,
   17244                     stackTrace->GetFrame(1));
   17245     bool is_eval = true;
   17246     // This is the source string inside the eval which has the call to baz.
   17247     checkStackFrame(NULL, "", 1, 5, is_eval, false,
   17248                     stackTrace->GetFrame(2));
   17249     // The last frame is an anonymous function which has the initial eval call.
   17250     checkStackFrame(origin, "", 10, 1, false, false,
   17251                     stackTrace->GetFrame(3));
   17252 
   17253     CHECK(stackTrace->AsArray()->IsArray());
   17254   }
   17255 }
   17256 
   17257 
   17258 // Tests the C++ StackTrace API.
   17259 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
   17260 // THREADED_TEST(CaptureStackTrace) {
   17261 TEST(CaptureStackTrace) {
   17262   v8::Isolate* isolate = CcTest::isolate();
   17263   v8::HandleScope scope(isolate);
   17264   v8::Handle<v8::String> origin =
   17265       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
   17266   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   17267   templ->Set(v8_str("AnalyzeStackInNativeCode"),
   17268              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
   17269   LocalContext context(0, templ);
   17270 
   17271   // Test getting OVERVIEW information. Should ignore information that is not
   17272   // script name, function name, line number, and column offset.
   17273   const char *overview_source =
   17274     "function bar() {\n"
   17275     "  var y; AnalyzeStackInNativeCode(1);\n"
   17276     "}\n"
   17277     "function foo() {\n"
   17278     "\n"
   17279     "  bar();\n"
   17280     "}\n"
   17281     "var x;eval('new foo();');";
   17282   v8::Handle<v8::String> overview_src =
   17283       v8::String::NewFromUtf8(isolate, overview_source);
   17284   v8::ScriptCompiler::Source script_source(overview_src,
   17285                                            v8::ScriptOrigin(origin));
   17286   v8::Handle<Value> overview_result(
   17287       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
   17288           ->BindToCurrentContext()
   17289           ->Run());
   17290   CHECK(!overview_result.IsEmpty());
   17291   CHECK(overview_result->IsObject());
   17292 
   17293   // Test getting DETAILED information.
   17294   const char *detailed_source =
   17295     "function bat() {AnalyzeStackInNativeCode(2);\n"
   17296     "}\n"
   17297     "\n"
   17298     "function baz() {\n"
   17299     "  bat();\n"
   17300     "}\n"
   17301     "eval('new baz();');";
   17302   v8::Handle<v8::String> detailed_src =
   17303       v8::String::NewFromUtf8(isolate, detailed_source);
   17304   // Make the script using a non-zero line and column offset.
   17305   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
   17306   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
   17307   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
   17308   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
   17309   v8::Handle<v8::UnboundScript> detailed_script(
   17310       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
   17311   v8::Handle<Value> detailed_result(
   17312       detailed_script->BindToCurrentContext()->Run());
   17313   CHECK(!detailed_result.IsEmpty());
   17314   CHECK(detailed_result->IsObject());
   17315 }
   17316 
   17317 
   17318 static void StackTraceForUncaughtExceptionListener(
   17319     v8::Handle<v8::Message> message,
   17320     v8::Handle<Value>) {
   17321   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   17322   CHECK_EQ(2, stack_trace->GetFrameCount());
   17323   checkStackFrame("origin", "foo", 2, 3, false, false,
   17324                   stack_trace->GetFrame(0));
   17325   checkStackFrame("origin", "bar", 5, 3, false, false,
   17326                   stack_trace->GetFrame(1));
   17327 }
   17328 
   17329 
   17330 TEST(CaptureStackTraceForUncaughtException) {
   17331   report_count = 0;
   17332   LocalContext env;
   17333   v8::HandleScope scope(env->GetIsolate());
   17334   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
   17335   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
   17336 
   17337   CompileRunWithOrigin(
   17338       "function foo() {\n"
   17339       "  throw 1;\n"
   17340       "};\n"
   17341       "function bar() {\n"
   17342       "  foo();\n"
   17343       "};",
   17344       "origin");
   17345   v8::Local<v8::Object> global = env->Global();
   17346   Local<Value> trouble = global->Get(v8_str("bar"));
   17347   CHECK(trouble->IsFunction());
   17348   Function::Cast(*trouble)->Call(global, 0, NULL);
   17349   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   17350   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
   17351 }
   17352 
   17353 
   17354 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
   17355   LocalContext env;
   17356   v8::HandleScope scope(env->GetIsolate());
   17357   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
   17358                                                     1024,
   17359                                                     v8::StackTrace::kDetailed);
   17360 
   17361   CompileRun(
   17362       "var setters = ['column', 'lineNumber', 'scriptName',\n"
   17363       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
   17364       "    'isConstructor'];\n"
   17365       "for (var i = 0; i < setters.length; i++) {\n"
   17366       "  var prop = setters[i];\n"
   17367       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
   17368       "}\n");
   17369   CompileRun("throw 'exception';");
   17370   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   17371 }
   17372 
   17373 
   17374 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
   17375                                      v8::Handle<v8::Value> data) {
   17376   // Use the frame where JavaScript is called from.
   17377   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   17378   CHECK(!stack_trace.IsEmpty());
   17379   int frame_count = stack_trace->GetFrameCount();
   17380   CHECK_EQ(3, frame_count);
   17381   int line_number[] = {1, 2, 5};
   17382   for (int i = 0; i < frame_count; i++) {
   17383     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
   17384   }
   17385 }
   17386 
   17387 
   17388 // Test that we only return the stack trace at the site where the exception
   17389 // is first thrown (not where it is rethrown).
   17390 TEST(RethrowStackTrace) {
   17391   LocalContext env;
   17392   v8::HandleScope scope(env->GetIsolate());
   17393   // We make sure that
   17394   // - the stack trace of the ReferenceError in g() is reported.
   17395   // - the stack trace is not overwritten when e1 is rethrown by t().
   17396   // - the stack trace of e2 does not overwrite that of e1.
   17397   const char* source =
   17398       "function g() { error; }          \n"
   17399       "function f() { g(); }            \n"
   17400       "function t(e) { throw e; }       \n"
   17401       "try {                            \n"
   17402       "  f();                           \n"
   17403       "} catch (e1) {                   \n"
   17404       "  try {                          \n"
   17405       "    error;                       \n"
   17406       "  } catch (e2) {                 \n"
   17407       "    t(e1);                       \n"
   17408       "  }                              \n"
   17409       "}                                \n";
   17410   v8::V8::AddMessageListener(RethrowStackTraceHandler);
   17411   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
   17412   CompileRun(source);
   17413   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   17414   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
   17415 }
   17416 
   17417 
   17418 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
   17419                                               v8::Handle<v8::Value> data) {
   17420   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   17421   CHECK(!stack_trace.IsEmpty());
   17422   int frame_count = stack_trace->GetFrameCount();
   17423   CHECK_EQ(2, frame_count);
   17424   int line_number[] = {3, 7};
   17425   for (int i = 0; i < frame_count; i++) {
   17426     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
   17427   }
   17428 }
   17429 
   17430 
   17431 // Test that we do not recognize identity for primitive exceptions.
   17432 TEST(RethrowPrimitiveStackTrace) {
   17433   LocalContext env;
   17434   v8::HandleScope scope(env->GetIsolate());
   17435   // We do not capture stack trace for non Error objects on creation time.
   17436   // Instead, we capture the stack trace on last throw.
   17437   const char* source =
   17438       "function g() { throw 404; }      \n"
   17439       "function f() { g(); }            \n"
   17440       "function t(e) { throw e; }       \n"
   17441       "try {                            \n"
   17442       "  f();                           \n"
   17443       "} catch (e1) {                   \n"
   17444       "  t(e1)                          \n"
   17445       "}                                \n";
   17446   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
   17447   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
   17448   CompileRun(source);
   17449   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   17450   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
   17451 }
   17452 
   17453 
   17454 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
   17455                                               v8::Handle<v8::Value> data) {
   17456   // Use the frame where JavaScript is called from.
   17457   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   17458   CHECK(!stack_trace.IsEmpty());
   17459   CHECK_EQ(1, stack_trace->GetFrameCount());
   17460   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
   17461 }
   17462 
   17463 
   17464 // Test that the stack trace is captured when the error object is created and
   17465 // not where it is thrown.
   17466 TEST(RethrowExistingStackTrace) {
   17467   LocalContext env;
   17468   v8::HandleScope scope(env->GetIsolate());
   17469   const char* source =
   17470       "var e = new Error();           \n"
   17471       "throw e;                       \n";
   17472   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
   17473   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
   17474   CompileRun(source);
   17475   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   17476   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
   17477 }
   17478 
   17479 
   17480 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
   17481                                                v8::Handle<v8::Value> data) {
   17482   // Use the frame where JavaScript is called from.
   17483   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   17484   CHECK(!stack_trace.IsEmpty());
   17485   CHECK_EQ(1, stack_trace->GetFrameCount());
   17486   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
   17487 }
   17488 
   17489 
   17490 // Test that the stack trace is captured where the bogus Error object is thrown.
   17491 TEST(RethrowBogusErrorStackTrace) {
   17492   LocalContext env;
   17493   v8::HandleScope scope(env->GetIsolate());
   17494   const char* source =
   17495       "var e = {__proto__: new Error()} \n"
   17496       "throw e;                         \n";
   17497   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
   17498   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
   17499   CompileRun(source);
   17500   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   17501   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
   17502 }
   17503 
   17504 
   17505 void AnalyzeStackOfEvalWithSourceURL(
   17506     const v8::FunctionCallbackInfo<v8::Value>& args) {
   17507   v8::HandleScope scope(args.GetIsolate());
   17508   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
   17509       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
   17510   CHECK_EQ(5, stackTrace->GetFrameCount());
   17511   v8::Handle<v8::String> url = v8_str("eval_url");
   17512   for (int i = 0; i < 3; i++) {
   17513     v8::Handle<v8::String> name =
   17514         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
   17515     CHECK(!name.IsEmpty());
   17516     CHECK_EQ(url, name);
   17517   }
   17518 }
   17519 
   17520 
   17521 TEST(SourceURLInStackTrace) {
   17522   v8::Isolate* isolate = CcTest::isolate();
   17523   v8::HandleScope scope(isolate);
   17524   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   17525   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
   17526              v8::FunctionTemplate::New(isolate,
   17527                                        AnalyzeStackOfEvalWithSourceURL));
   17528   LocalContext context(0, templ);
   17529 
   17530   const char *source =
   17531     "function outer() {\n"
   17532     "function bar() {\n"
   17533     "  AnalyzeStackOfEvalWithSourceURL();\n"
   17534     "}\n"
   17535     "function foo() {\n"
   17536     "\n"
   17537     "  bar();\n"
   17538     "}\n"
   17539     "foo();\n"
   17540     "}\n"
   17541     "eval('(' + outer +')()%s');";
   17542 
   17543   i::ScopedVector<char> code(1024);
   17544   i::SNPrintF(code, source, "//# sourceURL=eval_url");
   17545   CHECK(CompileRun(code.start())->IsUndefined());
   17546   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
   17547   CHECK(CompileRun(code.start())->IsUndefined());
   17548 }
   17549 
   17550 
   17551 static int scriptIdInStack[2];
   17552 
   17553 void AnalyzeScriptIdInStack(
   17554     const v8::FunctionCallbackInfo<v8::Value>& args) {
   17555   v8::HandleScope scope(args.GetIsolate());
   17556   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
   17557       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
   17558   CHECK_EQ(2, stackTrace->GetFrameCount());
   17559   for (int i = 0; i < 2; i++) {
   17560     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
   17561   }
   17562 }
   17563 
   17564 
   17565 TEST(ScriptIdInStackTrace) {
   17566   v8::Isolate* isolate = CcTest::isolate();
   17567   v8::HandleScope scope(isolate);
   17568   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   17569   templ->Set(v8_str("AnalyzeScriptIdInStack"),
   17570              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
   17571   LocalContext context(0, templ);
   17572 
   17573   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
   17574     isolate,
   17575     "function foo() {\n"
   17576     "  AnalyzeScriptIdInStack();"
   17577     "}\n"
   17578     "foo();\n");
   17579   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
   17580   script->Run();
   17581   for (int i = 0; i < 2; i++) {
   17582     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
   17583     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
   17584   }
   17585 }
   17586 
   17587 
   17588 void AnalyzeStackOfInlineScriptWithSourceURL(
   17589     const v8::FunctionCallbackInfo<v8::Value>& args) {
   17590   v8::HandleScope scope(args.GetIsolate());
   17591   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
   17592       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
   17593   CHECK_EQ(4, stackTrace->GetFrameCount());
   17594   v8::Handle<v8::String> url = v8_str("url");
   17595   for (int i = 0; i < 3; i++) {
   17596     v8::Handle<v8::String> name =
   17597         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
   17598     CHECK(!name.IsEmpty());
   17599     CHECK_EQ(url, name);
   17600   }
   17601 }
   17602 
   17603 
   17604 TEST(InlineScriptWithSourceURLInStackTrace) {
   17605   v8::Isolate* isolate = CcTest::isolate();
   17606   v8::HandleScope scope(isolate);
   17607   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   17608   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
   17609              v8::FunctionTemplate::New(
   17610                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
   17611   LocalContext context(0, templ);
   17612 
   17613   const char *source =
   17614     "function outer() {\n"
   17615     "function bar() {\n"
   17616     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
   17617     "}\n"
   17618     "function foo() {\n"
   17619     "\n"
   17620     "  bar();\n"
   17621     "}\n"
   17622     "foo();\n"
   17623     "}\n"
   17624     "outer()\n%s";
   17625 
   17626   i::ScopedVector<char> code(1024);
   17627   i::SNPrintF(code, source, "//# sourceURL=source_url");
   17628   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
   17629   i::SNPrintF(code, source, "//@ sourceURL=source_url");
   17630   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
   17631 }
   17632 
   17633 
   17634 void AnalyzeStackOfDynamicScriptWithSourceURL(
   17635     const v8::FunctionCallbackInfo<v8::Value>& args) {
   17636   v8::HandleScope scope(args.GetIsolate());
   17637   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
   17638       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
   17639   CHECK_EQ(4, stackTrace->GetFrameCount());
   17640   v8::Handle<v8::String> url = v8_str("source_url");
   17641   for (int i = 0; i < 3; i++) {
   17642     v8::Handle<v8::String> name =
   17643         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
   17644     CHECK(!name.IsEmpty());
   17645     CHECK_EQ(url, name);
   17646   }
   17647 }
   17648 
   17649 
   17650 TEST(DynamicWithSourceURLInStackTrace) {
   17651   v8::Isolate* isolate = CcTest::isolate();
   17652   v8::HandleScope scope(isolate);
   17653   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   17654   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
   17655              v8::FunctionTemplate::New(
   17656                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
   17657   LocalContext context(0, templ);
   17658 
   17659   const char *source =
   17660     "function outer() {\n"
   17661     "function bar() {\n"
   17662     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
   17663     "}\n"
   17664     "function foo() {\n"
   17665     "\n"
   17666     "  bar();\n"
   17667     "}\n"
   17668     "foo();\n"
   17669     "}\n"
   17670     "outer()\n%s";
   17671 
   17672   i::ScopedVector<char> code(1024);
   17673   i::SNPrintF(code, source, "//# sourceURL=source_url");
   17674   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
   17675   i::SNPrintF(code, source, "//@ sourceURL=source_url");
   17676   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
   17677 }
   17678 
   17679 
   17680 TEST(DynamicWithSourceURLInStackTraceString) {
   17681   LocalContext context;
   17682   v8::HandleScope scope(context->GetIsolate());
   17683 
   17684   const char *source =
   17685     "function outer() {\n"
   17686     "  function foo() {\n"
   17687     "    FAIL.FAIL;\n"
   17688     "  }\n"
   17689     "  foo();\n"
   17690     "}\n"
   17691     "outer()\n%s";
   17692 
   17693   i::ScopedVector<char> code(1024);
   17694   i::SNPrintF(code, source, "//# sourceURL=source_url");
   17695   v8::TryCatch try_catch;
   17696   CompileRunWithOrigin(code.start(), "", 0, 0);
   17697   CHECK(try_catch.HasCaught());
   17698   v8::String::Utf8Value stack(try_catch.StackTrace());
   17699   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
   17700 }
   17701 
   17702 
   17703 static void CreateGarbageInOldSpace() {
   17704   i::Factory* factory = CcTest::i_isolate()->factory();
   17705   v8::HandleScope scope(CcTest::isolate());
   17706   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
   17707   for (int i = 0; i < 1000; i++) {
   17708     factory->NewFixedArray(1000, i::TENURED);
   17709   }
   17710 }
   17711 
   17712 
   17713 // Test that idle notification can be handled and eventually returns true.
   17714 TEST(IdleNotification) {
   17715   const intptr_t MB = 1024 * 1024;
   17716   LocalContext env;
   17717   v8::HandleScope scope(env->GetIsolate());
   17718   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
   17719   CreateGarbageInOldSpace();
   17720   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
   17721   CHECK_GT(size_with_garbage, initial_size + MB);
   17722   bool finished = false;
   17723   for (int i = 0; i < 200 && !finished; i++) {
   17724     finished = v8::V8::IdleNotification();
   17725   }
   17726   intptr_t final_size = CcTest::heap()->SizeOfObjects();
   17727   CHECK(finished);
   17728   CHECK_LT(final_size, initial_size + 1);
   17729 }
   17730 
   17731 
   17732 // Test that idle notification can be handled and eventually collects garbage.
   17733 TEST(IdleNotificationWithSmallHint) {
   17734   const intptr_t MB = 1024 * 1024;
   17735   const int IdlePauseInMs = 900;
   17736   LocalContext env;
   17737   v8::HandleScope scope(env->GetIsolate());
   17738   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
   17739   CreateGarbageInOldSpace();
   17740   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
   17741   CHECK_GT(size_with_garbage, initial_size + MB);
   17742   bool finished = false;
   17743   for (int i = 0; i < 200 && !finished; i++) {
   17744     finished = v8::V8::IdleNotification(IdlePauseInMs);
   17745   }
   17746   intptr_t final_size = CcTest::heap()->SizeOfObjects();
   17747   CHECK(finished);
   17748   CHECK_LT(final_size, initial_size + 1);
   17749 }
   17750 
   17751 
   17752 // Test that idle notification can be handled and eventually collects garbage.
   17753 TEST(IdleNotificationWithLargeHint) {
   17754   const intptr_t MB = 1024 * 1024;
   17755   const int IdlePauseInMs = 900;
   17756   LocalContext env;
   17757   v8::HandleScope scope(env->GetIsolate());
   17758   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
   17759   CreateGarbageInOldSpace();
   17760   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
   17761   CHECK_GT(size_with_garbage, initial_size + MB);
   17762   bool finished = false;
   17763   for (int i = 0; i < 200 && !finished; i++) {
   17764     finished = v8::V8::IdleNotification(IdlePauseInMs);
   17765   }
   17766   intptr_t final_size = CcTest::heap()->SizeOfObjects();
   17767   CHECK(finished);
   17768   CHECK_LT(final_size, initial_size + 1);
   17769 }
   17770 
   17771 
   17772 TEST(Regress2107) {
   17773   const intptr_t MB = 1024 * 1024;
   17774   const int kShortIdlePauseInMs = 100;
   17775   const int kLongIdlePauseInMs = 1000;
   17776   LocalContext env;
   17777   v8::Isolate* isolate = env->GetIsolate();
   17778   v8::HandleScope scope(env->GetIsolate());
   17779   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
   17780   // Send idle notification to start a round of incremental GCs.
   17781   v8::V8::IdleNotification(kShortIdlePauseInMs);
   17782   // Emulate 7 page reloads.
   17783   for (int i = 0; i < 7; i++) {
   17784     {
   17785       v8::HandleScope inner_scope(env->GetIsolate());
   17786       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
   17787       ctx->Enter();
   17788       CreateGarbageInOldSpace();
   17789       ctx->Exit();
   17790     }
   17791     v8::V8::ContextDisposedNotification();
   17792     v8::V8::IdleNotification(kLongIdlePauseInMs);
   17793   }
   17794   // Create garbage and check that idle notification still collects it.
   17795   CreateGarbageInOldSpace();
   17796   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
   17797   CHECK_GT(size_with_garbage, initial_size + MB);
   17798   bool finished = false;
   17799   for (int i = 0; i < 200 && !finished; i++) {
   17800     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
   17801   }
   17802   intptr_t final_size = CcTest::heap()->SizeOfObjects();
   17803   CHECK_LT(final_size, initial_size + 1);
   17804 }
   17805 
   17806 
   17807 TEST(Regress2333) {
   17808   LocalContext env;
   17809   for (int i = 0; i < 3; i++) {
   17810     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
   17811   }
   17812 }
   17813 
   17814 static uint32_t* stack_limit;
   17815 
   17816 static void GetStackLimitCallback(
   17817     const v8::FunctionCallbackInfo<v8::Value>& args) {
   17818   stack_limit = reinterpret_cast<uint32_t*>(
   17819       CcTest::i_isolate()->stack_guard()->real_climit());
   17820 }
   17821 
   17822 
   17823 // Uses the address of a local variable to determine the stack top now.
   17824 // Given a size, returns an address that is that far from the current
   17825 // top of stack.
   17826 static uint32_t* ComputeStackLimit(uint32_t size) {
   17827   uint32_t* answer = &size - (size / sizeof(size));
   17828   // If the size is very large and the stack is very near the bottom of
   17829   // memory then the calculation above may wrap around and give an address
   17830   // that is above the (downwards-growing) stack.  In that case we return
   17831   // a very low address.
   17832   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
   17833   return answer;
   17834 }
   17835 
   17836 
   17837 // We need at least 165kB for an x64 debug build with clang and ASAN.
   17838 static const int stack_breathing_room = 256 * i::KB;
   17839 
   17840 
   17841 TEST(SetResourceConstraints) {
   17842   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
   17843 
   17844   // Set stack limit.
   17845   v8::ResourceConstraints constraints;
   17846   constraints.set_stack_limit(set_limit);
   17847   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
   17848 
   17849   // Execute a script.
   17850   LocalContext env;
   17851   v8::HandleScope scope(env->GetIsolate());
   17852   Local<v8::FunctionTemplate> fun_templ =
   17853       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
   17854   Local<Function> fun = fun_templ->GetFunction();
   17855   env->Global()->Set(v8_str("get_stack_limit"), fun);
   17856   CompileRun("get_stack_limit();");
   17857 
   17858   CHECK(stack_limit == set_limit);
   17859 }
   17860 
   17861 
   17862 TEST(SetResourceConstraintsInThread) {
   17863   uint32_t* set_limit;
   17864   {
   17865     v8::Locker locker(CcTest::isolate());
   17866     set_limit = ComputeStackLimit(stack_breathing_room);
   17867 
   17868     // Set stack limit.
   17869     v8::ResourceConstraints constraints;
   17870     constraints.set_stack_limit(set_limit);
   17871     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
   17872 
   17873     // Execute a script.
   17874     v8::HandleScope scope(CcTest::isolate());
   17875     LocalContext env;
   17876     Local<v8::FunctionTemplate> fun_templ =
   17877         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
   17878     Local<Function> fun = fun_templ->GetFunction();
   17879     env->Global()->Set(v8_str("get_stack_limit"), fun);
   17880     CompileRun("get_stack_limit();");
   17881 
   17882     CHECK(stack_limit == set_limit);
   17883   }
   17884   {
   17885     v8::Locker locker(CcTest::isolate());
   17886     CHECK(stack_limit == set_limit);
   17887   }
   17888 }
   17889 
   17890 
   17891 THREADED_TEST(GetHeapStatistics) {
   17892   LocalContext c1;
   17893   v8::HandleScope scope(c1->GetIsolate());
   17894   v8::HeapStatistics heap_statistics;
   17895   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
   17896   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
   17897   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
   17898   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
   17899   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
   17900 }
   17901 
   17902 
   17903 class VisitorImpl : public v8::ExternalResourceVisitor {
   17904  public:
   17905   explicit VisitorImpl(TestResource** resource) {
   17906     for (int i = 0; i < 4; i++) {
   17907       resource_[i] = resource[i];
   17908       found_resource_[i] = false;
   17909     }
   17910   }
   17911   virtual ~VisitorImpl() {}
   17912   virtual void VisitExternalString(v8::Handle<v8::String> string) {
   17913     if (!string->IsExternal()) {
   17914       CHECK(string->IsExternalAscii());
   17915       return;
   17916     }
   17917     v8::String::ExternalStringResource* resource =
   17918         string->GetExternalStringResource();
   17919     CHECK(resource);
   17920     for (int i = 0; i < 4; i++) {
   17921       if (resource_[i] == resource) {
   17922         CHECK(!found_resource_[i]);
   17923         found_resource_[i] = true;
   17924       }
   17925     }
   17926   }
   17927   void CheckVisitedResources() {
   17928     for (int i = 0; i < 4; i++) {
   17929       CHECK(found_resource_[i]);
   17930     }
   17931   }
   17932 
   17933  private:
   17934   v8::String::ExternalStringResource* resource_[4];
   17935   bool found_resource_[4];
   17936 };
   17937 
   17938 
   17939 TEST(ExternalizeOldSpaceTwoByteCons) {
   17940   LocalContext env;
   17941   v8::HandleScope scope(env->GetIsolate());
   17942   v8::Local<v8::String> cons =
   17943       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
   17944   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   17945   CcTest::heap()->CollectAllAvailableGarbage();
   17946   CHECK(CcTest::heap()->old_pointer_space()->Contains(
   17947             *v8::Utils::OpenHandle(*cons)));
   17948 
   17949   TestResource* resource = new TestResource(
   17950       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
   17951   cons->MakeExternal(resource);
   17952 
   17953   CHECK(cons->IsExternal());
   17954   CHECK_EQ(resource, cons->GetExternalStringResource());
   17955   String::Encoding encoding;
   17956   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
   17957   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
   17958 }
   17959 
   17960 
   17961 TEST(ExternalizeOldSpaceOneByteCons) {
   17962   LocalContext env;
   17963   v8::HandleScope scope(env->GetIsolate());
   17964   v8::Local<v8::String> cons =
   17965       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
   17966   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   17967   CcTest::heap()->CollectAllAvailableGarbage();
   17968   CHECK(CcTest::heap()->old_pointer_space()->Contains(
   17969             *v8::Utils::OpenHandle(*cons)));
   17970 
   17971   TestAsciiResource* resource =
   17972       new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
   17973   cons->MakeExternal(resource);
   17974 
   17975   CHECK(cons->IsExternalAscii());
   17976   CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
   17977   String::Encoding encoding;
   17978   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
   17979   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
   17980 }
   17981 
   17982 
   17983 TEST(VisitExternalStrings) {
   17984   LocalContext env;
   17985   v8::HandleScope scope(env->GetIsolate());
   17986   const char* string = "Some string";
   17987   uint16_t* two_byte_string = AsciiToTwoByteString(string);
   17988   TestResource* resource[4];
   17989   resource[0] = new TestResource(two_byte_string);
   17990   v8::Local<v8::String> string0 =
   17991       v8::String::NewExternal(env->GetIsolate(), resource[0]);
   17992   resource[1] = new TestResource(two_byte_string, NULL, false);
   17993   v8::Local<v8::String> string1 =
   17994       v8::String::NewExternal(env->GetIsolate(), resource[1]);
   17995 
   17996   // Externalized symbol.
   17997   resource[2] = new TestResource(two_byte_string, NULL, false);
   17998   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
   17999       env->GetIsolate(), string, v8::String::kInternalizedString);
   18000   CHECK(string2->MakeExternal(resource[2]));
   18001 
   18002   // Symbolized External.
   18003   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
   18004   v8::Local<v8::String> string3 =
   18005       v8::String::NewExternal(env->GetIsolate(), resource[3]);
   18006   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
   18007   // Turn into a symbol.
   18008   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
   18009   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
   18010       string3_i).is_null());
   18011   CHECK(string3_i->IsInternalizedString());
   18012 
   18013   // We need to add usages for string* to avoid warnings in GCC 4.7
   18014   CHECK(string0->IsExternal());
   18015   CHECK(string1->IsExternal());
   18016   CHECK(string2->IsExternal());
   18017   CHECK(string3->IsExternal());
   18018 
   18019   VisitorImpl visitor(resource);
   18020   v8::V8::VisitExternalResources(&visitor);
   18021   visitor.CheckVisitedResources();
   18022 }
   18023 
   18024 
   18025 TEST(ExternalStringCollectedAtTearDown) {
   18026   int destroyed = 0;
   18027   v8::Isolate* isolate = v8::Isolate::New();
   18028   { v8::Isolate::Scope isolate_scope(isolate);
   18029     v8::HandleScope handle_scope(isolate);
   18030     const char* s = "One string to test them all, one string to find them.";
   18031     TestAsciiResource* inscription =
   18032         new TestAsciiResource(i::StrDup(s), &destroyed);
   18033     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
   18034     // Ring is still alive.  Orcs are roaming freely across our lands.
   18035     CHECK_EQ(0, destroyed);
   18036     USE(ring);
   18037   }
   18038 
   18039   isolate->Dispose();
   18040   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
   18041   CHECK_EQ(1, destroyed);
   18042 }
   18043 
   18044 
   18045 TEST(ExternalInternalizedStringCollectedAtTearDown) {
   18046   int destroyed = 0;
   18047   v8::Isolate* isolate = v8::Isolate::New();
   18048   { v8::Isolate::Scope isolate_scope(isolate);
   18049     LocalContext env(isolate);
   18050     v8::HandleScope handle_scope(isolate);
   18051     CompileRun("var ring = 'One string to test them all';");
   18052     const char* s = "One string to test them all";
   18053     TestAsciiResource* inscription =
   18054         new TestAsciiResource(i::StrDup(s), &destroyed);
   18055     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
   18056     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
   18057     ring->MakeExternal(inscription);
   18058     // Ring is still alive.  Orcs are roaming freely across our lands.
   18059     CHECK_EQ(0, destroyed);
   18060     USE(ring);
   18061   }
   18062 
   18063   isolate->Dispose();
   18064   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
   18065   CHECK_EQ(1, destroyed);
   18066 }
   18067 
   18068 
   18069 TEST(ExternalInternalizedStringCollectedAtGC) {
   18070   int destroyed = 0;
   18071   { LocalContext env;
   18072     v8::HandleScope handle_scope(env->GetIsolate());
   18073     CompileRun("var ring = 'One string to test them all';");
   18074     const char* s = "One string to test them all";
   18075     TestAsciiResource* inscription =
   18076         new TestAsciiResource(i::StrDup(s), &destroyed);
   18077     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
   18078     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
   18079     ring->MakeExternal(inscription);
   18080     // Ring is still alive.  Orcs are roaming freely across our lands.
   18081     CHECK_EQ(0, destroyed);
   18082     USE(ring);
   18083   }
   18084 
   18085   // Garbage collector deals swift blows to evil.
   18086   CcTest::i_isolate()->compilation_cache()->Clear();
   18087   CcTest::heap()->CollectAllAvailableGarbage();
   18088 
   18089   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
   18090   CHECK_EQ(1, destroyed);
   18091 }
   18092 
   18093 
   18094 static double DoubleFromBits(uint64_t value) {
   18095   double target;
   18096   i::MemCopy(&target, &value, sizeof(target));
   18097   return target;
   18098 }
   18099 
   18100 
   18101 static uint64_t DoubleToBits(double value) {
   18102   uint64_t target;
   18103   i::MemCopy(&target, &value, sizeof(target));
   18104   return target;
   18105 }
   18106 
   18107 
   18108 static double DoubleToDateTime(double input) {
   18109   double date_limit = 864e13;
   18110   if (std::isnan(input) || input < -date_limit || input > date_limit) {
   18111     return i::OS::nan_value();
   18112   }
   18113   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
   18114 }
   18115 
   18116 
   18117 // We don't have a consistent way to write 64-bit constants syntactically, so we
   18118 // split them into two 32-bit constants and combine them programmatically.
   18119 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
   18120   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
   18121 }
   18122 
   18123 
   18124 THREADED_TEST(QuietSignalingNaNs) {
   18125   LocalContext context;
   18126   v8::Isolate* isolate = context->GetIsolate();
   18127   v8::HandleScope scope(isolate);
   18128   v8::TryCatch try_catch;
   18129 
   18130   // Special double values.
   18131   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
   18132   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
   18133   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
   18134   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
   18135   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
   18136   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
   18137   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
   18138 
   18139   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
   18140   // on either side of the epoch.
   18141   double date_limit = 864e13;
   18142 
   18143   double test_values[] = {
   18144       snan,
   18145       qnan,
   18146       infinity,
   18147       max_normal,
   18148       date_limit + 1,
   18149       date_limit,
   18150       min_normal,
   18151       max_denormal,
   18152       min_denormal,
   18153       0,
   18154       -0,
   18155       -min_denormal,
   18156       -max_denormal,
   18157       -min_normal,
   18158       -date_limit,
   18159       -date_limit - 1,
   18160       -max_normal,
   18161       -infinity,
   18162       -qnan,
   18163       -snan
   18164   };
   18165   int num_test_values = 20;
   18166 
   18167   for (int i = 0; i < num_test_values; i++) {
   18168     double test_value = test_values[i];
   18169 
   18170     // Check that Number::New preserves non-NaNs and quiets SNaNs.
   18171     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
   18172     double stored_number = number->NumberValue();
   18173     if (!std::isnan(test_value)) {
   18174       CHECK_EQ(test_value, stored_number);
   18175     } else {
   18176       uint64_t stored_bits = DoubleToBits(stored_number);
   18177       // Check if quiet nan (bits 51..62 all set).
   18178 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
   18179       // Most significant fraction bit for quiet nan is set to 0
   18180       // on MIPS architecture. Allowed by IEEE-754.
   18181       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
   18182 #else
   18183       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
   18184 #endif
   18185     }
   18186 
   18187     // Check that Date::New preserves non-NaNs in the date range and
   18188     // quiets SNaNs.
   18189     v8::Handle<v8::Value> date =
   18190         v8::Date::New(isolate, test_value);
   18191     double expected_stored_date = DoubleToDateTime(test_value);
   18192     double stored_date = date->NumberValue();
   18193     if (!std::isnan(expected_stored_date)) {
   18194       CHECK_EQ(expected_stored_date, stored_date);
   18195     } else {
   18196       uint64_t stored_bits = DoubleToBits(stored_date);
   18197       // Check if quiet nan (bits 51..62 all set).
   18198 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
   18199       // Most significant fraction bit for quiet nan is set to 0
   18200       // on MIPS architecture. Allowed by IEEE-754.
   18201       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
   18202 #else
   18203       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
   18204 #endif
   18205     }
   18206   }
   18207 }
   18208 
   18209 
   18210 static void SpaghettiIncident(
   18211     const v8::FunctionCallbackInfo<v8::Value>& args) {
   18212   v8::HandleScope scope(args.GetIsolate());
   18213   v8::TryCatch tc;
   18214   v8::Handle<v8::String> str(args[0]->ToString());
   18215   USE(str);
   18216   if (tc.HasCaught())
   18217     tc.ReThrow();
   18218 }
   18219 
   18220 
   18221 // Test that an exception can be propagated down through a spaghetti
   18222 // stack using ReThrow.
   18223 THREADED_TEST(SpaghettiStackReThrow) {
   18224   v8::Isolate* isolate = CcTest::isolate();
   18225   v8::HandleScope scope(isolate);
   18226   LocalContext context;
   18227   context->Global()->Set(
   18228       v8::String::NewFromUtf8(isolate, "s"),
   18229       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
   18230   v8::TryCatch try_catch;
   18231   CompileRun(
   18232       "var i = 0;"
   18233       "var o = {"
   18234       "  toString: function () {"
   18235       "    if (i == 10) {"
   18236       "      throw 'Hey!';"
   18237       "    } else {"
   18238       "      i++;"
   18239       "      return s(o);"
   18240       "    }"
   18241       "  }"
   18242       "};"
   18243       "s(o);");
   18244   CHECK(try_catch.HasCaught());
   18245   v8::String::Utf8Value value(try_catch.Exception());
   18246   CHECK_EQ(0, strcmp(*value, "Hey!"));
   18247 }
   18248 
   18249 
   18250 TEST(Regress528) {
   18251   v8::V8::Initialize();
   18252   v8::Isolate* isolate = CcTest::isolate();
   18253   v8::HandleScope scope(isolate);
   18254   v8::Local<Context> other_context;
   18255   int gc_count;
   18256 
   18257   // Create a context used to keep the code from aging in the compilation
   18258   // cache.
   18259   other_context = Context::New(isolate);
   18260 
   18261   // Context-dependent context data creates reference from the compilation
   18262   // cache to the global object.
   18263   const char* source_simple = "1";
   18264   {
   18265     v8::HandleScope scope(isolate);
   18266     v8::Local<Context> context = Context::New(isolate);
   18267 
   18268     context->Enter();
   18269     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
   18270     context->SetEmbedderData(0, obj);
   18271     CompileRun(source_simple);
   18272     context->Exit();
   18273   }
   18274   v8::V8::ContextDisposedNotification();
   18275   for (gc_count = 1; gc_count < 10; gc_count++) {
   18276     other_context->Enter();
   18277     CompileRun(source_simple);
   18278     other_context->Exit();
   18279     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18280     if (GetGlobalObjectsCount() == 1) break;
   18281   }
   18282   CHECK_GE(2, gc_count);
   18283   CHECK_EQ(1, GetGlobalObjectsCount());
   18284 
   18285   // Eval in a function creates reference from the compilation cache to the
   18286   // global object.
   18287   const char* source_eval = "function f(){eval('1')}; f()";
   18288   {
   18289     v8::HandleScope scope(isolate);
   18290     v8::Local<Context> context = Context::New(isolate);
   18291 
   18292     context->Enter();
   18293     CompileRun(source_eval);
   18294     context->Exit();
   18295   }
   18296   v8::V8::ContextDisposedNotification();
   18297   for (gc_count = 1; gc_count < 10; gc_count++) {
   18298     other_context->Enter();
   18299     CompileRun(source_eval);
   18300     other_context->Exit();
   18301     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18302     if (GetGlobalObjectsCount() == 1) break;
   18303   }
   18304   CHECK_GE(2, gc_count);
   18305   CHECK_EQ(1, GetGlobalObjectsCount());
   18306 
   18307   // Looking up the line number for an exception creates reference from the
   18308   // compilation cache to the global object.
   18309   const char* source_exception = "function f(){throw 1;} f()";
   18310   {
   18311     v8::HandleScope scope(isolate);
   18312     v8::Local<Context> context = Context::New(isolate);
   18313 
   18314     context->Enter();
   18315     v8::TryCatch try_catch;
   18316     CompileRun(source_exception);
   18317     CHECK(try_catch.HasCaught());
   18318     v8::Handle<v8::Message> message = try_catch.Message();
   18319     CHECK(!message.IsEmpty());
   18320     CHECK_EQ(1, message->GetLineNumber());
   18321     context->Exit();
   18322   }
   18323   v8::V8::ContextDisposedNotification();
   18324   for (gc_count = 1; gc_count < 10; gc_count++) {
   18325     other_context->Enter();
   18326     CompileRun(source_exception);
   18327     other_context->Exit();
   18328     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18329     if (GetGlobalObjectsCount() == 1) break;
   18330   }
   18331   CHECK_GE(2, gc_count);
   18332   CHECK_EQ(1, GetGlobalObjectsCount());
   18333 
   18334   v8::V8::ContextDisposedNotification();
   18335 }
   18336 
   18337 
   18338 THREADED_TEST(ScriptOrigin) {
   18339   LocalContext env;
   18340   v8::HandleScope scope(env->GetIsolate());
   18341   v8::ScriptOrigin origin =
   18342       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
   18343   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
   18344       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
   18345   v8::Script::Compile(script, &origin)->Run();
   18346   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   18347       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
   18348   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   18349       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
   18350 
   18351   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
   18352   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
   18353   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
   18354 
   18355   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
   18356   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
   18357   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
   18358 }
   18359 
   18360 
   18361 THREADED_TEST(FunctionGetInferredName) {
   18362   LocalContext env;
   18363   v8::HandleScope scope(env->GetIsolate());
   18364   v8::ScriptOrigin origin =
   18365       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
   18366   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
   18367       env->GetIsolate(),
   18368       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
   18369   v8::Script::Compile(script, &origin)->Run();
   18370   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   18371       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
   18372   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
   18373 }
   18374 
   18375 
   18376 THREADED_TEST(FunctionGetDisplayName) {
   18377   LocalContext env;
   18378   v8::HandleScope scope(env->GetIsolate());
   18379   const char* code = "var error = false;"
   18380                      "function a() { this.x = 1; };"
   18381                      "a.displayName = 'display_a';"
   18382                      "var b = (function() {"
   18383                      "  var f = function() { this.x = 2; };"
   18384                      "  f.displayName = 'display_b';"
   18385                      "  return f;"
   18386                      "})();"
   18387                      "var c = function() {};"
   18388                      "c.__defineGetter__('displayName', function() {"
   18389                      "  error = true;"
   18390                      "  throw new Error();"
   18391                      "});"
   18392                      "function d() {};"
   18393                      "d.__defineGetter__('displayName', function() {"
   18394                      "  error = true;"
   18395                      "  return 'wrong_display_name';"
   18396                      "});"
   18397                      "function e() {};"
   18398                      "e.displayName = 'wrong_display_name';"
   18399                      "e.__defineSetter__('displayName', function() {"
   18400                      "  error = true;"
   18401                      "  throw new Error();"
   18402                      "});"
   18403                      "function f() {};"
   18404                      "f.displayName = { 'foo': 6, toString: function() {"
   18405                      "  error = true;"
   18406                      "  return 'wrong_display_name';"
   18407                      "}};"
   18408                      "var g = function() {"
   18409                      "  arguments.callee.displayName = 'set_in_runtime';"
   18410                      "}; g();"
   18411                      ;
   18412   v8::ScriptOrigin origin =
   18413       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
   18414   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
   18415       ->Run();
   18416   v8::Local<v8::Value> error =
   18417       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
   18418   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
   18419       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
   18420   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
   18421       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
   18422   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
   18423       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
   18424   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
   18425       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
   18426   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
   18427       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
   18428   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   18429       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
   18430   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   18431       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
   18432   CHECK_EQ(false, error->BooleanValue());
   18433   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
   18434   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
   18435   CHECK(c->GetDisplayName()->IsUndefined());
   18436   CHECK(d->GetDisplayName()->IsUndefined());
   18437   CHECK(e->GetDisplayName()->IsUndefined());
   18438   CHECK(f->GetDisplayName()->IsUndefined());
   18439   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
   18440 }
   18441 
   18442 
   18443 THREADED_TEST(ScriptLineNumber) {
   18444   LocalContext env;
   18445   v8::HandleScope scope(env->GetIsolate());
   18446   v8::ScriptOrigin origin =
   18447       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
   18448   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
   18449       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
   18450   v8::Script::Compile(script, &origin)->Run();
   18451   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   18452       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
   18453   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   18454       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
   18455   CHECK_EQ(0, f->GetScriptLineNumber());
   18456   CHECK_EQ(2, g->GetScriptLineNumber());
   18457 }
   18458 
   18459 
   18460 THREADED_TEST(ScriptColumnNumber) {
   18461   LocalContext env;
   18462   v8::Isolate* isolate = env->GetIsolate();
   18463   v8::HandleScope scope(isolate);
   18464   v8::ScriptOrigin origin =
   18465       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
   18466                        v8::Integer::New(isolate, 3),
   18467                        v8::Integer::New(isolate, 2));
   18468   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
   18469       isolate, "function foo() {}\n\n     function bar() {}");
   18470   v8::Script::Compile(script, &origin)->Run();
   18471   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
   18472       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
   18473   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
   18474       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
   18475   CHECK_EQ(14, foo->GetScriptColumnNumber());
   18476   CHECK_EQ(17, bar->GetScriptColumnNumber());
   18477 }
   18478 
   18479 
   18480 THREADED_TEST(FunctionIsBuiltin) {
   18481   LocalContext env;
   18482   v8::Isolate* isolate = env->GetIsolate();
   18483   v8::HandleScope scope(isolate);
   18484   v8::Local<v8::Function> f;
   18485   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
   18486   CHECK(f->IsBuiltin());
   18487   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
   18488   CHECK(f->IsBuiltin());
   18489   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
   18490   CHECK(f->IsBuiltin());
   18491   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
   18492   CHECK(f->IsBuiltin());
   18493   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
   18494   CHECK(!f->IsBuiltin());
   18495 }
   18496 
   18497 
   18498 THREADED_TEST(FunctionGetScriptId) {
   18499   LocalContext env;
   18500   v8::Isolate* isolate = env->GetIsolate();
   18501   v8::HandleScope scope(isolate);
   18502   v8::ScriptOrigin origin =
   18503       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
   18504                        v8::Integer::New(isolate, 3),
   18505                        v8::Integer::New(isolate, 2));
   18506   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
   18507       isolate, "function foo() {}\n\n     function bar() {}");
   18508   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
   18509   script->Run();
   18510   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
   18511       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
   18512   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
   18513       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
   18514   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
   18515   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
   18516 }
   18517 
   18518 
   18519 THREADED_TEST(FunctionGetBoundFunction) {
   18520   LocalContext env;
   18521   v8::HandleScope scope(env->GetIsolate());
   18522   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
   18523       env->GetIsolate(), "test"));
   18524   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
   18525       env->GetIsolate(),
   18526       "var a = new Object();\n"
   18527       "a.x = 1;\n"
   18528       "function f () { return this.x };\n"
   18529       "var g = f.bind(a);\n"
   18530       "var b = g();");
   18531   v8::Script::Compile(script, &origin)->Run();
   18532   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
   18533       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
   18534   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
   18535       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
   18536   CHECK(g->GetBoundFunction()->IsFunction());
   18537   Local<v8::Function> original_function = Local<v8::Function>::Cast(
   18538       g->GetBoundFunction());
   18539   CHECK_EQ(f->GetName(), original_function->GetName());
   18540   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
   18541   CHECK_EQ(f->GetScriptColumnNumber(),
   18542            original_function->GetScriptColumnNumber());
   18543 }
   18544 
   18545 
   18546 static void GetterWhichReturns42(
   18547     Local<String> name,
   18548     const v8::PropertyCallbackInfo<v8::Value>& info) {
   18549   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   18550   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
   18551   info.GetReturnValue().Set(v8_num(42));
   18552 }
   18553 
   18554 
   18555 static void SetterWhichSetsYOnThisTo23(
   18556     Local<String> name,
   18557     Local<Value> value,
   18558     const v8::PropertyCallbackInfo<void>& info) {
   18559   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   18560   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
   18561   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
   18562 }
   18563 
   18564 
   18565 void FooGetInterceptor(Local<String> name,
   18566                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   18567   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   18568   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
   18569   if (!name->Equals(v8_str("foo"))) return;
   18570   info.GetReturnValue().Set(v8_num(42));
   18571 }
   18572 
   18573 
   18574 void FooSetInterceptor(Local<String> name,
   18575                        Local<Value> value,
   18576                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   18577   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   18578   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
   18579   if (!name->Equals(v8_str("foo"))) return;
   18580   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
   18581   info.GetReturnValue().Set(v8_num(23));
   18582 }
   18583 
   18584 
   18585 TEST(SetterOnConstructorPrototype) {
   18586   v8::Isolate* isolate = CcTest::isolate();
   18587   v8::HandleScope scope(isolate);
   18588   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   18589   templ->SetAccessor(v8_str("x"),
   18590                      GetterWhichReturns42,
   18591                      SetterWhichSetsYOnThisTo23);
   18592   LocalContext context;
   18593   context->Global()->Set(v8_str("P"), templ->NewInstance());
   18594   CompileRun("function C1() {"
   18595              "  this.x = 23;"
   18596              "};"
   18597              "C1.prototype = P;"
   18598              "function C2() {"
   18599              "  this.x = 23"
   18600              "};"
   18601              "C2.prototype = { };"
   18602              "C2.prototype.__proto__ = P;");
   18603 
   18604   v8::Local<v8::Script> script;
   18605   script = v8_compile("new C1();");
   18606   for (int i = 0; i < 10; i++) {
   18607     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
   18608     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
   18609     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
   18610   }
   18611 
   18612 script = v8_compile("new C2();");
   18613   for (int i = 0; i < 10; i++) {
   18614     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
   18615     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
   18616     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
   18617   }
   18618 }
   18619 
   18620 
   18621 static void NamedPropertyGetterWhichReturns42(
   18622     Local<String> name,
   18623     const v8::PropertyCallbackInfo<v8::Value>& info) {
   18624   info.GetReturnValue().Set(v8_num(42));
   18625 }
   18626 
   18627 
   18628 static void NamedPropertySetterWhichSetsYOnThisTo23(
   18629     Local<String> name,
   18630     Local<Value> value,
   18631     const v8::PropertyCallbackInfo<v8::Value>& info) {
   18632   if (name->Equals(v8_str("x"))) {
   18633     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
   18634   }
   18635 }
   18636 
   18637 
   18638 THREADED_TEST(InterceptorOnConstructorPrototype) {
   18639   v8::Isolate* isolate = CcTest::isolate();
   18640   v8::HandleScope scope(isolate);
   18641   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   18642   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
   18643                                  NamedPropertySetterWhichSetsYOnThisTo23);
   18644   LocalContext context;
   18645   context->Global()->Set(v8_str("P"), templ->NewInstance());
   18646   CompileRun("function C1() {"
   18647              "  this.x = 23;"
   18648              "};"
   18649              "C1.prototype = P;"
   18650              "function C2() {"
   18651              "  this.x = 23"
   18652              "};"
   18653              "C2.prototype = { };"
   18654              "C2.prototype.__proto__ = P;");
   18655 
   18656   v8::Local<v8::Script> script;
   18657   script = v8_compile("new C1();");
   18658   for (int i = 0; i < 10; i++) {
   18659     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
   18660     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
   18661     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
   18662   }
   18663 
   18664   script = v8_compile("new C2();");
   18665   for (int i = 0; i < 10; i++) {
   18666     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
   18667     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
   18668     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
   18669   }
   18670 }
   18671 
   18672 
   18673 TEST(Regress618) {
   18674   const char* source = "function C1() {"
   18675                        "  this.x = 23;"
   18676                        "};"
   18677                        "C1.prototype = P;";
   18678 
   18679   LocalContext context;
   18680   v8::Isolate* isolate = context->GetIsolate();
   18681   v8::HandleScope scope(isolate);
   18682   v8::Local<v8::Script> script;
   18683 
   18684   // Use a simple object as prototype.
   18685   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
   18686   prototype->Set(v8_str("y"), v8_num(42));
   18687   context->Global()->Set(v8_str("P"), prototype);
   18688 
   18689   // This compile will add the code to the compilation cache.
   18690   CompileRun(source);
   18691 
   18692   script = v8_compile("new C1();");
   18693   // Allow enough iterations for the inobject slack tracking logic
   18694   // to finalize instance size and install the fast construct stub.
   18695   for (int i = 0; i < 256; i++) {
   18696     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
   18697     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
   18698     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
   18699   }
   18700 
   18701   // Use an API object with accessors as prototype.
   18702   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   18703   templ->SetAccessor(v8_str("x"),
   18704                      GetterWhichReturns42,
   18705                      SetterWhichSetsYOnThisTo23);
   18706   context->Global()->Set(v8_str("P"), templ->NewInstance());
   18707 
   18708   // This compile will get the code from the compilation cache.
   18709   CompileRun(source);
   18710 
   18711   script = v8_compile("new C1();");
   18712   for (int i = 0; i < 10; i++) {
   18713     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
   18714     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
   18715     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
   18716   }
   18717 }
   18718 
   18719 v8::Isolate* gc_callbacks_isolate = NULL;
   18720 int prologue_call_count = 0;
   18721 int epilogue_call_count = 0;
   18722 int prologue_call_count_second = 0;
   18723 int epilogue_call_count_second = 0;
   18724 int prologue_call_count_alloc = 0;
   18725 int epilogue_call_count_alloc = 0;
   18726 
   18727 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
   18728   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18729   ++prologue_call_count;
   18730 }
   18731 
   18732 
   18733 void PrologueCallback(v8::Isolate* isolate,
   18734                       v8::GCType,
   18735                       v8::GCCallbackFlags flags) {
   18736   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18737   CHECK_EQ(gc_callbacks_isolate, isolate);
   18738   ++prologue_call_count;
   18739 }
   18740 
   18741 
   18742 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
   18743   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18744   ++epilogue_call_count;
   18745 }
   18746 
   18747 
   18748 void EpilogueCallback(v8::Isolate* isolate,
   18749                       v8::GCType,
   18750                       v8::GCCallbackFlags flags) {
   18751   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18752   CHECK_EQ(gc_callbacks_isolate, isolate);
   18753   ++epilogue_call_count;
   18754 }
   18755 
   18756 
   18757 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
   18758   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18759   ++prologue_call_count_second;
   18760 }
   18761 
   18762 
   18763 void PrologueCallbackSecond(v8::Isolate* isolate,
   18764                             v8::GCType,
   18765                             v8::GCCallbackFlags flags) {
   18766   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18767   CHECK_EQ(gc_callbacks_isolate, isolate);
   18768   ++prologue_call_count_second;
   18769 }
   18770 
   18771 
   18772 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
   18773   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18774   ++epilogue_call_count_second;
   18775 }
   18776 
   18777 
   18778 void EpilogueCallbackSecond(v8::Isolate* isolate,
   18779                             v8::GCType,
   18780                             v8::GCCallbackFlags flags) {
   18781   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18782   CHECK_EQ(gc_callbacks_isolate, isolate);
   18783   ++epilogue_call_count_second;
   18784 }
   18785 
   18786 
   18787 void PrologueCallbackAlloc(v8::Isolate* isolate,
   18788                            v8::GCType,
   18789                            v8::GCCallbackFlags flags) {
   18790   v8::HandleScope scope(isolate);
   18791 
   18792   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18793   CHECK_EQ(gc_callbacks_isolate, isolate);
   18794   ++prologue_call_count_alloc;
   18795 
   18796   // Simulate full heap to see if we will reenter this callback
   18797   SimulateFullSpace(CcTest::heap()->new_space());
   18798 
   18799   Local<Object> obj = Object::New(isolate);
   18800   CHECK(!obj.IsEmpty());
   18801 
   18802   CcTest::heap()->CollectAllGarbage(
   18803       i::Heap::kAbortIncrementalMarkingMask);
   18804 }
   18805 
   18806 
   18807 void EpilogueCallbackAlloc(v8::Isolate* isolate,
   18808                            v8::GCType,
   18809                            v8::GCCallbackFlags flags) {
   18810   v8::HandleScope scope(isolate);
   18811 
   18812   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
   18813   CHECK_EQ(gc_callbacks_isolate, isolate);
   18814   ++epilogue_call_count_alloc;
   18815 
   18816   // Simulate full heap to see if we will reenter this callback
   18817   SimulateFullSpace(CcTest::heap()->new_space());
   18818 
   18819   Local<Object> obj = Object::New(isolate);
   18820   CHECK(!obj.IsEmpty());
   18821 
   18822   CcTest::heap()->CollectAllGarbage(
   18823       i::Heap::kAbortIncrementalMarkingMask);
   18824 }
   18825 
   18826 
   18827 TEST(GCCallbacksOld) {
   18828   LocalContext context;
   18829 
   18830   v8::V8::AddGCPrologueCallback(PrologueCallback);
   18831   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
   18832   CHECK_EQ(0, prologue_call_count);
   18833   CHECK_EQ(0, epilogue_call_count);
   18834   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18835   CHECK_EQ(1, prologue_call_count);
   18836   CHECK_EQ(1, epilogue_call_count);
   18837   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
   18838   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
   18839   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18840   CHECK_EQ(2, prologue_call_count);
   18841   CHECK_EQ(2, epilogue_call_count);
   18842   CHECK_EQ(1, prologue_call_count_second);
   18843   CHECK_EQ(1, epilogue_call_count_second);
   18844   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
   18845   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
   18846   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18847   CHECK_EQ(2, prologue_call_count);
   18848   CHECK_EQ(2, epilogue_call_count);
   18849   CHECK_EQ(2, prologue_call_count_second);
   18850   CHECK_EQ(2, epilogue_call_count_second);
   18851   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
   18852   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
   18853   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18854   CHECK_EQ(2, prologue_call_count);
   18855   CHECK_EQ(2, epilogue_call_count);
   18856   CHECK_EQ(2, prologue_call_count_second);
   18857   CHECK_EQ(2, epilogue_call_count_second);
   18858 }
   18859 
   18860 
   18861 TEST(GCCallbacks) {
   18862   LocalContext context;
   18863   v8::Isolate* isolate = context->GetIsolate();
   18864   gc_callbacks_isolate = isolate;
   18865   isolate->AddGCPrologueCallback(PrologueCallback);
   18866   isolate->AddGCEpilogueCallback(EpilogueCallback);
   18867   CHECK_EQ(0, prologue_call_count);
   18868   CHECK_EQ(0, epilogue_call_count);
   18869   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18870   CHECK_EQ(1, prologue_call_count);
   18871   CHECK_EQ(1, epilogue_call_count);
   18872   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
   18873   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
   18874   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18875   CHECK_EQ(2, prologue_call_count);
   18876   CHECK_EQ(2, epilogue_call_count);
   18877   CHECK_EQ(1, prologue_call_count_second);
   18878   CHECK_EQ(1, epilogue_call_count_second);
   18879   isolate->RemoveGCPrologueCallback(PrologueCallback);
   18880   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
   18881   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18882   CHECK_EQ(2, prologue_call_count);
   18883   CHECK_EQ(2, epilogue_call_count);
   18884   CHECK_EQ(2, prologue_call_count_second);
   18885   CHECK_EQ(2, epilogue_call_count_second);
   18886   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
   18887   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
   18888   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   18889   CHECK_EQ(2, prologue_call_count);
   18890   CHECK_EQ(2, epilogue_call_count);
   18891   CHECK_EQ(2, prologue_call_count_second);
   18892   CHECK_EQ(2, epilogue_call_count_second);
   18893 
   18894   CHECK_EQ(0, prologue_call_count_alloc);
   18895   CHECK_EQ(0, epilogue_call_count_alloc);
   18896   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
   18897   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
   18898   CcTest::heap()->CollectAllGarbage(
   18899       i::Heap::kAbortIncrementalMarkingMask);
   18900   CHECK_EQ(1, prologue_call_count_alloc);
   18901   CHECK_EQ(1, epilogue_call_count_alloc);
   18902   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
   18903   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
   18904 }
   18905 
   18906 
   18907 THREADED_TEST(AddToJSFunctionResultCache) {
   18908   i::FLAG_stress_compaction = false;
   18909   i::FLAG_allow_natives_syntax = true;
   18910   v8::HandleScope scope(CcTest::isolate());
   18911 
   18912   LocalContext context;
   18913 
   18914   const char* code =
   18915       "(function() {"
   18916       "  var key0 = 'a';"
   18917       "  var key1 = 'b';"
   18918       "  var r0 = %_GetFromCache(0, key0);"
   18919       "  var r1 = %_GetFromCache(0, key1);"
   18920       "  var r0_ = %_GetFromCache(0, key0);"
   18921       "  if (r0 !== r0_)"
   18922       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
   18923       "  var r1_ = %_GetFromCache(0, key1);"
   18924       "  if (r1 !== r1_)"
   18925       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
   18926       "  return 'PASSED';"
   18927       "})()";
   18928   CcTest::heap()->ClearJSFunctionResultCaches();
   18929   ExpectString(code, "PASSED");
   18930 }
   18931 
   18932 
   18933 THREADED_TEST(FillJSFunctionResultCache) {
   18934   i::FLAG_allow_natives_syntax = true;
   18935   LocalContext context;
   18936   v8::HandleScope scope(context->GetIsolate());
   18937 
   18938   const char* code =
   18939       "(function() {"
   18940       "  var k = 'a';"
   18941       "  var r = %_GetFromCache(0, k);"
   18942       "  for (var i = 0; i < 16; i++) {"
   18943       "    %_GetFromCache(0, 'a' + i);"
   18944       "  };"
   18945       "  if (r === %_GetFromCache(0, k))"
   18946       "    return 'FAILED: k0CacheSize is too small';"
   18947       "  return 'PASSED';"
   18948       "})()";
   18949   CcTest::heap()->ClearJSFunctionResultCaches();
   18950   ExpectString(code, "PASSED");
   18951 }
   18952 
   18953 
   18954 THREADED_TEST(RoundRobinGetFromCache) {
   18955   i::FLAG_allow_natives_syntax = true;
   18956   LocalContext context;
   18957   v8::HandleScope scope(context->GetIsolate());
   18958 
   18959   const char* code =
   18960       "(function() {"
   18961       "  var keys = [];"
   18962       "  for (var i = 0; i < 16; i++) keys.push(i);"
   18963       "  var values = [];"
   18964       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
   18965       "  for (var i = 0; i < 16; i++) {"
   18966       "    var v = %_GetFromCache(0, keys[i]);"
   18967       "    if (v.toString() !== values[i].toString())"
   18968       "      return 'Wrong value for ' + "
   18969       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
   18970       "  };"
   18971       "  return 'PASSED';"
   18972       "})()";
   18973   CcTest::heap()->ClearJSFunctionResultCaches();
   18974   ExpectString(code, "PASSED");
   18975 }
   18976 
   18977 
   18978 THREADED_TEST(ReverseGetFromCache) {
   18979   i::FLAG_allow_natives_syntax = true;
   18980   LocalContext context;
   18981   v8::HandleScope scope(context->GetIsolate());
   18982 
   18983   const char* code =
   18984       "(function() {"
   18985       "  var keys = [];"
   18986       "  for (var i = 0; i < 16; i++) keys.push(i);"
   18987       "  var values = [];"
   18988       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
   18989       "  for (var i = 15; i >= 16; i--) {"
   18990       "    var v = %_GetFromCache(0, keys[i]);"
   18991       "    if (v !== values[i])"
   18992       "      return 'Wrong value for ' + "
   18993       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
   18994       "  };"
   18995       "  return 'PASSED';"
   18996       "})()";
   18997   CcTest::heap()->ClearJSFunctionResultCaches();
   18998   ExpectString(code, "PASSED");
   18999 }
   19000 
   19001 
   19002 THREADED_TEST(TestEviction) {
   19003   i::FLAG_allow_natives_syntax = true;
   19004   LocalContext context;
   19005   v8::HandleScope scope(context->GetIsolate());
   19006 
   19007   const char* code =
   19008       "(function() {"
   19009       "  for (var i = 0; i < 2*16; i++) {"
   19010       "    %_GetFromCache(0, 'a' + i);"
   19011       "  };"
   19012       "  return 'PASSED';"
   19013       "})()";
   19014   CcTest::heap()->ClearJSFunctionResultCaches();
   19015   ExpectString(code, "PASSED");
   19016 }
   19017 
   19018 
   19019 THREADED_TEST(TwoByteStringInAsciiCons) {
   19020   // See Chromium issue 47824.
   19021   LocalContext context;
   19022   v8::HandleScope scope(context->GetIsolate());
   19023 
   19024   const char* init_code =
   19025       "var str1 = 'abelspendabel';"
   19026       "var str2 = str1 + str1 + str1;"
   19027       "str2;";
   19028   Local<Value> result = CompileRun(init_code);
   19029 
   19030   Local<Value> indexof = CompileRun("str2.indexOf('els')");
   19031   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
   19032 
   19033   CHECK(result->IsString());
   19034   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
   19035   int length = string->length();
   19036   CHECK(string->IsOneByteRepresentation());
   19037 
   19038   i::Handle<i::String> flat_string = i::String::Flatten(string);
   19039 
   19040   CHECK(string->IsOneByteRepresentation());
   19041   CHECK(flat_string->IsOneByteRepresentation());
   19042 
   19043   // Create external resource.
   19044   uint16_t* uc16_buffer = new uint16_t[length + 1];
   19045 
   19046   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
   19047   uc16_buffer[length] = 0;
   19048 
   19049   TestResource resource(uc16_buffer);
   19050 
   19051   flat_string->MakeExternal(&resource);
   19052 
   19053   CHECK(flat_string->IsTwoByteRepresentation());
   19054 
   19055   // If the cons string has been short-circuited, skip the following checks.
   19056   if (!string.is_identical_to(flat_string)) {
   19057     // At this point, we should have a Cons string which is flat and ASCII,
   19058     // with a first half that is a two-byte string (although it only contains
   19059     // ASCII characters). This is a valid sequence of steps, and it can happen
   19060     // in real pages.
   19061     CHECK(string->IsOneByteRepresentation());
   19062     i::ConsString* cons = i::ConsString::cast(*string);
   19063     CHECK_EQ(0, cons->second()->length());
   19064     CHECK(cons->first()->IsTwoByteRepresentation());
   19065   }
   19066 
   19067   // Check that some string operations work.
   19068 
   19069   // Atom RegExp.
   19070   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
   19071   CHECK_EQ(6, reresult->Int32Value());
   19072 
   19073   // Nonatom RegExp.
   19074   reresult = CompileRun("str2.match(/abe./g).length;");
   19075   CHECK_EQ(6, reresult->Int32Value());
   19076 
   19077   reresult = CompileRun("str2.search(/bel/g);");
   19078   CHECK_EQ(1, reresult->Int32Value());
   19079 
   19080   reresult = CompileRun("str2.search(/be./g);");
   19081   CHECK_EQ(1, reresult->Int32Value());
   19082 
   19083   ExpectTrue("/bel/g.test(str2);");
   19084 
   19085   ExpectTrue("/be./g.test(str2);");
   19086 
   19087   reresult = CompileRun("/bel/g.exec(str2);");
   19088   CHECK(!reresult->IsNull());
   19089 
   19090   reresult = CompileRun("/be./g.exec(str2);");
   19091   CHECK(!reresult->IsNull());
   19092 
   19093   ExpectString("str2.substring(2, 10);", "elspenda");
   19094 
   19095   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
   19096 
   19097   ExpectString("str2.charAt(2);", "e");
   19098 
   19099   ExpectObject("str2.indexOf('els');", indexof);
   19100 
   19101   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
   19102 
   19103   reresult = CompileRun("str2.charCodeAt(2);");
   19104   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
   19105 }
   19106 
   19107 
   19108 TEST(ContainsOnlyOneByte) {
   19109   v8::V8::Initialize();
   19110   v8::Isolate* isolate = CcTest::isolate();
   19111   v8::HandleScope scope(isolate);
   19112   // Make a buffer long enough that it won't automatically be converted.
   19113   const int length = 512;
   19114   // Ensure word aligned assignment.
   19115   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
   19116   i::SmartArrayPointer<uintptr_t>
   19117   aligned_contents(new uintptr_t[aligned_length]);
   19118   uint16_t* string_contents =
   19119       reinterpret_cast<uint16_t*>(aligned_contents.get());
   19120   // Set to contain only one byte.
   19121   for (int i = 0; i < length-1; i++) {
   19122     string_contents[i] = 0x41;
   19123   }
   19124   string_contents[length-1] = 0;
   19125   // Simple case.
   19126   Handle<String> string =
   19127       String::NewExternal(isolate,
   19128                           new TestResource(string_contents, NULL, false));
   19129   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
   19130   // Counter example.
   19131   string = String::NewFromTwoByte(isolate, string_contents);
   19132   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
   19133   // Test left right and balanced cons strings.
   19134   Handle<String> base = String::NewFromUtf8(isolate, "a");
   19135   Handle<String> left = base;
   19136   Handle<String> right = base;
   19137   for (int i = 0; i < 1000; i++) {
   19138     left = String::Concat(base, left);
   19139     right = String::Concat(right, base);
   19140   }
   19141   Handle<String> balanced = String::Concat(left, base);
   19142   balanced = String::Concat(balanced, right);
   19143   Handle<String> cons_strings[] = {left, balanced, right};
   19144   Handle<String> two_byte =
   19145       String::NewExternal(isolate,
   19146                           new TestResource(string_contents, NULL, false));
   19147   USE(two_byte); USE(cons_strings);
   19148   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
   19149     // Base assumptions.
   19150     string = cons_strings[i];
   19151     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
   19152     // Test left and right concatentation.
   19153     string = String::Concat(two_byte, cons_strings[i]);
   19154     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
   19155     string = String::Concat(cons_strings[i], two_byte);
   19156     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
   19157   }
   19158   // Set bits in different positions
   19159   // for strings of different lengths and alignments.
   19160   for (int alignment = 0; alignment < 7; alignment++) {
   19161     for (int size = 2; alignment + size < length; size *= 2) {
   19162       int zero_offset = size + alignment;
   19163       string_contents[zero_offset] = 0;
   19164       for (int i = 0; i < size; i++) {
   19165         int shift = 8 + (i % 7);
   19166         string_contents[alignment + i] = 1 << shift;
   19167         string = String::NewExternal(
   19168             isolate,
   19169             new TestResource(string_contents + alignment, NULL, false));
   19170         CHECK_EQ(size, string->Length());
   19171         CHECK(!string->ContainsOnlyOneByte());
   19172         string_contents[alignment + i] = 0x41;
   19173       }
   19174       string_contents[zero_offset] = 0x41;
   19175     }
   19176   }
   19177 }
   19178 
   19179 
   19180 // Failed access check callback that performs a GC on each invocation.
   19181 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
   19182                                  v8::AccessType type,
   19183                                  Local<v8::Value> data) {
   19184   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   19185 }
   19186 
   19187 
   19188 TEST(GCInFailedAccessCheckCallback) {
   19189   // Install a failed access check callback that performs a GC on each
   19190   // invocation. Then force the callback to be called from va
   19191 
   19192   v8::V8::Initialize();
   19193   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
   19194 
   19195   v8::Isolate* isolate = CcTest::isolate();
   19196   v8::HandleScope scope(isolate);
   19197 
   19198   // Create an ObjectTemplate for global objects and install access
   19199   // check callbacks that will block access.
   19200   v8::Handle<v8::ObjectTemplate> global_template =
   19201       v8::ObjectTemplate::New(isolate);
   19202   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
   19203                                            IndexedGetAccessBlocker,
   19204                                            v8::Handle<v8::Value>(),
   19205                                            false);
   19206 
   19207   // Create a context and set an x property on it's global object.
   19208   LocalContext context0(NULL, global_template);
   19209   context0->Global()->Set(v8_str("x"), v8_num(42));
   19210   v8::Handle<v8::Object> global0 = context0->Global();
   19211 
   19212   // Create a context with a different security token so that the
   19213   // failed access check callback will be called on each access.
   19214   LocalContext context1(NULL, global_template);
   19215   context1->Global()->Set(v8_str("other"), global0);
   19216 
   19217   // Get property with failed access check.
   19218   ExpectUndefined("other.x");
   19219 
   19220   // Get element with failed access check.
   19221   ExpectUndefined("other[0]");
   19222 
   19223   // Set property with failed access check.
   19224   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
   19225   CHECK(result->IsObject());
   19226 
   19227   // Set element with failed access check.
   19228   result = CompileRun("other[0] = new Object()");
   19229   CHECK(result->IsObject());
   19230 
   19231   // Get property attribute with failed access check.
   19232   ExpectFalse("\'x\' in other");
   19233 
   19234   // Get property attribute for element with failed access check.
   19235   ExpectFalse("0 in other");
   19236 
   19237   // Delete property.
   19238   ExpectFalse("delete other.x");
   19239 
   19240   // Delete element.
   19241   CHECK_EQ(false, global0->Delete(0));
   19242 
   19243   // DefineAccessor.
   19244   CHECK_EQ(false,
   19245            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
   19246 
   19247   // Define JavaScript accessor.
   19248   ExpectUndefined("Object.prototype.__defineGetter__.call("
   19249                   "    other, \'x\', function() { return 42; })");
   19250 
   19251   // LookupAccessor.
   19252   ExpectUndefined("Object.prototype.__lookupGetter__.call("
   19253                   "    other, \'x\')");
   19254 
   19255   // HasOwnElement.
   19256   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
   19257 
   19258   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
   19259   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
   19260   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
   19261 
   19262   // Reset the failed access check callback so it does not influence
   19263   // the other tests.
   19264   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
   19265 }
   19266 
   19267 
   19268 TEST(IsolateNewDispose) {
   19269   v8::Isolate* current_isolate = CcTest::isolate();
   19270   v8::Isolate* isolate = v8::Isolate::New();
   19271   CHECK(isolate != NULL);
   19272   CHECK(current_isolate != isolate);
   19273   CHECK(current_isolate == CcTest::isolate());
   19274 
   19275   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   19276   last_location = last_message = NULL;
   19277   isolate->Dispose();
   19278   CHECK_EQ(last_location, NULL);
   19279   CHECK_EQ(last_message, NULL);
   19280 }
   19281 
   19282 
   19283 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
   19284   v8::Isolate* isolate = v8::Isolate::New();
   19285   {
   19286     v8::Isolate::Scope i_scope(isolate);
   19287     v8::HandleScope scope(isolate);
   19288     LocalContext context(isolate);
   19289     // Run something in this isolate.
   19290     ExpectTrue("true");
   19291     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   19292     last_location = last_message = NULL;
   19293     // Still entered, should fail.
   19294     isolate->Dispose();
   19295     CHECK_NE(last_location, NULL);
   19296     CHECK_NE(last_message, NULL);
   19297   }
   19298   isolate->Dispose();
   19299 }
   19300 
   19301 
   19302 TEST(RunTwoIsolatesOnSingleThread) {
   19303   // Run isolate 1.
   19304   v8::Isolate* isolate1 = v8::Isolate::New();
   19305   isolate1->Enter();
   19306   v8::Persistent<v8::Context> context1;
   19307   {
   19308     v8::HandleScope scope(isolate1);
   19309     context1.Reset(isolate1, Context::New(isolate1));
   19310   }
   19311 
   19312   {
   19313     v8::HandleScope scope(isolate1);
   19314     v8::Local<v8::Context> context =
   19315         v8::Local<v8::Context>::New(isolate1, context1);
   19316     v8::Context::Scope context_scope(context);
   19317     // Run something in new isolate.
   19318     CompileRun("var foo = 'isolate 1';");
   19319     ExpectString("function f() { return foo; }; f()", "isolate 1");
   19320   }
   19321 
   19322   // Run isolate 2.
   19323   v8::Isolate* isolate2 = v8::Isolate::New();
   19324   v8::Persistent<v8::Context> context2;
   19325 
   19326   {
   19327     v8::Isolate::Scope iscope(isolate2);
   19328     v8::HandleScope scope(isolate2);
   19329     context2.Reset(isolate2, Context::New(isolate2));
   19330     v8::Local<v8::Context> context =
   19331         v8::Local<v8::Context>::New(isolate2, context2);
   19332     v8::Context::Scope context_scope(context);
   19333 
   19334     // Run something in new isolate.
   19335     CompileRun("var foo = 'isolate 2';");
   19336     ExpectString("function f() { return foo; }; f()", "isolate 2");
   19337   }
   19338 
   19339   {
   19340     v8::HandleScope scope(isolate1);
   19341     v8::Local<v8::Context> context =
   19342         v8::Local<v8::Context>::New(isolate1, context1);
   19343     v8::Context::Scope context_scope(context);
   19344     // Now again in isolate 1
   19345     ExpectString("function f() { return foo; }; f()", "isolate 1");
   19346   }
   19347 
   19348   isolate1->Exit();
   19349 
   19350   // Run some stuff in default isolate.
   19351   v8::Persistent<v8::Context> context_default;
   19352   {
   19353     v8::Isolate* isolate = CcTest::isolate();
   19354     v8::Isolate::Scope iscope(isolate);
   19355     v8::HandleScope scope(isolate);
   19356     context_default.Reset(isolate, Context::New(isolate));
   19357   }
   19358 
   19359   {
   19360     v8::HandleScope scope(CcTest::isolate());
   19361     v8::Local<v8::Context> context =
   19362         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
   19363     v8::Context::Scope context_scope(context);
   19364     // Variables in other isolates should be not available, verify there
   19365     // is an exception.
   19366     ExpectTrue("function f() {"
   19367                "  try {"
   19368                "    foo;"
   19369                "    return false;"
   19370                "  } catch(e) {"
   19371                "    return true;"
   19372                "  }"
   19373                "};"
   19374                "var isDefaultIsolate = true;"
   19375                "f()");
   19376   }
   19377 
   19378   isolate1->Enter();
   19379 
   19380   {
   19381     v8::Isolate::Scope iscope(isolate2);
   19382     v8::HandleScope scope(isolate2);
   19383     v8::Local<v8::Context> context =
   19384         v8::Local<v8::Context>::New(isolate2, context2);
   19385     v8::Context::Scope context_scope(context);
   19386     ExpectString("function f() { return foo; }; f()", "isolate 2");
   19387   }
   19388 
   19389   {
   19390     v8::HandleScope scope(v8::Isolate::GetCurrent());
   19391     v8::Local<v8::Context> context =
   19392         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
   19393     v8::Context::Scope context_scope(context);
   19394     ExpectString("function f() { return foo; }; f()", "isolate 1");
   19395   }
   19396 
   19397   {
   19398     v8::Isolate::Scope iscope(isolate2);
   19399     context2.Reset();
   19400   }
   19401 
   19402   context1.Reset();
   19403   isolate1->Exit();
   19404 
   19405   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
   19406   last_location = last_message = NULL;
   19407 
   19408   isolate1->Dispose();
   19409   CHECK_EQ(last_location, NULL);
   19410   CHECK_EQ(last_message, NULL);
   19411 
   19412   isolate2->Dispose();
   19413   CHECK_EQ(last_location, NULL);
   19414   CHECK_EQ(last_message, NULL);
   19415 
   19416   // Check that default isolate still runs.
   19417   {
   19418     v8::HandleScope scope(CcTest::isolate());
   19419     v8::Local<v8::Context> context =
   19420         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
   19421     v8::Context::Scope context_scope(context);
   19422     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
   19423   }
   19424 }
   19425 
   19426 
   19427 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
   19428   v8::Isolate::Scope isolate_scope(isolate);
   19429   v8::HandleScope scope(isolate);
   19430   LocalContext context(isolate);
   19431   i::ScopedVector<char> code(1024);
   19432   i::SNPrintF(code, "function fib(n) {"
   19433                     "  if (n <= 2) return 1;"
   19434                     "  return fib(n-1) + fib(n-2);"
   19435                     "}"
   19436                     "fib(%d)", limit);
   19437   Local<Value> value = CompileRun(code.start());
   19438   CHECK(value->IsNumber());
   19439   return static_cast<int>(value->NumberValue());
   19440 }
   19441 
   19442 class IsolateThread : public v8::internal::Thread {
   19443  public:
   19444   IsolateThread(v8::Isolate* isolate, int fib_limit)
   19445       : Thread("IsolateThread"),
   19446         isolate_(isolate),
   19447         fib_limit_(fib_limit),
   19448         result_(0) { }
   19449 
   19450   void Run() {
   19451     result_ = CalcFibonacci(isolate_, fib_limit_);
   19452   }
   19453 
   19454   int result() { return result_; }
   19455 
   19456  private:
   19457   v8::Isolate* isolate_;
   19458   int fib_limit_;
   19459   int result_;
   19460 };
   19461 
   19462 
   19463 TEST(MultipleIsolatesOnIndividualThreads) {
   19464   v8::Isolate* isolate1 = v8::Isolate::New();
   19465   v8::Isolate* isolate2 = v8::Isolate::New();
   19466 
   19467   IsolateThread thread1(isolate1, 21);
   19468   IsolateThread thread2(isolate2, 12);
   19469 
   19470   // Compute some fibonacci numbers on 3 threads in 3 isolates.
   19471   thread1.Start();
   19472   thread2.Start();
   19473 
   19474   int result1 = CalcFibonacci(CcTest::isolate(), 21);
   19475   int result2 = CalcFibonacci(CcTest::isolate(), 12);
   19476 
   19477   thread1.Join();
   19478   thread2.Join();
   19479 
   19480   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
   19481   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
   19482   CHECK_EQ(result1, 10946);
   19483   CHECK_EQ(result2, 144);
   19484   CHECK_EQ(result1, thread1.result());
   19485   CHECK_EQ(result2, thread2.result());
   19486 
   19487   isolate1->Dispose();
   19488   isolate2->Dispose();
   19489 }
   19490 
   19491 
   19492 TEST(IsolateDifferentContexts) {
   19493   v8::Isolate* isolate = v8::Isolate::New();
   19494   Local<v8::Context> context;
   19495   {
   19496     v8::Isolate::Scope isolate_scope(isolate);
   19497     v8::HandleScope handle_scope(isolate);
   19498     context = v8::Context::New(isolate);
   19499     v8::Context::Scope context_scope(context);
   19500     Local<Value> v = CompileRun("2");
   19501     CHECK(v->IsNumber());
   19502     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
   19503   }
   19504   {
   19505     v8::Isolate::Scope isolate_scope(isolate);
   19506     v8::HandleScope handle_scope(isolate);
   19507     context = v8::Context::New(isolate);
   19508     v8::Context::Scope context_scope(context);
   19509     Local<Value> v = CompileRun("22");
   19510     CHECK(v->IsNumber());
   19511     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
   19512   }
   19513   isolate->Dispose();
   19514 }
   19515 
   19516 class InitDefaultIsolateThread : public v8::internal::Thread {
   19517  public:
   19518   enum TestCase {
   19519     SetResourceConstraints,
   19520     SetFatalHandler,
   19521     SetCounterFunction,
   19522     SetCreateHistogramFunction,
   19523     SetAddHistogramSampleFunction
   19524   };
   19525 
   19526   explicit InitDefaultIsolateThread(TestCase testCase)
   19527       : Thread("InitDefaultIsolateThread"),
   19528         testCase_(testCase),
   19529         result_(false) { }
   19530 
   19531   void Run() {
   19532     v8::Isolate* isolate = v8::Isolate::New();
   19533     isolate->Enter();
   19534     switch (testCase_) {
   19535       case SetResourceConstraints: {
   19536         v8::ResourceConstraints constraints;
   19537         constraints.set_max_semi_space_size(1);
   19538         constraints.set_max_old_space_size(4);
   19539         v8::SetResourceConstraints(CcTest::isolate(), &constraints);
   19540         break;
   19541       }
   19542 
   19543       case SetFatalHandler:
   19544         v8::V8::SetFatalErrorHandler(NULL);
   19545         break;
   19546 
   19547       case SetCounterFunction:
   19548         CcTest::isolate()->SetCounterFunction(NULL);
   19549         break;
   19550 
   19551       case SetCreateHistogramFunction:
   19552         CcTest::isolate()->SetCreateHistogramFunction(NULL);
   19553         break;
   19554 
   19555       case SetAddHistogramSampleFunction:
   19556         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
   19557         break;
   19558     }
   19559     isolate->Exit();
   19560     isolate->Dispose();
   19561     result_ = true;
   19562   }
   19563 
   19564   bool result() { return result_; }
   19565 
   19566  private:
   19567   TestCase testCase_;
   19568   bool result_;
   19569 };
   19570 
   19571 
   19572 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
   19573   InitDefaultIsolateThread thread(testCase);
   19574   thread.Start();
   19575   thread.Join();
   19576   CHECK_EQ(thread.result(), true);
   19577 }
   19578 
   19579 
   19580 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
   19581   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
   19582 }
   19583 
   19584 
   19585 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
   19586   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
   19587 }
   19588 
   19589 
   19590 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
   19591   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
   19592 }
   19593 
   19594 
   19595 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
   19596   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
   19597 }
   19598 
   19599 
   19600 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
   19601   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
   19602 }
   19603 
   19604 
   19605 TEST(StringCheckMultipleContexts) {
   19606   const char* code =
   19607       "(function() { return \"a\".charAt(0); })()";
   19608 
   19609   {
   19610     // Run the code twice in the first context to initialize the call IC.
   19611     LocalContext context1;
   19612     v8::HandleScope scope(context1->GetIsolate());
   19613     ExpectString(code, "a");
   19614     ExpectString(code, "a");
   19615   }
   19616 
   19617   {
   19618     // Change the String.prototype in the second context and check
   19619     // that the right function gets called.
   19620     LocalContext context2;
   19621     v8::HandleScope scope(context2->GetIsolate());
   19622     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
   19623     ExpectString(code, "not a");
   19624   }
   19625 }
   19626 
   19627 
   19628 TEST(NumberCheckMultipleContexts) {
   19629   const char* code =
   19630       "(function() { return (42).toString(); })()";
   19631 
   19632   {
   19633     // Run the code twice in the first context to initialize the call IC.
   19634     LocalContext context1;
   19635     v8::HandleScope scope(context1->GetIsolate());
   19636     ExpectString(code, "42");
   19637     ExpectString(code, "42");
   19638   }
   19639 
   19640   {
   19641     // Change the Number.prototype in the second context and check
   19642     // that the right function gets called.
   19643     LocalContext context2;
   19644     v8::HandleScope scope(context2->GetIsolate());
   19645     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
   19646     ExpectString(code, "not 42");
   19647   }
   19648 }
   19649 
   19650 
   19651 TEST(BooleanCheckMultipleContexts) {
   19652   const char* code =
   19653       "(function() { return true.toString(); })()";
   19654 
   19655   {
   19656     // Run the code twice in the first context to initialize the call IC.
   19657     LocalContext context1;
   19658     v8::HandleScope scope(context1->GetIsolate());
   19659     ExpectString(code, "true");
   19660     ExpectString(code, "true");
   19661   }
   19662 
   19663   {
   19664     // Change the Boolean.prototype in the second context and check
   19665     // that the right function gets called.
   19666     LocalContext context2;
   19667     v8::HandleScope scope(context2->GetIsolate());
   19668     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
   19669     ExpectString(code, "");
   19670   }
   19671 }
   19672 
   19673 
   19674 TEST(DontDeleteCellLoadIC) {
   19675   const char* function_code =
   19676       "function readCell() { while (true) { return cell; } }";
   19677 
   19678   {
   19679     // Run the code twice in the first context to initialize the load
   19680     // IC for a don't delete cell.
   19681     LocalContext context1;
   19682     v8::HandleScope scope(context1->GetIsolate());
   19683     CompileRun("var cell = \"first\";");
   19684     ExpectBoolean("delete cell", false);
   19685     CompileRun(function_code);
   19686     ExpectString("readCell()", "first");
   19687     ExpectString("readCell()", "first");
   19688   }
   19689 
   19690   {
   19691     // Use a deletable cell in the second context.
   19692     LocalContext context2;
   19693     v8::HandleScope scope(context2->GetIsolate());
   19694     CompileRun("cell = \"second\";");
   19695     CompileRun(function_code);
   19696     ExpectString("readCell()", "second");
   19697     ExpectBoolean("delete cell", true);
   19698     ExpectString("(function() {"
   19699                  "  try {"
   19700                  "    return readCell();"
   19701                  "  } catch(e) {"
   19702                  "    return e.toString();"
   19703                  "  }"
   19704                  "})()",
   19705                  "ReferenceError: cell is not defined");
   19706     CompileRun("cell = \"new_second\";");
   19707     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   19708     ExpectString("readCell()", "new_second");
   19709     ExpectString("readCell()", "new_second");
   19710   }
   19711 }
   19712 
   19713 
   19714 TEST(DontDeleteCellLoadICForceDelete) {
   19715   const char* function_code =
   19716       "function readCell() { while (true) { return cell; } }";
   19717 
   19718   // Run the code twice to initialize the load IC for a don't delete
   19719   // cell.
   19720   LocalContext context;
   19721   v8::HandleScope scope(context->GetIsolate());
   19722   CompileRun("var cell = \"value\";");
   19723   ExpectBoolean("delete cell", false);
   19724   CompileRun(function_code);
   19725   ExpectString("readCell()", "value");
   19726   ExpectString("readCell()", "value");
   19727 
   19728   // Delete the cell using the API and check the inlined code works
   19729   // correctly.
   19730   CHECK(context->Global()->ForceDelete(v8_str("cell")));
   19731   ExpectString("(function() {"
   19732                "  try {"
   19733                "    return readCell();"
   19734                "  } catch(e) {"
   19735                "    return e.toString();"
   19736                "  }"
   19737                "})()",
   19738                "ReferenceError: cell is not defined");
   19739 }
   19740 
   19741 
   19742 TEST(DontDeleteCellLoadICAPI) {
   19743   const char* function_code =
   19744       "function readCell() { while (true) { return cell; } }";
   19745 
   19746   // Run the code twice to initialize the load IC for a don't delete
   19747   // cell created using the API.
   19748   LocalContext context;
   19749   v8::HandleScope scope(context->GetIsolate());
   19750   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
   19751   ExpectBoolean("delete cell", false);
   19752   CompileRun(function_code);
   19753   ExpectString("readCell()", "value");
   19754   ExpectString("readCell()", "value");
   19755 
   19756   // Delete the cell using the API and check the inlined code works
   19757   // correctly.
   19758   CHECK(context->Global()->ForceDelete(v8_str("cell")));
   19759   ExpectString("(function() {"
   19760                "  try {"
   19761                "    return readCell();"
   19762                "  } catch(e) {"
   19763                "    return e.toString();"
   19764                "  }"
   19765                "})()",
   19766                "ReferenceError: cell is not defined");
   19767 }
   19768 
   19769 
   19770 class Visitor42 : public v8::PersistentHandleVisitor {
   19771  public:
   19772   explicit Visitor42(v8::Persistent<v8::Object>* object)
   19773       : counter_(0), object_(object) { }
   19774 
   19775   virtual void VisitPersistentHandle(Persistent<Value>* value,
   19776                                      uint16_t class_id) {
   19777     if (class_id != 42) return;
   19778     CHECK_EQ(42, value->WrapperClassId());
   19779     v8::Isolate* isolate = CcTest::isolate();
   19780     v8::HandleScope handle_scope(isolate);
   19781     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
   19782     v8::Handle<v8::Value> object =
   19783         v8::Local<v8::Object>::New(isolate, *object_);
   19784     CHECK(handle->IsObject());
   19785     CHECK_EQ(Handle<Object>::Cast(handle), object);
   19786     ++counter_;
   19787   }
   19788 
   19789   int counter_;
   19790   v8::Persistent<v8::Object>* object_;
   19791 };
   19792 
   19793 
   19794 TEST(PersistentHandleVisitor) {
   19795   LocalContext context;
   19796   v8::Isolate* isolate = context->GetIsolate();
   19797   v8::HandleScope scope(isolate);
   19798   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
   19799   CHECK_EQ(0, object.WrapperClassId());
   19800   object.SetWrapperClassId(42);
   19801   CHECK_EQ(42, object.WrapperClassId());
   19802 
   19803   Visitor42 visitor(&object);
   19804   v8::V8::VisitHandlesWithClassIds(&visitor);
   19805   CHECK_EQ(1, visitor.counter_);
   19806 
   19807   object.Reset();
   19808 }
   19809 
   19810 
   19811 TEST(WrapperClassId) {
   19812   LocalContext context;
   19813   v8::Isolate* isolate = context->GetIsolate();
   19814   v8::HandleScope scope(isolate);
   19815   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
   19816   CHECK_EQ(0, object.WrapperClassId());
   19817   object.SetWrapperClassId(65535);
   19818   CHECK_EQ(65535, object.WrapperClassId());
   19819   object.Reset();
   19820 }
   19821 
   19822 
   19823 TEST(PersistentHandleInNewSpaceVisitor) {
   19824   LocalContext context;
   19825   v8::Isolate* isolate = context->GetIsolate();
   19826   v8::HandleScope scope(isolate);
   19827   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
   19828   CHECK_EQ(0, object1.WrapperClassId());
   19829   object1.SetWrapperClassId(42);
   19830   CHECK_EQ(42, object1.WrapperClassId());
   19831 
   19832   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
   19833 
   19834   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
   19835   CHECK_EQ(0, object2.WrapperClassId());
   19836   object2.SetWrapperClassId(42);
   19837   CHECK_EQ(42, object2.WrapperClassId());
   19838 
   19839   Visitor42 visitor(&object2);
   19840   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
   19841   CHECK_EQ(1, visitor.counter_);
   19842 
   19843   object1.Reset();
   19844   object2.Reset();
   19845 }
   19846 
   19847 
   19848 TEST(RegExp) {
   19849   LocalContext context;
   19850   v8::HandleScope scope(context->GetIsolate());
   19851 
   19852   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
   19853   CHECK(re->IsRegExp());
   19854   CHECK(re->GetSource()->Equals(v8_str("foo")));
   19855   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
   19856 
   19857   re = v8::RegExp::New(v8_str("bar"),
   19858                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
   19859                                                       v8::RegExp::kGlobal));
   19860   CHECK(re->IsRegExp());
   19861   CHECK(re->GetSource()->Equals(v8_str("bar")));
   19862   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
   19863            static_cast<int>(re->GetFlags()));
   19864 
   19865   re = v8::RegExp::New(v8_str("baz"),
   19866                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
   19867                                                       v8::RegExp::kMultiline));
   19868   CHECK(re->IsRegExp());
   19869   CHECK(re->GetSource()->Equals(v8_str("baz")));
   19870   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
   19871            static_cast<int>(re->GetFlags()));
   19872 
   19873   re = CompileRun("/quux/").As<v8::RegExp>();
   19874   CHECK(re->IsRegExp());
   19875   CHECK(re->GetSource()->Equals(v8_str("quux")));
   19876   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
   19877 
   19878   re = CompileRun("/quux/gm").As<v8::RegExp>();
   19879   CHECK(re->IsRegExp());
   19880   CHECK(re->GetSource()->Equals(v8_str("quux")));
   19881   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
   19882            static_cast<int>(re->GetFlags()));
   19883 
   19884   // Override the RegExp constructor and check the API constructor
   19885   // still works.
   19886   CompileRun("RegExp = function() {}");
   19887 
   19888   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
   19889   CHECK(re->IsRegExp());
   19890   CHECK(re->GetSource()->Equals(v8_str("foobar")));
   19891   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
   19892 
   19893   re = v8::RegExp::New(v8_str("foobarbaz"),
   19894                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
   19895                                                       v8::RegExp::kMultiline));
   19896   CHECK(re->IsRegExp());
   19897   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
   19898   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
   19899            static_cast<int>(re->GetFlags()));
   19900 
   19901   context->Global()->Set(v8_str("re"), re);
   19902   ExpectTrue("re.test('FoobarbaZ')");
   19903 
   19904   // RegExps are objects on which you can set properties.
   19905   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
   19906   v8::Handle<v8::Value> value(CompileRun("re.property"));
   19907   CHECK_EQ(32, value->Int32Value());
   19908 
   19909   v8::TryCatch try_catch;
   19910   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
   19911   CHECK(re.IsEmpty());
   19912   CHECK(try_catch.HasCaught());
   19913   context->Global()->Set(v8_str("ex"), try_catch.Exception());
   19914   ExpectTrue("ex instanceof SyntaxError");
   19915 }
   19916 
   19917 
   19918 THREADED_TEST(Equals) {
   19919   LocalContext localContext;
   19920   v8::HandleScope handleScope(localContext->GetIsolate());
   19921 
   19922   v8::Handle<v8::Object> globalProxy = localContext->Global();
   19923   v8::Handle<Value> global = globalProxy->GetPrototype();
   19924 
   19925   CHECK(global->StrictEquals(global));
   19926   CHECK(!global->StrictEquals(globalProxy));
   19927   CHECK(!globalProxy->StrictEquals(global));
   19928   CHECK(globalProxy->StrictEquals(globalProxy));
   19929 
   19930   CHECK(global->Equals(global));
   19931   CHECK(!global->Equals(globalProxy));
   19932   CHECK(!globalProxy->Equals(global));
   19933   CHECK(globalProxy->Equals(globalProxy));
   19934 }
   19935 
   19936 
   19937 static void Getter(v8::Local<v8::String> property,
   19938                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
   19939   info.GetReturnValue().Set(v8_str("42!"));
   19940 }
   19941 
   19942 
   19943 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
   19944   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
   19945   result->Set(0, v8_str("universalAnswer"));
   19946   info.GetReturnValue().Set(result);
   19947 }
   19948 
   19949 
   19950 TEST(NamedEnumeratorAndForIn) {
   19951   LocalContext context;
   19952   v8::Isolate* isolate = context->GetIsolate();
   19953   v8::HandleScope handle_scope(isolate);
   19954   v8::Context::Scope context_scope(context.local());
   19955 
   19956   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
   19957   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
   19958   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
   19959   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
   19960         "var result = []; for (var k in o) result.push(k); result"));
   19961   CHECK_EQ(1, result->Length());
   19962   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
   19963 }
   19964 
   19965 
   19966 TEST(DefinePropertyPostDetach) {
   19967   LocalContext context;
   19968   v8::HandleScope scope(context->GetIsolate());
   19969   v8::Handle<v8::Object> proxy = context->Global();
   19970   v8::Handle<v8::Function> define_property =
   19971       CompileRun("(function() {"
   19972                  "  Object.defineProperty("
   19973                  "    this,"
   19974                  "    1,"
   19975                  "    { configurable: true, enumerable: true, value: 3 });"
   19976                  "})").As<Function>();
   19977   context->DetachGlobal();
   19978   define_property->Call(proxy, 0, NULL);
   19979 }
   19980 
   19981 
   19982 static void InstallContextId(v8::Handle<Context> context, int id) {
   19983   Context::Scope scope(context);
   19984   CompileRun("Object.prototype").As<Object>()->
   19985       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
   19986 }
   19987 
   19988 
   19989 static void CheckContextId(v8::Handle<Object> object, int expected) {
   19990   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
   19991 }
   19992 
   19993 
   19994 THREADED_TEST(CreationContext) {
   19995   v8::Isolate* isolate = CcTest::isolate();
   19996   HandleScope handle_scope(isolate);
   19997   Handle<Context> context1 = Context::New(isolate);
   19998   InstallContextId(context1, 1);
   19999   Handle<Context> context2 = Context::New(isolate);
   20000   InstallContextId(context2, 2);
   20001   Handle<Context> context3 = Context::New(isolate);
   20002   InstallContextId(context3, 3);
   20003 
   20004   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
   20005 
   20006   Local<Object> object1;
   20007   Local<Function> func1;
   20008   {
   20009     Context::Scope scope(context1);
   20010     object1 = Object::New(isolate);
   20011     func1 = tmpl->GetFunction();
   20012   }
   20013 
   20014   Local<Object> object2;
   20015   Local<Function> func2;
   20016   {
   20017     Context::Scope scope(context2);
   20018     object2 = Object::New(isolate);
   20019     func2 = tmpl->GetFunction();
   20020   }
   20021 
   20022   Local<Object> instance1;
   20023   Local<Object> instance2;
   20024 
   20025   {
   20026     Context::Scope scope(context3);
   20027     instance1 = func1->NewInstance();
   20028     instance2 = func2->NewInstance();
   20029   }
   20030 
   20031   CHECK(object1->CreationContext() == context1);
   20032   CheckContextId(object1, 1);
   20033   CHECK(func1->CreationContext() == context1);
   20034   CheckContextId(func1, 1);
   20035   CHECK(instance1->CreationContext() == context1);
   20036   CheckContextId(instance1, 1);
   20037   CHECK(object2->CreationContext() == context2);
   20038   CheckContextId(object2, 2);
   20039   CHECK(func2->CreationContext() == context2);
   20040   CheckContextId(func2, 2);
   20041   CHECK(instance2->CreationContext() == context2);
   20042   CheckContextId(instance2, 2);
   20043 
   20044   {
   20045     Context::Scope scope(context1);
   20046     CHECK(object1->CreationContext() == context1);
   20047     CheckContextId(object1, 1);
   20048     CHECK(func1->CreationContext() == context1);
   20049     CheckContextId(func1, 1);
   20050     CHECK(instance1->CreationContext() == context1);
   20051     CheckContextId(instance1, 1);
   20052     CHECK(object2->CreationContext() == context2);
   20053     CheckContextId(object2, 2);
   20054     CHECK(func2->CreationContext() == context2);
   20055     CheckContextId(func2, 2);
   20056     CHECK(instance2->CreationContext() == context2);
   20057     CheckContextId(instance2, 2);
   20058   }
   20059 
   20060   {
   20061     Context::Scope scope(context2);
   20062     CHECK(object1->CreationContext() == context1);
   20063     CheckContextId(object1, 1);
   20064     CHECK(func1->CreationContext() == context1);
   20065     CheckContextId(func1, 1);
   20066     CHECK(instance1->CreationContext() == context1);
   20067     CheckContextId(instance1, 1);
   20068     CHECK(object2->CreationContext() == context2);
   20069     CheckContextId(object2, 2);
   20070     CHECK(func2->CreationContext() == context2);
   20071     CheckContextId(func2, 2);
   20072     CHECK(instance2->CreationContext() == context2);
   20073     CheckContextId(instance2, 2);
   20074   }
   20075 }
   20076 
   20077 
   20078 THREADED_TEST(CreationContextOfJsFunction) {
   20079   HandleScope handle_scope(CcTest::isolate());
   20080   Handle<Context> context = Context::New(CcTest::isolate());
   20081   InstallContextId(context, 1);
   20082 
   20083   Local<Object> function;
   20084   {
   20085     Context::Scope scope(context);
   20086     function = CompileRun("function foo() {}; foo").As<Object>();
   20087   }
   20088 
   20089   CHECK(function->CreationContext() == context);
   20090   CheckContextId(function, 1);
   20091 }
   20092 
   20093 
   20094 void HasOwnPropertyIndexedPropertyGetter(
   20095     uint32_t index,
   20096     const v8::PropertyCallbackInfo<v8::Value>& info) {
   20097   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
   20098 }
   20099 
   20100 
   20101 void HasOwnPropertyNamedPropertyGetter(
   20102     Local<String> property,
   20103     const v8::PropertyCallbackInfo<v8::Value>& info) {
   20104   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
   20105 }
   20106 
   20107 
   20108 void HasOwnPropertyIndexedPropertyQuery(
   20109     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   20110   if (index == 42) info.GetReturnValue().Set(1);
   20111 }
   20112 
   20113 
   20114 void HasOwnPropertyNamedPropertyQuery(
   20115     Local<String> property,
   20116     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   20117   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
   20118 }
   20119 
   20120 
   20121 void HasOwnPropertyNamedPropertyQuery2(
   20122     Local<String> property,
   20123     const v8::PropertyCallbackInfo<v8::Integer>& info) {
   20124   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
   20125 }
   20126 
   20127 
   20128 void HasOwnPropertyAccessorGetter(
   20129     Local<String> property,
   20130     const v8::PropertyCallbackInfo<v8::Value>& info) {
   20131   info.GetReturnValue().Set(v8_str("yes"));
   20132 }
   20133 
   20134 
   20135 TEST(HasOwnProperty) {
   20136   LocalContext env;
   20137   v8::Isolate* isolate = env->GetIsolate();
   20138   v8::HandleScope scope(isolate);
   20139   { // Check normal properties and defined getters.
   20140     Handle<Value> value = CompileRun(
   20141         "function Foo() {"
   20142         "    this.foo = 11;"
   20143         "    this.__defineGetter__('baz', function() { return 1; });"
   20144         "};"
   20145         "function Bar() { "
   20146         "    this.bar = 13;"
   20147         "    this.__defineGetter__('bla', function() { return 2; });"
   20148         "};"
   20149         "Bar.prototype = new Foo();"
   20150         "new Bar();");
   20151     CHECK(value->IsObject());
   20152     Handle<Object> object = value->ToObject();
   20153     CHECK(object->Has(v8_str("foo")));
   20154     CHECK(!object->HasOwnProperty(v8_str("foo")));
   20155     CHECK(object->HasOwnProperty(v8_str("bar")));
   20156     CHECK(object->Has(v8_str("baz")));
   20157     CHECK(!object->HasOwnProperty(v8_str("baz")));
   20158     CHECK(object->HasOwnProperty(v8_str("bla")));
   20159   }
   20160   { // Check named getter interceptors.
   20161     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20162     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
   20163     Handle<Object> instance = templ->NewInstance();
   20164     CHECK(!instance->HasOwnProperty(v8_str("42")));
   20165     CHECK(instance->HasOwnProperty(v8_str("foo")));
   20166     CHECK(!instance->HasOwnProperty(v8_str("bar")));
   20167   }
   20168   { // Check indexed getter interceptors.
   20169     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20170     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
   20171     Handle<Object> instance = templ->NewInstance();
   20172     CHECK(instance->HasOwnProperty(v8_str("42")));
   20173     CHECK(!instance->HasOwnProperty(v8_str("43")));
   20174     CHECK(!instance->HasOwnProperty(v8_str("foo")));
   20175   }
   20176   { // Check named query interceptors.
   20177     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20178     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
   20179     Handle<Object> instance = templ->NewInstance();
   20180     CHECK(instance->HasOwnProperty(v8_str("foo")));
   20181     CHECK(!instance->HasOwnProperty(v8_str("bar")));
   20182   }
   20183   { // Check indexed query interceptors.
   20184     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20185     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
   20186     Handle<Object> instance = templ->NewInstance();
   20187     CHECK(instance->HasOwnProperty(v8_str("42")));
   20188     CHECK(!instance->HasOwnProperty(v8_str("41")));
   20189   }
   20190   { // Check callbacks.
   20191     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20192     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
   20193     Handle<Object> instance = templ->NewInstance();
   20194     CHECK(instance->HasOwnProperty(v8_str("foo")));
   20195     CHECK(!instance->HasOwnProperty(v8_str("bar")));
   20196   }
   20197   { // Check that query wins on disagreement.
   20198     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20199     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
   20200                                    0,
   20201                                    HasOwnPropertyNamedPropertyQuery2);
   20202     Handle<Object> instance = templ->NewInstance();
   20203     CHECK(!instance->HasOwnProperty(v8_str("foo")));
   20204     CHECK(instance->HasOwnProperty(v8_str("bar")));
   20205   }
   20206 }
   20207 
   20208 
   20209 TEST(IndexedInterceptorWithStringProto) {
   20210   v8::Isolate* isolate = CcTest::isolate();
   20211   v8::HandleScope scope(isolate);
   20212   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20213   templ->SetIndexedPropertyHandler(NULL,
   20214                                    NULL,
   20215                                    HasOwnPropertyIndexedPropertyQuery);
   20216   LocalContext context;
   20217   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   20218   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
   20219   // These should be intercepted.
   20220   CHECK(CompileRun("42 in obj")->BooleanValue());
   20221   CHECK(CompileRun("'42' in obj")->BooleanValue());
   20222   // These should fall through to the String prototype.
   20223   CHECK(CompileRun("0 in obj")->BooleanValue());
   20224   CHECK(CompileRun("'0' in obj")->BooleanValue());
   20225   // And these should both fail.
   20226   CHECK(!CompileRun("32 in obj")->BooleanValue());
   20227   CHECK(!CompileRun("'32' in obj")->BooleanValue());
   20228 }
   20229 
   20230 
   20231 void CheckCodeGenerationAllowed() {
   20232   Handle<Value> result = CompileRun("eval('42')");
   20233   CHECK_EQ(42, result->Int32Value());
   20234   result = CompileRun("(function(e) { return e('42'); })(eval)");
   20235   CHECK_EQ(42, result->Int32Value());
   20236   result = CompileRun("var f = new Function('return 42'); f()");
   20237   CHECK_EQ(42, result->Int32Value());
   20238 }
   20239 
   20240 
   20241 void CheckCodeGenerationDisallowed() {
   20242   TryCatch try_catch;
   20243 
   20244   Handle<Value> result = CompileRun("eval('42')");
   20245   CHECK(result.IsEmpty());
   20246   CHECK(try_catch.HasCaught());
   20247   try_catch.Reset();
   20248 
   20249   result = CompileRun("(function(e) { return e('42'); })(eval)");
   20250   CHECK(result.IsEmpty());
   20251   CHECK(try_catch.HasCaught());
   20252   try_catch.Reset();
   20253 
   20254   result = CompileRun("var f = new Function('return 42'); f()");
   20255   CHECK(result.IsEmpty());
   20256   CHECK(try_catch.HasCaught());
   20257 }
   20258 
   20259 
   20260 bool CodeGenerationAllowed(Local<Context> context) {
   20261   ApiTestFuzzer::Fuzz();
   20262   return true;
   20263 }
   20264 
   20265 
   20266 bool CodeGenerationDisallowed(Local<Context> context) {
   20267   ApiTestFuzzer::Fuzz();
   20268   return false;
   20269 }
   20270 
   20271 
   20272 THREADED_TEST(AllowCodeGenFromStrings) {
   20273   LocalContext context;
   20274   v8::HandleScope scope(context->GetIsolate());
   20275 
   20276   // eval and the Function constructor allowed by default.
   20277   CHECK(context->IsCodeGenerationFromStringsAllowed());
   20278   CheckCodeGenerationAllowed();
   20279 
   20280   // Disallow eval and the Function constructor.
   20281   context->AllowCodeGenerationFromStrings(false);
   20282   CHECK(!context->IsCodeGenerationFromStringsAllowed());
   20283   CheckCodeGenerationDisallowed();
   20284 
   20285   // Allow again.
   20286   context->AllowCodeGenerationFromStrings(true);
   20287   CheckCodeGenerationAllowed();
   20288 
   20289   // Disallow but setting a global callback that will allow the calls.
   20290   context->AllowCodeGenerationFromStrings(false);
   20291   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
   20292   CHECK(!context->IsCodeGenerationFromStringsAllowed());
   20293   CheckCodeGenerationAllowed();
   20294 
   20295   // Set a callback that disallows the code generation.
   20296   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
   20297   CHECK(!context->IsCodeGenerationFromStringsAllowed());
   20298   CheckCodeGenerationDisallowed();
   20299 }
   20300 
   20301 
   20302 TEST(SetErrorMessageForCodeGenFromStrings) {
   20303   LocalContext context;
   20304   v8::HandleScope scope(context->GetIsolate());
   20305   TryCatch try_catch;
   20306 
   20307   Handle<String> message = v8_str("Message") ;
   20308   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
   20309   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
   20310   context->AllowCodeGenerationFromStrings(false);
   20311   context->SetErrorMessageForCodeGenerationFromStrings(message);
   20312   Handle<Value> result = CompileRun("eval('42')");
   20313   CHECK(result.IsEmpty());
   20314   CHECK(try_catch.HasCaught());
   20315   Handle<String> actual_message = try_catch.Message()->Get();
   20316   CHECK(expected_message->Equals(actual_message));
   20317 }
   20318 
   20319 
   20320 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
   20321 }
   20322 
   20323 
   20324 THREADED_TEST(CallAPIFunctionOnNonObject) {
   20325   LocalContext context;
   20326   v8::Isolate* isolate = context->GetIsolate();
   20327   v8::HandleScope scope(isolate);
   20328   Handle<FunctionTemplate> templ =
   20329       v8::FunctionTemplate::New(isolate, NonObjectThis);
   20330   Handle<Function> function = templ->GetFunction();
   20331   context->Global()->Set(v8_str("f"), function);
   20332   TryCatch try_catch;
   20333   CompileRun("f.call(2)");
   20334 }
   20335 
   20336 
   20337 // Regression test for issue 1470.
   20338 THREADED_TEST(ReadOnlyIndexedProperties) {
   20339   v8::Isolate* isolate = CcTest::isolate();
   20340   v8::HandleScope scope(isolate);
   20341   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   20342 
   20343   LocalContext context;
   20344   Local<v8::Object> obj = templ->NewInstance();
   20345   context->Global()->Set(v8_str("obj"), obj);
   20346   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
   20347   obj->Set(v8_str("1"), v8_str("foobar"));
   20348   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
   20349   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
   20350   obj->Set(v8_num(2), v8_str("foobar"));
   20351   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
   20352 
   20353   // Test non-smi case.
   20354   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
   20355   obj->Set(v8_str("2000000000"), v8_str("foobar"));
   20356   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
   20357 }
   20358 
   20359 
   20360 THREADED_TEST(Regress1516) {
   20361   LocalContext context;
   20362   v8::HandleScope scope(context->GetIsolate());
   20363 
   20364   { v8::HandleScope temp_scope(context->GetIsolate());
   20365     CompileRun("({'a': 0})");
   20366   }
   20367 
   20368   int elements;
   20369   { i::MapCache* map_cache =
   20370         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
   20371     elements = map_cache->NumberOfElements();
   20372     CHECK_LE(1, elements);
   20373   }
   20374 
   20375   CcTest::heap()->CollectAllGarbage(
   20376       i::Heap::kAbortIncrementalMarkingMask);
   20377   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
   20378     if (raw_map_cache != CcTest::heap()->undefined_value()) {
   20379       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
   20380       CHECK_GT(elements, map_cache->NumberOfElements());
   20381     }
   20382   }
   20383 }
   20384 
   20385 
   20386 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
   20387                                                 Local<Value> name,
   20388                                                 v8::AccessType type,
   20389                                                 Local<Value> data) {
   20390   // Only block read access to __proto__.
   20391   if (type == v8::ACCESS_GET &&
   20392       name->IsString() &&
   20393       name->ToString()->Length() == 9 &&
   20394       name->ToString()->Utf8Length() == 9) {
   20395     char buffer[10];
   20396     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
   20397     return strncmp(buffer, "__proto__", 9) != 0;
   20398   }
   20399 
   20400   return true;
   20401 }
   20402 
   20403 
   20404 THREADED_TEST(Regress93759) {
   20405   v8::Isolate* isolate = CcTest::isolate();
   20406   HandleScope scope(isolate);
   20407 
   20408   // Template for object with security check.
   20409   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
   20410   // We don't do indexing, so any callback can be used for that.
   20411   no_proto_template->SetAccessCheckCallbacks(
   20412       BlockProtoNamedSecurityTestCallback,
   20413       IndexedSecurityTestCallback);
   20414 
   20415   // Templates for objects with hidden prototypes and possibly security check.
   20416   Local<FunctionTemplate> hidden_proto_template =
   20417       v8::FunctionTemplate::New(isolate);
   20418   hidden_proto_template->SetHiddenPrototype(true);
   20419 
   20420   Local<FunctionTemplate> protected_hidden_proto_template =
   20421       v8::FunctionTemplate::New(isolate);
   20422   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
   20423       BlockProtoNamedSecurityTestCallback,
   20424       IndexedSecurityTestCallback);
   20425   protected_hidden_proto_template->SetHiddenPrototype(true);
   20426 
   20427   // Context for "foreign" objects used in test.
   20428   Local<Context> context = v8::Context::New(isolate);
   20429   context->Enter();
   20430 
   20431   // Plain object, no security check.
   20432   Local<Object> simple_object = Object::New(isolate);
   20433 
   20434   // Object with explicit security check.
   20435   Local<Object> protected_object =
   20436       no_proto_template->NewInstance();
   20437 
   20438   // JSGlobalProxy object, always have security check.
   20439   Local<Object> proxy_object =
   20440       context->Global();
   20441 
   20442   // Global object, the  prototype of proxy_object. No security checks.
   20443   Local<Object> global_object =
   20444       proxy_object->GetPrototype()->ToObject();
   20445 
   20446   // Hidden prototype without security check.
   20447   Local<Object> hidden_prototype =
   20448       hidden_proto_template->GetFunction()->NewInstance();
   20449   Local<Object> object_with_hidden =
   20450     Object::New(isolate);
   20451   object_with_hidden->SetPrototype(hidden_prototype);
   20452 
   20453   // Hidden prototype with security check on the hidden prototype.
   20454   Local<Object> protected_hidden_prototype =
   20455       protected_hidden_proto_template->GetFunction()->NewInstance();
   20456   Local<Object> object_with_protected_hidden =
   20457     Object::New(isolate);
   20458   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
   20459 
   20460   context->Exit();
   20461 
   20462   // Template for object for second context. Values to test are put on it as
   20463   // properties.
   20464   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
   20465   global_template->Set(v8_str("simple"), simple_object);
   20466   global_template->Set(v8_str("protected"), protected_object);
   20467   global_template->Set(v8_str("global"), global_object);
   20468   global_template->Set(v8_str("proxy"), proxy_object);
   20469   global_template->Set(v8_str("hidden"), object_with_hidden);
   20470   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
   20471 
   20472   LocalContext context2(NULL, global_template);
   20473 
   20474   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
   20475   CHECK(result1->Equals(simple_object->GetPrototype()));
   20476 
   20477   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
   20478   CHECK(result2->Equals(Undefined(isolate)));
   20479 
   20480   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
   20481   CHECK(result3->Equals(global_object->GetPrototype()));
   20482 
   20483   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
   20484   CHECK(result4->Equals(Undefined(isolate)));
   20485 
   20486   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
   20487   CHECK(result5->Equals(
   20488       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
   20489 
   20490   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
   20491   CHECK(result6->Equals(Undefined(isolate)));
   20492 }
   20493 
   20494 
   20495 THREADED_TEST(Regress125988) {
   20496   v8::HandleScope scope(CcTest::isolate());
   20497   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
   20498   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
   20499   LocalContext env;
   20500   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
   20501   CompileRun("var a = new Object();"
   20502              "var b = new Intercept();"
   20503              "var c = new Object();"
   20504              "c.__proto__ = b;"
   20505              "b.__proto__ = a;"
   20506              "a.x = 23;"
   20507              "for (var i = 0; i < 3; i++) c.x;");
   20508   ExpectBoolean("c.hasOwnProperty('x')", false);
   20509   ExpectInt32("c.x", 23);
   20510   CompileRun("a.y = 42;"
   20511              "for (var i = 0; i < 3; i++) c.x;");
   20512   ExpectBoolean("c.hasOwnProperty('x')", false);
   20513   ExpectInt32("c.x", 23);
   20514   ExpectBoolean("c.hasOwnProperty('y')", false);
   20515   ExpectInt32("c.y", 42);
   20516 }
   20517 
   20518 
   20519 static void TestReceiver(Local<Value> expected_result,
   20520                          Local<Value> expected_receiver,
   20521                          const char* code) {
   20522   Local<Value> result = CompileRun(code);
   20523   CHECK(result->IsObject());
   20524   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
   20525   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
   20526 }
   20527 
   20528 
   20529 THREADED_TEST(ForeignFunctionReceiver) {
   20530   v8::Isolate* isolate = CcTest::isolate();
   20531   HandleScope scope(isolate);
   20532 
   20533   // Create two contexts with different "id" properties ('i' and 'o').
   20534   // Call a function both from its own context and from a the foreign
   20535   // context, and see what "this" is bound to (returning both "this"
   20536   // and "this.id" for comparison).
   20537 
   20538   Local<Context> foreign_context = v8::Context::New(isolate);
   20539   foreign_context->Enter();
   20540   Local<Value> foreign_function =
   20541     CompileRun("function func() { return { 0: this.id, "
   20542                "                           1: this, "
   20543                "                           toString: function() { "
   20544                "                               return this[0];"
   20545                "                           }"
   20546                "                         };"
   20547                "}"
   20548                "var id = 'i';"
   20549                "func;");
   20550   CHECK(foreign_function->IsFunction());
   20551   foreign_context->Exit();
   20552 
   20553   LocalContext context;
   20554 
   20555   Local<String> password = v8_str("Password");
   20556   // Don't get hit by security checks when accessing foreign_context's
   20557   // global receiver (aka. global proxy).
   20558   context->SetSecurityToken(password);
   20559   foreign_context->SetSecurityToken(password);
   20560 
   20561   Local<String> i = v8_str("i");
   20562   Local<String> o = v8_str("o");
   20563   Local<String> id = v8_str("id");
   20564 
   20565   CompileRun("function ownfunc() { return { 0: this.id, "
   20566              "                              1: this, "
   20567              "                              toString: function() { "
   20568              "                                  return this[0];"
   20569              "                              }"
   20570              "                             };"
   20571              "}"
   20572              "var id = 'o';"
   20573              "ownfunc");
   20574   context->Global()->Set(v8_str("func"), foreign_function);
   20575 
   20576   // Sanity check the contexts.
   20577   CHECK(i->Equals(foreign_context->Global()->Get(id)));
   20578   CHECK(o->Equals(context->Global()->Get(id)));
   20579 
   20580   // Checking local function's receiver.
   20581   // Calling function using its call/apply methods.
   20582   TestReceiver(o, context->Global(), "ownfunc.call()");
   20583   TestReceiver(o, context->Global(), "ownfunc.apply()");
   20584   // Making calls through built-in functions.
   20585   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
   20586   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
   20587   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
   20588   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
   20589   // Calling with environment record as base.
   20590   TestReceiver(o, context->Global(), "ownfunc()");
   20591   // Calling with no base.
   20592   TestReceiver(o, context->Global(), "(1,ownfunc)()");
   20593 
   20594   // Checking foreign function return value.
   20595   // Calling function using its call/apply methods.
   20596   TestReceiver(i, foreign_context->Global(), "func.call()");
   20597   TestReceiver(i, foreign_context->Global(), "func.apply()");
   20598   // Calling function using another context's call/apply methods.
   20599   TestReceiver(i, foreign_context->Global(),
   20600                "Function.prototype.call.call(func)");
   20601   TestReceiver(i, foreign_context->Global(),
   20602                "Function.prototype.call.apply(func)");
   20603   TestReceiver(i, foreign_context->Global(),
   20604                "Function.prototype.apply.call(func)");
   20605   TestReceiver(i, foreign_context->Global(),
   20606                "Function.prototype.apply.apply(func)");
   20607   // Making calls through built-in functions.
   20608   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
   20609   // ToString(func()) is func()[0], i.e., the returned this.id.
   20610   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
   20611   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
   20612   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
   20613 
   20614   // Calling with environment record as base.
   20615   TestReceiver(i, foreign_context->Global(), "func()");
   20616   // Calling with no base.
   20617   TestReceiver(i, foreign_context->Global(), "(1,func)()");
   20618 }
   20619 
   20620 
   20621 uint8_t callback_fired = 0;
   20622 
   20623 
   20624 void CallCompletedCallback1() {
   20625   i::OS::Print("Firing callback 1.\n");
   20626   callback_fired ^= 1;  // Toggle first bit.
   20627 }
   20628 
   20629 
   20630 void CallCompletedCallback2() {
   20631   i::OS::Print("Firing callback 2.\n");
   20632   callback_fired ^= 2;  // Toggle second bit.
   20633 }
   20634 
   20635 
   20636 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
   20637   int32_t level = args[0]->Int32Value();
   20638   if (level < 3) {
   20639     level++;
   20640     i::OS::Print("Entering recursion level %d.\n", level);
   20641     char script[64];
   20642     i::Vector<char> script_vector(script, sizeof(script));
   20643     i::SNPrintF(script_vector, "recursion(%d)", level);
   20644     CompileRun(script_vector.start());
   20645     i::OS::Print("Leaving recursion level %d.\n", level);
   20646     CHECK_EQ(0, callback_fired);
   20647   } else {
   20648     i::OS::Print("Recursion ends.\n");
   20649     CHECK_EQ(0, callback_fired);
   20650   }
   20651 }
   20652 
   20653 
   20654 TEST(CallCompletedCallback) {
   20655   LocalContext env;
   20656   v8::HandleScope scope(env->GetIsolate());
   20657   v8::Handle<v8::FunctionTemplate> recursive_runtime =
   20658       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
   20659   env->Global()->Set(v8_str("recursion"),
   20660                      recursive_runtime->GetFunction());
   20661   // Adding the same callback a second time has no effect.
   20662   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
   20663   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
   20664   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
   20665   i::OS::Print("--- Script (1) ---\n");
   20666   Local<Script> script = v8::Script::Compile(
   20667       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
   20668   script->Run();
   20669   CHECK_EQ(3, callback_fired);
   20670 
   20671   i::OS::Print("\n--- Script (2) ---\n");
   20672   callback_fired = 0;
   20673   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
   20674   script->Run();
   20675   CHECK_EQ(2, callback_fired);
   20676 
   20677   i::OS::Print("\n--- Function ---\n");
   20678   callback_fired = 0;
   20679   Local<Function> recursive_function =
   20680       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
   20681   v8::Handle<Value> args[] = { v8_num(0) };
   20682   recursive_function->Call(env->Global(), 1, args);
   20683   CHECK_EQ(2, callback_fired);
   20684 }
   20685 
   20686 
   20687 void CallCompletedCallbackNoException() {
   20688   v8::HandleScope scope(CcTest::isolate());
   20689   CompileRun("1+1;");
   20690 }
   20691 
   20692 
   20693 void CallCompletedCallbackException() {
   20694   v8::HandleScope scope(CcTest::isolate());
   20695   CompileRun("throw 'second exception';");
   20696 }
   20697 
   20698 
   20699 TEST(CallCompletedCallbackOneException) {
   20700   LocalContext env;
   20701   v8::HandleScope scope(env->GetIsolate());
   20702   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
   20703   CompileRun("throw 'exception';");
   20704 }
   20705 
   20706 
   20707 TEST(CallCompletedCallbackTwoExceptions) {
   20708   LocalContext env;
   20709   v8::HandleScope scope(env->GetIsolate());
   20710   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
   20711   CompileRun("throw 'first exception';");
   20712 }
   20713 
   20714 
   20715 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
   20716   v8::HandleScope scope(info.GetIsolate());
   20717   CompileRun("ext1Calls++;");
   20718 }
   20719 
   20720 
   20721 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
   20722   v8::HandleScope scope(info.GetIsolate());
   20723   CompileRun("ext2Calls++;");
   20724 }
   20725 
   20726 
   20727 void* g_passed_to_three = NULL;
   20728 
   20729 
   20730 static void MicrotaskThree(void* data) {
   20731   g_passed_to_three = data;
   20732 }
   20733 
   20734 
   20735 TEST(EnqueueMicrotask) {
   20736   LocalContext env;
   20737   v8::HandleScope scope(env->GetIsolate());
   20738   CompileRun(
   20739       "var ext1Calls = 0;"
   20740       "var ext2Calls = 0;");
   20741   CompileRun("1+1;");
   20742   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
   20743   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
   20744 
   20745   env->GetIsolate()->EnqueueMicrotask(
   20746       Function::New(env->GetIsolate(), MicrotaskOne));
   20747   CompileRun("1+1;");
   20748   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
   20749   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
   20750 
   20751   env->GetIsolate()->EnqueueMicrotask(
   20752       Function::New(env->GetIsolate(), MicrotaskOne));
   20753   env->GetIsolate()->EnqueueMicrotask(
   20754       Function::New(env->GetIsolate(), MicrotaskTwo));
   20755   CompileRun("1+1;");
   20756   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20757   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
   20758 
   20759   env->GetIsolate()->EnqueueMicrotask(
   20760       Function::New(env->GetIsolate(), MicrotaskTwo));
   20761   CompileRun("1+1;");
   20762   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20763   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
   20764 
   20765   CompileRun("1+1;");
   20766   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20767   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
   20768 
   20769   g_passed_to_three = NULL;
   20770   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
   20771   CompileRun("1+1;");
   20772   CHECK_EQ(NULL, g_passed_to_three);
   20773   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20774   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
   20775 
   20776   int dummy;
   20777   env->GetIsolate()->EnqueueMicrotask(
   20778       Function::New(env->GetIsolate(), MicrotaskOne));
   20779   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
   20780   env->GetIsolate()->EnqueueMicrotask(
   20781       Function::New(env->GetIsolate(), MicrotaskTwo));
   20782   CompileRun("1+1;");
   20783   CHECK_EQ(&dummy, g_passed_to_three);
   20784   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
   20785   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
   20786   g_passed_to_three = NULL;
   20787 }
   20788 
   20789 
   20790 static void MicrotaskExceptionOne(
   20791     const v8::FunctionCallbackInfo<Value>& info) {
   20792   v8::HandleScope scope(info.GetIsolate());
   20793   CompileRun("exception1Calls++;");
   20794   info.GetIsolate()->ThrowException(
   20795       v8::Exception::Error(v8_str("first")));
   20796 }
   20797 
   20798 
   20799 static void MicrotaskExceptionTwo(
   20800     const v8::FunctionCallbackInfo<Value>& info) {
   20801   v8::HandleScope scope(info.GetIsolate());
   20802   CompileRun("exception2Calls++;");
   20803   info.GetIsolate()->ThrowException(
   20804       v8::Exception::Error(v8_str("second")));
   20805 }
   20806 
   20807 
   20808 TEST(RunMicrotasksIgnoresThrownExceptions) {
   20809   LocalContext env;
   20810   v8::Isolate* isolate = env->GetIsolate();
   20811   v8::HandleScope scope(isolate);
   20812   CompileRun(
   20813       "var exception1Calls = 0;"
   20814       "var exception2Calls = 0;");
   20815   isolate->EnqueueMicrotask(
   20816       Function::New(isolate, MicrotaskExceptionOne));
   20817   isolate->EnqueueMicrotask(
   20818       Function::New(isolate, MicrotaskExceptionTwo));
   20819   TryCatch try_catch;
   20820   CompileRun("1+1;");
   20821   CHECK(!try_catch.HasCaught());
   20822   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
   20823   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
   20824 }
   20825 
   20826 
   20827 TEST(SetAutorunMicrotasks) {
   20828   LocalContext env;
   20829   v8::HandleScope scope(env->GetIsolate());
   20830   CompileRun(
   20831       "var ext1Calls = 0;"
   20832       "var ext2Calls = 0;");
   20833   CompileRun("1+1;");
   20834   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
   20835   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
   20836 
   20837   env->GetIsolate()->EnqueueMicrotask(
   20838       Function::New(env->GetIsolate(), MicrotaskOne));
   20839   CompileRun("1+1;");
   20840   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
   20841   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
   20842 
   20843   env->GetIsolate()->SetAutorunMicrotasks(false);
   20844   env->GetIsolate()->EnqueueMicrotask(
   20845       Function::New(env->GetIsolate(), MicrotaskOne));
   20846   env->GetIsolate()->EnqueueMicrotask(
   20847       Function::New(env->GetIsolate(), MicrotaskTwo));
   20848   CompileRun("1+1;");
   20849   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
   20850   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
   20851 
   20852   env->GetIsolate()->RunMicrotasks();
   20853   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20854   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
   20855 
   20856   env->GetIsolate()->EnqueueMicrotask(
   20857       Function::New(env->GetIsolate(), MicrotaskTwo));
   20858   CompileRun("1+1;");
   20859   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20860   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
   20861 
   20862   env->GetIsolate()->RunMicrotasks();
   20863   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20864   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
   20865 
   20866   env->GetIsolate()->SetAutorunMicrotasks(true);
   20867   env->GetIsolate()->EnqueueMicrotask(
   20868       Function::New(env->GetIsolate(), MicrotaskTwo));
   20869   CompileRun("1+1;");
   20870   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20871   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
   20872 
   20873   env->GetIsolate()->EnqueueMicrotask(
   20874       Function::New(env->GetIsolate(), MicrotaskTwo));
   20875   {
   20876     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
   20877     CompileRun("1+1;");
   20878     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20879     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
   20880   }
   20881 
   20882   CompileRun("1+1;");
   20883   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
   20884   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
   20885 }
   20886 
   20887 
   20888 TEST(RunMicrotasksWithoutEnteringContext) {
   20889   v8::Isolate* isolate = CcTest::isolate();
   20890   HandleScope handle_scope(isolate);
   20891   isolate->SetAutorunMicrotasks(false);
   20892   Handle<Context> context = Context::New(isolate);
   20893   {
   20894     Context::Scope context_scope(context);
   20895     CompileRun("var ext1Calls = 0;");
   20896     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
   20897   }
   20898   isolate->RunMicrotasks();
   20899   {
   20900     Context::Scope context_scope(context);
   20901     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
   20902   }
   20903   isolate->SetAutorunMicrotasks(true);
   20904 }
   20905 
   20906 
   20907 #ifdef DEBUG
   20908 static int probes_counter = 0;
   20909 static int misses_counter = 0;
   20910 static int updates_counter = 0;
   20911 
   20912 
   20913 static int* LookupCounter(const char* name) {
   20914   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
   20915     return &probes_counter;
   20916   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
   20917     return &misses_counter;
   20918   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
   20919     return &updates_counter;
   20920   }
   20921   return NULL;
   20922 }
   20923 
   20924 
   20925 static const char* kMegamorphicTestProgram =
   20926     "function ClassA() { };"
   20927     "function ClassB() { };"
   20928     "ClassA.prototype.foo = function() { };"
   20929     "ClassB.prototype.foo = function() { };"
   20930     "function fooify(obj) { obj.foo(); };"
   20931     "var a = new ClassA();"
   20932     "var b = new ClassB();"
   20933     "for (var i = 0; i < 10000; i++) {"
   20934     "  fooify(a);"
   20935     "  fooify(b);"
   20936     "}";
   20937 #endif
   20938 
   20939 
   20940 static void StubCacheHelper(bool primary) {
   20941 #ifdef DEBUG
   20942   i::FLAG_native_code_counters = true;
   20943   if (primary) {
   20944     i::FLAG_test_primary_stub_cache = true;
   20945   } else {
   20946     i::FLAG_test_secondary_stub_cache = true;
   20947   }
   20948   i::FLAG_crankshaft = false;
   20949   LocalContext env;
   20950   env->GetIsolate()->SetCounterFunction(LookupCounter);
   20951   v8::HandleScope scope(env->GetIsolate());
   20952   int initial_probes = probes_counter;
   20953   int initial_misses = misses_counter;
   20954   int initial_updates = updates_counter;
   20955   CompileRun(kMegamorphicTestProgram);
   20956   int probes = probes_counter - initial_probes;
   20957   int misses = misses_counter - initial_misses;
   20958   int updates = updates_counter - initial_updates;
   20959   CHECK_LT(updates, 10);
   20960   CHECK_LT(misses, 10);
   20961   // TODO(verwaest): Update this test to overflow the degree of polymorphism
   20962   // before megamorphism. The number of probes will only work once we teach the
   20963   // serializer to embed references to counters in the stubs, given that the
   20964   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
   20965   CHECK_GE(probes, 0);
   20966 #endif
   20967 }
   20968 
   20969 
   20970 TEST(SecondaryStubCache) {
   20971   StubCacheHelper(true);
   20972 }
   20973 
   20974 
   20975 TEST(PrimaryStubCache) {
   20976   StubCacheHelper(false);
   20977 }
   20978 
   20979 
   20980 #ifdef DEBUG
   20981 static int cow_arrays_created_runtime = 0;
   20982 
   20983 
   20984 static int* LookupCounterCOWArrays(const char* name) {
   20985   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
   20986     return &cow_arrays_created_runtime;
   20987   }
   20988   return NULL;
   20989 }
   20990 #endif
   20991 
   20992 
   20993 TEST(CheckCOWArraysCreatedRuntimeCounter) {
   20994 #ifdef DEBUG
   20995   i::FLAG_native_code_counters = true;
   20996   LocalContext env;
   20997   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
   20998   v8::HandleScope scope(env->GetIsolate());
   20999   int initial_cow_arrays = cow_arrays_created_runtime;
   21000   CompileRun("var o = [1, 2, 3];");
   21001   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
   21002   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
   21003   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
   21004   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
   21005   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
   21006 #endif
   21007 }
   21008 
   21009 
   21010 TEST(StaticGetters) {
   21011   LocalContext context;
   21012   i::Factory* factory = CcTest::i_isolate()->factory();
   21013   v8::Isolate* isolate = CcTest::isolate();
   21014   v8::HandleScope scope(isolate);
   21015   i::Handle<i::Object> undefined_value = factory->undefined_value();
   21016   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
   21017   i::Handle<i::Object> null_value = factory->null_value();
   21018   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
   21019   i::Handle<i::Object> true_value = factory->true_value();
   21020   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
   21021   i::Handle<i::Object> false_value = factory->false_value();
   21022   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
   21023 }
   21024 
   21025 
   21026 UNINITIALIZED_TEST(IsolateEmbedderData) {
   21027   CcTest::DisableAutomaticDispose();
   21028   v8::Isolate* isolate = v8::Isolate::New();
   21029   isolate->Enter();
   21030   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   21031   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
   21032     CHECK_EQ(NULL, isolate->GetData(slot));
   21033     CHECK_EQ(NULL, i_isolate->GetData(slot));
   21034   }
   21035   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
   21036     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
   21037     isolate->SetData(slot, data);
   21038   }
   21039   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
   21040     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
   21041     CHECK_EQ(data, isolate->GetData(slot));
   21042     CHECK_EQ(data, i_isolate->GetData(slot));
   21043   }
   21044   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
   21045     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
   21046     isolate->SetData(slot, data);
   21047   }
   21048   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
   21049     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
   21050     CHECK_EQ(data, isolate->GetData(slot));
   21051     CHECK_EQ(data, i_isolate->GetData(slot));
   21052   }
   21053   isolate->Exit();
   21054   isolate->Dispose();
   21055 }
   21056 
   21057 
   21058 TEST(StringEmpty) {
   21059   LocalContext context;
   21060   i::Factory* factory = CcTest::i_isolate()->factory();
   21061   v8::Isolate* isolate = CcTest::isolate();
   21062   v8::HandleScope scope(isolate);
   21063   i::Handle<i::Object> empty_string = factory->empty_string();
   21064   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
   21065 }
   21066 
   21067 
   21068 static int instance_checked_getter_count = 0;
   21069 static void InstanceCheckedGetter(
   21070     Local<String> name,
   21071     const v8::PropertyCallbackInfo<v8::Value>& info) {
   21072   CHECK_EQ(name, v8_str("foo"));
   21073   instance_checked_getter_count++;
   21074   info.GetReturnValue().Set(v8_num(11));
   21075 }
   21076 
   21077 
   21078 static int instance_checked_setter_count = 0;
   21079 static void InstanceCheckedSetter(Local<String> name,
   21080                       Local<Value> value,
   21081                       const v8::PropertyCallbackInfo<void>& info) {
   21082   CHECK_EQ(name, v8_str("foo"));
   21083   CHECK_EQ(value, v8_num(23));
   21084   instance_checked_setter_count++;
   21085 }
   21086 
   21087 
   21088 static void CheckInstanceCheckedResult(int getters,
   21089                                        int setters,
   21090                                        bool expects_callbacks,
   21091                                        TryCatch* try_catch) {
   21092   if (expects_callbacks) {
   21093     CHECK(!try_catch->HasCaught());
   21094     CHECK_EQ(getters, instance_checked_getter_count);
   21095     CHECK_EQ(setters, instance_checked_setter_count);
   21096   } else {
   21097     CHECK(try_catch->HasCaught());
   21098     CHECK_EQ(0, instance_checked_getter_count);
   21099     CHECK_EQ(0, instance_checked_setter_count);
   21100   }
   21101   try_catch->Reset();
   21102 }
   21103 
   21104 
   21105 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
   21106   instance_checked_getter_count = 0;
   21107   instance_checked_setter_count = 0;
   21108   TryCatch try_catch;
   21109 
   21110   // Test path through generic runtime code.
   21111   CompileRun("obj.foo");
   21112   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
   21113   CompileRun("obj.foo = 23");
   21114   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
   21115 
   21116   // Test path through generated LoadIC and StoredIC.
   21117   CompileRun("function test_get(o) { o.foo; }"
   21118              "test_get(obj);");
   21119   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
   21120   CompileRun("test_get(obj);");
   21121   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
   21122   CompileRun("test_get(obj);");
   21123   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
   21124   CompileRun("function test_set(o) { o.foo = 23; }"
   21125              "test_set(obj);");
   21126   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
   21127   CompileRun("test_set(obj);");
   21128   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
   21129   CompileRun("test_set(obj);");
   21130   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
   21131 
   21132   // Test path through optimized code.
   21133   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
   21134              "test_get(obj);");
   21135   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
   21136   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
   21137              "test_set(obj);");
   21138   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
   21139 
   21140   // Cleanup so that closures start out fresh in next check.
   21141   CompileRun("%DeoptimizeFunction(test_get);"
   21142              "%ClearFunctionTypeFeedback(test_get);"
   21143              "%DeoptimizeFunction(test_set);"
   21144              "%ClearFunctionTypeFeedback(test_set);");
   21145 }
   21146 
   21147 
   21148 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
   21149   v8::internal::FLAG_allow_natives_syntax = true;
   21150   LocalContext context;
   21151   v8::HandleScope scope(context->GetIsolate());
   21152 
   21153   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
   21154   Local<ObjectTemplate> inst = templ->InstanceTemplate();
   21155   inst->SetAccessor(v8_str("foo"),
   21156                     InstanceCheckedGetter, InstanceCheckedSetter,
   21157                     Handle<Value>(),
   21158                     v8::DEFAULT,
   21159                     v8::None,
   21160                     v8::AccessorSignature::New(context->GetIsolate(), templ));
   21161   context->Global()->Set(v8_str("f"), templ->GetFunction());
   21162 
   21163   printf("Testing positive ...\n");
   21164   CompileRun("var obj = new f();");
   21165   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21166   CheckInstanceCheckedAccessors(true);
   21167 
   21168   printf("Testing negative ...\n");
   21169   CompileRun("var obj = {};"
   21170              "obj.__proto__ = new f();");
   21171   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21172   CheckInstanceCheckedAccessors(false);
   21173 }
   21174 
   21175 
   21176 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
   21177   v8::internal::FLAG_allow_natives_syntax = true;
   21178   LocalContext context;
   21179   v8::HandleScope scope(context->GetIsolate());
   21180 
   21181   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
   21182   Local<ObjectTemplate> inst = templ->InstanceTemplate();
   21183   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
   21184   inst->SetAccessor(v8_str("foo"),
   21185                     InstanceCheckedGetter, InstanceCheckedSetter,
   21186                     Handle<Value>(),
   21187                     v8::DEFAULT,
   21188                     v8::None,
   21189                     v8::AccessorSignature::New(context->GetIsolate(), templ));
   21190   context->Global()->Set(v8_str("f"), templ->GetFunction());
   21191 
   21192   printf("Testing positive ...\n");
   21193   CompileRun("var obj = new f();");
   21194   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21195   CheckInstanceCheckedAccessors(true);
   21196 
   21197   printf("Testing negative ...\n");
   21198   CompileRun("var obj = {};"
   21199              "obj.__proto__ = new f();");
   21200   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21201   CheckInstanceCheckedAccessors(false);
   21202 }
   21203 
   21204 
   21205 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
   21206   v8::internal::FLAG_allow_natives_syntax = true;
   21207   LocalContext context;
   21208   v8::HandleScope scope(context->GetIsolate());
   21209 
   21210   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
   21211   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
   21212   proto->SetAccessor(v8_str("foo"),
   21213                      InstanceCheckedGetter, InstanceCheckedSetter,
   21214                      Handle<Value>(),
   21215                      v8::DEFAULT,
   21216                      v8::None,
   21217                      v8::AccessorSignature::New(context->GetIsolate(), templ));
   21218   context->Global()->Set(v8_str("f"), templ->GetFunction());
   21219 
   21220   printf("Testing positive ...\n");
   21221   CompileRun("var obj = new f();");
   21222   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21223   CheckInstanceCheckedAccessors(true);
   21224 
   21225   printf("Testing negative ...\n");
   21226   CompileRun("var obj = {};"
   21227              "obj.__proto__ = new f();");
   21228   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21229   CheckInstanceCheckedAccessors(false);
   21230 
   21231   printf("Testing positive with modified prototype chain ...\n");
   21232   CompileRun("var obj = new f();"
   21233              "var pro = {};"
   21234              "pro.__proto__ = obj.__proto__;"
   21235              "obj.__proto__ = pro;");
   21236   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
   21237   CheckInstanceCheckedAccessors(true);
   21238 }
   21239 
   21240 
   21241 TEST(TryFinallyMessage) {
   21242   LocalContext context;
   21243   v8::HandleScope scope(context->GetIsolate());
   21244   {
   21245     // Test that the original error message is not lost if there is a
   21246     // recursive call into Javascript is done in the finally block, e.g. to
   21247     // initialize an IC. (crbug.com/129171)
   21248     TryCatch try_catch;
   21249     const char* trigger_ic =
   21250         "try {                      \n"
   21251         "  throw new Error('test'); \n"
   21252         "} finally {                \n"
   21253         "  var x = 0;               \n"
   21254         "  x++;                     \n"  // Trigger an IC initialization here.
   21255         "}                          \n";
   21256     CompileRun(trigger_ic);
   21257     CHECK(try_catch.HasCaught());
   21258     Local<Message> message = try_catch.Message();
   21259     CHECK(!message.IsEmpty());
   21260     CHECK_EQ(2, message->GetLineNumber());
   21261   }
   21262 
   21263   {
   21264     // Test that the original exception message is indeed overwritten if
   21265     // a new error is thrown in the finally block.
   21266     TryCatch try_catch;
   21267     const char* throw_again =
   21268         "try {                       \n"
   21269         "  throw new Error('test');  \n"
   21270         "} finally {                 \n"
   21271         "  var x = 0;                \n"
   21272         "  x++;                      \n"
   21273         "  throw new Error('again'); \n"  // This is the new uncaught error.
   21274         "}                           \n";
   21275     CompileRun(throw_again);
   21276     CHECK(try_catch.HasCaught());
   21277     Local<Message> message = try_catch.Message();
   21278     CHECK(!message.IsEmpty());
   21279     CHECK_EQ(6, message->GetLineNumber());
   21280   }
   21281 }
   21282 
   21283 
   21284 static void Helper137002(bool do_store,
   21285                          bool polymorphic,
   21286                          bool remove_accessor,
   21287                          bool interceptor) {
   21288   LocalContext context;
   21289   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
   21290   if (interceptor) {
   21291     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
   21292   } else {
   21293     templ->SetAccessor(v8_str("foo"),
   21294                        GetterWhichReturns42,
   21295                        SetterWhichSetsYOnThisTo23);
   21296   }
   21297   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   21298 
   21299   // Turn monomorphic on slow object with native accessor, then turn
   21300   // polymorphic, finally optimize to create negative lookup and fail.
   21301   CompileRun(do_store ?
   21302              "function f(x) { x.foo = void 0; }" :
   21303              "function f(x) { return x.foo; }");
   21304   CompileRun("obj.y = void 0;");
   21305   if (!interceptor) {
   21306     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
   21307   }
   21308   CompileRun("obj.__proto__ = null;"
   21309              "f(obj); f(obj); f(obj);");
   21310   if (polymorphic) {
   21311     CompileRun("f({});");
   21312   }
   21313   CompileRun("obj.y = void 0;"
   21314              "%OptimizeFunctionOnNextCall(f);");
   21315   if (remove_accessor) {
   21316     CompileRun("delete obj.foo;");
   21317   }
   21318   CompileRun("var result = f(obj);");
   21319   if (do_store) {
   21320     CompileRun("result = obj.y;");
   21321   }
   21322   if (remove_accessor && !interceptor) {
   21323     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
   21324   } else {
   21325     CHECK_EQ(do_store ? 23 : 42,
   21326              context->Global()->Get(v8_str("result"))->Int32Value());
   21327   }
   21328 }
   21329 
   21330 
   21331 THREADED_TEST(Regress137002a) {
   21332   i::FLAG_allow_natives_syntax = true;
   21333   i::FLAG_compilation_cache = false;
   21334   v8::HandleScope scope(CcTest::isolate());
   21335   for (int i = 0; i < 16; i++) {
   21336     Helper137002(i & 8, i & 4, i & 2, i & 1);
   21337   }
   21338 }
   21339 
   21340 
   21341 THREADED_TEST(Regress137002b) {
   21342   i::FLAG_allow_natives_syntax = true;
   21343   LocalContext context;
   21344   v8::Isolate* isolate = context->GetIsolate();
   21345   v8::HandleScope scope(isolate);
   21346   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   21347   templ->SetAccessor(v8_str("foo"),
   21348                      GetterWhichReturns42,
   21349                      SetterWhichSetsYOnThisTo23);
   21350   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   21351 
   21352   // Turn monomorphic on slow object with native accessor, then just
   21353   // delete the property and fail.
   21354   CompileRun("function load(x) { return x.foo; }"
   21355              "function store(x) { x.foo = void 0; }"
   21356              "function keyed_load(x, key) { return x[key]; }"
   21357              // Second version of function has a different source (add void 0)
   21358              // so that it does not share code with the first version.  This
   21359              // ensures that the ICs are monomorphic.
   21360              "function load2(x) { void 0; return x.foo; }"
   21361              "function store2(x) { void 0; x.foo = void 0; }"
   21362              "function keyed_load2(x, key) { void 0; return x[key]; }"
   21363 
   21364              "obj.y = void 0;"
   21365              "obj.__proto__ = null;"
   21366              "var subobj = {};"
   21367              "subobj.y = void 0;"
   21368              "subobj.__proto__ = obj;"
   21369              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
   21370 
   21371              // Make the ICs monomorphic.
   21372              "load(obj); load(obj);"
   21373              "load2(subobj); load2(subobj);"
   21374              "store(obj); store(obj);"
   21375              "store2(subobj); store2(subobj);"
   21376              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
   21377              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
   21378 
   21379              // Actually test the shiny new ICs and better not crash. This
   21380              // serves as a regression test for issue 142088 as well.
   21381              "load(obj);"
   21382              "load2(subobj);"
   21383              "store(obj);"
   21384              "store2(subobj);"
   21385              "keyed_load(obj, 'foo');"
   21386              "keyed_load2(subobj, 'foo');"
   21387 
   21388              // Delete the accessor.  It better not be called any more now.
   21389              "delete obj.foo;"
   21390              "obj.y = void 0;"
   21391              "subobj.y = void 0;"
   21392 
   21393              "var load_result = load(obj);"
   21394              "var load_result2 = load2(subobj);"
   21395              "var keyed_load_result = keyed_load(obj, 'foo');"
   21396              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
   21397              "store(obj);"
   21398              "store2(subobj);"
   21399              "var y_from_obj = obj.y;"
   21400              "var y_from_subobj = subobj.y;");
   21401   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
   21402   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
   21403   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
   21404   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
   21405   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
   21406   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
   21407 }
   21408 
   21409 
   21410 THREADED_TEST(Regress142088) {
   21411   i::FLAG_allow_natives_syntax = true;
   21412   LocalContext context;
   21413   v8::Isolate* isolate = context->GetIsolate();
   21414   v8::HandleScope scope(isolate);
   21415   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   21416   templ->SetAccessor(v8_str("foo"),
   21417                      GetterWhichReturns42,
   21418                      SetterWhichSetsYOnThisTo23);
   21419   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   21420 
   21421   CompileRun("function load(x) { return x.foo; }"
   21422              "var o = Object.create(obj);"
   21423              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
   21424              "load(o); load(o); load(o); load(o);");
   21425 }
   21426 
   21427 
   21428 THREADED_TEST(Regress3337) {
   21429   LocalContext context;
   21430   v8::Isolate* isolate = context->GetIsolate();
   21431   v8::HandleScope scope(isolate);
   21432   Local<v8::Object> o1 = Object::New(isolate);
   21433   Local<v8::Object> o2 = Object::New(isolate);
   21434   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
   21435   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
   21436   CHECK(io1->map() == io2->map());
   21437   o1->SetIndexedPropertiesToExternalArrayData(
   21438       NULL, v8::kExternalUint32Array, 0);
   21439   o2->SetIndexedPropertiesToExternalArrayData(
   21440       NULL, v8::kExternalUint32Array, 0);
   21441   CHECK(io1->map() == io2->map());
   21442 }
   21443 
   21444 
   21445 THREADED_TEST(Regress137496) {
   21446   i::FLAG_expose_gc = true;
   21447   LocalContext context;
   21448   v8::HandleScope scope(context->GetIsolate());
   21449 
   21450   // Compile a try-finally clause where the finally block causes a GC
   21451   // while there still is a message pending for external reporting.
   21452   TryCatch try_catch;
   21453   try_catch.SetVerbose(true);
   21454   CompileRun("try { throw new Error(); } finally { gc(); }");
   21455   CHECK(try_catch.HasCaught());
   21456 }
   21457 
   21458 
   21459 THREADED_TEST(Regress149912) {
   21460   LocalContext context;
   21461   v8::HandleScope scope(context->GetIsolate());
   21462   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
   21463   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
   21464   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
   21465   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
   21466 }
   21467 
   21468 
   21469 THREADED_TEST(Regress157124) {
   21470   LocalContext context;
   21471   v8::Isolate* isolate = context->GetIsolate();
   21472   v8::HandleScope scope(isolate);
   21473   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   21474   Local<Object> obj = templ->NewInstance();
   21475   obj->GetIdentityHash();
   21476   obj->DeleteHiddenValue(v8_str("Bug"));
   21477 }
   21478 
   21479 
   21480 THREADED_TEST(Regress2535) {
   21481   i::FLAG_harmony_collections = true;
   21482   i::FLAG_harmony_symbols = true;
   21483   LocalContext context;
   21484   v8::HandleScope scope(context->GetIsolate());
   21485   Local<Value> set_value = CompileRun("new Set();");
   21486   Local<Object> set_object(Local<Object>::Cast(set_value));
   21487   CHECK_EQ(0, set_object->InternalFieldCount());
   21488   Local<Value> map_value = CompileRun("new Map();");
   21489   Local<Object> map_object(Local<Object>::Cast(map_value));
   21490   CHECK_EQ(0, map_object->InternalFieldCount());
   21491 }
   21492 
   21493 
   21494 THREADED_TEST(Regress2746) {
   21495   LocalContext context;
   21496   v8::Isolate* isolate = context->GetIsolate();
   21497   v8::HandleScope scope(isolate);
   21498   Local<Object> obj = Object::New(isolate);
   21499   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
   21500   obj->SetHiddenValue(key, v8::Undefined(isolate));
   21501   Local<Value> value = obj->GetHiddenValue(key);
   21502   CHECK(!value.IsEmpty());
   21503   CHECK(value->IsUndefined());
   21504 }
   21505 
   21506 
   21507 THREADED_TEST(Regress260106) {
   21508   LocalContext context;
   21509   v8::Isolate* isolate = context->GetIsolate();
   21510   v8::HandleScope scope(isolate);
   21511   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
   21512                                                         DummyCallHandler);
   21513   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
   21514   Local<Function> function = templ->GetFunction();
   21515   CHECK(!function.IsEmpty());
   21516   CHECK(function->IsFunction());
   21517 }
   21518 
   21519 
   21520 THREADED_TEST(JSONParseObject) {
   21521   LocalContext context;
   21522   HandleScope scope(context->GetIsolate());
   21523   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
   21524   Handle<Object> global = context->Global();
   21525   global->Set(v8_str("obj"), obj);
   21526   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
   21527 }
   21528 
   21529 
   21530 THREADED_TEST(JSONParseNumber) {
   21531   LocalContext context;
   21532   HandleScope scope(context->GetIsolate());
   21533   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
   21534   Handle<Object> global = context->Global();
   21535   global->Set(v8_str("obj"), obj);
   21536   ExpectString("JSON.stringify(obj)", "42");
   21537 }
   21538 
   21539 
   21540 #if V8_OS_POSIX
   21541 class ThreadInterruptTest {
   21542  public:
   21543   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
   21544   ~ThreadInterruptTest() {}
   21545 
   21546   void RunTest() {
   21547     InterruptThread i_thread(this);
   21548     i_thread.Start();
   21549 
   21550     sem_.Wait();
   21551     CHECK_EQ(kExpectedValue, sem_value_);
   21552   }
   21553 
   21554  private:
   21555   static const int kExpectedValue = 1;
   21556 
   21557   class InterruptThread : public i::Thread {
   21558    public:
   21559     explicit InterruptThread(ThreadInterruptTest* test)
   21560         : Thread("InterruptThread"), test_(test) {}
   21561 
   21562     virtual void Run() {
   21563       struct sigaction action;
   21564 
   21565       // Ensure that we'll enter waiting condition
   21566       i::OS::Sleep(100);
   21567 
   21568       // Setup signal handler
   21569       memset(&action, 0, sizeof(action));
   21570       action.sa_handler = SignalHandler;
   21571       sigaction(SIGCHLD, &action, NULL);
   21572 
   21573       // Send signal
   21574       kill(getpid(), SIGCHLD);
   21575 
   21576       // Ensure that if wait has returned because of error
   21577       i::OS::Sleep(100);
   21578 
   21579       // Set value and signal semaphore
   21580       test_->sem_value_ = 1;
   21581       test_->sem_.Signal();
   21582     }
   21583 
   21584     static void SignalHandler(int signal) {
   21585     }
   21586 
   21587    private:
   21588      ThreadInterruptTest* test_;
   21589   };
   21590 
   21591   i::Semaphore sem_;
   21592   volatile int sem_value_;
   21593 };
   21594 
   21595 
   21596 THREADED_TEST(SemaphoreInterruption) {
   21597   ThreadInterruptTest().RunTest();
   21598 }
   21599 
   21600 
   21601 #endif  // V8_OS_POSIX
   21602 
   21603 
   21604 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
   21605                                      Local<Value> name,
   21606                                      v8::AccessType type,
   21607                                      Local<Value> data) {
   21608   i::PrintF("Named access blocked.\n");
   21609   return false;
   21610 }
   21611 
   21612 
   21613 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
   21614                                      uint32_t key,
   21615                                      v8::AccessType type,
   21616                                      Local<Value> data) {
   21617   i::PrintF("Indexed access blocked.\n");
   21618   return false;
   21619 }
   21620 
   21621 
   21622 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   21623   CHECK(false);
   21624 }
   21625 
   21626 
   21627 TEST(JSONStringifyAccessCheck) {
   21628   v8::V8::Initialize();
   21629   v8::Isolate* isolate = CcTest::isolate();
   21630   v8::HandleScope scope(isolate);
   21631 
   21632   // Create an ObjectTemplate for global objects and install access
   21633   // check callbacks that will block access.
   21634   v8::Handle<v8::ObjectTemplate> global_template =
   21635       v8::ObjectTemplate::New(isolate);
   21636   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
   21637                                            IndexAccessAlwaysBlocked);
   21638 
   21639   // Create a context and set an x property on it's global object.
   21640   LocalContext context0(NULL, global_template);
   21641   v8::Handle<v8::Object> global0 = context0->Global();
   21642   global0->Set(v8_str("x"), v8_num(42));
   21643   ExpectString("JSON.stringify(this)", "{\"x\":42}");
   21644 
   21645   for (int i = 0; i < 2; i++) {
   21646     if (i == 1) {
   21647       // Install a toJSON function on the second run.
   21648       v8::Handle<v8::FunctionTemplate> toJSON =
   21649           v8::FunctionTemplate::New(isolate, UnreachableCallback);
   21650 
   21651       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
   21652     }
   21653     // Create a context with a different security token so that the
   21654     // failed access check callback will be called on each access.
   21655     LocalContext context1(NULL, global_template);
   21656     context1->Global()->Set(v8_str("other"), global0);
   21657 
   21658     ExpectString("JSON.stringify(other)", "{}");
   21659     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
   21660                  "{\"a\":{},\"b\":[\"c\"]}");
   21661     ExpectString("JSON.stringify([other, 'b', 'c'])",
   21662                  "[{},\"b\",\"c\"]");
   21663 
   21664     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
   21665     array->Set(0, v8_str("a"));
   21666     array->Set(1, v8_str("b"));
   21667     context1->Global()->Set(v8_str("array"), array);
   21668     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
   21669     array->TurnOnAccessCheck();
   21670     ExpectString("JSON.stringify(array)", "[]");
   21671     ExpectString("JSON.stringify([array])", "[[]]");
   21672     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
   21673   }
   21674 }
   21675 
   21676 
   21677 bool access_check_fail_thrown = false;
   21678 bool catch_callback_called = false;
   21679 
   21680 
   21681 // Failed access check callback that performs a GC on each invocation.
   21682 void FailedAccessCheckThrows(Local<v8::Object> target,
   21683                              v8::AccessType type,
   21684                              Local<v8::Value> data) {
   21685   access_check_fail_thrown = true;
   21686   i::PrintF("Access check failed. Error thrown.\n");
   21687   CcTest::isolate()->ThrowException(
   21688       v8::Exception::Error(v8_str("cross context")));
   21689 }
   21690 
   21691 
   21692 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   21693   for (int i = 0; i < args.Length(); i++) {
   21694     i::PrintF("%s\n", *String::Utf8Value(args[i]));
   21695   }
   21696   catch_callback_called = true;
   21697 }
   21698 
   21699 
   21700 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
   21701   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
   21702 }
   21703 
   21704 
   21705 void CheckCorrectThrow(const char* script) {
   21706   // Test that the script, when wrapped into a try-catch, triggers the catch
   21707   // clause due to failed access check throwing an exception.
   21708   // The subsequent try-catch should run without any exception.
   21709   access_check_fail_thrown = false;
   21710   catch_callback_called = false;
   21711   i::ScopedVector<char> source(1024);
   21712   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
   21713   CompileRun(source.start());
   21714   CHECK(access_check_fail_thrown);
   21715   CHECK(catch_callback_called);
   21716 
   21717   access_check_fail_thrown = false;
   21718   catch_callback_called = false;
   21719   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
   21720   CHECK(!access_check_fail_thrown);
   21721   CHECK(!catch_callback_called);
   21722 }
   21723 
   21724 
   21725 TEST(AccessCheckThrows) {
   21726   i::FLAG_allow_natives_syntax = true;
   21727   v8::V8::Initialize();
   21728   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
   21729   v8::Isolate* isolate = CcTest::isolate();
   21730   v8::HandleScope scope(isolate);
   21731 
   21732   // Create an ObjectTemplate for global objects and install access
   21733   // check callbacks that will block access.
   21734   v8::Handle<v8::ObjectTemplate> global_template =
   21735       v8::ObjectTemplate::New(isolate);
   21736   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
   21737                                            IndexAccessAlwaysBlocked);
   21738 
   21739   // Create a context and set an x property on it's global object.
   21740   LocalContext context0(NULL, global_template);
   21741   context0->Global()->Set(v8_str("x"), v8_num(42));
   21742   v8::Handle<v8::Object> global0 = context0->Global();
   21743 
   21744   // Create a context with a different security token so that the
   21745   // failed access check callback will be called on each access.
   21746   LocalContext context1(NULL, global_template);
   21747   context1->Global()->Set(v8_str("other"), global0);
   21748 
   21749   v8::Handle<v8::FunctionTemplate> catcher_fun =
   21750       v8::FunctionTemplate::New(isolate, CatcherCallback);
   21751   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
   21752 
   21753   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
   21754       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
   21755   context1->Global()->Set(v8_str("has_own_property"),
   21756                           has_own_property_fun->GetFunction());
   21757 
   21758   { v8::TryCatch try_catch;
   21759     access_check_fail_thrown = false;
   21760     CompileRun("other.x;");
   21761     CHECK(access_check_fail_thrown);
   21762     CHECK(try_catch.HasCaught());
   21763   }
   21764 
   21765   CheckCorrectThrow("other.x");
   21766   CheckCorrectThrow("other[1]");
   21767   CheckCorrectThrow("JSON.stringify(other)");
   21768   CheckCorrectThrow("has_own_property(other, 'x')");
   21769   CheckCorrectThrow("%GetProperty(other, 'x')");
   21770   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
   21771   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
   21772   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
   21773   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
   21774   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
   21775   CheckCorrectThrow("%HasProperty(other, 'x')");
   21776   CheckCorrectThrow("%HasElement(other, 1)");
   21777   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
   21778   CheckCorrectThrow("%GetPropertyNames(other)");
   21779   // PROPERTY_ATTRIBUTES_NONE = 0
   21780   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
   21781   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
   21782                         "other, 'x', null, null, 1)");
   21783 
   21784   // Reset the failed access check callback so it does not influence
   21785   // the other tests.
   21786   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
   21787 }
   21788 
   21789 
   21790 THREADED_TEST(Regress256330) {
   21791   i::FLAG_allow_natives_syntax = true;
   21792   LocalContext context;
   21793   v8::HandleScope scope(context->GetIsolate());
   21794   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
   21795   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
   21796   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
   21797   CompileRun("\"use strict\"; var o = new Bug;"
   21798              "function f(o) { o.x = 10; };"
   21799              "f(o); f(o); f(o);"
   21800              "%OptimizeFunctionOnNextCall(f);"
   21801              "f(o);");
   21802   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
   21803 }
   21804 
   21805 
   21806 THREADED_TEST(CrankshaftInterceptorSetter) {
   21807   i::FLAG_allow_natives_syntax = true;
   21808   v8::HandleScope scope(CcTest::isolate());
   21809   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   21810   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   21811   LocalContext env;
   21812   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   21813   CompileRun("var obj = new Obj;"
   21814              // Initialize fields to avoid transitions later.
   21815              "obj.age = 0;"
   21816              "obj.accessor_age = 42;"
   21817              "function setter(i) { this.accessor_age = i; };"
   21818              "function getter() { return this.accessor_age; };"
   21819              "function setAge(i) { obj.age = i; };"
   21820              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
   21821              "setAge(1);"
   21822              "setAge(2);"
   21823              "setAge(3);"
   21824              "%OptimizeFunctionOnNextCall(setAge);"
   21825              "setAge(4);");
   21826   // All stores went through the interceptor.
   21827   ExpectInt32("obj.interceptor_age", 4);
   21828   ExpectInt32("obj.accessor_age", 42);
   21829 }
   21830 
   21831 
   21832 THREADED_TEST(CrankshaftInterceptorGetter) {
   21833   i::FLAG_allow_natives_syntax = true;
   21834   v8::HandleScope scope(CcTest::isolate());
   21835   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   21836   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   21837   LocalContext env;
   21838   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   21839   CompileRun("var obj = new Obj;"
   21840              // Initialize fields to avoid transitions later.
   21841              "obj.age = 1;"
   21842              "obj.accessor_age = 42;"
   21843              "function getter() { return this.accessor_age; };"
   21844              "function getAge() { return obj.interceptor_age; };"
   21845              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
   21846              "getAge();"
   21847              "getAge();"
   21848              "getAge();"
   21849              "%OptimizeFunctionOnNextCall(getAge);");
   21850   // Access through interceptor.
   21851   ExpectInt32("getAge()", 1);
   21852 }
   21853 
   21854 
   21855 THREADED_TEST(CrankshaftInterceptorFieldRead) {
   21856   i::FLAG_allow_natives_syntax = true;
   21857   v8::HandleScope scope(CcTest::isolate());
   21858   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   21859   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   21860   LocalContext env;
   21861   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   21862   CompileRun("var obj = new Obj;"
   21863              "obj.__proto__.interceptor_age = 42;"
   21864              "obj.age = 100;"
   21865              "function getAge() { return obj.interceptor_age; };");
   21866   ExpectInt32("getAge();", 100);
   21867   ExpectInt32("getAge();", 100);
   21868   ExpectInt32("getAge();", 100);
   21869   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
   21870   // Access through interceptor.
   21871   ExpectInt32("getAge();", 100);
   21872 }
   21873 
   21874 
   21875 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
   21876   i::FLAG_allow_natives_syntax = true;
   21877   v8::HandleScope scope(CcTest::isolate());
   21878   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
   21879   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
   21880   LocalContext env;
   21881   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
   21882   CompileRun("var obj = new Obj;"
   21883              "obj.age = 100000;"
   21884              "function setAge(i) { obj.age = i };"
   21885              "setAge(100);"
   21886              "setAge(101);"
   21887              "setAge(102);"
   21888              "%OptimizeFunctionOnNextCall(setAge);"
   21889              "setAge(103);");
   21890   ExpectInt32("obj.age", 100000);
   21891   ExpectInt32("obj.interceptor_age", 103);
   21892 }
   21893 
   21894 
   21895 class RequestInterruptTestBase {
   21896  public:
   21897   RequestInterruptTestBase()
   21898       : env_(),
   21899         isolate_(env_->GetIsolate()),
   21900         sem_(0),
   21901         warmup_(20000),
   21902         should_continue_(true) {
   21903   }
   21904 
   21905   virtual ~RequestInterruptTestBase() { }
   21906 
   21907   virtual void StartInterruptThread() = 0;
   21908 
   21909   virtual void TestBody() = 0;
   21910 
   21911   void RunTest() {
   21912     StartInterruptThread();
   21913 
   21914     v8::HandleScope handle_scope(isolate_);
   21915 
   21916     TestBody();
   21917 
   21918     isolate_->ClearInterrupt();
   21919 
   21920     // Verify we arrived here because interruptor was called
   21921     // not due to a bug causing us to exit the loop too early.
   21922     CHECK(!should_continue());
   21923   }
   21924 
   21925   void WakeUpInterruptor() {
   21926     sem_.Signal();
   21927   }
   21928 
   21929   bool should_continue() const { return should_continue_; }
   21930 
   21931   bool ShouldContinue() {
   21932     if (warmup_ > 0) {
   21933       if (--warmup_ == 0) {
   21934         WakeUpInterruptor();
   21935       }
   21936     }
   21937 
   21938     return should_continue_;
   21939   }
   21940 
   21941   static void ShouldContinueCallback(
   21942       const v8::FunctionCallbackInfo<Value>& info) {
   21943     RequestInterruptTestBase* test =
   21944         reinterpret_cast<RequestInterruptTestBase*>(
   21945             info.Data().As<v8::External>()->Value());
   21946     info.GetReturnValue().Set(test->ShouldContinue());
   21947   }
   21948 
   21949   LocalContext env_;
   21950   v8::Isolate* isolate_;
   21951   i::Semaphore sem_;
   21952   int warmup_;
   21953   bool should_continue_;
   21954 };
   21955 
   21956 
   21957 class RequestInterruptTestBaseWithSimpleInterrupt
   21958     : public RequestInterruptTestBase {
   21959  public:
   21960   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
   21961 
   21962   virtual void StartInterruptThread() {
   21963     i_thread.Start();
   21964   }
   21965 
   21966  private:
   21967   class InterruptThread : public i::Thread {
   21968    public:
   21969     explicit InterruptThread(RequestInterruptTestBase* test)
   21970         : Thread("RequestInterruptTest"), test_(test) {}
   21971 
   21972     virtual void Run() {
   21973       test_->sem_.Wait();
   21974       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
   21975     }
   21976 
   21977     static void OnInterrupt(v8::Isolate* isolate, void* data) {
   21978       reinterpret_cast<RequestInterruptTestBase*>(data)->
   21979           should_continue_ = false;
   21980     }
   21981 
   21982    private:
   21983      RequestInterruptTestBase* test_;
   21984   };
   21985 
   21986   InterruptThread i_thread;
   21987 };
   21988 
   21989 
   21990 class RequestInterruptTestWithFunctionCall
   21991     : public RequestInterruptTestBaseWithSimpleInterrupt {
   21992  public:
   21993   virtual void TestBody() {
   21994     Local<Function> func = Function::New(
   21995         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
   21996     env_->Global()->Set(v8_str("ShouldContinue"), func);
   21997 
   21998     CompileRun("while (ShouldContinue()) { }");
   21999   }
   22000 };
   22001 
   22002 
   22003 class RequestInterruptTestWithMethodCall
   22004     : public RequestInterruptTestBaseWithSimpleInterrupt {
   22005  public:
   22006   virtual void TestBody() {
   22007     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
   22008     v8::Local<v8::Template> proto = t->PrototypeTemplate();
   22009     proto->Set(v8_str("shouldContinue"), Function::New(
   22010         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
   22011     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
   22012 
   22013     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
   22014   }
   22015 };
   22016 
   22017 
   22018 class RequestInterruptTestWithAccessor
   22019     : public RequestInterruptTestBaseWithSimpleInterrupt {
   22020  public:
   22021   virtual void TestBody() {
   22022     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
   22023     v8::Local<v8::Template> proto = t->PrototypeTemplate();
   22024     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
   22025         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
   22026     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
   22027 
   22028     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
   22029   }
   22030 };
   22031 
   22032 
   22033 class RequestInterruptTestWithNativeAccessor
   22034     : public RequestInterruptTestBaseWithSimpleInterrupt {
   22035  public:
   22036   virtual void TestBody() {
   22037     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
   22038     t->InstanceTemplate()->SetNativeDataProperty(
   22039         v8_str("shouldContinue"),
   22040         &ShouldContinueNativeGetter,
   22041         NULL,
   22042         v8::External::New(isolate_, this));
   22043     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
   22044 
   22045     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
   22046   }
   22047 
   22048  private:
   22049   static void ShouldContinueNativeGetter(
   22050       Local<String> property,
   22051       const v8::PropertyCallbackInfo<v8::Value>& info) {
   22052     RequestInterruptTestBase* test =
   22053         reinterpret_cast<RequestInterruptTestBase*>(
   22054             info.Data().As<v8::External>()->Value());
   22055     info.GetReturnValue().Set(test->ShouldContinue());
   22056   }
   22057 };
   22058 
   22059 
   22060 class RequestInterruptTestWithMethodCallAndInterceptor
   22061     : public RequestInterruptTestBaseWithSimpleInterrupt {
   22062  public:
   22063   virtual void TestBody() {
   22064     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
   22065     v8::Local<v8::Template> proto = t->PrototypeTemplate();
   22066     proto->Set(v8_str("shouldContinue"), Function::New(
   22067         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
   22068     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
   22069     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
   22070 
   22071     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
   22072 
   22073     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
   22074   }
   22075 
   22076  private:
   22077   static void EmptyInterceptor(
   22078       Local<String> property,
   22079       const v8::PropertyCallbackInfo<v8::Value>& info) {
   22080   }
   22081 };
   22082 
   22083 
   22084 class RequestInterruptTestWithMathAbs
   22085     : public RequestInterruptTestBaseWithSimpleInterrupt {
   22086  public:
   22087   virtual void TestBody() {
   22088     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
   22089         isolate_,
   22090         WakeUpInterruptorCallback,
   22091         v8::External::New(isolate_, this)));
   22092 
   22093     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
   22094         isolate_,
   22095         ShouldContinueCallback,
   22096         v8::External::New(isolate_, this)));
   22097 
   22098     i::FLAG_allow_natives_syntax = true;
   22099     CompileRun("function loopish(o) {"
   22100                "  var pre = 10;"
   22101                "  while (o.abs(1) > 0) {"
   22102                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
   22103                "    if (pre > 0) {"
   22104                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
   22105                "    }"
   22106                "  }"
   22107                "}"
   22108                "var i = 50;"
   22109                "var obj = {abs: function () { return i-- }, x: null};"
   22110                "delete obj.x;"
   22111                "loopish(obj);"
   22112                "%OptimizeFunctionOnNextCall(loopish);"
   22113                "loopish(Math);");
   22114 
   22115     i::FLAG_allow_natives_syntax = false;
   22116   }
   22117 
   22118  private:
   22119   static void WakeUpInterruptorCallback(
   22120       const v8::FunctionCallbackInfo<Value>& info) {
   22121     if (!info[0]->BooleanValue()) return;
   22122 
   22123     RequestInterruptTestBase* test =
   22124         reinterpret_cast<RequestInterruptTestBase*>(
   22125             info.Data().As<v8::External>()->Value());
   22126     test->WakeUpInterruptor();
   22127   }
   22128 
   22129   static void ShouldContinueCallback(
   22130       const v8::FunctionCallbackInfo<Value>& info) {
   22131     RequestInterruptTestBase* test =
   22132         reinterpret_cast<RequestInterruptTestBase*>(
   22133             info.Data().As<v8::External>()->Value());
   22134     info.GetReturnValue().Set(test->should_continue());
   22135   }
   22136 };
   22137 
   22138 
   22139 TEST(RequestInterruptTestWithFunctionCall) {
   22140   RequestInterruptTestWithFunctionCall().RunTest();
   22141 }
   22142 
   22143 
   22144 TEST(RequestInterruptTestWithMethodCall) {
   22145   RequestInterruptTestWithMethodCall().RunTest();
   22146 }
   22147 
   22148 
   22149 TEST(RequestInterruptTestWithAccessor) {
   22150   RequestInterruptTestWithAccessor().RunTest();
   22151 }
   22152 
   22153 
   22154 TEST(RequestInterruptTestWithNativeAccessor) {
   22155   RequestInterruptTestWithNativeAccessor().RunTest();
   22156 }
   22157 
   22158 
   22159 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
   22160   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
   22161 }
   22162 
   22163 
   22164 TEST(RequestInterruptTestWithMathAbs) {
   22165   RequestInterruptTestWithMathAbs().RunTest();
   22166 }
   22167 
   22168 
   22169 class ClearInterruptFromAnotherThread
   22170     : public RequestInterruptTestBase {
   22171  public:
   22172   ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
   22173 
   22174   virtual void StartInterruptThread() {
   22175     i_thread.Start();
   22176   }
   22177 
   22178   virtual void TestBody() {
   22179     Local<Function> func = Function::New(
   22180         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
   22181     env_->Global()->Set(v8_str("ShouldContinue"), func);
   22182 
   22183     CompileRun("while (ShouldContinue()) { }");
   22184   }
   22185 
   22186  private:
   22187   class InterruptThread : public i::Thread {
   22188    public:
   22189     explicit InterruptThread(ClearInterruptFromAnotherThread* test)
   22190         : Thread("RequestInterruptTest"), test_(test) {}
   22191 
   22192     virtual void Run() {
   22193       test_->sem_.Wait();
   22194       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
   22195       test_->sem_.Wait();
   22196       test_->isolate_->ClearInterrupt();
   22197       test_->sem2_.Signal();
   22198     }
   22199 
   22200     static void OnInterrupt(v8::Isolate* isolate, void* data) {
   22201       ClearInterruptFromAnotherThread* test =
   22202           reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
   22203       test->sem_.Signal();
   22204       bool success = test->sem2_.WaitFor(i::TimeDelta::FromSeconds(2));
   22205       // Crash instead of timeout to make this failure more prominent.
   22206       CHECK(success);
   22207       test->should_continue_ = false;
   22208     }
   22209 
   22210    private:
   22211      ClearInterruptFromAnotherThread* test_;
   22212   };
   22213 
   22214   InterruptThread i_thread;
   22215   i::Semaphore sem2_;
   22216 };
   22217 
   22218 
   22219 TEST(ClearInterruptFromAnotherThread) {
   22220   ClearInterruptFromAnotherThread().RunTest();
   22221 }
   22222 
   22223 
   22224 static Local<Value> function_new_expected_env;
   22225 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
   22226   CHECK_EQ(function_new_expected_env, info.Data());
   22227   info.GetReturnValue().Set(17);
   22228 }
   22229 
   22230 
   22231 THREADED_TEST(FunctionNew) {
   22232   LocalContext env;
   22233   v8::Isolate* isolate = env->GetIsolate();
   22234   v8::HandleScope scope(isolate);
   22235   Local<Object> data = v8::Object::New(isolate);
   22236   function_new_expected_env = data;
   22237   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
   22238   env->Global()->Set(v8_str("func"), func);
   22239   Local<Value> result = CompileRun("func();");
   22240   CHECK_EQ(v8::Integer::New(isolate, 17), result);
   22241   // Verify function not cached
   22242   int serial_number =
   22243       i::Smi::cast(v8::Utils::OpenHandle(*func)
   22244           ->shared()->get_api_func_data()->serial_number())->value();
   22245   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
   22246   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
   22247   i::Handle<i::Object> elm =
   22248       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
   22249   CHECK(elm->IsUndefined());
   22250   // Verify that each Function::New creates a new function instance
   22251   Local<Object> data2 = v8::Object::New(isolate);
   22252   function_new_expected_env = data2;
   22253   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
   22254   CHECK(!func2->IsNull());
   22255   CHECK_NE(func, func2);
   22256   env->Global()->Set(v8_str("func2"), func2);
   22257   Local<Value> result2 = CompileRun("func2();");
   22258   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
   22259 }
   22260 
   22261 
   22262 TEST(EscapeableHandleScope) {
   22263   HandleScope outer_scope(CcTest::isolate());
   22264   LocalContext context;
   22265   const int runs = 10;
   22266   Local<String> values[runs];
   22267   for (int i = 0; i < runs; i++) {
   22268     v8::EscapableHandleScope inner_scope(CcTest::isolate());
   22269     Local<String> value;
   22270     if (i != 0) value = v8_str("escape value");
   22271     values[i] = inner_scope.Escape(value);
   22272   }
   22273   for (int i = 0; i < runs; i++) {
   22274     Local<String> expected;
   22275     if (i != 0) {
   22276       CHECK_EQ(v8_str("escape value"), values[i]);
   22277     } else {
   22278       CHECK(values[i].IsEmpty());
   22279     }
   22280   }
   22281 }
   22282 
   22283 
   22284 static void SetterWhichExpectsThisAndHolderToDiffer(
   22285     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
   22286   CHECK(info.Holder() != info.This());
   22287 }
   22288 
   22289 
   22290 TEST(Regress239669) {
   22291   LocalContext context;
   22292   v8::Isolate* isolate = context->GetIsolate();
   22293   v8::HandleScope scope(isolate);
   22294   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
   22295   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
   22296   context->Global()->Set(v8_str("P"), templ->NewInstance());
   22297   CompileRun(
   22298       "function C1() {"
   22299       "  this.x = 23;"
   22300       "};"
   22301       "C1.prototype = P;"
   22302       "for (var i = 0; i < 4; i++ ) {"
   22303       "  new C1();"
   22304       "}");
   22305 }
   22306 
   22307 
   22308 class ApiCallOptimizationChecker {
   22309  private:
   22310   static Local<Object> data;
   22311   static Local<Object> receiver;
   22312   static Local<Object> holder;
   22313   static Local<Object> callee;
   22314   static int count;
   22315 
   22316   static void OptimizationCallback(
   22317       const v8::FunctionCallbackInfo<v8::Value>& info) {
   22318     CHECK(callee == info.Callee());
   22319     CHECK(data == info.Data());
   22320     CHECK(receiver == info.This());
   22321     if (info.Length() == 1) {
   22322       CHECK_EQ(v8_num(1), info[0]);
   22323     }
   22324     CHECK(holder == info.Holder());
   22325     count++;
   22326     info.GetReturnValue().Set(v8_str("returned"));
   22327   }
   22328 
   22329  public:
   22330   enum SignatureType {
   22331     kNoSignature,
   22332     kSignatureOnReceiver,
   22333     kSignatureOnPrototype
   22334   };
   22335 
   22336   void RunAll() {
   22337     SignatureType signature_types[] =
   22338       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
   22339     for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
   22340       SignatureType signature_type = signature_types[i];
   22341       for (int j = 0; j < 2; j++) {
   22342         bool global = j == 0;
   22343         int key = signature_type +
   22344             ARRAY_SIZE(signature_types) * (global ? 1 : 0);
   22345         Run(signature_type, global, key);
   22346       }
   22347     }
   22348   }
   22349 
   22350   void Run(SignatureType signature_type, bool global, int key) {
   22351     v8::Isolate* isolate = CcTest::isolate();
   22352     v8::HandleScope scope(isolate);
   22353     // Build a template for signature checks.
   22354     Local<v8::ObjectTemplate> signature_template;
   22355     Local<v8::Signature> signature;
   22356     {
   22357       Local<v8::FunctionTemplate> parent_template =
   22358         FunctionTemplate::New(isolate);
   22359       parent_template->SetHiddenPrototype(true);
   22360       Local<v8::FunctionTemplate> function_template
   22361           = FunctionTemplate::New(isolate);
   22362       function_template->Inherit(parent_template);
   22363       switch (signature_type) {
   22364         case kNoSignature:
   22365           break;
   22366         case kSignatureOnReceiver:
   22367           signature = v8::Signature::New(isolate, function_template);
   22368           break;
   22369         case kSignatureOnPrototype:
   22370           signature = v8::Signature::New(isolate, parent_template);
   22371           break;
   22372       }
   22373       signature_template = function_template->InstanceTemplate();
   22374     }
   22375     // Global object must pass checks.
   22376     Local<v8::Context> context =
   22377         v8::Context::New(isolate, NULL, signature_template);
   22378     v8::Context::Scope context_scope(context);
   22379     // Install regular object that can pass signature checks.
   22380     Local<Object> function_receiver = signature_template->NewInstance();
   22381     context->Global()->Set(v8_str("function_receiver"), function_receiver);
   22382     // Get the holder objects.
   22383     Local<Object> inner_global =
   22384         Local<Object>::Cast(context->Global()->GetPrototype());
   22385     // Install functions on hidden prototype object if there is one.
   22386     data = Object::New(isolate);
   22387     Local<FunctionTemplate> function_template = FunctionTemplate::New(
   22388         isolate, OptimizationCallback, data, signature);
   22389     Local<Function> function = function_template->GetFunction();
   22390     Local<Object> global_holder = inner_global;
   22391     Local<Object> function_holder = function_receiver;
   22392     if (signature_type == kSignatureOnPrototype) {
   22393       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
   22394       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
   22395     }
   22396     global_holder->Set(v8_str("g_f"), function);
   22397     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
   22398     function_holder->Set(v8_str("f"), function);
   22399     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
   22400     // Initialize expected values.
   22401     callee = function;
   22402     count = 0;
   22403     if (global) {
   22404       receiver = context->Global();
   22405       holder = inner_global;
   22406     } else {
   22407       holder = function_receiver;
   22408       // If not using a signature, add something else to the prototype chain
   22409       // to test the case that holder != receiver
   22410       if (signature_type == kNoSignature) {
   22411         receiver = Local<Object>::Cast(CompileRun(
   22412             "var receiver_subclass = {};\n"
   22413             "receiver_subclass.__proto__ = function_receiver;\n"
   22414             "receiver_subclass"));
   22415       } else {
   22416         receiver = Local<Object>::Cast(CompileRun(
   22417           "var receiver_subclass = function_receiver;\n"
   22418           "receiver_subclass"));
   22419       }
   22420     }
   22421     // With no signature, the holder is not set.
   22422     if (signature_type == kNoSignature) holder = receiver;
   22423     // build wrap_function
   22424     i::ScopedVector<char> wrap_function(200);
   22425     if (global) {
   22426       i::SNPrintF(
   22427           wrap_function,
   22428           "function wrap_f_%d() { var f = g_f; return f(); }\n"
   22429           "function wrap_get_%d() { return this.g_acc; }\n"
   22430           "function wrap_set_%d() { return this.g_acc = 1; }\n",
   22431           key, key, key);
   22432     } else {
   22433       i::SNPrintF(
   22434           wrap_function,
   22435           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
   22436           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
   22437           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
   22438           key, key, key);
   22439     }
   22440     // build source string
   22441     i::ScopedVector<char> source(1000);
   22442     i::SNPrintF(
   22443         source,
   22444         "%s\n"  // wrap functions
   22445         "function wrap_f() { return wrap_f_%d(); }\n"
   22446         "function wrap_get() { return wrap_get_%d(); }\n"
   22447         "function wrap_set() { return wrap_set_%d(); }\n"
   22448         "check = function(returned) {\n"
   22449         "  if (returned !== 'returned') { throw returned; }\n"
   22450         "}\n"
   22451         "\n"
   22452         "check(wrap_f());\n"
   22453         "check(wrap_f());\n"
   22454         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
   22455         "check(wrap_f());\n"
   22456         "\n"
   22457         "check(wrap_get());\n"
   22458         "check(wrap_get());\n"
   22459         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
   22460         "check(wrap_get());\n"
   22461         "\n"
   22462         "check = function(returned) {\n"
   22463         "  if (returned !== 1) { throw returned; }\n"
   22464         "}\n"
   22465         "check(wrap_set());\n"
   22466         "check(wrap_set());\n"
   22467         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
   22468         "check(wrap_set());\n",
   22469         wrap_function.start(), key, key, key, key, key, key);
   22470     v8::TryCatch try_catch;
   22471     CompileRun(source.start());
   22472     ASSERT(!try_catch.HasCaught());
   22473     CHECK_EQ(9, count);
   22474   }
   22475 };
   22476 
   22477 
   22478 Local<Object> ApiCallOptimizationChecker::data;
   22479 Local<Object> ApiCallOptimizationChecker::receiver;
   22480 Local<Object> ApiCallOptimizationChecker::holder;
   22481 Local<Object> ApiCallOptimizationChecker::callee;
   22482 int ApiCallOptimizationChecker::count = 0;
   22483 
   22484 
   22485 TEST(TestFunctionCallOptimization) {
   22486   i::FLAG_allow_natives_syntax = true;
   22487   ApiCallOptimizationChecker checker;
   22488   checker.RunAll();
   22489 }
   22490 
   22491 
   22492 static const char* last_event_message;
   22493 static int last_event_status;
   22494 void StoringEventLoggerCallback(const char* message, int status) {
   22495     last_event_message = message;
   22496     last_event_status = status;
   22497 }
   22498 
   22499 
   22500 TEST(EventLogging) {
   22501   v8::Isolate* isolate = CcTest::isolate();
   22502   isolate->SetEventLogger(StoringEventLoggerCallback);
   22503   v8::internal::HistogramTimer histogramTimer(
   22504       "V8.Test", 0, 10000, 50,
   22505       reinterpret_cast<v8::internal::Isolate*>(isolate));
   22506   histogramTimer.Start();
   22507   CHECK_EQ("V8.Test", last_event_message);
   22508   CHECK_EQ(0, last_event_status);
   22509   histogramTimer.Stop();
   22510   CHECK_EQ("V8.Test", last_event_message);
   22511   CHECK_EQ(1, last_event_status);
   22512 }
   22513 
   22514 
   22515 TEST(Promises) {
   22516   LocalContext context;
   22517   v8::Isolate* isolate = context->GetIsolate();
   22518   v8::HandleScope scope(isolate);
   22519   Handle<Object> global = context->Global();
   22520 
   22521   // Creation.
   22522   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
   22523   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
   22524   Handle<v8::Promise> p = pr->GetPromise();
   22525   Handle<v8::Promise> r = rr->GetPromise();
   22526 
   22527   // IsPromise predicate.
   22528   CHECK(p->IsPromise());
   22529   CHECK(r->IsPromise());
   22530   Handle<Value> o = v8::Object::New(isolate);
   22531   CHECK(!o->IsPromise());
   22532 
   22533   // Resolution and rejection.
   22534   pr->Resolve(v8::Integer::New(isolate, 1));
   22535   CHECK(p->IsPromise());
   22536   rr->Reject(v8::Integer::New(isolate, 2));
   22537   CHECK(r->IsPromise());
   22538 
   22539   // Chaining non-pending promises.
   22540   CompileRun(
   22541       "var x1 = 0;\n"
   22542       "var x2 = 0;\n"
   22543       "function f1(x) { x1 = x; return x+1 };\n"
   22544       "function f2(x) { x2 = x; return x+1 };\n");
   22545   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
   22546   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
   22547 
   22548   p->Chain(f1);
   22549   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22550   isolate->RunMicrotasks();
   22551   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
   22552 
   22553   p->Catch(f2);
   22554   isolate->RunMicrotasks();
   22555   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22556 
   22557   r->Catch(f2);
   22558   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22559   isolate->RunMicrotasks();
   22560   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
   22561 
   22562   r->Chain(f1);
   22563   isolate->RunMicrotasks();
   22564   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
   22565 
   22566   // Chaining pending promises.
   22567   CompileRun("x1 = x2 = 0;");
   22568   pr = v8::Promise::Resolver::New(isolate);
   22569   rr = v8::Promise::Resolver::New(isolate);
   22570 
   22571   pr->GetPromise()->Chain(f1);
   22572   rr->GetPromise()->Catch(f2);
   22573   isolate->RunMicrotasks();
   22574   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22575   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22576 
   22577   pr->Resolve(v8::Integer::New(isolate, 1));
   22578   rr->Reject(v8::Integer::New(isolate, 2));
   22579   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22580   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22581 
   22582   isolate->RunMicrotasks();
   22583   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
   22584   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
   22585 
   22586   // Multi-chaining.
   22587   CompileRun("x1 = x2 = 0;");
   22588   pr = v8::Promise::Resolver::New(isolate);
   22589   pr->GetPromise()->Chain(f1)->Chain(f2);
   22590   pr->Resolve(v8::Integer::New(isolate, 3));
   22591   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22592   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22593   isolate->RunMicrotasks();
   22594   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
   22595   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
   22596 
   22597   CompileRun("x1 = x2 = 0;");
   22598   rr = v8::Promise::Resolver::New(isolate);
   22599   rr->GetPromise()->Catch(f1)->Chain(f2);
   22600   rr->Reject(v8::Integer::New(isolate, 3));
   22601   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22602   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22603   isolate->RunMicrotasks();
   22604   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
   22605   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
   22606 }
   22607 
   22608 
   22609 TEST(PromiseThen) {
   22610   LocalContext context;
   22611   v8::Isolate* isolate = context->GetIsolate();
   22612   v8::HandleScope scope(isolate);
   22613   Handle<Object> global = context->Global();
   22614 
   22615   // Creation.
   22616   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
   22617   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
   22618   Handle<v8::Promise> p = pr->GetPromise();
   22619   Handle<v8::Promise> q = qr->GetPromise();
   22620 
   22621   CHECK(p->IsPromise());
   22622   CHECK(q->IsPromise());
   22623 
   22624   pr->Resolve(v8::Integer::New(isolate, 1));
   22625   qr->Resolve(p);
   22626 
   22627   // Chaining non-pending promises.
   22628   CompileRun(
   22629       "var x1 = 0;\n"
   22630       "var x2 = 0;\n"
   22631       "function f1(x) { x1 = x; return x+1 };\n"
   22632       "function f2(x) { x2 = x; return x+1 };\n");
   22633   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
   22634   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
   22635 
   22636   // Chain
   22637   q->Chain(f1);
   22638   CHECK(global->Get(v8_str("x1"))->IsNumber());
   22639   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22640   isolate->RunMicrotasks();
   22641   CHECK(!global->Get(v8_str("x1"))->IsNumber());
   22642   CHECK_EQ(p, global->Get(v8_str("x1")));
   22643 
   22644   // Then
   22645   CompileRun("x1 = x2 = 0;");
   22646   q->Then(f1);
   22647   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22648   isolate->RunMicrotasks();
   22649   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
   22650 
   22651   // Then
   22652   CompileRun("x1 = x2 = 0;");
   22653   pr = v8::Promise::Resolver::New(isolate);
   22654   qr = v8::Promise::Resolver::New(isolate);
   22655 
   22656   qr->Resolve(pr);
   22657   qr->GetPromise()->Then(f1)->Then(f2);
   22658 
   22659   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22660   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22661   isolate->RunMicrotasks();
   22662   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22663   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22664 
   22665   pr->Resolve(v8::Integer::New(isolate, 3));
   22666 
   22667   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
   22668   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
   22669   isolate->RunMicrotasks();
   22670   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
   22671   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
   22672 }
   22673 
   22674 
   22675 TEST(DisallowJavascriptExecutionScope) {
   22676   LocalContext context;
   22677   v8::Isolate* isolate = context->GetIsolate();
   22678   v8::HandleScope scope(isolate);
   22679   v8::Isolate::DisallowJavascriptExecutionScope no_js(
   22680       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
   22681   CompileRun("2+2");
   22682 }
   22683 
   22684 
   22685 TEST(AllowJavascriptExecutionScope) {
   22686   LocalContext context;
   22687   v8::Isolate* isolate = context->GetIsolate();
   22688   v8::HandleScope scope(isolate);
   22689   v8::Isolate::DisallowJavascriptExecutionScope no_js(
   22690       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
   22691   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
   22692       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
   22693   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
   22694     CompileRun("1+1");
   22695   }
   22696 }
   22697 
   22698 
   22699 TEST(ThrowOnJavascriptExecution) {
   22700   LocalContext context;
   22701   v8::Isolate* isolate = context->GetIsolate();
   22702   v8::HandleScope scope(isolate);
   22703   v8::TryCatch try_catch;
   22704   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
   22705       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
   22706   CompileRun("1+1");
   22707   CHECK(try_catch.HasCaught());
   22708 }
   22709 
   22710 
   22711 TEST(Regress354123) {
   22712   LocalContext current;
   22713   v8::Isolate* isolate = current->GetIsolate();
   22714   v8::HandleScope scope(isolate);
   22715 
   22716   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
   22717   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
   22718   current->Global()->Set(v8_str("friend"), templ->NewInstance());
   22719 
   22720   // Test access using __proto__ from the prototype chain.
   22721   named_access_count = 0;
   22722   CompileRun("friend.__proto__ = {};");
   22723   CHECK_EQ(2, named_access_count);
   22724   CompileRun("friend.__proto__;");
   22725   CHECK_EQ(4, named_access_count);
   22726 
   22727   // Test access using __proto__ as a hijacked function (A).
   22728   named_access_count = 0;
   22729   CompileRun("var p = Object.prototype;"
   22730              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
   22731              "f.call(friend, {});");
   22732   CHECK_EQ(1, named_access_count);
   22733   CompileRun("var p = Object.prototype;"
   22734              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
   22735              "f.call(friend);");
   22736   CHECK_EQ(2, named_access_count);
   22737 
   22738   // Test access using __proto__ as a hijacked function (B).
   22739   named_access_count = 0;
   22740   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
   22741              "f.call(friend, {});");
   22742   CHECK_EQ(1, named_access_count);
   22743   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
   22744              "f.call(friend);");
   22745   CHECK_EQ(2, named_access_count);
   22746 
   22747   // Test access using Object.setPrototypeOf reflective method.
   22748   named_access_count = 0;
   22749   CompileRun("Object.setPrototypeOf(friend, {});");
   22750   CHECK_EQ(1, named_access_count);
   22751   CompileRun("Object.getPrototypeOf(friend);");
   22752   CHECK_EQ(2, named_access_count);
   22753 }
   22754 
   22755 
   22756 TEST(CaptureStackTraceForStackOverflow) {
   22757   v8::internal::FLAG_stack_size = 150;
   22758   LocalContext current;
   22759   v8::Isolate* isolate = current->GetIsolate();
   22760   v8::HandleScope scope(isolate);
   22761   V8::SetCaptureStackTraceForUncaughtExceptions(
   22762       true, 10, v8::StackTrace::kDetailed);
   22763   v8::TryCatch try_catch;
   22764   CompileRun("(function f(x) { f(x+1); })(0)");
   22765   CHECK(try_catch.HasCaught());
   22766 }
   22767 
   22768 
   22769 TEST(ScriptNameAndLineNumber) {
   22770   LocalContext env;
   22771   v8::Isolate* isolate = env->GetIsolate();
   22772   v8::HandleScope scope(isolate);
   22773   const char* url = "http://www.foo.com/foo.js";
   22774   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
   22775   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
   22776   Local<Script> script = v8::ScriptCompiler::Compile(
   22777       isolate, &script_source);
   22778   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
   22779   CHECK(!script_name.IsEmpty());
   22780   CHECK(script_name->IsString());
   22781   String::Utf8Value utf8_name(script_name);
   22782   CHECK_EQ(url, *utf8_name);
   22783   int line_number = script->GetUnboundScript()->GetLineNumber(0);
   22784   CHECK_EQ(13, line_number);
   22785 }
   22786 
   22787 
   22788 Local<v8::Context> call_eval_context;
   22789 Local<v8::Function> call_eval_bound_function;
   22790 static void CallEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
   22791   v8::Context::Scope scope(call_eval_context);
   22792   args.GetReturnValue().Set(
   22793       call_eval_bound_function->Call(call_eval_context->Global(), 0, NULL));
   22794 }
   22795 
   22796 
   22797 TEST(CrossActivationEval) {
   22798   LocalContext env;
   22799   v8::Isolate* isolate = env->GetIsolate();
   22800   v8::HandleScope scope(isolate);
   22801   {
   22802     call_eval_context = v8::Context::New(isolate);
   22803     v8::Context::Scope scope(call_eval_context);
   22804     call_eval_bound_function =
   22805         Local<Function>::Cast(CompileRun("eval.bind(this, '1')"));
   22806   }
   22807   env->Global()->Set(v8_str("CallEval"),
   22808       v8::FunctionTemplate::New(isolate, CallEval)->GetFunction());
   22809   Local<Value> result = CompileRun("CallEval();");
   22810   CHECK_EQ(result, v8::Integer::New(isolate, 1));
   22811 }
   22812