v8: Upgrade 3.26.33 with 14 patches
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-api.cc
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 "v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "api.h"
40 #include "arguments.h"
41 #include "cctest.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
45 #include "isolate.h"
46 #include "objects.h"
47 #include "parser.h"
48 #include "platform.h"
49 #include "snapshot.h"
50 #include "unicode-inl.h"
51 #include "utils.h"
52 #include "vm-state.h"
53 #include "../include/v8-util.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 void ExpectString(const char* code, const char* expected) {
103   Local<Value> result = CompileRun(code);
104   CHECK(result->IsString());
105   String::Utf8Value utf8(result);
106   CHECK_EQ(expected, *utf8);
107 }
108
109
110 static void ExpectInt32(const char* code, int expected) {
111   Local<Value> result = CompileRun(code);
112   CHECK(result->IsInt32());
113   CHECK_EQ(expected, result->Int32Value());
114 }
115
116
117 static void ExpectBoolean(const char* code, bool expected) {
118   Local<Value> result = CompileRun(code);
119   CHECK(result->IsBoolean());
120   CHECK_EQ(expected, result->BooleanValue());
121 }
122
123
124 static void ExpectTrue(const char* code) {
125   ExpectBoolean(code, true);
126 }
127
128
129 static void ExpectFalse(const char* code) {
130   ExpectBoolean(code, false);
131 }
132
133
134 static void ExpectObject(const char* code, Local<Value> expected) {
135   Local<Value> result = CompileRun(code);
136   CHECK(result->Equals(expected));
137 }
138
139
140 static void ExpectUndefined(const char* code) {
141   Local<Value> result = CompileRun(code);
142   CHECK(result->IsUndefined());
143 }
144
145
146 static int signature_callback_count;
147 static Local<Value> signature_expected_receiver;
148 static void IncrementingSignatureCallback(
149     const v8::FunctionCallbackInfo<v8::Value>& args) {
150   ApiTestFuzzer::Fuzz();
151   signature_callback_count++;
152   CHECK_EQ(signature_expected_receiver, args.Holder());
153   CHECK_EQ(signature_expected_receiver, args.This());
154   v8::Handle<v8::Array> result =
155       v8::Array::New(args.GetIsolate(), args.Length());
156   for (int i = 0; i < args.Length(); i++)
157     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
158   args.GetReturnValue().Set(result);
159 }
160
161
162 static void SignatureCallback(
163     const v8::FunctionCallbackInfo<v8::Value>& args) {
164   ApiTestFuzzer::Fuzz();
165   v8::Handle<v8::Array> result =
166       v8::Array::New(args.GetIsolate(), args.Length());
167   for (int i = 0; i < args.Length(); i++) {
168     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
169   }
170   args.GetReturnValue().Set(result);
171 }
172
173
174 // Tests that call v8::V8::Dispose() cannot be threaded.
175 TEST(InitializeAndDisposeOnce) {
176   CHECK(v8::V8::Initialize());
177   CHECK(v8::V8::Dispose());
178 }
179
180
181 // Tests that call v8::V8::Dispose() cannot be threaded.
182 TEST(InitializeAndDisposeMultiple) {
183   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
184   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
185   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
186   // TODO(mstarzinger): This should fail gracefully instead of asserting.
187   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
188   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
189 }
190
191
192 THREADED_TEST(Handles) {
193   v8::HandleScope scope(CcTest::isolate());
194   Local<Context> local_env;
195   {
196     LocalContext env;
197     local_env = env.local();
198   }
199
200   // Local context should still be live.
201   CHECK(!local_env.IsEmpty());
202   local_env->Enter();
203
204   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
205   CHECK(!undef.IsEmpty());
206   CHECK(undef->IsUndefined());
207
208   const char* source = "1 + 2 + 3";
209   Local<Script> script = v8_compile(source);
210   CHECK_EQ(6, script->Run()->Int32Value());
211
212   local_env->Exit();
213 }
214
215
216 THREADED_TEST(IsolateOfContext) {
217   v8::HandleScope scope(CcTest::isolate());
218   v8::Handle<Context> env = Context::New(CcTest::isolate());
219
220   CHECK(!env->GetIsolate()->InContext());
221   CHECK(env->GetIsolate() == CcTest::isolate());
222   env->Enter();
223   CHECK(env->GetIsolate()->InContext());
224   CHECK(env->GetIsolate() == CcTest::isolate());
225   env->Exit();
226   CHECK(!env->GetIsolate()->InContext());
227   CHECK(env->GetIsolate() == CcTest::isolate());
228 }
229
230
231 static void TestSignature(const char* loop_js, Local<Value> receiver) {
232   i::ScopedVector<char> source(200);
233   i::OS::SNPrintF(source,
234                   "for (var i = 0; i < 10; i++) {"
235                   "  %s"
236                   "}",
237                   loop_js);
238   signature_callback_count = 0;
239   signature_expected_receiver = receiver;
240   bool expected_to_throw = receiver.IsEmpty();
241   v8::TryCatch try_catch;
242   CompileRun(source.start());
243   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
244   if (!expected_to_throw) {
245     CHECK_EQ(10, signature_callback_count);
246   } else {
247     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
248              try_catch.Exception()->ToString());
249   }
250 }
251
252
253 THREADED_TEST(ReceiverSignature) {
254   LocalContext env;
255   v8::Isolate* isolate = env->GetIsolate();
256   v8::HandleScope scope(isolate);
257   // Setup templates.
258   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
259   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
260   v8::Handle<v8::FunctionTemplate> callback_sig =
261       v8::FunctionTemplate::New(
262           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
263   v8::Handle<v8::FunctionTemplate> callback =
264       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
265   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
266   sub_fun->Inherit(fun);
267   v8::Handle<v8::FunctionTemplate> unrel_fun =
268       v8::FunctionTemplate::New(isolate);
269   // Install properties.
270   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
271   fun_proto->Set(v8_str("prop_sig"), callback_sig);
272   fun_proto->Set(v8_str("prop"), callback);
273   fun_proto->SetAccessorProperty(
274       v8_str("accessor_sig"), callback_sig, callback_sig);
275   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
276   // Instantiate templates.
277   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
278   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
279   // Setup global variables.
280   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
281   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
282   env->Global()->Set(v8_str("fun_instance"), fun_instance);
283   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
284   CompileRun(
285       "var accessor_sig_key = 'accessor_sig';"
286       "var accessor_key = 'accessor';"
287       "var prop_sig_key = 'prop_sig';"
288       "var prop_key = 'prop';"
289       ""
290       "function copy_props(obj) {"
291       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
292       "  var source = Fun.prototype;"
293       "  for (var i in keys) {"
294       "    var key = keys[i];"
295       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
296       "    Object.defineProperty(obj, key, desc);"
297       "  }"
298       "}"
299       ""
300       "var obj = {};"
301       "copy_props(obj);"
302       "var unrel = new UnrelFun();"
303       "copy_props(unrel);");
304   // Test with and without ICs
305   const char* test_objects[] = {
306       "fun_instance", "sub_fun_instance", "obj", "unrel" };
307   unsigned bad_signature_start_offset = 2;
308   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
309     i::ScopedVector<char> source(200);
310     i::OS::SNPrintF(
311         source, "var test_object = %s; test_object", test_objects[i]);
312     Local<Value> test_object = CompileRun(source.start());
313     TestSignature("test_object.prop();", test_object);
314     TestSignature("test_object.accessor;", test_object);
315     TestSignature("test_object[accessor_key];", test_object);
316     TestSignature("test_object.accessor = 1;", test_object);
317     TestSignature("test_object[accessor_key] = 1;", test_object);
318     if (i >= bad_signature_start_offset) test_object = Local<Value>();
319     TestSignature("test_object.prop_sig();", test_object);
320     TestSignature("test_object.accessor_sig;", test_object);
321     TestSignature("test_object[accessor_sig_key];", test_object);
322     TestSignature("test_object.accessor_sig = 1;", test_object);
323     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
324   }
325 }
326
327
328 THREADED_TEST(ArgumentSignature) {
329   LocalContext env;
330   v8::Isolate* isolate = env->GetIsolate();
331   v8::HandleScope scope(isolate);
332   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
333   cons->SetClassName(v8_str("Cons"));
334   v8::Handle<v8::Signature> sig = v8::Signature::New(
335       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
336   v8::Handle<v8::FunctionTemplate> fun =
337       v8::FunctionTemplate::New(isolate,
338                                 SignatureCallback,
339                                 v8::Handle<Value>(),
340                                 sig);
341   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
342   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
343
344   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
345   CHECK(value1->IsTrue());
346
347   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
348   CHECK(value2->IsTrue());
349
350   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
351   CHECK(value3->IsTrue());
352
353   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
354   cons1->SetClassName(v8_str("Cons1"));
355   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
356   cons2->SetClassName(v8_str("Cons2"));
357   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
358   cons3->SetClassName(v8_str("Cons3"));
359
360   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
361   v8::Handle<v8::Signature> wsig = v8::Signature::New(
362       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
363   v8::Handle<v8::FunctionTemplate> fun2 =
364       v8::FunctionTemplate::New(isolate,
365                                 SignatureCallback,
366                                 v8::Handle<Value>(),
367                                 wsig);
368
369   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
370   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
371   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
372   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
373   v8::Handle<Value> value4 = CompileRun(
374       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
375       "'[object Cons1],[object Cons2],[object Cons3]'");
376   CHECK(value4->IsTrue());
377
378   v8::Handle<Value> value5 = CompileRun(
379       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
380   CHECK(value5->IsTrue());
381
382   v8::Handle<Value> value6 = CompileRun(
383       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
384   CHECK(value6->IsTrue());
385
386   v8::Handle<Value> value7 = CompileRun(
387       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
388       "'[object Cons1],[object Cons2],[object Cons3],d';");
389   CHECK(value7->IsTrue());
390
391   v8::Handle<Value> value8 = CompileRun(
392       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
393   CHECK(value8->IsTrue());
394 }
395
396
397 THREADED_TEST(HulIgennem) {
398   LocalContext env;
399   v8::Isolate* isolate = env->GetIsolate();
400   v8::HandleScope scope(isolate);
401   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
402   Local<String> undef_str = undef->ToString();
403   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
404   undef_str->WriteUtf8(value);
405   CHECK_EQ(0, strcmp(value, "undefined"));
406   i::DeleteArray(value);
407 }
408
409
410 THREADED_TEST(Access) {
411   LocalContext env;
412   v8::Isolate* isolate = env->GetIsolate();
413   v8::HandleScope scope(isolate);
414   Local<v8::Object> obj = v8::Object::New(isolate);
415   Local<Value> foo_before = obj->Get(v8_str("foo"));
416   CHECK(foo_before->IsUndefined());
417   Local<String> bar_str = v8_str("bar");
418   obj->Set(v8_str("foo"), bar_str);
419   Local<Value> foo_after = obj->Get(v8_str("foo"));
420   CHECK(!foo_after->IsUndefined());
421   CHECK(foo_after->IsString());
422   CHECK_EQ(bar_str, foo_after);
423 }
424
425
426 THREADED_TEST(AccessElement) {
427   LocalContext env;
428   v8::HandleScope scope(env->GetIsolate());
429   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
430   Local<Value> before = obj->Get(1);
431   CHECK(before->IsUndefined());
432   Local<String> bar_str = v8_str("bar");
433   obj->Set(1, bar_str);
434   Local<Value> after = obj->Get(1);
435   CHECK(!after->IsUndefined());
436   CHECK(after->IsString());
437   CHECK_EQ(bar_str, after);
438
439   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
440   CHECK_EQ(v8_str("a"), value->Get(0));
441   CHECK_EQ(v8_str("b"), value->Get(1));
442 }
443
444
445 THREADED_TEST(Script) {
446   LocalContext env;
447   v8::HandleScope scope(env->GetIsolate());
448   const char* source = "1 + 2 + 3";
449   Local<Script> script = v8_compile(source);
450   CHECK_EQ(6, script->Run()->Int32Value());
451 }
452
453
454 static uint16_t* AsciiToTwoByteString(const char* source) {
455   int array_length = i::StrLength(source) + 1;
456   uint16_t* converted = i::NewArray<uint16_t>(array_length);
457   for (int i = 0; i < array_length; i++) converted[i] = source[i];
458   return converted;
459 }
460
461
462 class TestResource: public String::ExternalStringResource {
463  public:
464   TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
465       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
466     while (data[length_]) ++length_;
467   }
468
469   ~TestResource() {
470     if (owning_data_) i::DeleteArray(data_);
471     if (counter_ != NULL) ++*counter_;
472   }
473
474   const uint16_t* data() const {
475     return data_;
476   }
477
478   size_t length() const {
479     return length_;
480   }
481
482  private:
483   uint16_t* data_;
484   size_t length_;
485   int* counter_;
486   bool owning_data_;
487 };
488
489
490 class TestAsciiResource: public String::ExternalAsciiStringResource {
491  public:
492   TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
493       : orig_data_(data),
494         data_(data + offset),
495         length_(strlen(data) - offset),
496         counter_(counter) { }
497
498   ~TestAsciiResource() {
499     i::DeleteArray(orig_data_);
500     if (counter_ != NULL) ++*counter_;
501   }
502
503   const char* data() const {
504     return data_;
505   }
506
507   size_t length() const {
508     return length_;
509   }
510
511  private:
512   const char* orig_data_;
513   const char* data_;
514   size_t length_;
515   int* counter_;
516 };
517
518
519 THREADED_TEST(ScriptUsingStringResource) {
520   int dispose_count = 0;
521   const char* c_source = "1 + 2 * 3";
522   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
523   {
524     LocalContext env;
525     v8::HandleScope scope(env->GetIsolate());
526     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
527     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
528     Local<Script> script = v8_compile(source);
529     Local<Value> value = script->Run();
530     CHECK(value->IsNumber());
531     CHECK_EQ(7, value->Int32Value());
532     CHECK(source->IsExternal());
533     CHECK_EQ(resource,
534              static_cast<TestResource*>(source->GetExternalStringResource()));
535     String::Encoding encoding = String::UNKNOWN_ENCODING;
536     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
537              source->GetExternalStringResourceBase(&encoding));
538     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
539     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
540     CHECK_EQ(0, dispose_count);
541   }
542   CcTest::i_isolate()->compilation_cache()->Clear();
543   CcTest::heap()->CollectAllAvailableGarbage();
544   CHECK_EQ(1, dispose_count);
545 }
546
547
548 THREADED_TEST(ScriptUsingAsciiStringResource) {
549   int dispose_count = 0;
550   const char* c_source = "1 + 2 * 3";
551   {
552     LocalContext env;
553     v8::HandleScope scope(env->GetIsolate());
554     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
555                                                         &dispose_count);
556     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
557     CHECK(source->IsExternalAscii());
558     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
559              source->GetExternalAsciiStringResource());
560     String::Encoding encoding = String::UNKNOWN_ENCODING;
561     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
562              source->GetExternalStringResourceBase(&encoding));
563     CHECK_EQ(String::ASCII_ENCODING, encoding);
564     Local<Script> script = v8_compile(source);
565     Local<Value> value = script->Run();
566     CHECK(value->IsNumber());
567     CHECK_EQ(7, value->Int32Value());
568     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
569     CHECK_EQ(0, dispose_count);
570   }
571   CcTest::i_isolate()->compilation_cache()->Clear();
572   CcTest::heap()->CollectAllAvailableGarbage();
573   CHECK_EQ(1, dispose_count);
574 }
575
576
577 THREADED_TEST(ScriptMakingExternalString) {
578   int dispose_count = 0;
579   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
580   {
581     LocalContext env;
582     v8::HandleScope scope(env->GetIsolate());
583     Local<String> source =
584         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
585     // Trigger GCs so that the newly allocated string moves to old gen.
586     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
587     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
588     CHECK_EQ(source->IsExternal(), false);
589     CHECK_EQ(source->IsExternalAscii(), false);
590     String::Encoding encoding = String::UNKNOWN_ENCODING;
591     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
592     CHECK_EQ(String::ASCII_ENCODING, encoding);
593     bool success = source->MakeExternal(new TestResource(two_byte_source,
594                                                          &dispose_count));
595     CHECK(success);
596     Local<Script> script = v8_compile(source);
597     Local<Value> value = script->Run();
598     CHECK(value->IsNumber());
599     CHECK_EQ(7, value->Int32Value());
600     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
601     CHECK_EQ(0, dispose_count);
602   }
603   CcTest::i_isolate()->compilation_cache()->Clear();
604   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
605   CHECK_EQ(1, dispose_count);
606 }
607
608
609 THREADED_TEST(ScriptMakingExternalAsciiString) {
610   int dispose_count = 0;
611   const char* c_source = "1 + 2 * 3";
612   {
613     LocalContext env;
614     v8::HandleScope scope(env->GetIsolate());
615     Local<String> source = v8_str(c_source);
616     // Trigger GCs so that the newly allocated string moves to old gen.
617     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
618     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
619     bool success = source->MakeExternal(
620         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
621     CHECK(success);
622     Local<Script> script = v8_compile(source);
623     Local<Value> value = script->Run();
624     CHECK(value->IsNumber());
625     CHECK_EQ(7, value->Int32Value());
626     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
627     CHECK_EQ(0, dispose_count);
628   }
629   CcTest::i_isolate()->compilation_cache()->Clear();
630   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
631   CHECK_EQ(1, dispose_count);
632 }
633
634
635 TEST(MakingExternalStringConditions) {
636   LocalContext env;
637   v8::HandleScope scope(env->GetIsolate());
638
639   // Free some space in the new space so that we can check freshness.
640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642
643   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
644   Local<String> small_string =
645       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
646   i::DeleteArray(two_byte_string);
647
648   // We should refuse to externalize newly created small string.
649   CHECK(!small_string->CanMakeExternal());
650   // Trigger GCs so that the newly allocated string moves to old gen.
651   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
652   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
653   // Old space strings should be accepted.
654   CHECK(small_string->CanMakeExternal());
655
656   two_byte_string = AsciiToTwoByteString("small string 2");
657   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
658   i::DeleteArray(two_byte_string);
659
660   // We should refuse externalizing newly created small string.
661   CHECK(!small_string->CanMakeExternal());
662   for (int i = 0; i < 100; i++) {
663     String::Value value(small_string);
664   }
665   // Frequently used strings should be accepted.
666   CHECK(small_string->CanMakeExternal());
667
668   const int buf_size = 10 * 1024;
669   char* buf = i::NewArray<char>(buf_size);
670   memset(buf, 'a', buf_size);
671   buf[buf_size - 1] = '\0';
672
673   two_byte_string = AsciiToTwoByteString(buf);
674   Local<String> large_string =
675       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
676   i::DeleteArray(buf);
677   i::DeleteArray(two_byte_string);
678   // Large strings should be immediately accepted.
679   CHECK(large_string->CanMakeExternal());
680 }
681
682
683 TEST(MakingExternalAsciiStringConditions) {
684   LocalContext env;
685   v8::HandleScope scope(env->GetIsolate());
686
687   // Free some space in the new space so that we can check freshness.
688   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
689   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
690
691   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
692   // We should refuse to externalize newly created small string.
693   CHECK(!small_string->CanMakeExternal());
694   // Trigger GCs so that the newly allocated string moves to old gen.
695   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
696   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
697   // Old space strings should be accepted.
698   CHECK(small_string->CanMakeExternal());
699
700   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
701   // We should refuse externalizing newly created small string.
702   CHECK(!small_string->CanMakeExternal());
703   for (int i = 0; i < 100; i++) {
704     String::Value value(small_string);
705   }
706   // Frequently used strings should be accepted.
707   CHECK(small_string->CanMakeExternal());
708
709   const int buf_size = 10 * 1024;
710   char* buf = i::NewArray<char>(buf_size);
711   memset(buf, 'a', buf_size);
712   buf[buf_size - 1] = '\0';
713   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
714   i::DeleteArray(buf);
715   // Large strings should be immediately accepted.
716   CHECK(large_string->CanMakeExternal());
717 }
718
719
720 TEST(MakingExternalUnalignedAsciiString) {
721   LocalContext env;
722   v8::HandleScope scope(env->GetIsolate());
723
724   CompileRun("function cons(a, b) { return a + b; }"
725              "function slice(a) { return a.substring(1); }");
726   // Create a cons string that will land in old pointer space.
727   Local<String> cons = Local<String>::Cast(CompileRun(
728       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
729   // Create a sliced string that will land in old pointer space.
730   Local<String> slice = Local<String>::Cast(CompileRun(
731       "slice('abcdefghijklmnopqrstuvwxyz');"));
732
733   // Trigger GCs so that the newly allocated string moves to old gen.
734   SimulateFullSpace(CcTest::heap()->old_pointer_space());
735   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
736   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
737
738   // Turn into external string with unaligned resource data.
739   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
740   bool success = cons->MakeExternal(
741       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
742   CHECK(success);
743   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
744   success = slice->MakeExternal(
745       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
746   CHECK(success);
747
748   // Trigger GCs and force evacuation.
749   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
750   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
751 }
752
753
754 THREADED_TEST(UsingExternalString) {
755   i::Factory* factory = CcTest::i_isolate()->factory();
756   {
757     v8::HandleScope scope(CcTest::isolate());
758     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
759     Local<String> string = String::NewExternal(
760         CcTest::isolate(), new TestResource(two_byte_string));
761     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
762     // Trigger GCs so that the newly allocated string moves to old gen.
763     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
764     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
765     i::Handle<i::String> isymbol =
766         factory->InternalizeString(istring);
767     CHECK(isymbol->IsInternalizedString());
768   }
769   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
770   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
771 }
772
773
774 THREADED_TEST(UsingExternalAsciiString) {
775   i::Factory* factory = CcTest::i_isolate()->factory();
776   {
777     v8::HandleScope scope(CcTest::isolate());
778     const char* one_byte_string = "test string";
779     Local<String> string = String::NewExternal(
780         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
781     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
782     // Trigger GCs so that the newly allocated string moves to old gen.
783     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
784     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
785     i::Handle<i::String> isymbol =
786         factory->InternalizeString(istring);
787     CHECK(isymbol->IsInternalizedString());
788   }
789   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
790   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
791 }
792
793
794 THREADED_TEST(ScavengeExternalString) {
795   i::FLAG_stress_compaction = false;
796   i::FLAG_gc_global = false;
797   int dispose_count = 0;
798   bool in_new_space = false;
799   {
800     v8::HandleScope scope(CcTest::isolate());
801     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
802     Local<String> string = String::NewExternal(
803         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
804     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
805     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
806     in_new_space = CcTest::heap()->InNewSpace(*istring);
807     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
808     CHECK_EQ(0, dispose_count);
809   }
810   CcTest::heap()->CollectGarbage(
811       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
812   CHECK_EQ(1, dispose_count);
813 }
814
815
816 THREADED_TEST(ScavengeExternalAsciiString) {
817   i::FLAG_stress_compaction = false;
818   i::FLAG_gc_global = false;
819   int dispose_count = 0;
820   bool in_new_space = false;
821   {
822     v8::HandleScope scope(CcTest::isolate());
823     const char* one_byte_string = "test string";
824     Local<String> string = String::NewExternal(
825         CcTest::isolate(),
826         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
827     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
828     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
829     in_new_space = CcTest::heap()->InNewSpace(*istring);
830     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
831     CHECK_EQ(0, dispose_count);
832   }
833   CcTest::heap()->CollectGarbage(
834       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
835   CHECK_EQ(1, dispose_count);
836 }
837
838
839 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
840  public:
841   // Only used by non-threaded tests, so it can use static fields.
842   static int dispose_calls;
843   static int dispose_count;
844
845   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
846       : TestAsciiResource(data, &dispose_count),
847         dispose_(dispose) { }
848
849   void Dispose() {
850     ++dispose_calls;
851     if (dispose_) delete this;
852   }
853  private:
854   bool dispose_;
855 };
856
857
858 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
859 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
860
861
862 TEST(ExternalStringWithDisposeHandling) {
863   const char* c_source = "1 + 2 * 3";
864
865   // Use a stack allocated external string resource allocated object.
866   TestAsciiResourceWithDisposeControl::dispose_count = 0;
867   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
868   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
869   {
870     LocalContext env;
871     v8::HandleScope scope(env->GetIsolate());
872     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
873     Local<Script> script = v8_compile(source);
874     Local<Value> value = script->Run();
875     CHECK(value->IsNumber());
876     CHECK_EQ(7, value->Int32Value());
877     CcTest::heap()->CollectAllAvailableGarbage();
878     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
879   }
880   CcTest::i_isolate()->compilation_cache()->Clear();
881   CcTest::heap()->CollectAllAvailableGarbage();
882   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
883   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
884
885   // Use a heap allocated external string resource allocated object.
886   TestAsciiResourceWithDisposeControl::dispose_count = 0;
887   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
888   TestAsciiResource* res_heap =
889       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
890   {
891     LocalContext env;
892     v8::HandleScope scope(env->GetIsolate());
893     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
894     Local<Script> script = v8_compile(source);
895     Local<Value> value = script->Run();
896     CHECK(value->IsNumber());
897     CHECK_EQ(7, value->Int32Value());
898     CcTest::heap()->CollectAllAvailableGarbage();
899     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
900   }
901   CcTest::i_isolate()->compilation_cache()->Clear();
902   CcTest::heap()->CollectAllAvailableGarbage();
903   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
904   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
905 }
906
907
908 THREADED_TEST(StringConcat) {
909   {
910     LocalContext env;
911     v8::HandleScope scope(env->GetIsolate());
912     const char* one_byte_string_1 = "function a_times_t";
913     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
914     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
915     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
916     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
917     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
919     Local<String> left = v8_str(one_byte_string_1);
920
921     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
922     Local<String> right =
923         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
924     i::DeleteArray(two_byte_source);
925
926     Local<String> source = String::Concat(left, right);
927     right = String::NewExternal(
928         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
929     source = String::Concat(source, right);
930     right = String::NewExternal(
931         env->GetIsolate(),
932         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
933     source = String::Concat(source, right);
934     right = v8_str(one_byte_string_2);
935     source = String::Concat(source, right);
936
937     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
938     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
939     i::DeleteArray(two_byte_source);
940
941     source = String::Concat(source, right);
942     right = String::NewExternal(
943         env->GetIsolate(),
944         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
945     source = String::Concat(source, right);
946     Local<Script> script = v8_compile(source);
947     Local<Value> value = script->Run();
948     CHECK(value->IsNumber());
949     CHECK_EQ(68, value->Int32Value());
950   }
951   CcTest::i_isolate()->compilation_cache()->Clear();
952   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
953   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
954 }
955
956
957 THREADED_TEST(GlobalProperties) {
958   LocalContext env;
959   v8::HandleScope scope(env->GetIsolate());
960   v8::Handle<v8::Object> global = env->Global();
961   global->Set(v8_str("pi"), v8_num(3.1415926));
962   Local<Value> pi = global->Get(v8_str("pi"));
963   CHECK_EQ(3.1415926, pi->NumberValue());
964 }
965
966
967 template<typename T>
968 static void CheckReturnValue(const T& t, i::Address callback) {
969   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
970   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
971   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
972   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
973   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
974   // Verify reset
975   bool is_runtime = (*o)->IsTheHole();
976   rv.Set(true);
977   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
978   rv.Set(v8::Handle<v8::Object>());
979   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
980   CHECK_EQ(is_runtime, (*o)->IsTheHole());
981
982   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
983   // If CPU profiler is active check that when API callback is invoked
984   // VMState is set to EXTERNAL.
985   if (isolate->cpu_profiler()->is_profiling()) {
986     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
987     CHECK(isolate->external_callback_scope());
988     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
989   }
990 }
991
992
993 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
994                                  i::Address callback) {
995   ApiTestFuzzer::Fuzz();
996   CheckReturnValue(info, callback);
997   info.GetReturnValue().Set(v8_str("bad value"));
998   info.GetReturnValue().Set(v8_num(102));
999 }
1000
1001
1002 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1003   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1004 }
1005
1006
1007 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1008   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1009 }
1010
1011 static void construct_callback(
1012     const v8::FunctionCallbackInfo<Value>& info) {
1013   ApiTestFuzzer::Fuzz();
1014   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1015   info.This()->Set(v8_str("x"), v8_num(1));
1016   info.This()->Set(v8_str("y"), v8_num(2));
1017   info.GetReturnValue().Set(v8_str("bad value"));
1018   info.GetReturnValue().Set(info.This());
1019 }
1020
1021
1022 static void Return239Callback(
1023     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1024   ApiTestFuzzer::Fuzz();
1025   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1026   info.GetReturnValue().Set(v8_str("bad value"));
1027   info.GetReturnValue().Set(v8_num(239));
1028 }
1029
1030
1031 template<typename Handler>
1032 static void TestFunctionTemplateInitializer(Handler handler,
1033                                             Handler handler_2) {
1034   // Test constructor calls.
1035   {
1036     LocalContext env;
1037     v8::Isolate* isolate = env->GetIsolate();
1038     v8::HandleScope scope(isolate);
1039
1040     Local<v8::FunctionTemplate> fun_templ =
1041         v8::FunctionTemplate::New(isolate, handler);
1042     Local<Function> fun = fun_templ->GetFunction();
1043     env->Global()->Set(v8_str("obj"), fun);
1044     Local<Script> script = v8_compile("obj()");
1045     for (int i = 0; i < 30; i++) {
1046       CHECK_EQ(102, script->Run()->Int32Value());
1047     }
1048   }
1049   // Use SetCallHandler to initialize a function template, should work like
1050   // the previous one.
1051   {
1052     LocalContext env;
1053     v8::Isolate* isolate = env->GetIsolate();
1054     v8::HandleScope scope(isolate);
1055
1056     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1057     fun_templ->SetCallHandler(handler_2);
1058     Local<Function> fun = fun_templ->GetFunction();
1059     env->Global()->Set(v8_str("obj"), fun);
1060     Local<Script> script = v8_compile("obj()");
1061     for (int i = 0; i < 30; i++) {
1062       CHECK_EQ(102, script->Run()->Int32Value());
1063     }
1064   }
1065 }
1066
1067
1068 template<typename Constructor, typename Accessor>
1069 static void TestFunctionTemplateAccessor(Constructor constructor,
1070                                          Accessor accessor) {
1071   LocalContext env;
1072   v8::HandleScope scope(env->GetIsolate());
1073
1074   Local<v8::FunctionTemplate> fun_templ =
1075       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1076   fun_templ->SetClassName(v8_str("funky"));
1077   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1078   Local<Function> fun = fun_templ->GetFunction();
1079   env->Global()->Set(v8_str("obj"), fun);
1080   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1081   CHECK_EQ(v8_str("[object funky]"), result);
1082   CompileRun("var obj_instance = new obj();");
1083   Local<Script> script;
1084   script = v8_compile("obj_instance.x");
1085   for (int i = 0; i < 30; i++) {
1086     CHECK_EQ(1, script->Run()->Int32Value());
1087   }
1088   script = v8_compile("obj_instance.m");
1089   for (int i = 0; i < 30; i++) {
1090     CHECK_EQ(239, script->Run()->Int32Value());
1091   }
1092 }
1093
1094
1095 THREADED_PROFILED_TEST(FunctionTemplate) {
1096   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1097   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1098 }
1099
1100
1101 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1102   ApiTestFuzzer::Fuzz();
1103   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1104   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1105 }
1106
1107
1108 template<typename Callback>
1109 static void TestSimpleCallback(Callback callback) {
1110   LocalContext env;
1111   v8::Isolate* isolate = env->GetIsolate();
1112   v8::HandleScope scope(isolate);
1113
1114   v8::Handle<v8::ObjectTemplate> object_template =
1115       v8::ObjectTemplate::New(isolate);
1116   object_template->Set(isolate, "callback",
1117                        v8::FunctionTemplate::New(isolate, callback));
1118   v8::Local<v8::Object> object = object_template->NewInstance();
1119   (*env)->Global()->Set(v8_str("callback_object"), object);
1120   v8::Handle<v8::Script> script;
1121   script = v8_compile("callback_object.callback(17)");
1122   for (int i = 0; i < 30; i++) {
1123     CHECK_EQ(51424, script->Run()->Int32Value());
1124   }
1125   script = v8_compile("callback_object.callback(17, 24)");
1126   for (int i = 0; i < 30; i++) {
1127     CHECK_EQ(51425, script->Run()->Int32Value());
1128   }
1129 }
1130
1131
1132 THREADED_PROFILED_TEST(SimpleCallback) {
1133   TestSimpleCallback(SimpleCallback);
1134 }
1135
1136
1137 template<typename T>
1138 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1139
1140 // constant return values
1141 static int32_t fast_return_value_int32 = 471;
1142 static uint32_t fast_return_value_uint32 = 571;
1143 static const double kFastReturnValueDouble = 2.7;
1144 // variable return values
1145 static bool fast_return_value_bool = false;
1146 enum ReturnValueOddball {
1147   kNullReturnValue,
1148   kUndefinedReturnValue,
1149   kEmptyStringReturnValue
1150 };
1151 static ReturnValueOddball fast_return_value_void;
1152 static bool fast_return_value_object_is_empty = false;
1153
1154 // Helper function to avoid compiler error: insufficient contextual information
1155 // to determine type when applying FUNCTION_ADDR to a template function.
1156 static i::Address address_of(v8::FunctionCallback callback) {
1157   return FUNCTION_ADDR(callback);
1158 }
1159
1160 template<>
1161 void FastReturnValueCallback<int32_t>(
1162     const v8::FunctionCallbackInfo<v8::Value>& info) {
1163   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1164   info.GetReturnValue().Set(fast_return_value_int32);
1165 }
1166
1167 template<>
1168 void FastReturnValueCallback<uint32_t>(
1169     const v8::FunctionCallbackInfo<v8::Value>& info) {
1170   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1171   info.GetReturnValue().Set(fast_return_value_uint32);
1172 }
1173
1174 template<>
1175 void FastReturnValueCallback<double>(
1176     const v8::FunctionCallbackInfo<v8::Value>& info) {
1177   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1178   info.GetReturnValue().Set(kFastReturnValueDouble);
1179 }
1180
1181 template<>
1182 void FastReturnValueCallback<bool>(
1183     const v8::FunctionCallbackInfo<v8::Value>& info) {
1184   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1185   info.GetReturnValue().Set(fast_return_value_bool);
1186 }
1187
1188 template<>
1189 void FastReturnValueCallback<void>(
1190     const v8::FunctionCallbackInfo<v8::Value>& info) {
1191   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1192   switch (fast_return_value_void) {
1193     case kNullReturnValue:
1194       info.GetReturnValue().SetNull();
1195       break;
1196     case kUndefinedReturnValue:
1197       info.GetReturnValue().SetUndefined();
1198       break;
1199     case kEmptyStringReturnValue:
1200       info.GetReturnValue().SetEmptyString();
1201       break;
1202   }
1203 }
1204
1205 template<>
1206 void FastReturnValueCallback<Object>(
1207     const v8::FunctionCallbackInfo<v8::Value>& info) {
1208   v8::Handle<v8::Object> object;
1209   if (!fast_return_value_object_is_empty) {
1210     object = Object::New(info.GetIsolate());
1211   }
1212   info.GetReturnValue().Set(object);
1213 }
1214
1215 template<typename T>
1216 Handle<Value> TestFastReturnValues() {
1217   LocalContext env;
1218   v8::Isolate* isolate = env->GetIsolate();
1219   v8::EscapableHandleScope scope(isolate);
1220   v8::Handle<v8::ObjectTemplate> object_template =
1221       v8::ObjectTemplate::New(isolate);
1222   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1223   object_template->Set(isolate, "callback",
1224                        v8::FunctionTemplate::New(isolate, callback));
1225   v8::Local<v8::Object> object = object_template->NewInstance();
1226   (*env)->Global()->Set(v8_str("callback_object"), object);
1227   return scope.Escape(CompileRun("callback_object.callback()"));
1228 }
1229
1230
1231 THREADED_PROFILED_TEST(FastReturnValues) {
1232   LocalContext env;
1233   v8::HandleScope scope(CcTest::isolate());
1234   v8::Handle<v8::Value> value;
1235   // check int32_t and uint32_t
1236   int32_t int_values[] = {
1237       0, 234, -723,
1238       i::Smi::kMinValue, i::Smi::kMaxValue
1239   };
1240   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1241     for (int modifier = -1; modifier <= 1; modifier++) {
1242       int int_value = int_values[i] + modifier;
1243       // check int32_t
1244       fast_return_value_int32 = int_value;
1245       value = TestFastReturnValues<int32_t>();
1246       CHECK(value->IsInt32());
1247       CHECK(fast_return_value_int32 == value->Int32Value());
1248       // check uint32_t
1249       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1250       value = TestFastReturnValues<uint32_t>();
1251       CHECK(value->IsUint32());
1252       CHECK(fast_return_value_uint32 == value->Uint32Value());
1253     }
1254   }
1255   // check double
1256   value = TestFastReturnValues<double>();
1257   CHECK(value->IsNumber());
1258   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1259   // check bool values
1260   for (int i = 0; i < 2; i++) {
1261     fast_return_value_bool = i == 0;
1262     value = TestFastReturnValues<bool>();
1263     CHECK(value->IsBoolean());
1264     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1265   }
1266   // check oddballs
1267   ReturnValueOddball oddballs[] = {
1268       kNullReturnValue,
1269       kUndefinedReturnValue,
1270       kEmptyStringReturnValue
1271   };
1272   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1273     fast_return_value_void = oddballs[i];
1274     value = TestFastReturnValues<void>();
1275     switch (fast_return_value_void) {
1276       case kNullReturnValue:
1277         CHECK(value->IsNull());
1278         break;
1279       case kUndefinedReturnValue:
1280         CHECK(value->IsUndefined());
1281         break;
1282       case kEmptyStringReturnValue:
1283         CHECK(value->IsString());
1284         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1285         break;
1286     }
1287   }
1288   // check handles
1289   fast_return_value_object_is_empty = false;
1290   value = TestFastReturnValues<Object>();
1291   CHECK(value->IsObject());
1292   fast_return_value_object_is_empty = true;
1293   value = TestFastReturnValues<Object>();
1294   CHECK(value->IsUndefined());
1295 }
1296
1297
1298 THREADED_TEST(FunctionTemplateSetLength) {
1299   LocalContext env;
1300   v8::Isolate* isolate = env->GetIsolate();
1301   v8::HandleScope scope(isolate);
1302   {
1303     Local<v8::FunctionTemplate> fun_templ =
1304         v8::FunctionTemplate::New(isolate,
1305                                   handle_callback,
1306                                   Handle<v8::Value>(),
1307                                   Handle<v8::Signature>(),
1308                                   23);
1309     Local<Function> fun = fun_templ->GetFunction();
1310     env->Global()->Set(v8_str("obj"), fun);
1311     Local<Script> script = v8_compile("obj.length");
1312     CHECK_EQ(23, script->Run()->Int32Value());
1313   }
1314   {
1315     Local<v8::FunctionTemplate> fun_templ =
1316         v8::FunctionTemplate::New(isolate, handle_callback);
1317     fun_templ->SetLength(22);
1318     Local<Function> fun = fun_templ->GetFunction();
1319     env->Global()->Set(v8_str("obj"), fun);
1320     Local<Script> script = v8_compile("obj.length");
1321     CHECK_EQ(22, script->Run()->Int32Value());
1322   }
1323   {
1324     // Without setting length it defaults to 0.
1325     Local<v8::FunctionTemplate> fun_templ =
1326         v8::FunctionTemplate::New(isolate, handle_callback);
1327     Local<Function> fun = fun_templ->GetFunction();
1328     env->Global()->Set(v8_str("obj"), fun);
1329     Local<Script> script = v8_compile("obj.length");
1330     CHECK_EQ(0, script->Run()->Int32Value());
1331   }
1332 }
1333
1334
1335 static void* expected_ptr;
1336 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1337   void* ptr = v8::External::Cast(*args.Data())->Value();
1338   CHECK_EQ(expected_ptr, ptr);
1339   args.GetReturnValue().Set(true);
1340 }
1341
1342
1343 static void TestExternalPointerWrapping() {
1344   LocalContext env;
1345   v8::Isolate* isolate = env->GetIsolate();
1346   v8::HandleScope scope(isolate);
1347
1348   v8::Handle<v8::Value> data =
1349       v8::External::New(isolate, expected_ptr);
1350
1351   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1352   obj->Set(v8_str("func"),
1353            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1354   env->Global()->Set(v8_str("obj"), obj);
1355
1356   CHECK(CompileRun(
1357         "function foo() {\n"
1358         "  for (var i = 0; i < 13; i++) obj.func();\n"
1359         "}\n"
1360         "foo(), true")->BooleanValue());
1361 }
1362
1363
1364 THREADED_TEST(ExternalWrap) {
1365   // Check heap allocated object.
1366   int* ptr = new int;
1367   expected_ptr = ptr;
1368   TestExternalPointerWrapping();
1369   delete ptr;
1370
1371   // Check stack allocated object.
1372   int foo;
1373   expected_ptr = &foo;
1374   TestExternalPointerWrapping();
1375
1376   // Check not aligned addresses.
1377   const int n = 100;
1378   char* s = new char[n];
1379   for (int i = 0; i < n; i++) {
1380     expected_ptr = s + i;
1381     TestExternalPointerWrapping();
1382   }
1383
1384   delete[] s;
1385
1386   // Check several invalid addresses.
1387   expected_ptr = reinterpret_cast<void*>(1);
1388   TestExternalPointerWrapping();
1389
1390   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1391   TestExternalPointerWrapping();
1392
1393   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1394   TestExternalPointerWrapping();
1395
1396 #if defined(V8_HOST_ARCH_X64)
1397   // Check a value with a leading 1 bit in x64 Smi encoding.
1398   expected_ptr = reinterpret_cast<void*>(0x400000000);
1399   TestExternalPointerWrapping();
1400
1401   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1402   TestExternalPointerWrapping();
1403
1404   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1405   TestExternalPointerWrapping();
1406 #endif
1407 }
1408
1409
1410 THREADED_TEST(FindInstanceInPrototypeChain) {
1411   LocalContext env;
1412   v8::Isolate* isolate = env->GetIsolate();
1413   v8::HandleScope scope(isolate);
1414
1415   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1416   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1417   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1418   derived->Inherit(base);
1419
1420   Local<v8::Function> base_function = base->GetFunction();
1421   Local<v8::Function> derived_function = derived->GetFunction();
1422   Local<v8::Function> other_function = other->GetFunction();
1423
1424   Local<v8::Object> base_instance = base_function->NewInstance();
1425   Local<v8::Object> derived_instance = derived_function->NewInstance();
1426   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1427   Local<v8::Object> other_instance = other_function->NewInstance();
1428   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1429   other_instance->Set(v8_str("__proto__"), derived_instance2);
1430
1431   // base_instance is only an instance of base.
1432   CHECK_EQ(base_instance,
1433            base_instance->FindInstanceInPrototypeChain(base));
1434   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1435   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1436
1437   // derived_instance is an instance of base and derived.
1438   CHECK_EQ(derived_instance,
1439            derived_instance->FindInstanceInPrototypeChain(base));
1440   CHECK_EQ(derived_instance,
1441            derived_instance->FindInstanceInPrototypeChain(derived));
1442   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1443
1444   // other_instance is an instance of other and its immediate
1445   // prototype derived_instance2 is an instance of base and derived.
1446   // Note, derived_instance is an instance of base and derived too,
1447   // but it comes after derived_instance2 in the prototype chain of
1448   // other_instance.
1449   CHECK_EQ(derived_instance2,
1450            other_instance->FindInstanceInPrototypeChain(base));
1451   CHECK_EQ(derived_instance2,
1452            other_instance->FindInstanceInPrototypeChain(derived));
1453   CHECK_EQ(other_instance,
1454            other_instance->FindInstanceInPrototypeChain(other));
1455 }
1456
1457
1458 THREADED_TEST(TinyInteger) {
1459   LocalContext env;
1460   v8::Isolate* isolate = env->GetIsolate();
1461   v8::HandleScope scope(isolate);
1462
1463   int32_t value = 239;
1464   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1465   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1466
1467   value_obj = v8::Integer::New(isolate, value);
1468   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1469 }
1470
1471
1472 THREADED_TEST(BigSmiInteger) {
1473   LocalContext env;
1474   v8::HandleScope scope(env->GetIsolate());
1475   v8::Isolate* isolate = CcTest::isolate();
1476
1477   int32_t value = i::Smi::kMaxValue;
1478   // We cannot add one to a Smi::kMaxValue without wrapping.
1479   if (i::SmiValuesAre31Bits()) {
1480     CHECK(i::Smi::IsValid(value));
1481     CHECK(!i::Smi::IsValid(value + 1));
1482
1483     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1484     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1485
1486     value_obj = v8::Integer::New(isolate, value);
1487     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1488   }
1489 }
1490
1491
1492 THREADED_TEST(BigInteger) {
1493   LocalContext env;
1494   v8::HandleScope scope(env->GetIsolate());
1495   v8::Isolate* isolate = CcTest::isolate();
1496
1497   // We cannot add one to a Smi::kMaxValue without wrapping.
1498   if (i::SmiValuesAre31Bits()) {
1499     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1500     // The code will not be run in that case, due to the "if" guard.
1501     int32_t value =
1502         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1503     CHECK(value > i::Smi::kMaxValue);
1504     CHECK(!i::Smi::IsValid(value));
1505
1506     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1507     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1508
1509     value_obj = v8::Integer::New(isolate, value);
1510     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1511   }
1512 }
1513
1514
1515 THREADED_TEST(TinyUnsignedInteger) {
1516   LocalContext env;
1517   v8::HandleScope scope(env->GetIsolate());
1518   v8::Isolate* isolate = CcTest::isolate();
1519
1520   uint32_t value = 239;
1521
1522   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1523   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1524
1525   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1526   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1527 }
1528
1529
1530 THREADED_TEST(BigUnsignedSmiInteger) {
1531   LocalContext env;
1532   v8::HandleScope scope(env->GetIsolate());
1533   v8::Isolate* isolate = CcTest::isolate();
1534
1535   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1536   CHECK(i::Smi::IsValid(value));
1537   CHECK(!i::Smi::IsValid(value + 1));
1538
1539   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1540   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1541
1542   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1543   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1544 }
1545
1546
1547 THREADED_TEST(BigUnsignedInteger) {
1548   LocalContext env;
1549   v8::HandleScope scope(env->GetIsolate());
1550   v8::Isolate* isolate = CcTest::isolate();
1551
1552   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1553   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1554   CHECK(!i::Smi::IsValid(value));
1555
1556   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1557   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1558
1559   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1560   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1561 }
1562
1563
1564 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1565   LocalContext env;
1566   v8::HandleScope scope(env->GetIsolate());
1567   v8::Isolate* isolate = CcTest::isolate();
1568
1569   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1570   uint32_t value = INT32_MAX_AS_UINT + 1;
1571   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1572
1573   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1574   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1575
1576   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1577   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1578 }
1579
1580
1581 THREADED_TEST(IsNativeError) {
1582   LocalContext env;
1583   v8::HandleScope scope(env->GetIsolate());
1584   v8::Handle<Value> syntax_error = CompileRun(
1585       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1586   CHECK(syntax_error->IsNativeError());
1587   v8::Handle<Value> not_error = CompileRun("{a:42}");
1588   CHECK(!not_error->IsNativeError());
1589   v8::Handle<Value> not_object = CompileRun("42");
1590   CHECK(!not_object->IsNativeError());
1591 }
1592
1593
1594 THREADED_TEST(StringObject) {
1595   LocalContext env;
1596   v8::HandleScope scope(env->GetIsolate());
1597   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1598   CHECK(boxed_string->IsStringObject());
1599   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1600   CHECK(!unboxed_string->IsStringObject());
1601   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1602   CHECK(!boxed_not_string->IsStringObject());
1603   v8::Handle<Value> not_object = CompileRun("0");
1604   CHECK(!not_object->IsStringObject());
1605   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1606   CHECK(!as_boxed.IsEmpty());
1607   Local<v8::String> the_string = as_boxed->ValueOf();
1608   CHECK(!the_string.IsEmpty());
1609   ExpectObject("\"test\"", the_string);
1610   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1611   CHECK(new_boxed_string->IsStringObject());
1612   as_boxed = new_boxed_string.As<v8::StringObject>();
1613   the_string = as_boxed->ValueOf();
1614   CHECK(!the_string.IsEmpty());
1615   ExpectObject("\"test\"", the_string);
1616 }
1617
1618
1619 THREADED_TEST(NumberObject) {
1620   LocalContext env;
1621   v8::HandleScope scope(env->GetIsolate());
1622   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1623   CHECK(boxed_number->IsNumberObject());
1624   v8::Handle<Value> unboxed_number = CompileRun("42");
1625   CHECK(!unboxed_number->IsNumberObject());
1626   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1627   CHECK(!boxed_not_number->IsNumberObject());
1628   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1629   CHECK(!as_boxed.IsEmpty());
1630   double the_number = as_boxed->ValueOf();
1631   CHECK_EQ(42.0, the_number);
1632   v8::Handle<v8::Value> new_boxed_number =
1633       v8::NumberObject::New(env->GetIsolate(), 43);
1634   CHECK(new_boxed_number->IsNumberObject());
1635   as_boxed = new_boxed_number.As<v8::NumberObject>();
1636   the_number = as_boxed->ValueOf();
1637   CHECK_EQ(43.0, the_number);
1638 }
1639
1640
1641 THREADED_TEST(BooleanObject) {
1642   LocalContext env;
1643   v8::HandleScope scope(env->GetIsolate());
1644   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1645   CHECK(boxed_boolean->IsBooleanObject());
1646   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1647   CHECK(!unboxed_boolean->IsBooleanObject());
1648   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1649   CHECK(!boxed_not_boolean->IsBooleanObject());
1650   v8::Handle<v8::BooleanObject> as_boxed =
1651       boxed_boolean.As<v8::BooleanObject>();
1652   CHECK(!as_boxed.IsEmpty());
1653   bool the_boolean = as_boxed->ValueOf();
1654   CHECK_EQ(true, the_boolean);
1655   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1656   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1657   CHECK(boxed_true->IsBooleanObject());
1658   CHECK(boxed_false->IsBooleanObject());
1659   as_boxed = boxed_true.As<v8::BooleanObject>();
1660   CHECK_EQ(true, as_boxed->ValueOf());
1661   as_boxed = boxed_false.As<v8::BooleanObject>();
1662   CHECK_EQ(false, as_boxed->ValueOf());
1663 }
1664
1665
1666 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1667   LocalContext env;
1668   v8::HandleScope scope(env->GetIsolate());
1669
1670   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1671   CHECK(primitive_false->IsBoolean());
1672   CHECK(!primitive_false->IsBooleanObject());
1673   CHECK(!primitive_false->BooleanValue());
1674   CHECK(!primitive_false->IsTrue());
1675   CHECK(primitive_false->IsFalse());
1676
1677   Local<Value> false_value = BooleanObject::New(false);
1678   CHECK(!false_value->IsBoolean());
1679   CHECK(false_value->IsBooleanObject());
1680   CHECK(false_value->BooleanValue());
1681   CHECK(!false_value->IsTrue());
1682   CHECK(!false_value->IsFalse());
1683
1684   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1685   CHECK(!false_boolean_object->IsBoolean());
1686   CHECK(false_boolean_object->IsBooleanObject());
1687   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1688   // CHECK(false_boolean_object->BooleanValue());
1689   CHECK(!false_boolean_object->ValueOf());
1690   CHECK(!false_boolean_object->IsTrue());
1691   CHECK(!false_boolean_object->IsFalse());
1692
1693   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1694   CHECK(primitive_true->IsBoolean());
1695   CHECK(!primitive_true->IsBooleanObject());
1696   CHECK(primitive_true->BooleanValue());
1697   CHECK(primitive_true->IsTrue());
1698   CHECK(!primitive_true->IsFalse());
1699
1700   Local<Value> true_value = BooleanObject::New(true);
1701   CHECK(!true_value->IsBoolean());
1702   CHECK(true_value->IsBooleanObject());
1703   CHECK(true_value->BooleanValue());
1704   CHECK(!true_value->IsTrue());
1705   CHECK(!true_value->IsFalse());
1706
1707   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1708   CHECK(!true_boolean_object->IsBoolean());
1709   CHECK(true_boolean_object->IsBooleanObject());
1710   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1711   // CHECK(true_boolean_object->BooleanValue());
1712   CHECK(true_boolean_object->ValueOf());
1713   CHECK(!true_boolean_object->IsTrue());
1714   CHECK(!true_boolean_object->IsFalse());
1715 }
1716
1717
1718 THREADED_TEST(Number) {
1719   LocalContext env;
1720   v8::HandleScope scope(env->GetIsolate());
1721   double PI = 3.1415926;
1722   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1723   CHECK_EQ(PI, pi_obj->NumberValue());
1724 }
1725
1726
1727 THREADED_TEST(ToNumber) {
1728   LocalContext env;
1729   v8::Isolate* isolate = CcTest::isolate();
1730   v8::HandleScope scope(isolate);
1731   Local<String> str = v8_str("3.1415926");
1732   CHECK_EQ(3.1415926, str->NumberValue());
1733   v8::Handle<v8::Boolean> t = v8::True(isolate);
1734   CHECK_EQ(1.0, t->NumberValue());
1735   v8::Handle<v8::Boolean> f = v8::False(isolate);
1736   CHECK_EQ(0.0, f->NumberValue());
1737 }
1738
1739
1740 THREADED_TEST(Date) {
1741   LocalContext env;
1742   v8::HandleScope scope(env->GetIsolate());
1743   double PI = 3.1415926;
1744   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1745   CHECK_EQ(3.0, date->NumberValue());
1746   date.As<v8::Date>()->Set(v8_str("property"),
1747                            v8::Integer::New(env->GetIsolate(), 42));
1748   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1749 }
1750
1751
1752 THREADED_TEST(Boolean) {
1753   LocalContext env;
1754   v8::Isolate* isolate = env->GetIsolate();
1755   v8::HandleScope scope(isolate);
1756   v8::Handle<v8::Boolean> t = v8::True(isolate);
1757   CHECK(t->Value());
1758   v8::Handle<v8::Boolean> f = v8::False(isolate);
1759   CHECK(!f->Value());
1760   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1761   CHECK(!u->BooleanValue());
1762   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1763   CHECK(!n->BooleanValue());
1764   v8::Handle<String> str1 = v8_str("");
1765   CHECK(!str1->BooleanValue());
1766   v8::Handle<String> str2 = v8_str("x");
1767   CHECK(str2->BooleanValue());
1768   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1769   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1770   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1771   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1772   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1773 }
1774
1775
1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1777   ApiTestFuzzer::Fuzz();
1778   args.GetReturnValue().Set(v8_num(13.4));
1779 }
1780
1781
1782 static void GetM(Local<String> name,
1783                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1784   ApiTestFuzzer::Fuzz();
1785   info.GetReturnValue().Set(v8_num(876));
1786 }
1787
1788
1789 THREADED_TEST(GlobalPrototype) {
1790   v8::Isolate* isolate = CcTest::isolate();
1791   v8::HandleScope scope(isolate);
1792   v8::Handle<v8::FunctionTemplate> func_templ =
1793       v8::FunctionTemplate::New(isolate);
1794   func_templ->PrototypeTemplate()->Set(
1795       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1796   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1797   templ->Set(isolate, "x", v8_num(200));
1798   templ->SetAccessor(v8_str("m"), GetM);
1799   LocalContext env(0, templ);
1800   v8::Handle<Script> script(v8_compile("dummy()"));
1801   v8::Handle<Value> result(script->Run());
1802   CHECK_EQ(13.4, result->NumberValue());
1803   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1804   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1805 }
1806
1807
1808 THREADED_TEST(ObjectTemplate) {
1809   v8::Isolate* isolate = CcTest::isolate();
1810   v8::HandleScope scope(isolate);
1811   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1812   templ1->Set(isolate, "x", v8_num(10));
1813   templ1->Set(isolate, "y", v8_num(13));
1814   LocalContext env;
1815   Local<v8::Object> instance1 = templ1->NewInstance();
1816   env->Global()->Set(v8_str("p"), instance1);
1817   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1818   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1819   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1821   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1822   templ2->Set(isolate, "a", v8_num(12));
1823   templ2->Set(isolate, "b", templ1);
1824   Local<v8::Object> instance2 = templ2->NewInstance();
1825   env->Global()->Set(v8_str("q"), instance2);
1826   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1827   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1828   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1829   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1830 }
1831
1832
1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1834   ApiTestFuzzer::Fuzz();
1835   args.GetReturnValue().Set(v8_num(17.2));
1836 }
1837
1838
1839 static void GetKnurd(Local<String> property,
1840                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1841   ApiTestFuzzer::Fuzz();
1842   info.GetReturnValue().Set(v8_num(15.2));
1843 }
1844
1845
1846 THREADED_TEST(DescriptorInheritance) {
1847   v8::Isolate* isolate = CcTest::isolate();
1848   v8::HandleScope scope(isolate);
1849   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1850   super->PrototypeTemplate()->Set(isolate, "flabby",
1851                                   v8::FunctionTemplate::New(isolate,
1852                                                             GetFlabby));
1853   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1854
1855   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1856
1857   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1858   base1->Inherit(super);
1859   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1860
1861   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1862   base2->Inherit(super);
1863   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1864
1865   LocalContext env;
1866
1867   env->Global()->Set(v8_str("s"), super->GetFunction());
1868   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1869   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1870
1871   // Checks right __proto__ chain.
1872   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1873   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1874
1875   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1876
1877   // Instance accessor should not be visible on function object or its prototype
1878   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1879   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1880   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1881
1882   env->Global()->Set(v8_str("obj"),
1883                      base1->GetFunction()->NewInstance());
1884   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1885   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1886   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1887   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1888   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1889
1890   env->Global()->Set(v8_str("obj2"),
1891                      base2->GetFunction()->NewInstance());
1892   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1893   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1894   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1895   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1896   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1897
1898   // base1 and base2 cannot cross reference to each's prototype
1899   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1900   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1901 }
1902
1903
1904 int echo_named_call_count;
1905
1906
1907 static void EchoNamedProperty(Local<String> name,
1908                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1909   ApiTestFuzzer::Fuzz();
1910   CHECK_EQ(v8_str("data"), info.Data());
1911   echo_named_call_count++;
1912   info.GetReturnValue().Set(name);
1913 }
1914
1915
1916 // Helper functions for Interceptor/Accessor interaction tests
1917
1918 void SimpleAccessorGetter(Local<String> name,
1919                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1920   Handle<Object> self = Handle<Object>::Cast(info.This());
1921   info.GetReturnValue().Set(
1922       self->Get(String::Concat(v8_str("accessor_"), name)));
1923 }
1924
1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1926                           const v8::PropertyCallbackInfo<void>& info) {
1927   Handle<Object> self = Handle<Object>::Cast(info.This());
1928   self->Set(String::Concat(v8_str("accessor_"), name), value);
1929 }
1930
1931 void EmptyInterceptorGetter(Local<String> name,
1932                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1933 }
1934
1935 void EmptyInterceptorSetter(Local<String> name,
1936                             Local<Value> value,
1937                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1938 }
1939
1940 void InterceptorGetter(Local<String> name,
1941                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1942   // Intercept names that start with 'interceptor_'.
1943   String::Utf8Value utf8(name);
1944   char* name_str = *utf8;
1945   char prefix[] = "interceptor_";
1946   int i;
1947   for (i = 0; name_str[i] && prefix[i]; ++i) {
1948     if (name_str[i] != prefix[i]) return;
1949   }
1950   Handle<Object> self = Handle<Object>::Cast(info.This());
1951   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1952 }
1953
1954 void InterceptorSetter(Local<String> name,
1955                        Local<Value> value,
1956                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1957   // Intercept accesses that set certain integer values, for which the name does
1958   // not start with 'accessor_'.
1959   String::Utf8Value utf8(name);
1960   char* name_str = *utf8;
1961   char prefix[] = "accessor_";
1962   int i;
1963   for (i = 0; name_str[i] && prefix[i]; ++i) {
1964     if (name_str[i] != prefix[i]) break;
1965   }
1966   if (!prefix[i]) return;
1967
1968   if (value->IsInt32() && value->Int32Value() < 10000) {
1969     Handle<Object> self = Handle<Object>::Cast(info.This());
1970     self->SetHiddenValue(name, value);
1971     info.GetReturnValue().Set(value);
1972   }
1973 }
1974
1975 void AddAccessor(Handle<FunctionTemplate> templ,
1976                  Handle<String> name,
1977                  v8::AccessorGetterCallback getter,
1978                  v8::AccessorSetterCallback setter) {
1979   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1980 }
1981
1982 void AddInterceptor(Handle<FunctionTemplate> templ,
1983                     v8::NamedPropertyGetterCallback getter,
1984                     v8::NamedPropertySetterCallback setter) {
1985   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1986 }
1987
1988
1989 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1990   v8::HandleScope scope(CcTest::isolate());
1991   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1992   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1993   child->Inherit(parent);
1994   AddAccessor(parent, v8_str("age"),
1995               SimpleAccessorGetter, SimpleAccessorSetter);
1996   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1997   LocalContext env;
1998   env->Global()->Set(v8_str("Child"), child->GetFunction());
1999   CompileRun("var child = new Child;"
2000              "child.age = 10;");
2001   ExpectBoolean("child.hasOwnProperty('age')", false);
2002   ExpectInt32("child.age", 10);
2003   ExpectInt32("child.accessor_age", 10);
2004 }
2005
2006
2007 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2008   v8::HandleScope scope(CcTest::isolate());
2009   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2010   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2011   LocalContext env;
2012   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2013   CompileRun("var o1 = new Constructor;"
2014              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2015              "Object.defineProperty(o1, 'x', {value: 10});");
2016   CompileRun("var o2 = new Constructor;"
2017              "o2.a = 1;"
2018              "Object.defineProperty(o2, 'x', {value: 10});");
2019 }
2020
2021
2022 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2023   v8::Isolate* isolate = CcTest::isolate();
2024   v8::HandleScope scope(isolate);
2025   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2026   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2027   child->Inherit(parent);
2028   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2029   LocalContext env;
2030   env->Global()->Set(v8_str("Child"), child->GetFunction());
2031   CompileRun("var child = new Child;"
2032              "var parent = child.__proto__;"
2033              "Object.defineProperty(parent, 'age', "
2034              "  {get: function(){ return this.accessor_age; }, "
2035              "   set: function(v){ this.accessor_age = v; }, "
2036              "   enumerable: true, configurable: true});"
2037              "child.age = 10;");
2038   ExpectBoolean("child.hasOwnProperty('age')", false);
2039   ExpectInt32("child.age", 10);
2040   ExpectInt32("child.accessor_age", 10);
2041 }
2042
2043
2044 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2045   v8::Isolate* isolate = CcTest::isolate();
2046   v8::HandleScope scope(isolate);
2047   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2048   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2049   child->Inherit(parent);
2050   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2051   LocalContext env;
2052   env->Global()->Set(v8_str("Child"), child->GetFunction());
2053   CompileRun("var child = new Child;"
2054              "var parent = child.__proto__;"
2055              "parent.name = 'Alice';");
2056   ExpectBoolean("child.hasOwnProperty('name')", false);
2057   ExpectString("child.name", "Alice");
2058   CompileRun("child.name = 'Bob';");
2059   ExpectString("child.name", "Bob");
2060   ExpectBoolean("child.hasOwnProperty('name')", true);
2061   ExpectString("parent.name", "Alice");
2062 }
2063
2064
2065 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2066   v8::HandleScope scope(CcTest::isolate());
2067   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2068   AddAccessor(templ, v8_str("age"),
2069               SimpleAccessorGetter, SimpleAccessorSetter);
2070   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2071   LocalContext env;
2072   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2073   CompileRun("var obj = new Obj;"
2074              "function setAge(i){ obj.age = i; };"
2075              "for(var i = 0; i <= 10000; i++) setAge(i);");
2076   // All i < 10000 go to the interceptor.
2077   ExpectInt32("obj.interceptor_age", 9999);
2078   // The last i goes to the accessor.
2079   ExpectInt32("obj.accessor_age", 10000);
2080 }
2081
2082
2083 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2084   v8::HandleScope scope(CcTest::isolate());
2085   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2086   AddAccessor(templ, v8_str("age"),
2087               SimpleAccessorGetter, SimpleAccessorSetter);
2088   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2089   LocalContext env;
2090   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2091   CompileRun("var obj = new Obj;"
2092              "function setAge(i){ obj.age = i; };"
2093              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2094   // All i >= 10000 go to the accessor.
2095   ExpectInt32("obj.accessor_age", 10000);
2096   // The last i goes to the interceptor.
2097   ExpectInt32("obj.interceptor_age", 9999);
2098 }
2099
2100
2101 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2102   v8::HandleScope scope(CcTest::isolate());
2103   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2104   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2105   child->Inherit(parent);
2106   AddAccessor(parent, v8_str("age"),
2107               SimpleAccessorGetter, SimpleAccessorSetter);
2108   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2109   LocalContext env;
2110   env->Global()->Set(v8_str("Child"), child->GetFunction());
2111   CompileRun("var child = new Child;"
2112              "function setAge(i){ child.age = i; };"
2113              "for(var i = 0; i <= 10000; i++) setAge(i);");
2114   // All i < 10000 go to the interceptor.
2115   ExpectInt32("child.interceptor_age", 9999);
2116   // The last i goes to the accessor.
2117   ExpectInt32("child.accessor_age", 10000);
2118 }
2119
2120
2121 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2122   v8::HandleScope scope(CcTest::isolate());
2123   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2124   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2125   child->Inherit(parent);
2126   AddAccessor(parent, v8_str("age"),
2127               SimpleAccessorGetter, SimpleAccessorSetter);
2128   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2129   LocalContext env;
2130   env->Global()->Set(v8_str("Child"), child->GetFunction());
2131   CompileRun("var child = new Child;"
2132              "function setAge(i){ child.age = i; };"
2133              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2134   // All i >= 10000 go to the accessor.
2135   ExpectInt32("child.accessor_age", 10000);
2136   // The last i goes to the interceptor.
2137   ExpectInt32("child.interceptor_age", 9999);
2138 }
2139
2140
2141 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2142   v8::HandleScope scope(CcTest::isolate());
2143   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2144   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2145   LocalContext env;
2146   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2147   CompileRun("var obj = new Obj;"
2148              "function setter(i) { this.accessor_age = i; };"
2149              "function getter() { return this.accessor_age; };"
2150              "function setAge(i) { obj.age = i; };"
2151              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2152              "for(var i = 0; i <= 10000; i++) setAge(i);");
2153   // All i < 10000 go to the interceptor.
2154   ExpectInt32("obj.interceptor_age", 9999);
2155   // The last i goes to the JavaScript accessor.
2156   ExpectInt32("obj.accessor_age", 10000);
2157   // The installed JavaScript getter is still intact.
2158   // This last part is a regression test for issue 1651 and relies on the fact
2159   // that both interceptor and accessor are being installed on the same object.
2160   ExpectInt32("obj.age", 10000);
2161   ExpectBoolean("obj.hasOwnProperty('age')", true);
2162   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2163 }
2164
2165
2166 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2167   v8::HandleScope scope(CcTest::isolate());
2168   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2169   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2170   LocalContext env;
2171   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2172   CompileRun("var obj = new Obj;"
2173              "function setter(i) { this.accessor_age = i; };"
2174              "function getter() { return this.accessor_age; };"
2175              "function setAge(i) { obj.age = i; };"
2176              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2177              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2178   // All i >= 10000 go to the accessor.
2179   ExpectInt32("obj.accessor_age", 10000);
2180   // The last i goes to the interceptor.
2181   ExpectInt32("obj.interceptor_age", 9999);
2182   // The installed JavaScript getter is still intact.
2183   // This last part is a regression test for issue 1651 and relies on the fact
2184   // that both interceptor and accessor are being installed on the same object.
2185   ExpectInt32("obj.age", 10000);
2186   ExpectBoolean("obj.hasOwnProperty('age')", true);
2187   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2188 }
2189
2190
2191 THREADED_TEST(SwitchFromInterceptorToProperty) {
2192   v8::HandleScope scope(CcTest::isolate());
2193   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2194   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2195   child->Inherit(parent);
2196   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2197   LocalContext env;
2198   env->Global()->Set(v8_str("Child"), child->GetFunction());
2199   CompileRun("var child = new Child;"
2200              "function setAge(i){ child.age = i; };"
2201              "for(var i = 0; i <= 10000; i++) setAge(i);");
2202   // All i < 10000 go to the interceptor.
2203   ExpectInt32("child.interceptor_age", 9999);
2204   // The last i goes to child's own property.
2205   ExpectInt32("child.age", 10000);
2206 }
2207
2208
2209 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2210   v8::HandleScope scope(CcTest::isolate());
2211   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2212   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2213   child->Inherit(parent);
2214   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2215   LocalContext env;
2216   env->Global()->Set(v8_str("Child"), child->GetFunction());
2217   CompileRun("var child = new Child;"
2218              "function setAge(i){ child.age = i; };"
2219              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2220   // All i >= 10000 go to child's own property.
2221   ExpectInt32("child.age", 10000);
2222   // The last i goes to the interceptor.
2223   ExpectInt32("child.interceptor_age", 9999);
2224 }
2225
2226
2227 THREADED_TEST(NamedPropertyHandlerGetter) {
2228   echo_named_call_count = 0;
2229   v8::HandleScope scope(CcTest::isolate());
2230   v8::Handle<v8::FunctionTemplate> templ =
2231       v8::FunctionTemplate::New(CcTest::isolate());
2232   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2233                                                      0, 0, 0, 0,
2234                                                      v8_str("data"));
2235   LocalContext env;
2236   env->Global()->Set(v8_str("obj"),
2237                      templ->GetFunction()->NewInstance());
2238   CHECK_EQ(echo_named_call_count, 0);
2239   v8_compile("obj.x")->Run();
2240   CHECK_EQ(echo_named_call_count, 1);
2241   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2242   v8::Handle<Value> str = CompileRun(code);
2243   String::Utf8Value value(str);
2244   CHECK_EQ(*value, "oddlepoddle");
2245   // Check default behavior
2246   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2247   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2248   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2249 }
2250
2251
2252 int echo_indexed_call_count = 0;
2253
2254
2255 static void EchoIndexedProperty(
2256     uint32_t index,
2257     const v8::PropertyCallbackInfo<v8::Value>& info) {
2258   ApiTestFuzzer::Fuzz();
2259   CHECK_EQ(v8_num(637), info.Data());
2260   echo_indexed_call_count++;
2261   info.GetReturnValue().Set(v8_num(index));
2262 }
2263
2264
2265 THREADED_TEST(IndexedPropertyHandlerGetter) {
2266   v8::Isolate* isolate = CcTest::isolate();
2267   v8::HandleScope scope(isolate);
2268   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2269   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2270                                                        0, 0, 0, 0,
2271                                                        v8_num(637));
2272   LocalContext env;
2273   env->Global()->Set(v8_str("obj"),
2274                      templ->GetFunction()->NewInstance());
2275   Local<Script> script = v8_compile("obj[900]");
2276   CHECK_EQ(script->Run()->Int32Value(), 900);
2277 }
2278
2279
2280 v8::Handle<v8::Object> bottom;
2281
2282 static void CheckThisIndexedPropertyHandler(
2283     uint32_t index,
2284     const v8::PropertyCallbackInfo<v8::Value>& info) {
2285   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2286   ApiTestFuzzer::Fuzz();
2287   CHECK(info.This()->Equals(bottom));
2288 }
2289
2290 static void CheckThisNamedPropertyHandler(
2291     Local<String> name,
2292     const v8::PropertyCallbackInfo<v8::Value>& info) {
2293   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2294   ApiTestFuzzer::Fuzz();
2295   CHECK(info.This()->Equals(bottom));
2296 }
2297
2298 void CheckThisIndexedPropertySetter(
2299     uint32_t index,
2300     Local<Value> value,
2301     const v8::PropertyCallbackInfo<v8::Value>& info) {
2302   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2303   ApiTestFuzzer::Fuzz();
2304   CHECK(info.This()->Equals(bottom));
2305 }
2306
2307
2308 void CheckThisNamedPropertySetter(
2309     Local<String> property,
2310     Local<Value> value,
2311     const v8::PropertyCallbackInfo<v8::Value>& info) {
2312   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2313   ApiTestFuzzer::Fuzz();
2314   CHECK(info.This()->Equals(bottom));
2315 }
2316
2317 void CheckThisIndexedPropertyQuery(
2318     uint32_t index,
2319     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2320   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2321   ApiTestFuzzer::Fuzz();
2322   CHECK(info.This()->Equals(bottom));
2323 }
2324
2325
2326 void CheckThisNamedPropertyQuery(
2327     Local<String> property,
2328     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2329   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2330   ApiTestFuzzer::Fuzz();
2331   CHECK(info.This()->Equals(bottom));
2332 }
2333
2334
2335 void CheckThisIndexedPropertyDeleter(
2336     uint32_t index,
2337     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2338   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2339   ApiTestFuzzer::Fuzz();
2340   CHECK(info.This()->Equals(bottom));
2341 }
2342
2343
2344 void CheckThisNamedPropertyDeleter(
2345     Local<String> property,
2346     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2347   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2348   ApiTestFuzzer::Fuzz();
2349   CHECK(info.This()->Equals(bottom));
2350 }
2351
2352
2353 void CheckThisIndexedPropertyEnumerator(
2354     const v8::PropertyCallbackInfo<v8::Array>& info) {
2355   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2356   ApiTestFuzzer::Fuzz();
2357   CHECK(info.This()->Equals(bottom));
2358 }
2359
2360
2361 void CheckThisNamedPropertyEnumerator(
2362     const v8::PropertyCallbackInfo<v8::Array>& info) {
2363   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2364   ApiTestFuzzer::Fuzz();
2365   CHECK(info.This()->Equals(bottom));
2366 }
2367
2368
2369 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2370   LocalContext env;
2371   v8::Isolate* isolate = env->GetIsolate();
2372   v8::HandleScope scope(isolate);
2373
2374   // Set up a prototype chain with three interceptors.
2375   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2376   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2377       CheckThisIndexedPropertyHandler,
2378       CheckThisIndexedPropertySetter,
2379       CheckThisIndexedPropertyQuery,
2380       CheckThisIndexedPropertyDeleter,
2381       CheckThisIndexedPropertyEnumerator);
2382
2383   templ->InstanceTemplate()->SetNamedPropertyHandler(
2384       CheckThisNamedPropertyHandler,
2385       CheckThisNamedPropertySetter,
2386       CheckThisNamedPropertyQuery,
2387       CheckThisNamedPropertyDeleter,
2388       CheckThisNamedPropertyEnumerator);
2389
2390   bottom = templ->GetFunction()->NewInstance();
2391   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2392   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2393
2394   bottom->SetPrototype(middle);
2395   middle->SetPrototype(top);
2396   env->Global()->Set(v8_str("obj"), bottom);
2397
2398   // Indexed and named get.
2399   CompileRun("obj[0]");
2400   CompileRun("obj.x");
2401
2402   // Indexed and named set.
2403   CompileRun("obj[1] = 42");
2404   CompileRun("obj.y = 42");
2405
2406   // Indexed and named query.
2407   CompileRun("0 in obj");
2408   CompileRun("'x' in obj");
2409
2410   // Indexed and named deleter.
2411   CompileRun("delete obj[0]");
2412   CompileRun("delete obj.x");
2413
2414   // Enumerators.
2415   CompileRun("for (var p in obj) ;");
2416 }
2417
2418
2419 static void PrePropertyHandlerGet(
2420     Local<String> key,
2421     const v8::PropertyCallbackInfo<v8::Value>& info) {
2422   ApiTestFuzzer::Fuzz();
2423   if (v8_str("pre")->Equals(key)) {
2424     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2425   }
2426 }
2427
2428
2429 static void PrePropertyHandlerQuery(
2430     Local<String> key,
2431     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2432   if (v8_str("pre")->Equals(key)) {
2433     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2434   }
2435 }
2436
2437
2438 THREADED_TEST(PrePropertyHandler) {
2439   v8::Isolate* isolate = CcTest::isolate();
2440   v8::HandleScope scope(isolate);
2441   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2442   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2443                                                     0,
2444                                                     PrePropertyHandlerQuery);
2445   LocalContext env(NULL, desc->InstanceTemplate());
2446   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2447   v8::Handle<Value> result_pre = CompileRun("pre");
2448   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2449   v8::Handle<Value> result_on = CompileRun("on");
2450   CHECK_EQ(v8_str("Object: on"), result_on);
2451   v8::Handle<Value> result_post = CompileRun("post");
2452   CHECK(result_post.IsEmpty());
2453 }
2454
2455
2456 THREADED_TEST(UndefinedIsNotEnumerable) {
2457   LocalContext env;
2458   v8::HandleScope scope(env->GetIsolate());
2459   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2460   CHECK(result->IsFalse());
2461 }
2462
2463
2464 v8::Handle<Script> call_recursively_script;
2465 static const int kTargetRecursionDepth = 200;  // near maximum
2466
2467
2468 static void CallScriptRecursivelyCall(
2469     const v8::FunctionCallbackInfo<v8::Value>& args) {
2470   ApiTestFuzzer::Fuzz();
2471   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2472   if (depth == kTargetRecursionDepth) return;
2473   args.This()->Set(v8_str("depth"),
2474                    v8::Integer::New(args.GetIsolate(), depth + 1));
2475   args.GetReturnValue().Set(call_recursively_script->Run());
2476 }
2477
2478
2479 static void CallFunctionRecursivelyCall(
2480     const v8::FunctionCallbackInfo<v8::Value>& args) {
2481   ApiTestFuzzer::Fuzz();
2482   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2483   if (depth == kTargetRecursionDepth) {
2484     printf("[depth = %d]\n", depth);
2485     return;
2486   }
2487   args.This()->Set(v8_str("depth"),
2488                    v8::Integer::New(args.GetIsolate(), depth + 1));
2489   v8::Handle<Value> function =
2490       args.This()->Get(v8_str("callFunctionRecursively"));
2491   args.GetReturnValue().Set(
2492       function.As<Function>()->Call(args.This(), 0, NULL));
2493 }
2494
2495
2496 THREADED_TEST(DeepCrossLanguageRecursion) {
2497   v8::Isolate* isolate = CcTest::isolate();
2498   v8::HandleScope scope(isolate);
2499   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2500   global->Set(v8_str("callScriptRecursively"),
2501               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2502   global->Set(v8_str("callFunctionRecursively"),
2503               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2504   LocalContext env(NULL, global);
2505
2506   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2507   call_recursively_script = v8_compile("callScriptRecursively()");
2508   call_recursively_script->Run();
2509   call_recursively_script = v8::Handle<Script>();
2510
2511   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2512   CompileRun("callFunctionRecursively()");
2513 }
2514
2515
2516 static void ThrowingPropertyHandlerGet(
2517     Local<String> key,
2518     const v8::PropertyCallbackInfo<v8::Value>& info) {
2519   ApiTestFuzzer::Fuzz();
2520   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2521 }
2522
2523
2524 static void ThrowingPropertyHandlerSet(
2525     Local<String> key,
2526     Local<Value>,
2527     const v8::PropertyCallbackInfo<v8::Value>& info) {
2528   info.GetIsolate()->ThrowException(key);
2529   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2530 }
2531
2532
2533 THREADED_TEST(CallbackExceptionRegression) {
2534   v8::Isolate* isolate = CcTest::isolate();
2535   v8::HandleScope scope(isolate);
2536   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2537   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2538                                ThrowingPropertyHandlerSet);
2539   LocalContext env;
2540   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2541   v8::Handle<Value> otto = CompileRun(
2542       "try { with (obj) { otto; } } catch (e) { e; }");
2543   CHECK_EQ(v8_str("otto"), otto);
2544   v8::Handle<Value> netto = CompileRun(
2545       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2546   CHECK_EQ(v8_str("netto"), netto);
2547 }
2548
2549
2550 THREADED_TEST(FunctionPrototype) {
2551   v8::Isolate* isolate = CcTest::isolate();
2552   v8::HandleScope scope(isolate);
2553   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2554   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2555   LocalContext env;
2556   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2557   Local<Script> script = v8_compile("Foo.prototype.plak");
2558   CHECK_EQ(script->Run()->Int32Value(), 321);
2559 }
2560
2561
2562 THREADED_TEST(InternalFields) {
2563   LocalContext env;
2564   v8::Isolate* isolate = env->GetIsolate();
2565   v8::HandleScope scope(isolate);
2566
2567   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2568   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2569   instance_templ->SetInternalFieldCount(1);
2570   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2571   CHECK_EQ(1, obj->InternalFieldCount());
2572   CHECK(obj->GetInternalField(0)->IsUndefined());
2573   obj->SetInternalField(0, v8_num(17));
2574   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2575 }
2576
2577
2578 THREADED_TEST(GlobalObjectInternalFields) {
2579   v8::Isolate* isolate = CcTest::isolate();
2580   v8::HandleScope scope(isolate);
2581   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2582   global_template->SetInternalFieldCount(1);
2583   LocalContext env(NULL, global_template);
2584   v8::Handle<v8::Object> global_proxy = env->Global();
2585   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2586   CHECK_EQ(1, global->InternalFieldCount());
2587   CHECK(global->GetInternalField(0)->IsUndefined());
2588   global->SetInternalField(0, v8_num(17));
2589   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2590 }
2591
2592
2593 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2594   LocalContext env;
2595   v8::HandleScope scope(CcTest::isolate());
2596
2597   v8::Local<v8::Object> global = env->Global();
2598   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2599   CHECK(global->HasRealIndexedProperty(0));
2600 }
2601
2602
2603 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2604                                                void* value) {
2605   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2606   obj->SetAlignedPointerInInternalField(0, value);
2607   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2608   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2609 }
2610
2611
2612 THREADED_TEST(InternalFieldsAlignedPointers) {
2613   LocalContext env;
2614   v8::Isolate* isolate = env->GetIsolate();
2615   v8::HandleScope scope(isolate);
2616
2617   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2618   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2619   instance_templ->SetInternalFieldCount(1);
2620   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2621   CHECK_EQ(1, obj->InternalFieldCount());
2622
2623   CheckAlignedPointerInInternalField(obj, NULL);
2624
2625   int* heap_allocated = new int[100];
2626   CheckAlignedPointerInInternalField(obj, heap_allocated);
2627   delete[] heap_allocated;
2628
2629   int stack_allocated[100];
2630   CheckAlignedPointerInInternalField(obj, stack_allocated);
2631
2632   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2633   CheckAlignedPointerInInternalField(obj, huge);
2634
2635   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2636   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2637   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2638 }
2639
2640
2641 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2642                                               int index,
2643                                               void* value) {
2644   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2645   (*env)->SetAlignedPointerInEmbedderData(index, value);
2646   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2647   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2648 }
2649
2650
2651 static void* AlignedTestPointer(int i) {
2652   return reinterpret_cast<void*>(i * 1234);
2653 }
2654
2655
2656 THREADED_TEST(EmbedderDataAlignedPointers) {
2657   LocalContext env;
2658   v8::HandleScope scope(env->GetIsolate());
2659
2660   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2661
2662   int* heap_allocated = new int[100];
2663   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2664   delete[] heap_allocated;
2665
2666   int stack_allocated[100];
2667   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2668
2669   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2670   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2671
2672   // Test growing of the embedder data's backing store.
2673   for (int i = 0; i < 100; i++) {
2674     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2675   }
2676   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2677   for (int i = 0; i < 100; i++) {
2678     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2679   }
2680 }
2681
2682
2683 static void CheckEmbedderData(LocalContext* env,
2684                               int index,
2685                               v8::Handle<Value> data) {
2686   (*env)->SetEmbedderData(index, data);
2687   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2688 }
2689
2690
2691 THREADED_TEST(EmbedderData) {
2692   LocalContext env;
2693   v8::Isolate* isolate = env->GetIsolate();
2694   v8::HandleScope scope(isolate);
2695
2696   CheckEmbedderData(
2697       &env, 3,
2698       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2699   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2700                                                      "over the lazy dog."));
2701   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2702   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2703 }
2704
2705
2706 THREADED_TEST(IdentityHash) {
2707   LocalContext env;
2708   v8::Isolate* isolate = env->GetIsolate();
2709   v8::HandleScope scope(isolate);
2710
2711   // Ensure that the test starts with an fresh heap to test whether the hash
2712   // code is based on the address.
2713   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2714   Local<v8::Object> obj = v8::Object::New(isolate);
2715   int hash = obj->GetIdentityHash();
2716   int hash1 = obj->GetIdentityHash();
2717   CHECK_EQ(hash, hash1);
2718   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2719   // Since the identity hash is essentially a random number two consecutive
2720   // objects should not be assigned the same hash code. If the test below fails
2721   // the random number generator should be evaluated.
2722   CHECK_NE(hash, hash2);
2723   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2724   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2725   // Make sure that the identity hash is not based on the initial address of
2726   // the object alone. If the test below fails the random number generator
2727   // should be evaluated.
2728   CHECK_NE(hash, hash3);
2729   int hash4 = obj->GetIdentityHash();
2730   CHECK_EQ(hash, hash4);
2731
2732   // Check identity hashes behaviour in the presence of JS accessors.
2733   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2734   {
2735     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2736     Local<v8::Object> o1 = v8::Object::New(isolate);
2737     Local<v8::Object> o2 = v8::Object::New(isolate);
2738     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2739   }
2740   {
2741     CompileRun(
2742         "function cnst() { return 42; };\n"
2743         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2744     Local<v8::Object> o1 = v8::Object::New(isolate);
2745     Local<v8::Object> o2 = v8::Object::New(isolate);
2746     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2747   }
2748 }
2749
2750
2751 THREADED_TEST(GlobalProxyIdentityHash) {
2752   LocalContext env;
2753   v8::Isolate* isolate = env->GetIsolate();
2754   v8::HandleScope scope(isolate);
2755   Handle<Object> global_proxy = env->Global();
2756   int hash1 = global_proxy->GetIdentityHash();
2757   // Hash should be retained after being detached.
2758   env->DetachGlobal();
2759   int hash2 = global_proxy->GetIdentityHash();
2760   CHECK_EQ(hash1, hash2);
2761   {
2762     // Re-attach global proxy to a new context, hash should stay the same.
2763     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2764     int hash3 = global_proxy->GetIdentityHash();
2765     CHECK_EQ(hash1, hash3);
2766   }
2767 }
2768
2769
2770 THREADED_TEST(SymbolProperties) {
2771   i::FLAG_harmony_symbols = true;
2772
2773   LocalContext env;
2774   v8::Isolate* isolate = env->GetIsolate();
2775   v8::HandleScope scope(isolate);
2776
2777   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2778   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2779   v8::Local<v8::Symbol> sym2 =
2780       v8::Symbol::New(isolate, v8_str("my-symbol"));
2781
2782   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2783
2784   // Check basic symbol functionality.
2785   CHECK(sym1->IsSymbol());
2786   CHECK(sym2->IsSymbol());
2787   CHECK(!obj->IsSymbol());
2788
2789   CHECK(sym1->Equals(sym1));
2790   CHECK(sym2->Equals(sym2));
2791   CHECK(!sym1->Equals(sym2));
2792   CHECK(!sym2->Equals(sym1));
2793   CHECK(sym1->StrictEquals(sym1));
2794   CHECK(sym2->StrictEquals(sym2));
2795   CHECK(!sym1->StrictEquals(sym2));
2796   CHECK(!sym2->StrictEquals(sym1));
2797
2798   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2799
2800   v8::Local<v8::Value> sym_val = sym2;
2801   CHECK(sym_val->IsSymbol());
2802   CHECK(sym_val->Equals(sym2));
2803   CHECK(sym_val->StrictEquals(sym2));
2804   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2805
2806   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2807   CHECK(sym_obj->IsSymbolObject());
2808   CHECK(!sym2->IsSymbolObject());
2809   CHECK(!obj->IsSymbolObject());
2810   CHECK(!sym_obj->Equals(sym2));
2811   CHECK(!sym_obj->StrictEquals(sym2));
2812   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2813   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2814
2815   // Make sure delete of a non-existent symbol property works.
2816   CHECK(obj->Delete(sym1));
2817   CHECK(!obj->Has(sym1));
2818
2819   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2820   CHECK(obj->Has(sym1));
2821   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2822   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2823   CHECK(obj->Has(sym1));
2824   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2825   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2826
2827   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2828   int num_props = obj->GetPropertyNames()->Length();
2829   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2830                  v8::Integer::New(isolate, 20)));
2831   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2832   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2833
2834   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2835
2836   // Add another property and delete it afterwards to force the object in
2837   // slow case.
2838   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2839   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2840   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2841   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2842   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2843
2844   CHECK(obj->Has(sym1));
2845   CHECK(obj->Has(sym2));
2846   CHECK(obj->Delete(sym2));
2847   CHECK(obj->Has(sym1));
2848   CHECK(!obj->Has(sym2));
2849   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2850   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2851
2852   // Symbol properties are inherited.
2853   v8::Local<v8::Object> child = v8::Object::New(isolate);
2854   child->SetPrototype(obj);
2855   CHECK(child->Has(sym1));
2856   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2857   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2858 }
2859
2860
2861 THREADED_TEST(PrivateProperties) {
2862   LocalContext env;
2863   v8::Isolate* isolate = env->GetIsolate();
2864   v8::HandleScope scope(isolate);
2865
2866   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2867   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2868   v8::Local<v8::Private> priv2 =
2869       v8::Private::New(isolate, v8_str("my-private"));
2870
2871   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2872
2873   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2874
2875   // Make sure delete of a non-existent private symbol property works.
2876   CHECK(obj->DeletePrivate(priv1));
2877   CHECK(!obj->HasPrivate(priv1));
2878
2879   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2880   CHECK(obj->HasPrivate(priv1));
2881   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2882   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2883   CHECK(obj->HasPrivate(priv1));
2884   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2885
2886   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2887   int num_props = obj->GetPropertyNames()->Length();
2888   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2889                  v8::Integer::New(isolate, 20)));
2890   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2891   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2892
2893   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2894
2895   // Add another property and delete it afterwards to force the object in
2896   // slow case.
2897   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2898   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2899   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2900   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2901   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2902
2903   CHECK(obj->HasPrivate(priv1));
2904   CHECK(obj->HasPrivate(priv2));
2905   CHECK(obj->DeletePrivate(priv2));
2906   CHECK(obj->HasPrivate(priv1));
2907   CHECK(!obj->HasPrivate(priv2));
2908   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2909   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2910
2911   // Private properties are inherited (for the time being).
2912   v8::Local<v8::Object> child = v8::Object::New(isolate);
2913   child->SetPrototype(obj);
2914   CHECK(child->HasPrivate(priv1));
2915   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2916   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2917 }
2918
2919
2920 THREADED_TEST(GlobalSymbols) {
2921   i::FLAG_harmony_symbols = true;
2922
2923   LocalContext env;
2924   v8::Isolate* isolate = env->GetIsolate();
2925   v8::HandleScope scope(isolate);
2926
2927   v8::Local<String> name = v8_str("my-symbol");
2928   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2929   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2930   CHECK(glob2->SameValue(glob));
2931
2932   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2933   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2934   CHECK(glob_api2->SameValue(glob_api));
2935   CHECK(!glob_api->SameValue(glob));
2936
2937   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2938   CHECK(!sym->SameValue(glob));
2939
2940   CompileRun("var sym2 = Symbol.for('my-symbol')");
2941   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2942   CHECK(sym2->SameValue(glob));
2943   CHECK(!sym2->SameValue(glob_api));
2944 }
2945
2946
2947 THREADED_TEST(GlobalPrivates) {
2948   LocalContext env;
2949   v8::Isolate* isolate = env->GetIsolate();
2950   v8::HandleScope scope(isolate);
2951
2952   v8::Local<String> name = v8_str("my-private");
2953   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2954   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2955   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2956
2957   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2958   CHECK(obj->HasPrivate(glob2));
2959
2960   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2961   CHECK(!obj->HasPrivate(priv));
2962
2963   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2964   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2965   CHECK(!obj->Has(intern));
2966 }
2967
2968
2969 class ScopedArrayBufferContents {
2970  public:
2971   explicit ScopedArrayBufferContents(
2972       const v8::ArrayBuffer::Contents& contents)
2973     : contents_(contents) {}
2974   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2975   void* Data() const { return contents_.Data(); }
2976   size_t ByteLength() const { return contents_.ByteLength(); }
2977  private:
2978   const v8::ArrayBuffer::Contents contents_;
2979 };
2980
2981 template <typename T>
2982 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2983   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2984   for (int i = 0; i < value->InternalFieldCount(); i++) {
2985     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2986   }
2987 }
2988
2989
2990 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2991   LocalContext env;
2992   v8::Isolate* isolate = env->GetIsolate();
2993   v8::HandleScope handle_scope(isolate);
2994
2995   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2996   CheckInternalFieldsAreZero(ab);
2997   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2998   CHECK(!ab->IsExternal());
2999   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3000
3001   ScopedArrayBufferContents ab_contents(ab->Externalize());
3002   CHECK(ab->IsExternal());
3003
3004   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3005   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3006   ASSERT(data != NULL);
3007   env->Global()->Set(v8_str("ab"), ab);
3008
3009   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3010   CHECK_EQ(1024, result->Int32Value());
3011
3012   result = CompileRun("var u8 = new Uint8Array(ab);"
3013                       "u8[0] = 0xFF;"
3014                       "u8[1] = 0xAA;"
3015                       "u8.length");
3016   CHECK_EQ(1024, result->Int32Value());
3017   CHECK_EQ(0xFF, data[0]);
3018   CHECK_EQ(0xAA, data[1]);
3019   data[0] = 0xCC;
3020   data[1] = 0x11;
3021   result = CompileRun("u8[0] + u8[1]");
3022   CHECK_EQ(0xDD, result->Int32Value());
3023 }
3024
3025
3026 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3027   LocalContext env;
3028   v8::Isolate* isolate = env->GetIsolate();
3029   v8::HandleScope handle_scope(isolate);
3030
3031
3032   v8::Local<v8::Value> result =
3033       CompileRun("var ab1 = new ArrayBuffer(2);"
3034                  "var u8_a = new Uint8Array(ab1);"
3035                  "u8_a[0] = 0xAA;"
3036                  "u8_a[1] = 0xFF; u8_a.buffer");
3037   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3038   CheckInternalFieldsAreZero(ab1);
3039   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3040   CHECK(!ab1->IsExternal());
3041   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3042   CHECK(ab1->IsExternal());
3043
3044   result = CompileRun("ab1.byteLength");
3045   CHECK_EQ(2, result->Int32Value());
3046   result = CompileRun("u8_a[0]");
3047   CHECK_EQ(0xAA, result->Int32Value());
3048   result = CompileRun("u8_a[1]");
3049   CHECK_EQ(0xFF, result->Int32Value());
3050   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3051                       "u8_b[0] = 0xBB;"
3052                       "u8_a[0]");
3053   CHECK_EQ(0xBB, result->Int32Value());
3054   result = CompileRun("u8_b[1]");
3055   CHECK_EQ(0xFF, result->Int32Value());
3056
3057   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3058   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3059   CHECK_EQ(0xBB, ab1_data[0]);
3060   CHECK_EQ(0xFF, ab1_data[1]);
3061   ab1_data[0] = 0xCC;
3062   ab1_data[1] = 0x11;
3063   result = CompileRun("u8_a[0] + u8_a[1]");
3064   CHECK_EQ(0xDD, result->Int32Value());
3065 }
3066
3067
3068 THREADED_TEST(ArrayBuffer_External) {
3069   LocalContext env;
3070   v8::Isolate* isolate = env->GetIsolate();
3071   v8::HandleScope handle_scope(isolate);
3072
3073   i::ScopedVector<uint8_t> my_data(100);
3074   memset(my_data.start(), 0, 100);
3075   Local<v8::ArrayBuffer> ab3 =
3076       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3077   CheckInternalFieldsAreZero(ab3);
3078   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3079   CHECK(ab3->IsExternal());
3080
3081   env->Global()->Set(v8_str("ab3"), ab3);
3082
3083   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3084   CHECK_EQ(100, result->Int32Value());
3085
3086   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3087                       "u8_b[0] = 0xBB;"
3088                       "u8_b[1] = 0xCC;"
3089                       "u8_b.length");
3090   CHECK_EQ(100, result->Int32Value());
3091   CHECK_EQ(0xBB, my_data[0]);
3092   CHECK_EQ(0xCC, my_data[1]);
3093   my_data[0] = 0xCC;
3094   my_data[1] = 0x11;
3095   result = CompileRun("u8_b[0] + u8_b[1]");
3096   CHECK_EQ(0xDD, result->Int32Value());
3097 }
3098
3099
3100 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3101   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3102   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3103 }
3104
3105
3106 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3107   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3108   CHECK_EQ(0, static_cast<int>(ta->Length()));
3109   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3110 }
3111
3112
3113 static void CheckIsTypedArrayVarNeutered(const char* name) {
3114   i::ScopedVector<char> source(1024);
3115   i::OS::SNPrintF(source,
3116       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3117       name, name, name);
3118   CHECK(CompileRun(source.start())->IsTrue());
3119   v8::Handle<v8::TypedArray> ta =
3120     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3121   CheckIsNeutered(ta);
3122 }
3123
3124
3125 template <typename TypedArray, int kElementSize>
3126 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3127                                          int byteOffset,
3128                                          int length) {
3129   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3130   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3131   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3132   CHECK_EQ(length, static_cast<int>(ta->Length()));
3133   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3134   return ta;
3135 }
3136
3137
3138 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3139   LocalContext env;
3140   v8::Isolate* isolate = env->GetIsolate();
3141   v8::HandleScope handle_scope(isolate);
3142
3143   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3144
3145   v8::Handle<v8::Uint8Array> u8a =
3146     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3147   v8::Handle<v8::Uint8ClampedArray> u8c =
3148     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3149   v8::Handle<v8::Int8Array> i8a =
3150     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3151
3152   v8::Handle<v8::Uint16Array> u16a =
3153     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3154   v8::Handle<v8::Int16Array> i16a =
3155     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3156
3157   v8::Handle<v8::Uint32Array> u32a =
3158     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3159   v8::Handle<v8::Int32Array> i32a =
3160     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3161
3162   v8::Handle<v8::Float32Array> f32a =
3163     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3164   v8::Handle<v8::Float64Array> f64a =
3165     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3166
3167   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3168   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3169   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3170   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3171
3172   ScopedArrayBufferContents contents(buffer->Externalize());
3173   buffer->Neuter();
3174   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3175   CheckIsNeutered(u8a);
3176   CheckIsNeutered(u8c);
3177   CheckIsNeutered(i8a);
3178   CheckIsNeutered(u16a);
3179   CheckIsNeutered(i16a);
3180   CheckIsNeutered(u32a);
3181   CheckIsNeutered(i32a);
3182   CheckIsNeutered(f32a);
3183   CheckIsNeutered(f64a);
3184   CheckDataViewIsNeutered(dv);
3185 }
3186
3187
3188 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3189   LocalContext env;
3190   v8::Isolate* isolate = env->GetIsolate();
3191   v8::HandleScope handle_scope(isolate);
3192
3193   CompileRun(
3194       "var ab = new ArrayBuffer(1024);"
3195       "var u8a = new Uint8Array(ab, 1, 1023);"
3196       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3197       "var i8a = new Int8Array(ab, 1, 1023);"
3198       "var u16a = new Uint16Array(ab, 2, 511);"
3199       "var i16a = new Int16Array(ab, 2, 511);"
3200       "var u32a = new Uint32Array(ab, 4, 255);"
3201       "var i32a = new Int32Array(ab, 4, 255);"
3202       "var f32a = new Float32Array(ab, 4, 255);"
3203       "var f64a = new Float64Array(ab, 8, 127);"
3204       "var dv = new DataView(ab, 1, 1023);");
3205
3206   v8::Handle<v8::ArrayBuffer> ab =
3207       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3208
3209   v8::Handle<v8::DataView> dv =
3210     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3211
3212   ScopedArrayBufferContents contents(ab->Externalize());
3213   ab->Neuter();
3214   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3215   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3216
3217   CheckIsTypedArrayVarNeutered("u8a");
3218   CheckIsTypedArrayVarNeutered("u8c");
3219   CheckIsTypedArrayVarNeutered("i8a");
3220   CheckIsTypedArrayVarNeutered("u16a");
3221   CheckIsTypedArrayVarNeutered("i16a");
3222   CheckIsTypedArrayVarNeutered("u32a");
3223   CheckIsTypedArrayVarNeutered("i32a");
3224   CheckIsTypedArrayVarNeutered("f32a");
3225   CheckIsTypedArrayVarNeutered("f64a");
3226
3227   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3228   CheckDataViewIsNeutered(dv);
3229 }
3230
3231
3232
3233 THREADED_TEST(HiddenProperties) {
3234   LocalContext env;
3235   v8::Isolate* isolate = env->GetIsolate();
3236   v8::HandleScope scope(isolate);
3237
3238   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3239   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3240   v8::Local<v8::String> empty = v8_str("");
3241   v8::Local<v8::String> prop_name = v8_str("prop_name");
3242
3243   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3244
3245   // Make sure delete of a non-existent hidden value works
3246   CHECK(obj->DeleteHiddenValue(key));
3247
3248   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3249   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3250   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3251   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3252
3253   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3254
3255   // Make sure we do not find the hidden property.
3256   CHECK(!obj->Has(empty));
3257   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3258   CHECK(obj->Get(empty)->IsUndefined());
3259   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3260   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3261   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3262   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3263
3264   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3265
3266   // Add another property and delete it afterwards to force the object in
3267   // slow case.
3268   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3269   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3270   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3271   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3272   CHECK(obj->Delete(prop_name));
3273   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3274
3275   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3276
3277   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3278   CHECK(obj->GetHiddenValue(key).IsEmpty());
3279
3280   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3281   CHECK(obj->DeleteHiddenValue(key));
3282   CHECK(obj->GetHiddenValue(key).IsEmpty());
3283 }
3284
3285
3286 THREADED_TEST(Regress97784) {
3287   // Regression test for crbug.com/97784
3288   // Messing with the Object.prototype should not have effect on
3289   // hidden properties.
3290   LocalContext env;
3291   v8::HandleScope scope(env->GetIsolate());
3292
3293   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3294   v8::Local<v8::String> key = v8_str("hidden");
3295
3296   CompileRun(
3297       "set_called = false;"
3298       "Object.defineProperty("
3299       "    Object.prototype,"
3300       "    'hidden',"
3301       "    {get: function() { return 45; },"
3302       "     set: function() { set_called = true; }})");
3303
3304   CHECK(obj->GetHiddenValue(key).IsEmpty());
3305   // Make sure that the getter and setter from Object.prototype is not invoked.
3306   // If it did we would have full access to the hidden properties in
3307   // the accessor.
3308   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3309   ExpectFalse("set_called");
3310   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3311 }
3312
3313
3314 static bool interceptor_for_hidden_properties_called;
3315 static void InterceptorForHiddenProperties(
3316     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3317   interceptor_for_hidden_properties_called = true;
3318 }
3319
3320
3321 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3322   LocalContext context;
3323   v8::Isolate* isolate = context->GetIsolate();
3324   v8::HandleScope scope(isolate);
3325
3326   interceptor_for_hidden_properties_called = false;
3327
3328   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3329
3330   // Associate an interceptor with an object and start setting hidden values.
3331   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3332   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3333   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3334   Local<v8::Function> function = fun_templ->GetFunction();
3335   Local<v8::Object> obj = function->NewInstance();
3336   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3337   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3338   CHECK(!interceptor_for_hidden_properties_called);
3339 }
3340
3341
3342 THREADED_TEST(External) {
3343   v8::HandleScope scope(CcTest::isolate());
3344   int x = 3;
3345   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3346   LocalContext env;
3347   env->Global()->Set(v8_str("ext"), ext);
3348   Local<Value> reext_obj = CompileRun("this.ext");
3349   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3350   int* ptr = static_cast<int*>(reext->Value());
3351   CHECK_EQ(x, 3);
3352   *ptr = 10;
3353   CHECK_EQ(x, 10);
3354
3355   // Make sure unaligned pointers are wrapped properly.
3356   char* data = i::StrDup("0123456789");
3357   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3358   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3359   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3360   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3361
3362   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3363   CHECK_EQ('0', *char_ptr);
3364   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3365   CHECK_EQ('1', *char_ptr);
3366   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3367   CHECK_EQ('2', *char_ptr);
3368   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3369   CHECK_EQ('3', *char_ptr);
3370   i::DeleteArray(data);
3371 }
3372
3373
3374 THREADED_TEST(GlobalHandle) {
3375   v8::Isolate* isolate = CcTest::isolate();
3376   v8::Persistent<String> global;
3377   {
3378     v8::HandleScope scope(isolate);
3379     global.Reset(isolate, v8_str("str"));
3380   }
3381   {
3382     v8::HandleScope scope(isolate);
3383     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3384   }
3385   global.Reset();
3386   {
3387     v8::HandleScope scope(isolate);
3388     global.Reset(isolate, v8_str("str"));
3389   }
3390   {
3391     v8::HandleScope scope(isolate);
3392     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3393   }
3394   global.Reset();
3395 }
3396
3397
3398 THREADED_TEST(ResettingGlobalHandle) {
3399   v8::Isolate* isolate = CcTest::isolate();
3400   v8::Persistent<String> global;
3401   {
3402     v8::HandleScope scope(isolate);
3403     global.Reset(isolate, v8_str("str"));
3404   }
3405   v8::internal::GlobalHandles* global_handles =
3406       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3407   int initial_handle_count = global_handles->global_handles_count();
3408   {
3409     v8::HandleScope scope(isolate);
3410     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3411   }
3412   {
3413     v8::HandleScope scope(isolate);
3414     global.Reset(isolate, v8_str("longer"));
3415   }
3416   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3417   {
3418     v8::HandleScope scope(isolate);
3419     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3420   }
3421   global.Reset();
3422   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3423 }
3424
3425
3426 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3427   v8::Isolate* isolate = CcTest::isolate();
3428   v8::Persistent<String> global;
3429   {
3430     v8::HandleScope scope(isolate);
3431     global.Reset(isolate, v8_str("str"));
3432   }
3433   v8::internal::GlobalHandles* global_handles =
3434       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3435   int initial_handle_count = global_handles->global_handles_count();
3436   {
3437     v8::HandleScope scope(isolate);
3438     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3439   }
3440   {
3441     v8::HandleScope scope(isolate);
3442     Local<String> empty;
3443     global.Reset(isolate, empty);
3444   }
3445   CHECK(global.IsEmpty());
3446   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3447 }
3448
3449
3450 template<class T>
3451 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3452   return unique.Pass();
3453 }
3454
3455
3456 template<class T>
3457 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3458                                             const v8::Persistent<T> & global) {
3459   v8::UniquePersistent<String> unique(isolate, global);
3460   return unique.Pass();
3461 }
3462
3463
3464 THREADED_TEST(UniquePersistent) {
3465   v8::Isolate* isolate = CcTest::isolate();
3466   v8::Persistent<String> global;
3467   {
3468     v8::HandleScope scope(isolate);
3469     global.Reset(isolate, v8_str("str"));
3470   }
3471   v8::internal::GlobalHandles* global_handles =
3472       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3473   int initial_handle_count = global_handles->global_handles_count();
3474   {
3475     v8::UniquePersistent<String> unique(isolate, global);
3476     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3477     // Test assignment via Pass
3478     {
3479       v8::UniquePersistent<String> copy = unique.Pass();
3480       CHECK(unique.IsEmpty());
3481       CHECK(copy == global);
3482       CHECK_EQ(initial_handle_count + 1,
3483                global_handles->global_handles_count());
3484       unique = copy.Pass();
3485     }
3486     // Test ctor via Pass
3487     {
3488       v8::UniquePersistent<String> copy(unique.Pass());
3489       CHECK(unique.IsEmpty());
3490       CHECK(copy == global);
3491       CHECK_EQ(initial_handle_count + 1,
3492                global_handles->global_handles_count());
3493       unique = copy.Pass();
3494     }
3495     // Test pass through function call
3496     {
3497       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3498       CHECK(unique.IsEmpty());
3499       CHECK(copy == global);
3500       CHECK_EQ(initial_handle_count + 1,
3501                global_handles->global_handles_count());
3502       unique = copy.Pass();
3503     }
3504     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3505   }
3506   // Test pass from function call
3507   {
3508     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3509     CHECK(unique == global);
3510     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3511   }
3512   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3513   global.Reset();
3514 }
3515
3516
3517 template<typename K, typename V>
3518 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3519  public:
3520   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3521       MapType;
3522   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3523   struct WeakCallbackDataType {
3524     MapType* map;
3525     K key;
3526   };
3527   static WeakCallbackDataType* WeakCallbackParameter(
3528       MapType* map, const K& key, Local<V> value) {
3529     WeakCallbackDataType* data = new WeakCallbackDataType;
3530     data->map = map;
3531     data->key = key;
3532     return data;
3533   }
3534   static MapType* MapFromWeakCallbackData(
3535       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3536     return data.GetParameter()->map;
3537   }
3538   static K KeyFromWeakCallbackData(
3539       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3540     return data.GetParameter()->key;
3541   }
3542   static void DisposeCallbackData(WeakCallbackDataType* data) {
3543     delete data;
3544   }
3545   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3546       K key) { }
3547 };
3548
3549
3550 template<typename Map>
3551 static void TestPersistentValueMap() {
3552   LocalContext env;
3553   v8::Isolate* isolate = env->GetIsolate();
3554   Map map(isolate);
3555   v8::internal::GlobalHandles* global_handles =
3556       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3557   int initial_handle_count = global_handles->global_handles_count();
3558   CHECK_EQ(0, static_cast<int>(map.Size()));
3559   {
3560     HandleScope scope(isolate);
3561     Local<v8::Object> obj = map.Get(7);
3562     CHECK(obj.IsEmpty());
3563     Local<v8::Object> expected = v8::Object::New(isolate);
3564     map.Set(7, expected);
3565     CHECK_EQ(1, static_cast<int>(map.Size()));
3566     obj = map.Get(7);
3567     CHECK_EQ(expected, obj);
3568     {
3569       typename Map::PersistentValueReference ref = map.GetReference(7);
3570       CHECK_EQ(expected, ref.NewLocal(isolate));
3571     }
3572     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3573     CHECK_EQ(0, static_cast<int>(map.Size()));
3574     CHECK(expected == removed);
3575     removed = map.Remove(7);
3576     CHECK(removed.IsEmpty());
3577     map.Set(8, expected);
3578     CHECK_EQ(1, static_cast<int>(map.Size()));
3579     map.Set(8, expected);
3580     CHECK_EQ(1, static_cast<int>(map.Size()));
3581     {
3582       typename Map::PersistentValueReference ref;
3583       Local<v8::Object> expected2 = v8::Object::New(isolate);
3584       removed = map.Set(8,
3585           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3586       CHECK_EQ(1, static_cast<int>(map.Size()));
3587       CHECK(expected == removed);
3588       CHECK_EQ(expected2, ref.NewLocal(isolate));
3589     }
3590   }
3591   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3592   if (map.IsWeak()) {
3593     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3594         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3595   } else {
3596     map.Clear();
3597   }
3598   CHECK_EQ(0, static_cast<int>(map.Size()));
3599   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3600 }
3601
3602
3603 TEST(PersistentValueMap) {
3604   // Default case, w/o weak callbacks:
3605   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3606
3607   // Custom traits with weak callbacks:
3608   typedef v8::PersistentValueMap<int, v8::Object,
3609       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3610   TestPersistentValueMap<WeakPersistentValueMap>();
3611 }
3612
3613
3614 TEST(PersistentValueVector) {
3615   LocalContext env;
3616   v8::Isolate* isolate = env->GetIsolate();
3617   v8::internal::GlobalHandles* global_handles =
3618       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3619   int handle_count = global_handles->global_handles_count();
3620   HandleScope scope(isolate);
3621
3622   v8::PersistentValueVector<v8::Object> vector(isolate);
3623
3624   Local<v8::Object> obj1 = v8::Object::New(isolate);
3625   Local<v8::Object> obj2 = v8::Object::New(isolate);
3626   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3627
3628   CHECK(vector.IsEmpty());
3629   CHECK_EQ(0, static_cast<int>(vector.Size()));
3630
3631   vector.ReserveCapacity(3);
3632   CHECK(vector.IsEmpty());
3633
3634   vector.Append(obj1);
3635   vector.Append(obj2);
3636   vector.Append(obj1);
3637   vector.Append(obj3.Pass());
3638   vector.Append(obj1);
3639
3640   CHECK(!vector.IsEmpty());
3641   CHECK_EQ(5, static_cast<int>(vector.Size()));
3642   CHECK(obj3.IsEmpty());
3643   CHECK_EQ(obj1, vector.Get(0));
3644   CHECK_EQ(obj1, vector.Get(2));
3645   CHECK_EQ(obj1, vector.Get(4));
3646   CHECK_EQ(obj2, vector.Get(1));
3647
3648   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3649
3650   vector.Clear();
3651   CHECK(vector.IsEmpty());
3652   CHECK_EQ(0, static_cast<int>(vector.Size()));
3653   CHECK_EQ(handle_count, global_handles->global_handles_count());
3654 }
3655
3656
3657 THREADED_TEST(GlobalHandleUpcast) {
3658   v8::Isolate* isolate = CcTest::isolate();
3659   v8::HandleScope scope(isolate);
3660   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3661   v8::Persistent<String> global_string(isolate, local);
3662   v8::Persistent<Value>& global_value =
3663       v8::Persistent<Value>::Cast(global_string);
3664   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3665   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3666   global_string.Reset();
3667 }
3668
3669
3670 THREADED_TEST(HandleEquality) {
3671   v8::Isolate* isolate = CcTest::isolate();
3672   v8::Persistent<String> global1;
3673   v8::Persistent<String> global2;
3674   {
3675     v8::HandleScope scope(isolate);
3676     global1.Reset(isolate, v8_str("str"));
3677     global2.Reset(isolate, v8_str("str2"));
3678   }
3679   CHECK_EQ(global1 == global1, true);
3680   CHECK_EQ(global1 != global1, false);
3681   {
3682     v8::HandleScope scope(isolate);
3683     Local<String> local1 = Local<String>::New(isolate, global1);
3684     Local<String> local2 = Local<String>::New(isolate, global2);
3685
3686     CHECK_EQ(global1 == local1, true);
3687     CHECK_EQ(global1 != local1, false);
3688     CHECK_EQ(local1 == global1, true);
3689     CHECK_EQ(local1 != global1, false);
3690
3691     CHECK_EQ(global1 == local2, false);
3692     CHECK_EQ(global1 != local2, true);
3693     CHECK_EQ(local2 == global1, false);
3694     CHECK_EQ(local2 != global1, true);
3695
3696     CHECK_EQ(local1 == local2, false);
3697     CHECK_EQ(local1 != local2, true);
3698
3699     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3700     CHECK_EQ(local1 == anotherLocal1, true);
3701     CHECK_EQ(local1 != anotherLocal1, false);
3702   }
3703   global1.Reset();
3704   global2.Reset();
3705 }
3706
3707
3708 THREADED_TEST(LocalHandle) {
3709   v8::HandleScope scope(CcTest::isolate());
3710   v8::Local<String> local =
3711       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3712   CHECK_EQ(local->Length(), 3);
3713 }
3714
3715
3716 class WeakCallCounter {
3717  public:
3718   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3719   int id() { return id_; }
3720   void increment() { number_of_weak_calls_++; }
3721   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3722  private:
3723   int id_;
3724   int number_of_weak_calls_;
3725 };
3726
3727
3728 template<typename T>
3729 struct WeakCallCounterAndPersistent {
3730   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3731       : counter(counter) {}
3732   WeakCallCounter* counter;
3733   v8::Persistent<T> handle;
3734 };
3735
3736
3737 template <typename T>
3738 static void WeakPointerCallback(
3739     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3740   CHECK_EQ(1234, data.GetParameter()->counter->id());
3741   data.GetParameter()->counter->increment();
3742   data.GetParameter()->handle.Reset();
3743 }
3744
3745
3746 template<typename T>
3747 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3748   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3749 }
3750
3751
3752 THREADED_TEST(ApiObjectGroups) {
3753   LocalContext env;
3754   v8::Isolate* iso = env->GetIsolate();
3755   HandleScope scope(iso);
3756
3757   WeakCallCounter counter(1234);
3758
3759   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3760   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3761   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3762   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3763   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3764   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3765
3766   {
3767     HandleScope scope(iso);
3768     g1s1.handle.Reset(iso, Object::New(iso));
3769     g1s2.handle.Reset(iso, Object::New(iso));
3770     g1c1.handle.Reset(iso, Object::New(iso));
3771     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3772     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3773     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3774
3775     g2s1.handle.Reset(iso, Object::New(iso));
3776     g2s2.handle.Reset(iso, Object::New(iso));
3777     g2c1.handle.Reset(iso, Object::New(iso));
3778     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3779     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3780     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3781   }
3782
3783   WeakCallCounterAndPersistent<Value> root(&counter);
3784   root.handle.Reset(iso, g1s1.handle);  // make a root.
3785
3786   // Connect group 1 and 2, make a cycle.
3787   {
3788     HandleScope scope(iso);
3789     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3790             Set(0, Local<Value>::New(iso, g2s2.handle)));
3791     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3792             Set(0, Local<Value>::New(iso, g1s1.handle)));
3793   }
3794
3795   {
3796     UniqueId id1 = MakeUniqueId(g1s1.handle);
3797     UniqueId id2 = MakeUniqueId(g2s2.handle);
3798     iso->SetObjectGroupId(g1s1.handle, id1);
3799     iso->SetObjectGroupId(g1s2.handle, id1);
3800     iso->SetReferenceFromGroup(id1, g1c1.handle);
3801     iso->SetObjectGroupId(g2s1.handle, id2);
3802     iso->SetObjectGroupId(g2s2.handle, id2);
3803     iso->SetReferenceFromGroup(id2, g2c1.handle);
3804   }
3805   // Do a single full GC, ensure incremental marking is stopped.
3806   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3807       iso)->heap();
3808   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3809
3810   // All object should be alive.
3811   CHECK_EQ(0, counter.NumberOfWeakCalls());
3812
3813   // Weaken the root.
3814   root.handle.SetWeak(&root, &WeakPointerCallback);
3815   // But make children strong roots---all the objects (except for children)
3816   // should be collectable now.
3817   g1c1.handle.ClearWeak();
3818   g2c1.handle.ClearWeak();
3819
3820   // Groups are deleted, rebuild groups.
3821   {
3822     UniqueId id1 = MakeUniqueId(g1s1.handle);
3823     UniqueId id2 = MakeUniqueId(g2s2.handle);
3824     iso->SetObjectGroupId(g1s1.handle, id1);
3825     iso->SetObjectGroupId(g1s2.handle, id1);
3826     iso->SetReferenceFromGroup(id1, g1c1.handle);
3827     iso->SetObjectGroupId(g2s1.handle, id2);
3828     iso->SetObjectGroupId(g2s2.handle, id2);
3829     iso->SetReferenceFromGroup(id2, g2c1.handle);
3830   }
3831
3832   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3833
3834   // All objects should be gone. 5 global handles in total.
3835   CHECK_EQ(5, counter.NumberOfWeakCalls());
3836
3837   // And now make children weak again and collect them.
3838   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3839   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3840
3841   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3842   CHECK_EQ(7, counter.NumberOfWeakCalls());
3843 }
3844
3845
3846 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3847   LocalContext env;
3848   v8::Isolate* iso = env->GetIsolate();
3849   HandleScope scope(iso);
3850
3851   WeakCallCounter counter(1234);
3852
3853   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3854   WeakCallCounterAndPersistent<String> g1s2(&counter);
3855   WeakCallCounterAndPersistent<String> g1c1(&counter);
3856   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3857   WeakCallCounterAndPersistent<String> g2s2(&counter);
3858   WeakCallCounterAndPersistent<String> g2c1(&counter);
3859
3860   {
3861     HandleScope scope(iso);
3862     g1s1.handle.Reset(iso, Object::New(iso));
3863     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3864     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3865     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3866     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3867     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3868
3869     g2s1.handle.Reset(iso, Object::New(iso));
3870     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3871     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3872     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3873     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3874     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3875   }
3876
3877   WeakCallCounterAndPersistent<Value> root(&counter);
3878   root.handle.Reset(iso, g1s1.handle);  // make a root.
3879
3880   // Connect group 1 and 2, make a cycle.
3881   {
3882     HandleScope scope(iso);
3883     CHECK(Local<Object>::New(iso, g1s1.handle)
3884               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3885     CHECK(Local<Object>::New(iso, g2s1.handle)
3886               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3887   }
3888
3889   {
3890     UniqueId id1 = MakeUniqueId(g1s1.handle);
3891     UniqueId id2 = MakeUniqueId(g2s2.handle);
3892     iso->SetObjectGroupId(g1s1.handle, id1);
3893     iso->SetObjectGroupId(g1s2.handle, id1);
3894     iso->SetReference(g1s1.handle, g1c1.handle);
3895     iso->SetObjectGroupId(g2s1.handle, id2);
3896     iso->SetObjectGroupId(g2s2.handle, id2);
3897     iso->SetReferenceFromGroup(id2, g2c1.handle);
3898   }
3899   // Do a single full GC, ensure incremental marking is stopped.
3900   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3901       iso)->heap();
3902   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3903
3904   // All object should be alive.
3905   CHECK_EQ(0, counter.NumberOfWeakCalls());
3906
3907   // Weaken the root.
3908   root.handle.SetWeak(&root, &WeakPointerCallback);
3909   // But make children strong roots---all the objects (except for children)
3910   // should be collectable now.
3911   g1c1.handle.ClearWeak();
3912   g2c1.handle.ClearWeak();
3913
3914   // Groups are deleted, rebuild groups.
3915   {
3916     UniqueId id1 = MakeUniqueId(g1s1.handle);
3917     UniqueId id2 = MakeUniqueId(g2s2.handle);
3918     iso->SetObjectGroupId(g1s1.handle, id1);
3919     iso->SetObjectGroupId(g1s2.handle, id1);
3920     iso->SetReference(g1s1.handle, g1c1.handle);
3921     iso->SetObjectGroupId(g2s1.handle, id2);
3922     iso->SetObjectGroupId(g2s2.handle, id2);
3923     iso->SetReferenceFromGroup(id2, g2c1.handle);
3924   }
3925
3926   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3927
3928   // All objects should be gone. 5 global handles in total.
3929   CHECK_EQ(5, counter.NumberOfWeakCalls());
3930
3931   // And now make children weak again and collect them.
3932   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3933   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3934
3935   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3936   CHECK_EQ(7, counter.NumberOfWeakCalls());
3937 }
3938
3939
3940 THREADED_TEST(ApiObjectGroupsCycle) {
3941   LocalContext env;
3942   v8::Isolate* iso = env->GetIsolate();
3943   HandleScope scope(iso);
3944
3945   WeakCallCounter counter(1234);
3946
3947   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3948   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3949   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3950   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3951   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3952   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3953   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3954   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3955
3956   {
3957     HandleScope scope(iso);
3958     g1s1.handle.Reset(iso, Object::New(iso));
3959     g1s2.handle.Reset(iso, Object::New(iso));
3960     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3961     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3962     CHECK(g1s1.handle.IsWeak());
3963     CHECK(g1s2.handle.IsWeak());
3964
3965     g2s1.handle.Reset(iso, Object::New(iso));
3966     g2s2.handle.Reset(iso, Object::New(iso));
3967     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3968     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3969     CHECK(g2s1.handle.IsWeak());
3970     CHECK(g2s2.handle.IsWeak());
3971
3972     g3s1.handle.Reset(iso, Object::New(iso));
3973     g3s2.handle.Reset(iso, Object::New(iso));
3974     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3975     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3976     CHECK(g3s1.handle.IsWeak());
3977     CHECK(g3s2.handle.IsWeak());
3978
3979     g4s1.handle.Reset(iso, Object::New(iso));
3980     g4s2.handle.Reset(iso, Object::New(iso));
3981     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3982     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3983     CHECK(g4s1.handle.IsWeak());
3984     CHECK(g4s2.handle.IsWeak());
3985   }
3986
3987   WeakCallCounterAndPersistent<Value> root(&counter);
3988   root.handle.Reset(iso, g1s1.handle);  // make a root.
3989
3990   // Connect groups.  We're building the following cycle:
3991   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3992   // groups.
3993   {
3994     UniqueId id1 = MakeUniqueId(g1s1.handle);
3995     UniqueId id2 = MakeUniqueId(g2s1.handle);
3996     UniqueId id3 = MakeUniqueId(g3s1.handle);
3997     UniqueId id4 = MakeUniqueId(g4s1.handle);
3998     iso->SetObjectGroupId(g1s1.handle, id1);
3999     iso->SetObjectGroupId(g1s2.handle, id1);
4000     iso->SetReferenceFromGroup(id1, g2s1.handle);
4001     iso->SetObjectGroupId(g2s1.handle, id2);
4002     iso->SetObjectGroupId(g2s2.handle, id2);
4003     iso->SetReferenceFromGroup(id2, g3s1.handle);
4004     iso->SetObjectGroupId(g3s1.handle, id3);
4005     iso->SetObjectGroupId(g3s2.handle, id3);
4006     iso->SetReferenceFromGroup(id3, g4s1.handle);
4007     iso->SetObjectGroupId(g4s1.handle, id4);
4008     iso->SetObjectGroupId(g4s2.handle, id4);
4009     iso->SetReferenceFromGroup(id4, g1s1.handle);
4010   }
4011   // Do a single full GC
4012   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4013       iso)->heap();
4014   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4015
4016   // All object should be alive.
4017   CHECK_EQ(0, counter.NumberOfWeakCalls());
4018
4019   // Weaken the root.
4020   root.handle.SetWeak(&root, &WeakPointerCallback);
4021
4022   // Groups are deleted, rebuild groups.
4023   {
4024     UniqueId id1 = MakeUniqueId(g1s1.handle);
4025     UniqueId id2 = MakeUniqueId(g2s1.handle);
4026     UniqueId id3 = MakeUniqueId(g3s1.handle);
4027     UniqueId id4 = MakeUniqueId(g4s1.handle);
4028     iso->SetObjectGroupId(g1s1.handle, id1);
4029     iso->SetObjectGroupId(g1s2.handle, id1);
4030     iso->SetReferenceFromGroup(id1, g2s1.handle);
4031     iso->SetObjectGroupId(g2s1.handle, id2);
4032     iso->SetObjectGroupId(g2s2.handle, id2);
4033     iso->SetReferenceFromGroup(id2, g3s1.handle);
4034     iso->SetObjectGroupId(g3s1.handle, id3);
4035     iso->SetObjectGroupId(g3s2.handle, id3);
4036     iso->SetReferenceFromGroup(id3, g4s1.handle);
4037     iso->SetObjectGroupId(g4s1.handle, id4);
4038     iso->SetObjectGroupId(g4s2.handle, id4);
4039     iso->SetReferenceFromGroup(id4, g1s1.handle);
4040   }
4041
4042   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4043
4044   // All objects should be gone. 9 global handles in total.
4045   CHECK_EQ(9, counter.NumberOfWeakCalls());
4046 }
4047
4048
4049 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4050 // on the buildbots, so was made non-threaded for the time being.
4051 TEST(ApiObjectGroupsCycleForScavenger) {
4052   i::FLAG_stress_compaction = false;
4053   i::FLAG_gc_global = false;
4054   LocalContext env;
4055   v8::Isolate* iso = env->GetIsolate();
4056   HandleScope scope(iso);
4057
4058   WeakCallCounter counter(1234);
4059
4060   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4061   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4062   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4063   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4064   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4065   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4066
4067   {
4068     HandleScope scope(iso);
4069     g1s1.handle.Reset(iso, Object::New(iso));
4070     g1s2.handle.Reset(iso, Object::New(iso));
4071     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4072     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4073
4074     g2s1.handle.Reset(iso, Object::New(iso));
4075     g2s2.handle.Reset(iso, Object::New(iso));
4076     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4077     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4078
4079     g3s1.handle.Reset(iso, Object::New(iso));
4080     g3s2.handle.Reset(iso, Object::New(iso));
4081     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4082     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4083   }
4084
4085   // Make a root.
4086   WeakCallCounterAndPersistent<Value> root(&counter);
4087   root.handle.Reset(iso, g1s1.handle);
4088   root.handle.MarkPartiallyDependent();
4089
4090   // Connect groups.  We're building the following cycle:
4091   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4092   // groups.
4093   {
4094     HandleScope handle_scope(iso);
4095     g1s1.handle.MarkPartiallyDependent();
4096     g1s2.handle.MarkPartiallyDependent();
4097     g2s1.handle.MarkPartiallyDependent();
4098     g2s2.handle.MarkPartiallyDependent();
4099     g3s1.handle.MarkPartiallyDependent();
4100     g3s2.handle.MarkPartiallyDependent();
4101     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4102     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4103     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4104         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4105     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4106     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4107     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4108         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4109     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4110     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4111     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4112         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4113   }
4114
4115   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4116       iso)->heap();
4117   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4118
4119   // All objects should be alive.
4120   CHECK_EQ(0, counter.NumberOfWeakCalls());
4121
4122   // Weaken the root.
4123   root.handle.SetWeak(&root, &WeakPointerCallback);
4124   root.handle.MarkPartiallyDependent();
4125
4126   // Groups are deleted, rebuild groups.
4127   {
4128     HandleScope handle_scope(iso);
4129     g1s1.handle.MarkPartiallyDependent();
4130     g1s2.handle.MarkPartiallyDependent();
4131     g2s1.handle.MarkPartiallyDependent();
4132     g2s2.handle.MarkPartiallyDependent();
4133     g3s1.handle.MarkPartiallyDependent();
4134     g3s2.handle.MarkPartiallyDependent();
4135     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4136     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4137     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4138         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4139     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4140     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4141     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4142         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4143     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4144     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4145     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4146         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4147   }
4148
4149   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4150
4151   // All objects should be gone. 7 global handles in total.
4152   CHECK_EQ(7, counter.NumberOfWeakCalls());
4153 }
4154
4155
4156 THREADED_TEST(ScriptException) {
4157   LocalContext env;
4158   v8::HandleScope scope(env->GetIsolate());
4159   Local<Script> script = v8_compile("throw 'panama!';");
4160   v8::TryCatch try_catch;
4161   Local<Value> result = script->Run();
4162   CHECK(result.IsEmpty());
4163   CHECK(try_catch.HasCaught());
4164   String::Utf8Value exception_value(try_catch.Exception());
4165   CHECK_EQ(*exception_value, "panama!");
4166 }
4167
4168
4169 TEST(TryCatchCustomException) {
4170   LocalContext env;
4171   v8::HandleScope scope(env->GetIsolate());
4172   v8::TryCatch try_catch;
4173   CompileRun("function CustomError() { this.a = 'b'; }"
4174              "(function f() { throw new CustomError(); })();");
4175   CHECK(try_catch.HasCaught());
4176   CHECK(try_catch.Exception()->ToObject()->
4177             Get(v8_str("a"))->Equals(v8_str("b")));
4178 }
4179
4180
4181 bool message_received;
4182
4183
4184 static void check_message_0(v8::Handle<v8::Message> message,
4185                             v8::Handle<Value> data) {
4186   CHECK_EQ(5.76, data->NumberValue());
4187   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4188   CHECK(!message->IsSharedCrossOrigin());
4189   message_received = true;
4190 }
4191
4192
4193 THREADED_TEST(MessageHandler0) {
4194   message_received = false;
4195   v8::HandleScope scope(CcTest::isolate());
4196   CHECK(!message_received);
4197   LocalContext context;
4198   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4199   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4200   script->Run();
4201   CHECK(message_received);
4202   // clear out the message listener
4203   v8::V8::RemoveMessageListeners(check_message_0);
4204 }
4205
4206
4207 static void check_message_1(v8::Handle<v8::Message> message,
4208                             v8::Handle<Value> data) {
4209   CHECK(data->IsNumber());
4210   CHECK_EQ(1337, data->Int32Value());
4211   CHECK(!message->IsSharedCrossOrigin());
4212   message_received = true;
4213 }
4214
4215
4216 TEST(MessageHandler1) {
4217   message_received = false;
4218   v8::HandleScope scope(CcTest::isolate());
4219   CHECK(!message_received);
4220   v8::V8::AddMessageListener(check_message_1);
4221   LocalContext context;
4222   CompileRun("throw 1337;");
4223   CHECK(message_received);
4224   // clear out the message listener
4225   v8::V8::RemoveMessageListeners(check_message_1);
4226 }
4227
4228
4229 static void check_message_2(v8::Handle<v8::Message> message,
4230                             v8::Handle<Value> data) {
4231   LocalContext context;
4232   CHECK(data->IsObject());
4233   v8::Local<v8::Value> hidden_property =
4234       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4235   CHECK(v8_str("hidden value")->Equals(hidden_property));
4236   CHECK(!message->IsSharedCrossOrigin());
4237   message_received = true;
4238 }
4239
4240
4241 TEST(MessageHandler2) {
4242   message_received = false;
4243   v8::HandleScope scope(CcTest::isolate());
4244   CHECK(!message_received);
4245   v8::V8::AddMessageListener(check_message_2);
4246   LocalContext context;
4247   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4248   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4249                                            v8_str("hidden value"));
4250   context->Global()->Set(v8_str("error"), error);
4251   CompileRun("throw error;");
4252   CHECK(message_received);
4253   // clear out the message listener
4254   v8::V8::RemoveMessageListeners(check_message_2);
4255 }
4256
4257
4258 static void check_message_3(v8::Handle<v8::Message> message,
4259                             v8::Handle<Value> data) {
4260   CHECK(message->IsSharedCrossOrigin());
4261   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4262   message_received = true;
4263 }
4264
4265
4266 TEST(MessageHandler3) {
4267   message_received = false;
4268   v8::Isolate* isolate = CcTest::isolate();
4269   v8::HandleScope scope(isolate);
4270   CHECK(!message_received);
4271   v8::V8::AddMessageListener(check_message_3);
4272   LocalContext context;
4273   v8::ScriptOrigin origin =
4274       v8::ScriptOrigin(v8_str("6.75"),
4275                        v8::Integer::New(isolate, 1),
4276                        v8::Integer::New(isolate, 2),
4277                        v8::True(isolate));
4278   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4279                                                   &origin);
4280   script->Run();
4281   CHECK(message_received);
4282   // clear out the message listener
4283   v8::V8::RemoveMessageListeners(check_message_3);
4284 }
4285
4286
4287 static void check_message_4(v8::Handle<v8::Message> message,
4288                             v8::Handle<Value> data) {
4289   CHECK(!message->IsSharedCrossOrigin());
4290   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4291   message_received = true;
4292 }
4293
4294
4295 TEST(MessageHandler4) {
4296   message_received = false;
4297   v8::Isolate* isolate = CcTest::isolate();
4298   v8::HandleScope scope(isolate);
4299   CHECK(!message_received);
4300   v8::V8::AddMessageListener(check_message_4);
4301   LocalContext context;
4302   v8::ScriptOrigin origin =
4303       v8::ScriptOrigin(v8_str("6.75"),
4304                        v8::Integer::New(isolate, 1),
4305                        v8::Integer::New(isolate, 2),
4306                        v8::False(isolate));
4307   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4308                                                   &origin);
4309   script->Run();
4310   CHECK(message_received);
4311   // clear out the message listener
4312   v8::V8::RemoveMessageListeners(check_message_4);
4313 }
4314
4315
4316 static void check_message_5a(v8::Handle<v8::Message> message,
4317                             v8::Handle<Value> data) {
4318   CHECK(message->IsSharedCrossOrigin());
4319   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4320   message_received = true;
4321 }
4322
4323
4324 static void check_message_5b(v8::Handle<v8::Message> message,
4325                             v8::Handle<Value> data) {
4326   CHECK(!message->IsSharedCrossOrigin());
4327   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4328   message_received = true;
4329 }
4330
4331
4332 TEST(MessageHandler5) {
4333   message_received = false;
4334   v8::Isolate* isolate = CcTest::isolate();
4335   v8::HandleScope scope(isolate);
4336   CHECK(!message_received);
4337   v8::V8::AddMessageListener(check_message_5a);
4338   LocalContext context;
4339   v8::ScriptOrigin origin =
4340       v8::ScriptOrigin(v8_str("6.75"),
4341                        v8::Integer::New(isolate, 1),
4342                        v8::Integer::New(isolate, 2),
4343                        v8::True(isolate));
4344   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4345                                                   &origin);
4346   script->Run();
4347   CHECK(message_received);
4348   // clear out the message listener
4349   v8::V8::RemoveMessageListeners(check_message_5a);
4350
4351   message_received = false;
4352   v8::V8::AddMessageListener(check_message_5b);
4353   origin =
4354       v8::ScriptOrigin(v8_str("6.75"),
4355                        v8::Integer::New(isolate, 1),
4356                        v8::Integer::New(isolate, 2),
4357                        v8::False(isolate));
4358   script = Script::Compile(v8_str("throw 'error'"),
4359                            &origin);
4360   script->Run();
4361   CHECK(message_received);
4362   // clear out the message listener
4363   v8::V8::RemoveMessageListeners(check_message_5b);
4364 }
4365
4366
4367 THREADED_TEST(GetSetProperty) {
4368   LocalContext context;
4369   v8::Isolate* isolate = context->GetIsolate();
4370   v8::HandleScope scope(isolate);
4371   context->Global()->Set(v8_str("foo"), v8_num(14));
4372   context->Global()->Set(v8_str("12"), v8_num(92));
4373   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4374   context->Global()->Set(v8_num(13), v8_num(56));
4375   Local<Value> foo = CompileRun("this.foo");
4376   CHECK_EQ(14, foo->Int32Value());
4377   Local<Value> twelve = CompileRun("this[12]");
4378   CHECK_EQ(92, twelve->Int32Value());
4379   Local<Value> sixteen = CompileRun("this[16]");
4380   CHECK_EQ(32, sixteen->Int32Value());
4381   Local<Value> thirteen = CompileRun("this[13]");
4382   CHECK_EQ(56, thirteen->Int32Value());
4383   CHECK_EQ(92,
4384            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4385   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4386   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4387   CHECK_EQ(32,
4388            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4389   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4390   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4391   CHECK_EQ(56,
4392            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4393   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4394   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4395 }
4396
4397
4398 THREADED_TEST(PropertyAttributes) {
4399   LocalContext context;
4400   v8::HandleScope scope(context->GetIsolate());
4401   // none
4402   Local<String> prop = v8_str("none");
4403   context->Global()->Set(prop, v8_num(7));
4404   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4405   // read-only
4406   prop = v8_str("read_only");
4407   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4408   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4409   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4410   CompileRun("read_only = 9");
4411   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4412   context->Global()->Set(prop, v8_num(10));
4413   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4414   // dont-delete
4415   prop = v8_str("dont_delete");
4416   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4417   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4418   CompileRun("delete dont_delete");
4419   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4420   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4421   // dont-enum
4422   prop = v8_str("dont_enum");
4423   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4424   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4425   // absent
4426   prop = v8_str("absent");
4427   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4428   Local<Value> fake_prop = v8_num(1);
4429   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4430   // exception
4431   TryCatch try_catch;
4432   Local<Value> exception =
4433       CompileRun("({ toString: function() { throw 'exception';} })");
4434   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4435   CHECK(try_catch.HasCaught());
4436   String::Utf8Value exception_value(try_catch.Exception());
4437   CHECK_EQ("exception", *exception_value);
4438   try_catch.Reset();
4439 }
4440
4441
4442 THREADED_TEST(Array) {
4443   LocalContext context;
4444   v8::HandleScope scope(context->GetIsolate());
4445   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4446   CHECK_EQ(0, array->Length());
4447   CHECK(array->Get(0)->IsUndefined());
4448   CHECK(!array->Has(0));
4449   CHECK(array->Get(100)->IsUndefined());
4450   CHECK(!array->Has(100));
4451   array->Set(2, v8_num(7));
4452   CHECK_EQ(3, array->Length());
4453   CHECK(!array->Has(0));
4454   CHECK(!array->Has(1));
4455   CHECK(array->Has(2));
4456   CHECK_EQ(7, array->Get(2)->Int32Value());
4457   Local<Value> obj = CompileRun("[1, 2, 3]");
4458   Local<v8::Array> arr = obj.As<v8::Array>();
4459   CHECK_EQ(3, arr->Length());
4460   CHECK_EQ(1, arr->Get(0)->Int32Value());
4461   CHECK_EQ(2, arr->Get(1)->Int32Value());
4462   CHECK_EQ(3, arr->Get(2)->Int32Value());
4463   array = v8::Array::New(context->GetIsolate(), 27);
4464   CHECK_EQ(27, array->Length());
4465   array = v8::Array::New(context->GetIsolate(), -27);
4466   CHECK_EQ(0, array->Length());
4467 }
4468
4469
4470 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4471   v8::EscapableHandleScope scope(args.GetIsolate());
4472   ApiTestFuzzer::Fuzz();
4473   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4474   for (int i = 0; i < args.Length(); i++)
4475     result->Set(i, args[i]);
4476   args.GetReturnValue().Set(scope.Escape(result));
4477 }
4478
4479
4480 THREADED_TEST(Vector) {
4481   v8::Isolate* isolate = CcTest::isolate();
4482   v8::HandleScope scope(isolate);
4483   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4484   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4485   LocalContext context(0, global);
4486
4487   const char* fun = "f()";
4488   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4489   CHECK_EQ(0, a0->Length());
4490
4491   const char* fun2 = "f(11)";
4492   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4493   CHECK_EQ(1, a1->Length());
4494   CHECK_EQ(11, a1->Get(0)->Int32Value());
4495
4496   const char* fun3 = "f(12, 13)";
4497   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4498   CHECK_EQ(2, a2->Length());
4499   CHECK_EQ(12, a2->Get(0)->Int32Value());
4500   CHECK_EQ(13, a2->Get(1)->Int32Value());
4501
4502   const char* fun4 = "f(14, 15, 16)";
4503   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4504   CHECK_EQ(3, a3->Length());
4505   CHECK_EQ(14, a3->Get(0)->Int32Value());
4506   CHECK_EQ(15, a3->Get(1)->Int32Value());
4507   CHECK_EQ(16, a3->Get(2)->Int32Value());
4508
4509   const char* fun5 = "f(17, 18, 19, 20)";
4510   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4511   CHECK_EQ(4, a4->Length());
4512   CHECK_EQ(17, a4->Get(0)->Int32Value());
4513   CHECK_EQ(18, a4->Get(1)->Int32Value());
4514   CHECK_EQ(19, a4->Get(2)->Int32Value());
4515   CHECK_EQ(20, a4->Get(3)->Int32Value());
4516 }
4517
4518
4519 THREADED_TEST(FunctionCall) {
4520   LocalContext context;
4521   v8::Isolate* isolate = context->GetIsolate();
4522   v8::HandleScope scope(isolate);
4523   CompileRun(
4524     "function Foo() {"
4525     "  var result = [];"
4526     "  for (var i = 0; i < arguments.length; i++) {"
4527     "    result.push(arguments[i]);"
4528     "  }"
4529     "  return result;"
4530     "}"
4531     "function ReturnThisSloppy() {"
4532     "  return this;"
4533     "}"
4534     "function ReturnThisStrict() {"
4535     "  'use strict';"
4536     "  return this;"
4537     "}");
4538   Local<Function> Foo =
4539       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4540   Local<Function> ReturnThisSloppy =
4541       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4542   Local<Function> ReturnThisStrict =
4543       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4544
4545   v8::Handle<Value>* args0 = NULL;
4546   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4547   CHECK_EQ(0, a0->Length());
4548
4549   v8::Handle<Value> args1[] = { v8_num(1.1) };
4550   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4551   CHECK_EQ(1, a1->Length());
4552   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4553
4554   v8::Handle<Value> args2[] = { v8_num(2.2),
4555                                 v8_num(3.3) };
4556   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4557   CHECK_EQ(2, a2->Length());
4558   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4559   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4560
4561   v8::Handle<Value> args3[] = { v8_num(4.4),
4562                                 v8_num(5.5),
4563                                 v8_num(6.6) };
4564   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4565   CHECK_EQ(3, a3->Length());
4566   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4567   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4568   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4569
4570   v8::Handle<Value> args4[] = { v8_num(7.7),
4571                                 v8_num(8.8),
4572                                 v8_num(9.9),
4573                                 v8_num(10.11) };
4574   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4575   CHECK_EQ(4, a4->Length());
4576   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4577   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4578   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4579   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4580
4581   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4582   CHECK(r1->StrictEquals(context->Global()));
4583   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4584   CHECK(r2->StrictEquals(context->Global()));
4585   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4586   CHECK(r3->IsNumberObject());
4587   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4588   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4589   CHECK(r4->IsStringObject());
4590   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4591   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4592   CHECK(r5->IsBooleanObject());
4593   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4594
4595   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4596   CHECK(r6->IsUndefined());
4597   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4598   CHECK(r7->IsNull());
4599   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4600   CHECK(r8->StrictEquals(v8_num(42)));
4601   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4602   CHECK(r9->StrictEquals(v8_str("hello")));
4603   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4604   CHECK(r10->StrictEquals(v8::True(isolate)));
4605 }
4606
4607
4608 THREADED_TEST(ConstructCall) {
4609   LocalContext context;
4610   v8::Isolate* isolate = context->GetIsolate();
4611   v8::HandleScope scope(isolate);
4612   CompileRun(
4613     "function Foo() {"
4614     "  var result = [];"
4615     "  for (var i = 0; i < arguments.length; i++) {"
4616     "    result.push(arguments[i]);"
4617     "  }"
4618     "  return result;"
4619     "}");
4620   Local<Function> Foo =
4621       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4622
4623   v8::Handle<Value>* args0 = NULL;
4624   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4625   CHECK_EQ(0, a0->Length());
4626
4627   v8::Handle<Value> args1[] = { v8_num(1.1) };
4628   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4629   CHECK_EQ(1, a1->Length());
4630   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4631
4632   v8::Handle<Value> args2[] = { v8_num(2.2),
4633                                 v8_num(3.3) };
4634   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4635   CHECK_EQ(2, a2->Length());
4636   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4637   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4638
4639   v8::Handle<Value> args3[] = { v8_num(4.4),
4640                                 v8_num(5.5),
4641                                 v8_num(6.6) };
4642   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4643   CHECK_EQ(3, a3->Length());
4644   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4645   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4646   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4647
4648   v8::Handle<Value> args4[] = { v8_num(7.7),
4649                                 v8_num(8.8),
4650                                 v8_num(9.9),
4651                                 v8_num(10.11) };
4652   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4653   CHECK_EQ(4, a4->Length());
4654   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4655   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4656   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4657   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4658 }
4659
4660
4661 static void CheckUncle(v8::TryCatch* try_catch) {
4662   CHECK(try_catch->HasCaught());
4663   String::Utf8Value str_value(try_catch->Exception());
4664   CHECK_EQ(*str_value, "uncle?");
4665   try_catch->Reset();
4666 }
4667
4668
4669 THREADED_TEST(ConversionNumber) {
4670   LocalContext env;
4671   v8::HandleScope scope(env->GetIsolate());
4672   // Very large number.
4673   CompileRun("var obj = Math.pow(2,32) * 1237;");
4674   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4675   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4676   CHECK_EQ(0, obj->ToInt32()->Value());
4677   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4678   // Large number.
4679   CompileRun("var obj = -1234567890123;");
4680   obj = env->Global()->Get(v8_str("obj"));
4681   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4682   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4683   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4684   // Small positive integer.
4685   CompileRun("var obj = 42;");
4686   obj = env->Global()->Get(v8_str("obj"));
4687   CHECK_EQ(42.0, obj->ToNumber()->Value());
4688   CHECK_EQ(42, obj->ToInt32()->Value());
4689   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4690   // Negative integer.
4691   CompileRun("var obj = -37;");
4692   obj = env->Global()->Get(v8_str("obj"));
4693   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4694   CHECK_EQ(-37, obj->ToInt32()->Value());
4695   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4696   // Positive non-int32 integer.
4697   CompileRun("var obj = 0x81234567;");
4698   obj = env->Global()->Get(v8_str("obj"));
4699   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4700   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4701   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4702   // Fraction.
4703   CompileRun("var obj = 42.3;");
4704   obj = env->Global()->Get(v8_str("obj"));
4705   CHECK_EQ(42.3, obj->ToNumber()->Value());
4706   CHECK_EQ(42, obj->ToInt32()->Value());
4707   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4708   // Large negative fraction.
4709   CompileRun("var obj = -5726623061.75;");
4710   obj = env->Global()->Get(v8_str("obj"));
4711   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4712   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4713   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4714 }
4715
4716
4717 THREADED_TEST(isNumberType) {
4718   LocalContext env;
4719   v8::HandleScope scope(env->GetIsolate());
4720   // Very large number.
4721   CompileRun("var obj = Math.pow(2,32) * 1237;");
4722   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4723   CHECK(!obj->IsInt32());
4724   CHECK(!obj->IsUint32());
4725   // Large negative number.
4726   CompileRun("var obj = -1234567890123;");
4727   obj = env->Global()->Get(v8_str("obj"));
4728   CHECK(!obj->IsInt32());
4729   CHECK(!obj->IsUint32());
4730   // Small positive integer.
4731   CompileRun("var obj = 42;");
4732   obj = env->Global()->Get(v8_str("obj"));
4733   CHECK(obj->IsInt32());
4734   CHECK(obj->IsUint32());
4735   // Negative integer.
4736   CompileRun("var obj = -37;");
4737   obj = env->Global()->Get(v8_str("obj"));
4738   CHECK(obj->IsInt32());
4739   CHECK(!obj->IsUint32());
4740   // Positive non-int32 integer.
4741   CompileRun("var obj = 0x81234567;");
4742   obj = env->Global()->Get(v8_str("obj"));
4743   CHECK(!obj->IsInt32());
4744   CHECK(obj->IsUint32());
4745   // Fraction.
4746   CompileRun("var obj = 42.3;");
4747   obj = env->Global()->Get(v8_str("obj"));
4748   CHECK(!obj->IsInt32());
4749   CHECK(!obj->IsUint32());
4750   // Large negative fraction.
4751   CompileRun("var obj = -5726623061.75;");
4752   obj = env->Global()->Get(v8_str("obj"));
4753   CHECK(!obj->IsInt32());
4754   CHECK(!obj->IsUint32());
4755   // Positive zero
4756   CompileRun("var obj = 0.0;");
4757   obj = env->Global()->Get(v8_str("obj"));
4758   CHECK(obj->IsInt32());
4759   CHECK(obj->IsUint32());
4760   // Positive zero
4761   CompileRun("var obj = -0.0;");
4762   obj = env->Global()->Get(v8_str("obj"));
4763   CHECK(!obj->IsInt32());
4764   CHECK(!obj->IsUint32());
4765 }
4766
4767
4768 THREADED_TEST(ConversionException) {
4769   LocalContext env;
4770   v8::Isolate* isolate = env->GetIsolate();
4771   v8::HandleScope scope(isolate);
4772   CompileRun(
4773     "function TestClass() { };"
4774     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4775     "var obj = new TestClass();");
4776   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4777
4778   v8::TryCatch try_catch;
4779
4780   Local<Value> to_string_result = obj->ToString();
4781   CHECK(to_string_result.IsEmpty());
4782   CheckUncle(&try_catch);
4783
4784   Local<Value> to_number_result = obj->ToNumber();
4785   CHECK(to_number_result.IsEmpty());
4786   CheckUncle(&try_catch);
4787
4788   Local<Value> to_integer_result = obj->ToInteger();
4789   CHECK(to_integer_result.IsEmpty());
4790   CheckUncle(&try_catch);
4791
4792   Local<Value> to_uint32_result = obj->ToUint32();
4793   CHECK(to_uint32_result.IsEmpty());
4794   CheckUncle(&try_catch);
4795
4796   Local<Value> to_int32_result = obj->ToInt32();
4797   CHECK(to_int32_result.IsEmpty());
4798   CheckUncle(&try_catch);
4799
4800   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4801   CHECK(to_object_result.IsEmpty());
4802   CHECK(try_catch.HasCaught());
4803   try_catch.Reset();
4804
4805   int32_t int32_value = obj->Int32Value();
4806   CHECK_EQ(0, int32_value);
4807   CheckUncle(&try_catch);
4808
4809   uint32_t uint32_value = obj->Uint32Value();
4810   CHECK_EQ(0, uint32_value);
4811   CheckUncle(&try_catch);
4812
4813   double number_value = obj->NumberValue();
4814   CHECK_NE(0, std::isnan(number_value));
4815   CheckUncle(&try_catch);
4816
4817   int64_t integer_value = obj->IntegerValue();
4818   CHECK_EQ(0.0, static_cast<double>(integer_value));
4819   CheckUncle(&try_catch);
4820 }
4821
4822
4823 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4824   ApiTestFuzzer::Fuzz();
4825   args.GetIsolate()->ThrowException(v8_str("konto"));
4826 }
4827
4828
4829 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4830   if (args.Length() < 1) {
4831     args.GetReturnValue().Set(false);
4832     return;
4833   }
4834   v8::HandleScope scope(args.GetIsolate());
4835   v8::TryCatch try_catch;
4836   Local<Value> result = CompileRun(args[0]->ToString());
4837   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4838   args.GetReturnValue().Set(try_catch.HasCaught());
4839 }
4840
4841
4842 THREADED_TEST(APICatch) {
4843   v8::Isolate* isolate = CcTest::isolate();
4844   v8::HandleScope scope(isolate);
4845   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4846   templ->Set(v8_str("ThrowFromC"),
4847              v8::FunctionTemplate::New(isolate, ThrowFromC));
4848   LocalContext context(0, templ);
4849   CompileRun(
4850     "var thrown = false;"
4851     "try {"
4852     "  ThrowFromC();"
4853     "} catch (e) {"
4854     "  thrown = true;"
4855     "}");
4856   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4857   CHECK(thrown->BooleanValue());
4858 }
4859
4860
4861 THREADED_TEST(APIThrowTryCatch) {
4862   v8::Isolate* isolate = CcTest::isolate();
4863   v8::HandleScope scope(isolate);
4864   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4865   templ->Set(v8_str("ThrowFromC"),
4866              v8::FunctionTemplate::New(isolate, ThrowFromC));
4867   LocalContext context(0, templ);
4868   v8::TryCatch try_catch;
4869   CompileRun("ThrowFromC();");
4870   CHECK(try_catch.HasCaught());
4871 }
4872
4873
4874 // Test that a try-finally block doesn't shadow a try-catch block
4875 // when setting up an external handler.
4876 //
4877 // BUG(271): Some of the exception propagation does not work on the
4878 // ARM simulator because the simulator separates the C++ stack and the
4879 // JS stack.  This test therefore fails on the simulator.  The test is
4880 // not threaded to allow the threading tests to run on the simulator.
4881 TEST(TryCatchInTryFinally) {
4882   v8::Isolate* isolate = CcTest::isolate();
4883   v8::HandleScope scope(isolate);
4884   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4885   templ->Set(v8_str("CCatcher"),
4886              v8::FunctionTemplate::New(isolate, CCatcher));
4887   LocalContext context(0, templ);
4888   Local<Value> result = CompileRun("try {"
4889                                    "  try {"
4890                                    "    CCatcher('throw 7;');"
4891                                    "  } finally {"
4892                                    "  }"
4893                                    "} catch (e) {"
4894                                    "}");
4895   CHECK(result->IsTrue());
4896 }
4897
4898
4899 static void check_reference_error_message(
4900     v8::Handle<v8::Message> message,
4901     v8::Handle<v8::Value> data) {
4902   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4903   CHECK(message->Get()->Equals(v8_str(reference_error)));
4904 }
4905
4906
4907 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4908   ApiTestFuzzer::Fuzz();
4909   CHECK(false);
4910 }
4911
4912
4913 // Test that overwritten methods are not invoked on uncaught exception
4914 // formatting. However, they are invoked when performing normal error
4915 // string conversions.
4916 TEST(APIThrowMessageOverwrittenToString) {
4917   v8::Isolate* isolate = CcTest::isolate();
4918   v8::HandleScope scope(isolate);
4919   v8::V8::AddMessageListener(check_reference_error_message);
4920   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4921   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4922   LocalContext context(NULL, templ);
4923   CompileRun("asdf;");
4924   CompileRun("var limit = {};"
4925              "limit.valueOf = fail;"
4926              "Error.stackTraceLimit = limit;");
4927   CompileRun("asdf");
4928   CompileRun("Array.prototype.pop = fail;");
4929   CompileRun("Object.prototype.hasOwnProperty = fail;");
4930   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4931   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4932   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4933   CompileRun("ReferenceError.prototype.toString ="
4934              "  function() { return 'Whoops' }");
4935   CompileRun("asdf;");
4936   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4937   CompileRun("asdf;");
4938   CompileRun("ReferenceError.prototype.constructor = void 0;");
4939   CompileRun("asdf;");
4940   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4941   CompileRun("asdf;");
4942   CompileRun("ReferenceError.prototype = new Object();");
4943   CompileRun("asdf;");
4944   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4945   CHECK(string->Equals(v8_str("Whoops")));
4946   CompileRun("ReferenceError.prototype.constructor = new Object();"
4947              "ReferenceError.prototype.constructor.name = 1;"
4948              "Number.prototype.toString = function() { return 'Whoops'; };"
4949              "ReferenceError.prototype.toString = Object.prototype.toString;");
4950   CompileRun("asdf;");
4951   v8::V8::RemoveMessageListeners(check_reference_error_message);
4952 }
4953
4954
4955 static void check_custom_error_tostring(
4956     v8::Handle<v8::Message> message,
4957     v8::Handle<v8::Value> data) {
4958   const char* uncaught_error = "Uncaught MyError toString";
4959   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4960 }
4961
4962
4963 TEST(CustomErrorToString) {
4964   LocalContext context;
4965   v8::HandleScope scope(context->GetIsolate());
4966   v8::V8::AddMessageListener(check_custom_error_tostring);
4967   CompileRun(
4968     "function MyError(name, message) {                   "
4969     "  this.name = name;                                 "
4970     "  this.message = message;                           "
4971     "}                                                   "
4972     "MyError.prototype = Object.create(Error.prototype); "
4973     "MyError.prototype.toString = function() {           "
4974     "  return 'MyError toString';                        "
4975     "};                                                  "
4976     "throw new MyError('my name', 'my message');         ");
4977   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4978 }
4979
4980
4981 static void check_custom_error_message(
4982     v8::Handle<v8::Message> message,
4983     v8::Handle<v8::Value> data) {
4984   const char* uncaught_error = "Uncaught MyError: my message";
4985   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4986   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4987 }
4988
4989
4990 TEST(CustomErrorMessage) {
4991   LocalContext context;
4992   v8::HandleScope scope(context->GetIsolate());
4993   v8::V8::AddMessageListener(check_custom_error_message);
4994
4995   // Handlebars.
4996   CompileRun(
4997     "function MyError(msg) {                             "
4998     "  this.name = 'MyError';                            "
4999     "  this.message = msg;                               "
5000     "}                                                   "
5001     "MyError.prototype = new Error();                    "
5002     "throw new MyError('my message');                    ");
5003
5004   // Closure.
5005   CompileRun(
5006     "function MyError(msg) {                             "
5007     "  this.name = 'MyError';                            "
5008     "  this.message = msg;                               "
5009     "}                                                   "
5010     "inherits = function(childCtor, parentCtor) {        "
5011     "    function tempCtor() {};                         "
5012     "    tempCtor.prototype = parentCtor.prototype;      "
5013     "    childCtor.superClass_ = parentCtor.prototype;   "
5014     "    childCtor.prototype = new tempCtor();           "
5015     "    childCtor.prototype.constructor = childCtor;    "
5016     "};                                                  "
5017     "inherits(MyError, Error);                           "
5018     "throw new MyError('my message');                    ");
5019
5020   // Object.create.
5021   CompileRun(
5022     "function MyError(msg) {                             "
5023     "  this.name = 'MyError';                            "
5024     "  this.message = msg;                               "
5025     "}                                                   "
5026     "MyError.prototype = Object.create(Error.prototype); "
5027     "throw new MyError('my message');                    ");
5028
5029   v8::V8::RemoveMessageListeners(check_custom_error_message);
5030 }
5031
5032
5033 static void receive_message(v8::Handle<v8::Message> message,
5034                             v8::Handle<v8::Value> data) {
5035   message->Get();
5036   message_received = true;
5037 }
5038
5039
5040 TEST(APIThrowMessage) {
5041   message_received = false;
5042   v8::Isolate* isolate = CcTest::isolate();
5043   v8::HandleScope scope(isolate);
5044   v8::V8::AddMessageListener(receive_message);
5045   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5046   templ->Set(v8_str("ThrowFromC"),
5047              v8::FunctionTemplate::New(isolate, ThrowFromC));
5048   LocalContext context(0, templ);
5049   CompileRun("ThrowFromC();");
5050   CHECK(message_received);
5051   v8::V8::RemoveMessageListeners(receive_message);
5052 }
5053
5054
5055 TEST(APIThrowMessageAndVerboseTryCatch) {
5056   message_received = false;
5057   v8::Isolate* isolate = CcTest::isolate();
5058   v8::HandleScope scope(isolate);
5059   v8::V8::AddMessageListener(receive_message);
5060   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5061   templ->Set(v8_str("ThrowFromC"),
5062              v8::FunctionTemplate::New(isolate, ThrowFromC));
5063   LocalContext context(0, templ);
5064   v8::TryCatch try_catch;
5065   try_catch.SetVerbose(true);
5066   Local<Value> result = CompileRun("ThrowFromC();");
5067   CHECK(try_catch.HasCaught());
5068   CHECK(result.IsEmpty());
5069   CHECK(message_received);
5070   v8::V8::RemoveMessageListeners(receive_message);
5071 }
5072
5073
5074 TEST(APIStackOverflowAndVerboseTryCatch) {
5075   message_received = false;
5076   LocalContext context;
5077   v8::HandleScope scope(context->GetIsolate());
5078   v8::V8::AddMessageListener(receive_message);
5079   v8::TryCatch try_catch;
5080   try_catch.SetVerbose(true);
5081   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5082   CHECK(try_catch.HasCaught());
5083   CHECK(result.IsEmpty());
5084   CHECK(message_received);
5085   v8::V8::RemoveMessageListeners(receive_message);
5086 }
5087
5088
5089 THREADED_TEST(ExternalScriptException) {
5090   v8::Isolate* isolate = CcTest::isolate();
5091   v8::HandleScope scope(isolate);
5092   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5093   templ->Set(v8_str("ThrowFromC"),
5094              v8::FunctionTemplate::New(isolate, ThrowFromC));
5095   LocalContext context(0, templ);
5096
5097   v8::TryCatch try_catch;
5098   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5099   CHECK(result.IsEmpty());
5100   CHECK(try_catch.HasCaught());
5101   String::Utf8Value exception_value(try_catch.Exception());
5102   CHECK_EQ("konto", *exception_value);
5103 }
5104
5105
5106
5107 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5108   ApiTestFuzzer::Fuzz();
5109   CHECK_EQ(4, args.Length());
5110   int count = args[0]->Int32Value();
5111   int cInterval = args[2]->Int32Value();
5112   if (count == 0) {
5113     args.GetIsolate()->ThrowException(v8_str("FromC"));
5114     return;
5115   } else {
5116     Local<v8::Object> global =
5117         args.GetIsolate()->GetCurrentContext()->Global();
5118     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5119     v8::Handle<Value> argv[] = { v8_num(count - 1),
5120                                  args[1],
5121                                  args[2],
5122                                  args[3] };
5123     if (count % cInterval == 0) {
5124       v8::TryCatch try_catch;
5125       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5126       int expected = args[3]->Int32Value();
5127       if (try_catch.HasCaught()) {
5128         CHECK_EQ(expected, count);
5129         CHECK(result.IsEmpty());
5130         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5131       } else {
5132         CHECK_NE(expected, count);
5133       }
5134       args.GetReturnValue().Set(result);
5135       return;
5136     } else {
5137       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5138       return;
5139     }
5140   }
5141 }
5142
5143
5144 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5145   ApiTestFuzzer::Fuzz();
5146   CHECK_EQ(3, args.Length());
5147   bool equality = args[0]->BooleanValue();
5148   int count = args[1]->Int32Value();
5149   int expected = args[2]->Int32Value();
5150   if (equality) {
5151     CHECK_EQ(count, expected);
5152   } else {
5153     CHECK_NE(count, expected);
5154   }
5155 }
5156
5157
5158 THREADED_TEST(EvalInTryFinally) {
5159   LocalContext context;
5160   v8::HandleScope scope(context->GetIsolate());
5161   v8::TryCatch try_catch;
5162   CompileRun("(function() {"
5163              "  try {"
5164              "    eval('asldkf (*&^&*^');"
5165              "  } finally {"
5166              "    return;"
5167              "  }"
5168              "})()");
5169   CHECK(!try_catch.HasCaught());
5170 }
5171
5172
5173 // This test works by making a stack of alternating JavaScript and C
5174 // activations.  These activations set up exception handlers with regular
5175 // intervals, one interval for C activations and another for JavaScript
5176 // activations.  When enough activations have been created an exception is
5177 // thrown and we check that the right activation catches the exception and that
5178 // no other activations do.  The right activation is always the topmost one with
5179 // a handler, regardless of whether it is in JavaScript or C.
5180 //
5181 // The notation used to describe a test case looks like this:
5182 //
5183 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5184 //
5185 // Each entry is an activation, either JS or C.  The index is the count at that
5186 // level.  Stars identify activations with exception handlers, the @ identifies
5187 // the exception handler that should catch the exception.
5188 //
5189 // BUG(271): Some of the exception propagation does not work on the
5190 // ARM simulator because the simulator separates the C++ stack and the
5191 // JS stack.  This test therefore fails on the simulator.  The test is
5192 // not threaded to allow the threading tests to run on the simulator.
5193 TEST(ExceptionOrder) {
5194   v8::Isolate* isolate = CcTest::isolate();
5195   v8::HandleScope scope(isolate);
5196   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5197   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5198   templ->Set(v8_str("CThrowCountDown"),
5199              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5200   LocalContext context(0, templ);
5201   CompileRun(
5202     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5203     "  if (count == 0) throw 'FromJS';"
5204     "  if (count % jsInterval == 0) {"
5205     "    try {"
5206     "      var value = CThrowCountDown(count - 1,"
5207     "                                  jsInterval,"
5208     "                                  cInterval,"
5209     "                                  expected);"
5210     "      check(false, count, expected);"
5211     "      return value;"
5212     "    } catch (e) {"
5213     "      check(true, count, expected);"
5214     "    }"
5215     "  } else {"
5216     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5217     "  }"
5218     "}");
5219   Local<Function> fun =
5220       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5221
5222   const int argc = 4;
5223   //                             count      jsInterval cInterval  expected
5224
5225   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5226   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5227   fun->Call(fun, argc, a0);
5228
5229   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5230   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5231   fun->Call(fun, argc, a1);
5232
5233   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5234   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5235   fun->Call(fun, argc, a2);
5236
5237   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5238   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5239   fun->Call(fun, argc, a3);
5240
5241   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5242   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5243   fun->Call(fun, argc, a4);
5244
5245   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5246   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5247   fun->Call(fun, argc, a5);
5248 }
5249
5250
5251 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5252   ApiTestFuzzer::Fuzz();
5253   CHECK_EQ(1, args.Length());
5254   args.GetIsolate()->ThrowException(args[0]);
5255 }
5256
5257
5258 THREADED_TEST(ThrowValues) {
5259   v8::Isolate* isolate = CcTest::isolate();
5260   v8::HandleScope scope(isolate);
5261   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5262   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5263   LocalContext context(0, templ);
5264   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5265     "function Run(obj) {"
5266     "  try {"
5267     "    Throw(obj);"
5268     "  } catch (e) {"
5269     "    return e;"
5270     "  }"
5271     "  return 'no exception';"
5272     "}"
5273     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5274   CHECK_EQ(5, result->Length());
5275   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5276   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5277   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5278   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5279   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5280   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5281   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5282 }
5283
5284
5285 THREADED_TEST(CatchZero) {
5286   LocalContext context;
5287   v8::HandleScope scope(context->GetIsolate());
5288   v8::TryCatch try_catch;
5289   CHECK(!try_catch.HasCaught());
5290   CompileRun("throw 10");
5291   CHECK(try_catch.HasCaught());
5292   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5293   try_catch.Reset();
5294   CHECK(!try_catch.HasCaught());
5295   CompileRun("throw 0");
5296   CHECK(try_catch.HasCaught());
5297   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5298 }
5299
5300
5301 THREADED_TEST(CatchExceptionFromWith) {
5302   LocalContext context;
5303   v8::HandleScope scope(context->GetIsolate());
5304   v8::TryCatch try_catch;
5305   CHECK(!try_catch.HasCaught());
5306   CompileRun("var o = {}; with (o) { throw 42; }");
5307   CHECK(try_catch.HasCaught());
5308 }
5309
5310
5311 THREADED_TEST(TryCatchAndFinallyHidingException) {
5312   LocalContext context;
5313   v8::HandleScope scope(context->GetIsolate());
5314   v8::TryCatch try_catch;
5315   CHECK(!try_catch.HasCaught());
5316   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5317   CompileRun("f({toString: function() { throw 42; }});");
5318   CHECK(!try_catch.HasCaught());
5319 }
5320
5321
5322 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5323   v8::TryCatch try_catch;
5324 }
5325
5326
5327 THREADED_TEST(TryCatchAndFinally) {
5328   LocalContext context;
5329   v8::Isolate* isolate = context->GetIsolate();
5330   v8::HandleScope scope(isolate);
5331   context->Global()->Set(
5332       v8_str("native_with_try_catch"),
5333       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5334   v8::TryCatch try_catch;
5335   CHECK(!try_catch.HasCaught());
5336   CompileRun(
5337       "try {\n"
5338       "  throw new Error('a');\n"
5339       "} finally {\n"
5340       "  native_with_try_catch();\n"
5341       "}\n");
5342   CHECK(try_catch.HasCaught());
5343 }
5344
5345
5346 static void TryCatchNestedHelper(int depth) {
5347   if (depth > 0) {
5348     v8::TryCatch try_catch;
5349     try_catch.SetVerbose(true);
5350     TryCatchNestedHelper(depth - 1);
5351     CHECK(try_catch.HasCaught());
5352     try_catch.ReThrow();
5353   } else {
5354     CcTest::isolate()->ThrowException(v8_str("back"));
5355   }
5356 }
5357
5358
5359 TEST(TryCatchNested) {
5360   v8::V8::Initialize();
5361   LocalContext context;
5362   v8::HandleScope scope(context->GetIsolate());
5363   v8::TryCatch try_catch;
5364   TryCatchNestedHelper(5);
5365   CHECK(try_catch.HasCaught());
5366   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5367 }
5368
5369
5370 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5371   CHECK(try_catch->HasCaught());
5372   Handle<Message> message = try_catch->Message();
5373   Handle<Value> resource = message->GetScriptResourceName();
5374   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5375   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5376                      "Uncaught Error: a"));
5377   CHECK_EQ(1, message->GetLineNumber());
5378   CHECK_EQ(6, message->GetStartColumn());
5379 }
5380
5381
5382 void TryCatchMixedNestingHelper(
5383     const v8::FunctionCallbackInfo<v8::Value>& args) {
5384   ApiTestFuzzer::Fuzz();
5385   v8::TryCatch try_catch;
5386   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5387   CHECK(try_catch.HasCaught());
5388   TryCatchMixedNestingCheck(&try_catch);
5389   try_catch.ReThrow();
5390 }
5391
5392
5393 // This test ensures that an outer TryCatch in the following situation:
5394 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5395 // does not clobber the Message object generated for the inner TryCatch.
5396 // This exercises the ability of TryCatch.ReThrow() to restore the
5397 // inner pending Message before throwing the exception again.
5398 TEST(TryCatchMixedNesting) {
5399   v8::Isolate* isolate = CcTest::isolate();
5400   v8::HandleScope scope(isolate);
5401   v8::V8::Initialize();
5402   v8::TryCatch try_catch;
5403   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5404   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5405              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5406   LocalContext context(0, templ);
5407   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5408   TryCatchMixedNestingCheck(&try_catch);
5409 }
5410
5411
5412 THREADED_TEST(Equality) {
5413   LocalContext context;
5414   v8::Isolate* isolate = context->GetIsolate();
5415   v8::HandleScope scope(context->GetIsolate());
5416   // Check that equality works at all before relying on CHECK_EQ
5417   CHECK(v8_str("a")->Equals(v8_str("a")));
5418   CHECK(!v8_str("a")->Equals(v8_str("b")));
5419
5420   CHECK_EQ(v8_str("a"), v8_str("a"));
5421   CHECK_NE(v8_str("a"), v8_str("b"));
5422   CHECK_EQ(v8_num(1), v8_num(1));
5423   CHECK_EQ(v8_num(1.00), v8_num(1));
5424   CHECK_NE(v8_num(1), v8_num(2));
5425
5426   // Assume String is not internalized.
5427   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5428   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5429   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5430   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5431   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5432   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5433   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5434   CHECK(!not_a_number->StrictEquals(not_a_number));
5435   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5436   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5437
5438   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5439   v8::Persistent<v8::Object> alias(isolate, obj);
5440   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5441   alias.Reset();
5442
5443   CHECK(v8_str("a")->SameValue(v8_str("a")));
5444   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5445   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5446   CHECK(v8_num(1)->SameValue(v8_num(1)));
5447   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5448   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5449   CHECK(not_a_number->SameValue(not_a_number));
5450   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5451   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5452 }
5453
5454
5455 THREADED_TEST(MultiRun) {
5456   LocalContext context;
5457   v8::HandleScope scope(context->GetIsolate());
5458   Local<Script> script = v8_compile("x");
5459   for (int i = 0; i < 10; i++)
5460     script->Run();
5461 }
5462
5463
5464 static void GetXValue(Local<String> name,
5465                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5466   ApiTestFuzzer::Fuzz();
5467   CHECK_EQ(info.Data(), v8_str("donut"));
5468   CHECK_EQ(name, v8_str("x"));
5469   info.GetReturnValue().Set(name);
5470 }
5471
5472
5473 THREADED_TEST(SimplePropertyRead) {
5474   LocalContext context;
5475   v8::Isolate* isolate = context->GetIsolate();
5476   v8::HandleScope scope(isolate);
5477   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5478   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5479   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5480   Local<Script> script = v8_compile("obj.x");
5481   for (int i = 0; i < 10; i++) {
5482     Local<Value> result = script->Run();
5483     CHECK_EQ(result, v8_str("x"));
5484   }
5485 }
5486
5487
5488 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5489   LocalContext context;
5490   v8::Isolate* isolate = context->GetIsolate();
5491   v8::HandleScope scope(isolate);
5492   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5493   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5494   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5495
5496   // Uses getOwnPropertyDescriptor to check the configurable status
5497   Local<Script> script_desc = v8_compile(
5498       "var prop = Object.getOwnPropertyDescriptor( "
5499       "obj, 'x');"
5500       "prop.configurable;");
5501   Local<Value> result = script_desc->Run();
5502   CHECK_EQ(result->BooleanValue(), true);
5503
5504   // Redefine get - but still configurable
5505   Local<Script> script_define = v8_compile(
5506       "var desc = { get: function(){return 42; },"
5507       "            configurable: true };"
5508       "Object.defineProperty(obj, 'x', desc);"
5509       "obj.x");
5510   result = script_define->Run();
5511   CHECK_EQ(result, v8_num(42));
5512
5513   // Check that the accessor is still configurable
5514   result = script_desc->Run();
5515   CHECK_EQ(result->BooleanValue(), true);
5516
5517   // Redefine to a non-configurable
5518   script_define = v8_compile(
5519       "var desc = { get: function(){return 43; },"
5520       "             configurable: false };"
5521       "Object.defineProperty(obj, 'x', desc);"
5522       "obj.x");
5523   result = script_define->Run();
5524   CHECK_EQ(result, v8_num(43));
5525   result = script_desc->Run();
5526   CHECK_EQ(result->BooleanValue(), false);
5527
5528   // Make sure that it is not possible to redefine again
5529   v8::TryCatch try_catch;
5530   result = script_define->Run();
5531   CHECK(try_catch.HasCaught());
5532   String::Utf8Value exception_value(try_catch.Exception());
5533   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5534 }
5535
5536
5537 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5538   v8::Isolate* isolate = CcTest::isolate();
5539   v8::HandleScope scope(isolate);
5540   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5541   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5542   LocalContext context;
5543   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5544
5545   Local<Script> script_desc = v8_compile(
5546       "var prop ="
5547       "Object.getOwnPropertyDescriptor( "
5548       "obj, 'x');"
5549       "prop.configurable;");
5550   Local<Value> result = script_desc->Run();
5551   CHECK_EQ(result->BooleanValue(), true);
5552
5553   Local<Script> script_define = v8_compile(
5554       "var desc = {get: function(){return 42; },"
5555       "            configurable: true };"
5556       "Object.defineProperty(obj, 'x', desc);"
5557       "obj.x");
5558   result = script_define->Run();
5559   CHECK_EQ(result, v8_num(42));
5560
5561
5562   result = script_desc->Run();
5563   CHECK_EQ(result->BooleanValue(), true);
5564
5565
5566   script_define = v8_compile(
5567       "var desc = {get: function(){return 43; },"
5568       "            configurable: false };"
5569       "Object.defineProperty(obj, 'x', desc);"
5570       "obj.x");
5571   result = script_define->Run();
5572   CHECK_EQ(result, v8_num(43));
5573   result = script_desc->Run();
5574
5575   CHECK_EQ(result->BooleanValue(), false);
5576
5577   v8::TryCatch try_catch;
5578   result = script_define->Run();
5579   CHECK(try_catch.HasCaught());
5580   String::Utf8Value exception_value(try_catch.Exception());
5581   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5582 }
5583
5584
5585 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5586                                                 char const* name) {
5587   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5588 }
5589
5590
5591 THREADED_TEST(DefineAPIAccessorOnObject) {
5592   v8::Isolate* isolate = CcTest::isolate();
5593   v8::HandleScope scope(isolate);
5594   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5595   LocalContext context;
5596
5597   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5598   CompileRun("var obj2 = {};");
5599
5600   CHECK(CompileRun("obj1.x")->IsUndefined());
5601   CHECK(CompileRun("obj2.x")->IsUndefined());
5602
5603   CHECK(GetGlobalProperty(&context, "obj1")->
5604       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5605
5606   ExpectString("obj1.x", "x");
5607   CHECK(CompileRun("obj2.x")->IsUndefined());
5608
5609   CHECK(GetGlobalProperty(&context, "obj2")->
5610       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5611
5612   ExpectString("obj1.x", "x");
5613   ExpectString("obj2.x", "x");
5614
5615   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5616   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5617
5618   CompileRun("Object.defineProperty(obj1, 'x',"
5619              "{ get: function() { return 'y'; }, configurable: true })");
5620
5621   ExpectString("obj1.x", "y");
5622   ExpectString("obj2.x", "x");
5623
5624   CompileRun("Object.defineProperty(obj2, 'x',"
5625              "{ get: function() { return 'y'; }, configurable: true })");
5626
5627   ExpectString("obj1.x", "y");
5628   ExpectString("obj2.x", "y");
5629
5630   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5631   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5632
5633   CHECK(GetGlobalProperty(&context, "obj1")->
5634       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5635   CHECK(GetGlobalProperty(&context, "obj2")->
5636       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5637
5638   ExpectString("obj1.x", "x");
5639   ExpectString("obj2.x", "x");
5640
5641   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5642   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5643
5644   // Define getters/setters, but now make them not configurable.
5645   CompileRun("Object.defineProperty(obj1, 'x',"
5646              "{ get: function() { return 'z'; }, configurable: false })");
5647   CompileRun("Object.defineProperty(obj2, 'x',"
5648              "{ get: function() { return 'z'; }, configurable: false })");
5649
5650   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5651   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5652
5653   ExpectString("obj1.x", "z");
5654   ExpectString("obj2.x", "z");
5655
5656   CHECK(!GetGlobalProperty(&context, "obj1")->
5657       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5658   CHECK(!GetGlobalProperty(&context, "obj2")->
5659       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5660
5661   ExpectString("obj1.x", "z");
5662   ExpectString("obj2.x", "z");
5663 }
5664
5665
5666 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5667   v8::Isolate* isolate = CcTest::isolate();
5668   v8::HandleScope scope(isolate);
5669   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5670   LocalContext context;
5671
5672   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5673   CompileRun("var obj2 = {};");
5674
5675   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5676         v8_str("x"),
5677         GetXValue, NULL,
5678         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5679   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5680         v8_str("x"),
5681         GetXValue, NULL,
5682         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5683
5684   ExpectString("obj1.x", "x");
5685   ExpectString("obj2.x", "x");
5686
5687   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5688   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5689
5690   CHECK(!GetGlobalProperty(&context, "obj1")->
5691       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5692   CHECK(!GetGlobalProperty(&context, "obj2")->
5693       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5694
5695   {
5696     v8::TryCatch try_catch;
5697     CompileRun("Object.defineProperty(obj1, 'x',"
5698         "{get: function() { return 'func'; }})");
5699     CHECK(try_catch.HasCaught());
5700     String::Utf8Value exception_value(try_catch.Exception());
5701     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5702   }
5703   {
5704     v8::TryCatch try_catch;
5705     CompileRun("Object.defineProperty(obj2, 'x',"
5706         "{get: function() { return 'func'; }})");
5707     CHECK(try_catch.HasCaught());
5708     String::Utf8Value exception_value(try_catch.Exception());
5709     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5710   }
5711 }
5712
5713
5714 static void Get239Value(Local<String> name,
5715                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5716   ApiTestFuzzer::Fuzz();
5717   CHECK_EQ(info.Data(), v8_str("donut"));
5718   CHECK_EQ(name, v8_str("239"));
5719   info.GetReturnValue().Set(name);
5720 }
5721
5722
5723 THREADED_TEST(ElementAPIAccessor) {
5724   v8::Isolate* isolate = CcTest::isolate();
5725   v8::HandleScope scope(isolate);
5726   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5727   LocalContext context;
5728
5729   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5730   CompileRun("var obj2 = {};");
5731
5732   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5733         v8_str("239"),
5734         Get239Value, NULL,
5735         v8_str("donut")));
5736   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5737         v8_str("239"),
5738         Get239Value, NULL,
5739         v8_str("donut")));
5740
5741   ExpectString("obj1[239]", "239");
5742   ExpectString("obj2[239]", "239");
5743   ExpectString("obj1['239']", "239");
5744   ExpectString("obj2['239']", "239");
5745 }
5746
5747
5748 v8::Persistent<Value> xValue;
5749
5750
5751 static void SetXValue(Local<String> name,
5752                       Local<Value> value,
5753                       const v8::PropertyCallbackInfo<void>& info) {
5754   CHECK_EQ(value, v8_num(4));
5755   CHECK_EQ(info.Data(), v8_str("donut"));
5756   CHECK_EQ(name, v8_str("x"));
5757   CHECK(xValue.IsEmpty());
5758   xValue.Reset(info.GetIsolate(), value);
5759 }
5760
5761
5762 THREADED_TEST(SimplePropertyWrite) {
5763   v8::Isolate* isolate = CcTest::isolate();
5764   v8::HandleScope scope(isolate);
5765   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5766   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5767   LocalContext context;
5768   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5769   Local<Script> script = v8_compile("obj.x = 4");
5770   for (int i = 0; i < 10; i++) {
5771     CHECK(xValue.IsEmpty());
5772     script->Run();
5773     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5774     xValue.Reset();
5775   }
5776 }
5777
5778
5779 THREADED_TEST(SetterOnly) {
5780   v8::Isolate* isolate = CcTest::isolate();
5781   v8::HandleScope scope(isolate);
5782   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5783   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5784   LocalContext context;
5785   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5786   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5787   for (int i = 0; i < 10; i++) {
5788     CHECK(xValue.IsEmpty());
5789     script->Run();
5790     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5791     xValue.Reset();
5792   }
5793 }
5794
5795
5796 THREADED_TEST(NoAccessors) {
5797   v8::Isolate* isolate = CcTest::isolate();
5798   v8::HandleScope scope(isolate);
5799   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5800   templ->SetAccessor(v8_str("x"),
5801                      static_cast<v8::AccessorGetterCallback>(NULL),
5802                      NULL,
5803                      v8_str("donut"));
5804   LocalContext context;
5805   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5806   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5807   for (int i = 0; i < 10; i++) {
5808     script->Run();
5809   }
5810 }
5811
5812
5813 static void XPropertyGetter(Local<String> property,
5814                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5815   ApiTestFuzzer::Fuzz();
5816   CHECK(info.Data()->IsUndefined());
5817   info.GetReturnValue().Set(property);
5818 }
5819
5820
5821 THREADED_TEST(NamedInterceptorPropertyRead) {
5822   v8::Isolate* isolate = CcTest::isolate();
5823   v8::HandleScope scope(isolate);
5824   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5825   templ->SetNamedPropertyHandler(XPropertyGetter);
5826   LocalContext context;
5827   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5828   Local<Script> script = v8_compile("obj.x");
5829   for (int i = 0; i < 10; i++) {
5830     Local<Value> result = script->Run();
5831     CHECK_EQ(result, v8_str("x"));
5832   }
5833 }
5834
5835
5836 THREADED_TEST(NamedInterceptorDictionaryIC) {
5837   v8::Isolate* isolate = CcTest::isolate();
5838   v8::HandleScope scope(isolate);
5839   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5840   templ->SetNamedPropertyHandler(XPropertyGetter);
5841   LocalContext context;
5842   // Create an object with a named interceptor.
5843   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5844   Local<Script> script = v8_compile("interceptor_obj.x");
5845   for (int i = 0; i < 10; i++) {
5846     Local<Value> result = script->Run();
5847     CHECK_EQ(result, v8_str("x"));
5848   }
5849   // Create a slow case object and a function accessing a property in
5850   // that slow case object (with dictionary probing in generated
5851   // code). Then force object with a named interceptor into slow-case,
5852   // pass it to the function, and check that the interceptor is called
5853   // instead of accessing the local property.
5854   Local<Value> result =
5855       CompileRun("function get_x(o) { return o.x; };"
5856                  "var obj = { x : 42, y : 0 };"
5857                  "delete obj.y;"
5858                  "for (var i = 0; i < 10; i++) get_x(obj);"
5859                  "interceptor_obj.x = 42;"
5860                  "interceptor_obj.y = 10;"
5861                  "delete interceptor_obj.y;"
5862                  "get_x(interceptor_obj)");
5863   CHECK_EQ(result, v8_str("x"));
5864 }
5865
5866
5867 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5868   v8::Isolate* isolate = CcTest::isolate();
5869   v8::HandleScope scope(isolate);
5870   v8::Local<Context> context1 = Context::New(isolate);
5871
5872   context1->Enter();
5873   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5874   templ->SetNamedPropertyHandler(XPropertyGetter);
5875   // Create an object with a named interceptor.
5876   v8::Local<v8::Object> object = templ->NewInstance();
5877   context1->Global()->Set(v8_str("interceptor_obj"), object);
5878
5879   // Force the object into the slow case.
5880   CompileRun("interceptor_obj.y = 0;"
5881              "delete interceptor_obj.y;");
5882   context1->Exit();
5883
5884   {
5885     // Introduce the object into a different context.
5886     // Repeat named loads to exercise ICs.
5887     LocalContext context2;
5888     context2->Global()->Set(v8_str("interceptor_obj"), object);
5889     Local<Value> result =
5890       CompileRun("function get_x(o) { return o.x; }"
5891                  "interceptor_obj.x = 42;"
5892                  "for (var i=0; i != 10; i++) {"
5893                  "  get_x(interceptor_obj);"
5894                  "}"
5895                  "get_x(interceptor_obj)");
5896     // Check that the interceptor was actually invoked.
5897     CHECK_EQ(result, v8_str("x"));
5898   }
5899
5900   // Return to the original context and force some object to the slow case
5901   // to cause the NormalizedMapCache to verify.
5902   context1->Enter();
5903   CompileRun("var obj = { x : 0 }; delete obj.x;");
5904   context1->Exit();
5905 }
5906
5907
5908 static void SetXOnPrototypeGetter(
5909     Local<String> property,
5910     const v8::PropertyCallbackInfo<v8::Value>& info) {
5911   // Set x on the prototype object and do not handle the get request.
5912   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5913   proto.As<v8::Object>()->Set(v8_str("x"),
5914                               v8::Integer::New(info.GetIsolate(), 23));
5915 }
5916
5917
5918 // This is a regression test for http://crbug.com/20104. Map
5919 // transitions should not interfere with post interceptor lookup.
5920 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5921   v8::Isolate* isolate = CcTest::isolate();
5922   v8::HandleScope scope(isolate);
5923   Local<v8::FunctionTemplate> function_template =
5924       v8::FunctionTemplate::New(isolate);
5925   Local<v8::ObjectTemplate> instance_template
5926       = function_template->InstanceTemplate();
5927   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5928   LocalContext context;
5929   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5930   // Create an instance of F and introduce a map transition for x.
5931   CompileRun("var o = new F(); o.x = 23;");
5932   // Create an instance of F and invoke the getter. The result should be 23.
5933   Local<Value> result = CompileRun("o = new F(); o.x");
5934   CHECK_EQ(result->Int32Value(), 23);
5935 }
5936
5937
5938 static void IndexedPropertyGetter(
5939     uint32_t index,
5940     const v8::PropertyCallbackInfo<v8::Value>& info) {
5941   ApiTestFuzzer::Fuzz();
5942   if (index == 37) {
5943     info.GetReturnValue().Set(v8_num(625));
5944   }
5945 }
5946
5947
5948 static void IndexedPropertySetter(
5949     uint32_t index,
5950     Local<Value> value,
5951     const v8::PropertyCallbackInfo<v8::Value>& info) {
5952   ApiTestFuzzer::Fuzz();
5953   if (index == 39) {
5954     info.GetReturnValue().Set(value);
5955   }
5956 }
5957
5958
5959 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5960   v8::Isolate* isolate = CcTest::isolate();
5961   v8::HandleScope scope(isolate);
5962   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5963   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5964                                    IndexedPropertySetter);
5965   LocalContext context;
5966   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5967   Local<Script> getter_script = v8_compile(
5968       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5969   Local<Script> setter_script = v8_compile(
5970       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5971       "obj[17] = 23;"
5972       "obj.foo;");
5973   Local<Script> interceptor_setter_script = v8_compile(
5974       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5975       "obj[39] = 47;"
5976       "obj.foo;");  // This setter should not run, due to the interceptor.
5977   Local<Script> interceptor_getter_script = v8_compile(
5978       "obj[37];");
5979   Local<Value> result = getter_script->Run();
5980   CHECK_EQ(v8_num(5), result);
5981   result = setter_script->Run();
5982   CHECK_EQ(v8_num(23), result);
5983   result = interceptor_setter_script->Run();
5984   CHECK_EQ(v8_num(23), result);
5985   result = interceptor_getter_script->Run();
5986   CHECK_EQ(v8_num(625), result);
5987 }
5988
5989
5990 static void UnboxedDoubleIndexedPropertyGetter(
5991     uint32_t index,
5992     const v8::PropertyCallbackInfo<v8::Value>& info) {
5993   ApiTestFuzzer::Fuzz();
5994   if (index < 25) {
5995     info.GetReturnValue().Set(v8_num(index));
5996   }
5997 }
5998
5999
6000 static void UnboxedDoubleIndexedPropertySetter(
6001     uint32_t index,
6002     Local<Value> value,
6003     const v8::PropertyCallbackInfo<v8::Value>& info) {
6004   ApiTestFuzzer::Fuzz();
6005   if (index < 25) {
6006     info.GetReturnValue().Set(v8_num(index));
6007   }
6008 }
6009
6010
6011 void UnboxedDoubleIndexedPropertyEnumerator(
6012     const v8::PropertyCallbackInfo<v8::Array>& info) {
6013   // Force the list of returned keys to be stored in a FastDoubleArray.
6014   Local<Script> indexed_property_names_script = v8_compile(
6015       "keys = new Array(); keys[125000] = 1;"
6016       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6017       "keys.length = 25; keys;");
6018   Local<Value> result = indexed_property_names_script->Run();
6019   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6020 }
6021
6022
6023 // Make sure that the the interceptor code in the runtime properly handles
6024 // merging property name lists for double-array-backed arrays.
6025 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6026   v8::Isolate* isolate = CcTest::isolate();
6027   v8::HandleScope scope(isolate);
6028   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6029   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6030                                    UnboxedDoubleIndexedPropertySetter,
6031                                    0,
6032                                    0,
6033                                    UnboxedDoubleIndexedPropertyEnumerator);
6034   LocalContext context;
6035   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6036   // When obj is created, force it to be Stored in a FastDoubleArray.
6037   Local<Script> create_unboxed_double_script = v8_compile(
6038       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6039       "key_count = 0; "
6040       "for (x in obj) {key_count++;};"
6041       "obj;");
6042   Local<Value> result = create_unboxed_double_script->Run();
6043   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6044   Local<Script> key_count_check = v8_compile("key_count;");
6045   result = key_count_check->Run();
6046   CHECK_EQ(v8_num(40013), result);
6047 }
6048
6049
6050 void SloppyArgsIndexedPropertyEnumerator(
6051     const v8::PropertyCallbackInfo<v8::Array>& info) {
6052   // Force the list of returned keys to be stored in a Arguments object.
6053   Local<Script> indexed_property_names_script = v8_compile(
6054       "function f(w,x) {"
6055       " return arguments;"
6056       "}"
6057       "keys = f(0, 1, 2, 3);"
6058       "keys;");
6059   Local<Object> result =
6060       Local<Object>::Cast(indexed_property_names_script->Run());
6061   // Have to populate the handle manually, as it's not Cast-able.
6062   i::Handle<i::JSObject> o =
6063       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6064   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6065   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6066 }
6067
6068
6069 static void SloppyIndexedPropertyGetter(
6070     uint32_t index,
6071     const v8::PropertyCallbackInfo<v8::Value>& info) {
6072   ApiTestFuzzer::Fuzz();
6073   if (index < 4) {
6074     info.GetReturnValue().Set(v8_num(index));
6075   }
6076 }
6077
6078
6079 // Make sure that the the interceptor code in the runtime properly handles
6080 // merging property name lists for non-string arguments arrays.
6081 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6082   v8::Isolate* isolate = CcTest::isolate();
6083   v8::HandleScope scope(isolate);
6084   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6085   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6086                                    0,
6087                                    0,
6088                                    0,
6089                                    SloppyArgsIndexedPropertyEnumerator);
6090   LocalContext context;
6091   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6092   Local<Script> create_args_script = v8_compile(
6093       "var key_count = 0;"
6094       "for (x in obj) {key_count++;} key_count;");
6095   Local<Value> result = create_args_script->Run();
6096   CHECK_EQ(v8_num(4), result);
6097 }
6098
6099
6100 static void IdentityIndexedPropertyGetter(
6101     uint32_t index,
6102     const v8::PropertyCallbackInfo<v8::Value>& info) {
6103   info.GetReturnValue().Set(index);
6104 }
6105
6106
6107 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6108   v8::Isolate* isolate = CcTest::isolate();
6109   v8::HandleScope scope(isolate);
6110   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6111   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6112
6113   LocalContext context;
6114   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6115
6116   // Check fast object case.
6117   const char* fast_case_code =
6118       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6119   ExpectString(fast_case_code, "0");
6120
6121   // Check slow case.
6122   const char* slow_case_code =
6123       "obj.x = 1; delete obj.x;"
6124       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6125   ExpectString(slow_case_code, "1");
6126 }
6127
6128
6129 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6130   v8::Isolate* isolate = CcTest::isolate();
6131   v8::HandleScope scope(isolate);
6132   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6133   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6134
6135   LocalContext context;
6136   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6137
6138   const char* code =
6139       "try {"
6140       "  obj[0] = 239;"
6141       "  for (var i = 0; i < 100; i++) {"
6142       "    var v = obj[0];"
6143       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6144       "  }"
6145       "  'PASSED'"
6146       "} catch(e) {"
6147       "  e"
6148       "}";
6149   ExpectString(code, "PASSED");
6150 }
6151
6152
6153 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6154   v8::Isolate* isolate = CcTest::isolate();
6155   v8::HandleScope scope(isolate);
6156   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6157   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6158
6159   LocalContext context;
6160   Local<v8::Object> obj = templ->NewInstance();
6161   obj->TurnOnAccessCheck();
6162   context->Global()->Set(v8_str("obj"), obj);
6163
6164   const char* code =
6165       "try {"
6166       "  for (var i = 0; i < 100; i++) {"
6167       "    var v = obj[0];"
6168       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6169       "  }"
6170       "  'PASSED'"
6171       "} catch(e) {"
6172       "  e"
6173       "}";
6174   ExpectString(code, "PASSED");
6175 }
6176
6177
6178 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6179   i::FLAG_allow_natives_syntax = true;
6180   v8::Isolate* isolate = CcTest::isolate();
6181   v8::HandleScope scope(isolate);
6182   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6183   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6184
6185   LocalContext context;
6186   Local<v8::Object> obj = templ->NewInstance();
6187   context->Global()->Set(v8_str("obj"), obj);
6188
6189   const char* code =
6190       "try {"
6191       "  for (var i = 0; i < 100; i++) {"
6192       "    var expected = i;"
6193       "    if (i == 5) {"
6194       "      %EnableAccessChecks(obj);"
6195       "      expected = undefined;"
6196       "    }"
6197       "    var v = obj[i];"
6198       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6199       "    if (i == 5) %DisableAccessChecks(obj);"
6200       "  }"
6201       "  'PASSED'"
6202       "} catch(e) {"
6203       "  e"
6204       "}";
6205   ExpectString(code, "PASSED");
6206 }
6207
6208
6209 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6210   v8::Isolate* isolate = CcTest::isolate();
6211   v8::HandleScope scope(isolate);
6212   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6213   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6214
6215   LocalContext context;
6216   Local<v8::Object> obj = templ->NewInstance();
6217   context->Global()->Set(v8_str("obj"), obj);
6218
6219   const char* code =
6220       "try {"
6221       "  for (var i = 0; i < 100; i++) {"
6222       "    var v = obj[i];"
6223       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6224       "  }"
6225       "  'PASSED'"
6226       "} catch(e) {"
6227       "  e"
6228       "}";
6229   ExpectString(code, "PASSED");
6230 }
6231
6232
6233 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6234   v8::Isolate* isolate = CcTest::isolate();
6235   v8::HandleScope scope(isolate);
6236   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6237   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6238
6239   LocalContext context;
6240   Local<v8::Object> obj = templ->NewInstance();
6241   context->Global()->Set(v8_str("obj"), obj);
6242
6243   const char* code =
6244       "try {"
6245       "  for (var i = 0; i < 100; i++) {"
6246       "    var expected = i;"
6247       "    var key = i;"
6248       "    if (i == 25) {"
6249       "       key = -1;"
6250       "       expected = undefined;"
6251       "    }"
6252       "    if (i == 50) {"
6253       "       /* probe minimal Smi number on 32-bit platforms */"
6254       "       key = -(1 << 30);"
6255       "       expected = undefined;"
6256       "    }"
6257       "    if (i == 75) {"
6258       "       /* probe minimal Smi number on 64-bit platforms */"
6259       "       key = 1 << 31;"
6260       "       expected = undefined;"
6261       "    }"
6262       "    var v = obj[key];"
6263       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6264       "  }"
6265       "  'PASSED'"
6266       "} catch(e) {"
6267       "  e"
6268       "}";
6269   ExpectString(code, "PASSED");
6270 }
6271
6272
6273 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6274   v8::Isolate* isolate = CcTest::isolate();
6275   v8::HandleScope scope(isolate);
6276   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6277   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6278
6279   LocalContext context;
6280   Local<v8::Object> obj = templ->NewInstance();
6281   context->Global()->Set(v8_str("obj"), obj);
6282
6283   const char* code =
6284       "try {"
6285       "  for (var i = 0; i < 100; i++) {"
6286       "    var expected = i;"
6287       "    var key = i;"
6288       "    if (i == 50) {"
6289       "       key = 'foobar';"
6290       "       expected = undefined;"
6291       "    }"
6292       "    var v = obj[key];"
6293       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6294       "  }"
6295       "  'PASSED'"
6296       "} catch(e) {"
6297       "  e"
6298       "}";
6299   ExpectString(code, "PASSED");
6300 }
6301
6302
6303 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
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 == 50) {"
6319       "       obj = {50: 'foobar'};"
6320       "       expected = 'foobar';"
6321       "    }"
6322       "    var v = obj[i];"
6323       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6324       "    if (i == 50) obj = original;"
6325       "  }"
6326       "  'PASSED'"
6327       "} catch(e) {"
6328       "  e"
6329       "}";
6330   ExpectString(code, "PASSED");
6331 }
6332
6333
6334 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
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 original = obj;"
6346       "try {"
6347       "  for (var i = 0; i < 100; i++) {"
6348       "    var expected = i;"
6349       "    if (i == 5) {"
6350       "       obj = 239;"
6351       "       expected = undefined;"
6352       "    }"
6353       "    var v = obj[i];"
6354       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6355       "    if (i == 5) obj = original;"
6356       "  }"
6357       "  'PASSED'"
6358       "} catch(e) {"
6359       "  e"
6360       "}";
6361   ExpectString(code, "PASSED");
6362 }
6363
6364
6365 THREADED_TEST(IndexedInterceptorOnProto) {
6366   v8::Isolate* isolate = CcTest::isolate();
6367   v8::HandleScope scope(isolate);
6368   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6369   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6370
6371   LocalContext context;
6372   Local<v8::Object> obj = templ->NewInstance();
6373   context->Global()->Set(v8_str("obj"), obj);
6374
6375   const char* code =
6376       "var o = {__proto__: obj};"
6377       "try {"
6378       "  for (var i = 0; i < 100; i++) {"
6379       "    var v = o[i];"
6380       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6381       "  }"
6382       "  'PASSED'"
6383       "} catch(e) {"
6384       "  e"
6385       "}";
6386   ExpectString(code, "PASSED");
6387 }
6388
6389
6390 THREADED_TEST(MultiContexts) {
6391   v8::Isolate* isolate = CcTest::isolate();
6392   v8::HandleScope scope(isolate);
6393   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6394   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6395                                                         DummyCallHandler));
6396
6397   Local<String> password = v8_str("Password");
6398
6399   // Create an environment
6400   LocalContext context0(0, templ);
6401   context0->SetSecurityToken(password);
6402   v8::Handle<v8::Object> global0 = context0->Global();
6403   global0->Set(v8_str("custom"), v8_num(1234));
6404   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6405
6406   // Create an independent environment
6407   LocalContext context1(0, templ);
6408   context1->SetSecurityToken(password);
6409   v8::Handle<v8::Object> global1 = context1->Global();
6410   global1->Set(v8_str("custom"), v8_num(1234));
6411   CHECK_NE(global0, global1);
6412   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6413   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6414
6415   // Now create a new context with the old global
6416   LocalContext context2(0, templ, global1);
6417   context2->SetSecurityToken(password);
6418   v8::Handle<v8::Object> global2 = context2->Global();
6419   CHECK_EQ(global1, global2);
6420   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6421   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6422 }
6423
6424
6425 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6426   // Make sure that functions created by cloning boilerplates cannot
6427   // communicate through their __proto__ field.
6428
6429   v8::HandleScope scope(CcTest::isolate());
6430
6431   LocalContext env0;
6432   v8::Handle<v8::Object> global0 =
6433       env0->Global();
6434   v8::Handle<v8::Object> object0 =
6435       global0->Get(v8_str("Object")).As<v8::Object>();
6436   v8::Handle<v8::Object> tostring0 =
6437       object0->Get(v8_str("toString")).As<v8::Object>();
6438   v8::Handle<v8::Object> proto0 =
6439       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6440   proto0->Set(v8_str("custom"), v8_num(1234));
6441
6442   LocalContext env1;
6443   v8::Handle<v8::Object> global1 =
6444       env1->Global();
6445   v8::Handle<v8::Object> object1 =
6446       global1->Get(v8_str("Object")).As<v8::Object>();
6447   v8::Handle<v8::Object> tostring1 =
6448       object1->Get(v8_str("toString")).As<v8::Object>();
6449   v8::Handle<v8::Object> proto1 =
6450       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6451   CHECK(!proto1->Has(v8_str("custom")));
6452 }
6453
6454
6455 THREADED_TEST(Regress892105) {
6456   // Make sure that object and array literals created by cloning
6457   // boilerplates cannot communicate through their __proto__
6458   // field. This is rather difficult to check, but we try to add stuff
6459   // to Object.prototype and Array.prototype and create a new
6460   // environment. This should succeed.
6461
6462   v8::HandleScope scope(CcTest::isolate());
6463
6464   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6465                                 "Array.prototype.arr = 4567;"
6466                                 "8901");
6467
6468   LocalContext env0;
6469   Local<Script> script0 = v8_compile(source);
6470   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6471
6472   LocalContext env1;
6473   Local<Script> script1 = v8_compile(source);
6474   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6475 }
6476
6477
6478 THREADED_TEST(UndetectableObject) {
6479   LocalContext env;
6480   v8::HandleScope scope(env->GetIsolate());
6481
6482   Local<v8::FunctionTemplate> desc =
6483       v8::FunctionTemplate::New(env->GetIsolate());
6484   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6485
6486   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6487   env->Global()->Set(v8_str("undetectable"), obj);
6488
6489   ExpectString("undetectable.toString()", "[object Object]");
6490   ExpectString("typeof undetectable", "undefined");
6491   ExpectString("typeof(undetectable)", "undefined");
6492   ExpectBoolean("typeof undetectable == 'undefined'", true);
6493   ExpectBoolean("typeof undetectable == 'object'", false);
6494   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6495   ExpectBoolean("!undetectable", true);
6496
6497   ExpectObject("true&&undetectable", obj);
6498   ExpectBoolean("false&&undetectable", false);
6499   ExpectBoolean("true||undetectable", true);
6500   ExpectObject("false||undetectable", obj);
6501
6502   ExpectObject("undetectable&&true", obj);
6503   ExpectObject("undetectable&&false", obj);
6504   ExpectBoolean("undetectable||true", true);
6505   ExpectBoolean("undetectable||false", false);
6506
6507   ExpectBoolean("undetectable==null", true);
6508   ExpectBoolean("null==undetectable", true);
6509   ExpectBoolean("undetectable==undefined", true);
6510   ExpectBoolean("undefined==undetectable", true);
6511   ExpectBoolean("undetectable==undetectable", true);
6512
6513
6514   ExpectBoolean("undetectable===null", false);
6515   ExpectBoolean("null===undetectable", false);
6516   ExpectBoolean("undetectable===undefined", false);
6517   ExpectBoolean("undefined===undetectable", false);
6518   ExpectBoolean("undetectable===undetectable", true);
6519 }
6520
6521
6522 THREADED_TEST(VoidLiteral) {
6523   LocalContext env;
6524   v8::Isolate* isolate = env->GetIsolate();
6525   v8::HandleScope scope(isolate);
6526
6527   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6528   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6529
6530   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6531   env->Global()->Set(v8_str("undetectable"), obj);
6532
6533   ExpectBoolean("undefined == void 0", true);
6534   ExpectBoolean("undetectable == void 0", true);
6535   ExpectBoolean("null == void 0", true);
6536   ExpectBoolean("undefined === void 0", true);
6537   ExpectBoolean("undetectable === void 0", false);
6538   ExpectBoolean("null === void 0", false);
6539
6540   ExpectBoolean("void 0 == undefined", true);
6541   ExpectBoolean("void 0 == undetectable", true);
6542   ExpectBoolean("void 0 == null", true);
6543   ExpectBoolean("void 0 === undefined", true);
6544   ExpectBoolean("void 0 === undetectable", false);
6545   ExpectBoolean("void 0 === null", false);
6546
6547   ExpectString("(function() {"
6548                "  try {"
6549                "    return x === void 0;"
6550                "  } catch(e) {"
6551                "    return e.toString();"
6552                "  }"
6553                "})()",
6554                "ReferenceError: x is not defined");
6555   ExpectString("(function() {"
6556                "  try {"
6557                "    return void 0 === x;"
6558                "  } catch(e) {"
6559                "    return e.toString();"
6560                "  }"
6561                "})()",
6562                "ReferenceError: x is not defined");
6563 }
6564
6565
6566 THREADED_TEST(ExtensibleOnUndetectable) {
6567   LocalContext env;
6568   v8::Isolate* isolate = env->GetIsolate();
6569   v8::HandleScope scope(isolate);
6570
6571   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6572   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6573
6574   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6575   env->Global()->Set(v8_str("undetectable"), obj);
6576
6577   Local<String> source = v8_str("undetectable.x = 42;"
6578                                 "undetectable.x");
6579
6580   Local<Script> script = v8_compile(source);
6581
6582   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6583
6584   ExpectBoolean("Object.isExtensible(undetectable)", true);
6585
6586   source = v8_str("Object.preventExtensions(undetectable);");
6587   script = v8_compile(source);
6588   script->Run();
6589   ExpectBoolean("Object.isExtensible(undetectable)", false);
6590
6591   source = v8_str("undetectable.y = 2000;");
6592   script = v8_compile(source);
6593   script->Run();
6594   ExpectBoolean("undetectable.y == undefined", true);
6595 }
6596
6597
6598
6599 THREADED_TEST(UndetectableString) {
6600   LocalContext env;
6601   v8::HandleScope scope(env->GetIsolate());
6602
6603   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6604                                           String::kUndetectableString);
6605   env->Global()->Set(v8_str("undetectable"), obj);
6606
6607   ExpectString("undetectable", "foo");
6608   ExpectString("typeof undetectable", "undefined");
6609   ExpectString("typeof(undetectable)", "undefined");
6610   ExpectBoolean("typeof undetectable == 'undefined'", true);
6611   ExpectBoolean("typeof undetectable == 'string'", false);
6612   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6613   ExpectBoolean("!undetectable", true);
6614
6615   ExpectObject("true&&undetectable", obj);
6616   ExpectBoolean("false&&undetectable", false);
6617   ExpectBoolean("true||undetectable", true);
6618   ExpectObject("false||undetectable", obj);
6619
6620   ExpectObject("undetectable&&true", obj);
6621   ExpectObject("undetectable&&false", obj);
6622   ExpectBoolean("undetectable||true", true);
6623   ExpectBoolean("undetectable||false", false);
6624
6625   ExpectBoolean("undetectable==null", true);
6626   ExpectBoolean("null==undetectable", true);
6627   ExpectBoolean("undetectable==undefined", true);
6628   ExpectBoolean("undefined==undetectable", true);
6629   ExpectBoolean("undetectable==undetectable", true);
6630
6631
6632   ExpectBoolean("undetectable===null", false);
6633   ExpectBoolean("null===undetectable", false);
6634   ExpectBoolean("undetectable===undefined", false);
6635   ExpectBoolean("undefined===undetectable", false);
6636   ExpectBoolean("undetectable===undetectable", true);
6637 }
6638
6639
6640 TEST(UndetectableOptimized) {
6641   i::FLAG_allow_natives_syntax = true;
6642   LocalContext env;
6643   v8::HandleScope scope(env->GetIsolate());
6644
6645   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6646                                           String::kUndetectableString);
6647   env->Global()->Set(v8_str("undetectable"), obj);
6648   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6649
6650   ExpectString(
6651       "function testBranch() {"
6652       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6653       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6654       "}\n"
6655       "function testBool() {"
6656       "  var b1 = !%_IsUndetectableObject(undetectable);"
6657       "  var b2 = %_IsUndetectableObject(detectable);"
6658       "  if (b1) throw 3;"
6659       "  if (b2) throw 4;"
6660       "  return b1 == b2;"
6661       "}\n"
6662       "%OptimizeFunctionOnNextCall(testBranch);"
6663       "%OptimizeFunctionOnNextCall(testBool);"
6664       "for (var i = 0; i < 10; i++) {"
6665       "  testBranch();"
6666       "  testBool();"
6667       "}\n"
6668       "\"PASS\"",
6669       "PASS");
6670 }
6671
6672
6673 template <typename T> static void USE(T) { }
6674
6675
6676 // The point of this test is type checking. We run it only so compilers
6677 // don't complain about an unused function.
6678 TEST(PersistentHandles) {
6679   LocalContext env;
6680   v8::Isolate* isolate = CcTest::isolate();
6681   v8::HandleScope scope(isolate);
6682   Local<String> str = v8_str("foo");
6683   v8::Persistent<String> p_str(isolate, str);
6684   p_str.Reset();
6685   Local<Script> scr = v8_compile("");
6686   v8::Persistent<Script> p_scr(isolate, scr);
6687   p_scr.Reset();
6688   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6689   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6690   p_templ.Reset();
6691 }
6692
6693
6694 static void HandleLogDelegator(
6695     const v8::FunctionCallbackInfo<v8::Value>& args) {
6696   ApiTestFuzzer::Fuzz();
6697 }
6698
6699
6700 THREADED_TEST(GlobalObjectTemplate) {
6701   v8::Isolate* isolate = CcTest::isolate();
6702   v8::HandleScope handle_scope(isolate);
6703   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6704   global_template->Set(v8_str("JSNI_Log"),
6705                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6706   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6707   Context::Scope context_scope(context);
6708   CompileRun("JSNI_Log('LOG')");
6709 }
6710
6711
6712 static const char* kSimpleExtensionSource =
6713   "function Foo() {"
6714   "  return 4;"
6715   "}";
6716
6717
6718 TEST(SimpleExtensions) {
6719   v8::HandleScope handle_scope(CcTest::isolate());
6720   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6721   const char* extension_names[] = { "simpletest" };
6722   v8::ExtensionConfiguration extensions(1, extension_names);
6723   v8::Handle<Context> context =
6724       Context::New(CcTest::isolate(), &extensions);
6725   Context::Scope lock(context);
6726   v8::Handle<Value> result = CompileRun("Foo()");
6727   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6728 }
6729
6730
6731 TEST(NullExtensions) {
6732   v8::HandleScope handle_scope(CcTest::isolate());
6733   v8::RegisterExtension(new Extension("nulltest", NULL));
6734   const char* extension_names[] = { "nulltest" };
6735   v8::ExtensionConfiguration extensions(1, extension_names);
6736   v8::Handle<Context> context =
6737       Context::New(CcTest::isolate(), &extensions);
6738   Context::Scope lock(context);
6739   v8::Handle<Value> result = CompileRun("1+3");
6740   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6741 }
6742
6743
6744 static const char* kEmbeddedExtensionSource =
6745     "function Ret54321(){return 54321;}~~@@$"
6746     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6747 static const int kEmbeddedExtensionSourceValidLen = 34;
6748
6749
6750 TEST(ExtensionMissingSourceLength) {
6751   v8::HandleScope handle_scope(CcTest::isolate());
6752   v8::RegisterExtension(new Extension("srclentest_fail",
6753                                       kEmbeddedExtensionSource));
6754   const char* extension_names[] = { "srclentest_fail" };
6755   v8::ExtensionConfiguration extensions(1, extension_names);
6756   v8::Handle<Context> context =
6757       Context::New(CcTest::isolate(), &extensions);
6758   CHECK_EQ(0, *context);
6759 }
6760
6761
6762 TEST(ExtensionWithSourceLength) {
6763   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6764        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6765     v8::HandleScope handle_scope(CcTest::isolate());
6766     i::ScopedVector<char> extension_name(32);
6767     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6768     v8::RegisterExtension(new Extension(extension_name.start(),
6769                                         kEmbeddedExtensionSource, 0, 0,
6770                                         source_len));
6771     const char* extension_names[1] = { extension_name.start() };
6772     v8::ExtensionConfiguration extensions(1, extension_names);
6773     v8::Handle<Context> context =
6774       Context::New(CcTest::isolate(), &extensions);
6775     if (source_len == kEmbeddedExtensionSourceValidLen) {
6776       Context::Scope lock(context);
6777       v8::Handle<Value> result = CompileRun("Ret54321()");
6778       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6779     } else {
6780       // Anything but exactly the right length should fail to compile.
6781       CHECK_EQ(0, *context);
6782     }
6783   }
6784 }
6785
6786
6787 static const char* kEvalExtensionSource1 =
6788   "function UseEval1() {"
6789   "  var x = 42;"
6790   "  return eval('x');"
6791   "}";
6792
6793
6794 static const char* kEvalExtensionSource2 =
6795   "(function() {"
6796   "  var x = 42;"
6797   "  function e() {"
6798   "    return eval('x');"
6799   "  }"
6800   "  this.UseEval2 = e;"
6801   "})()";
6802
6803
6804 TEST(UseEvalFromExtension) {
6805   v8::HandleScope handle_scope(CcTest::isolate());
6806   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6807   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6808   const char* extension_names[] = { "evaltest1", "evaltest2" };
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("UseEval1()");
6814   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6815   result = CompileRun("UseEval2()");
6816   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6817 }
6818
6819
6820 static const char* kWithExtensionSource1 =
6821   "function UseWith1() {"
6822   "  var x = 42;"
6823   "  with({x:87}) { return x; }"
6824   "}";
6825
6826
6827
6828 static const char* kWithExtensionSource2 =
6829   "(function() {"
6830   "  var x = 42;"
6831   "  function e() {"
6832   "    with ({x:87}) { return x; }"
6833   "  }"
6834   "  this.UseWith2 = e;"
6835   "})()";
6836
6837
6838 TEST(UseWithFromExtension) {
6839   v8::HandleScope handle_scope(CcTest::isolate());
6840   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6841   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6842   const char* extension_names[] = { "withtest1", "withtest2" };
6843   v8::ExtensionConfiguration extensions(2, extension_names);
6844   v8::Handle<Context> context =
6845       Context::New(CcTest::isolate(), &extensions);
6846   Context::Scope lock(context);
6847   v8::Handle<Value> result = CompileRun("UseWith1()");
6848   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6849   result = CompileRun("UseWith2()");
6850   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6851 }
6852
6853
6854 TEST(AutoExtensions) {
6855   v8::HandleScope handle_scope(CcTest::isolate());
6856   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6857   extension->set_auto_enable(true);
6858   v8::RegisterExtension(extension);
6859   v8::Handle<Context> context =
6860       Context::New(CcTest::isolate());
6861   Context::Scope lock(context);
6862   v8::Handle<Value> result = CompileRun("Foo()");
6863   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6864 }
6865
6866
6867 static const char* kSyntaxErrorInExtensionSource =
6868     "[";
6869
6870
6871 // Test that a syntax error in an extension does not cause a fatal
6872 // error but results in an empty context.
6873 TEST(SyntaxErrorExtensions) {
6874   v8::HandleScope handle_scope(CcTest::isolate());
6875   v8::RegisterExtension(new Extension("syntaxerror",
6876                                       kSyntaxErrorInExtensionSource));
6877   const char* extension_names[] = { "syntaxerror" };
6878   v8::ExtensionConfiguration extensions(1, extension_names);
6879   v8::Handle<Context> context =
6880       Context::New(CcTest::isolate(), &extensions);
6881   CHECK(context.IsEmpty());
6882 }
6883
6884
6885 static const char* kExceptionInExtensionSource =
6886     "throw 42";
6887
6888
6889 // Test that an exception when installing an extension does not cause
6890 // a fatal error but results in an empty context.
6891 TEST(ExceptionExtensions) {
6892   v8::HandleScope handle_scope(CcTest::isolate());
6893   v8::RegisterExtension(new Extension("exception",
6894                                       kExceptionInExtensionSource));
6895   const char* extension_names[] = { "exception" };
6896   v8::ExtensionConfiguration extensions(1, extension_names);
6897   v8::Handle<Context> context =
6898       Context::New(CcTest::isolate(), &extensions);
6899   CHECK(context.IsEmpty());
6900 }
6901
6902
6903 static const char* kNativeCallInExtensionSource =
6904     "function call_runtime_last_index_of(x) {"
6905     "  return %StringLastIndexOf(x, 'bob', 10);"
6906     "}";
6907
6908
6909 static const char* kNativeCallTest =
6910     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6911
6912 // Test that a native runtime calls are supported in extensions.
6913 TEST(NativeCallInExtensions) {
6914   v8::HandleScope handle_scope(CcTest::isolate());
6915   v8::RegisterExtension(new Extension("nativecall",
6916                                       kNativeCallInExtensionSource));
6917   const char* extension_names[] = { "nativecall" };
6918   v8::ExtensionConfiguration extensions(1, extension_names);
6919   v8::Handle<Context> context =
6920       Context::New(CcTest::isolate(), &extensions);
6921   Context::Scope lock(context);
6922   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6923   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6924 }
6925
6926
6927 class NativeFunctionExtension : public Extension {
6928  public:
6929   NativeFunctionExtension(const char* name,
6930                           const char* source,
6931                           v8::FunctionCallback fun = &Echo)
6932       : Extension(name, source),
6933         function_(fun) { }
6934
6935   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6936       v8::Isolate* isolate,
6937       v8::Handle<v8::String> name) {
6938     return v8::FunctionTemplate::New(isolate, function_);
6939   }
6940
6941   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6942     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6943   }
6944  private:
6945   v8::FunctionCallback function_;
6946 };
6947
6948
6949 TEST(NativeFunctionDeclaration) {
6950   v8::HandleScope handle_scope(CcTest::isolate());
6951   const char* name = "nativedecl";
6952   v8::RegisterExtension(new NativeFunctionExtension(name,
6953                                                     "native function foo();"));
6954   const char* extension_names[] = { name };
6955   v8::ExtensionConfiguration extensions(1, extension_names);
6956   v8::Handle<Context> context =
6957       Context::New(CcTest::isolate(), &extensions);
6958   Context::Scope lock(context);
6959   v8::Handle<Value> result = CompileRun("foo(42);");
6960   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6961 }
6962
6963
6964 TEST(NativeFunctionDeclarationError) {
6965   v8::HandleScope handle_scope(CcTest::isolate());
6966   const char* name = "nativedeclerr";
6967   // Syntax error in extension code.
6968   v8::RegisterExtension(new NativeFunctionExtension(name,
6969                                                     "native\nfunction foo();"));
6970   const char* extension_names[] = { name };
6971   v8::ExtensionConfiguration extensions(1, extension_names);
6972   v8::Handle<Context> context =
6973       Context::New(CcTest::isolate(), &extensions);
6974   CHECK(context.IsEmpty());
6975 }
6976
6977
6978 TEST(NativeFunctionDeclarationErrorEscape) {
6979   v8::HandleScope handle_scope(CcTest::isolate());
6980   const char* name = "nativedeclerresc";
6981   // Syntax error in extension code - escape code in "native" means that
6982   // it's not treated as a keyword.
6983   v8::RegisterExtension(new NativeFunctionExtension(
6984       name,
6985       "nativ\\u0065 function foo();"));
6986   const char* extension_names[] = { name };
6987   v8::ExtensionConfiguration extensions(1, extension_names);
6988   v8::Handle<Context> context =
6989       Context::New(CcTest::isolate(), &extensions);
6990   CHECK(context.IsEmpty());
6991 }
6992
6993
6994 static void CheckDependencies(const char* name, const char* expected) {
6995   v8::HandleScope handle_scope(CcTest::isolate());
6996   v8::ExtensionConfiguration config(1, &name);
6997   LocalContext context(&config);
6998   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6999            context->Global()->Get(v8_str("loaded")));
7000 }
7001
7002
7003 /*
7004  * Configuration:
7005  *
7006  *     /-- B <--\
7007  * A <-          -- D <-- E
7008  *     \-- C <--/
7009  */
7010 THREADED_TEST(ExtensionDependency) {
7011   static const char* kEDeps[] = { "D" };
7012   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7013   static const char* kDDeps[] = { "B", "C" };
7014   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7015   static const char* kBCDeps[] = { "A" };
7016   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7017   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7018   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7019   CheckDependencies("A", "undefinedA");
7020   CheckDependencies("B", "undefinedAB");
7021   CheckDependencies("C", "undefinedAC");
7022   CheckDependencies("D", "undefinedABCD");
7023   CheckDependencies("E", "undefinedABCDE");
7024   v8::HandleScope handle_scope(CcTest::isolate());
7025   static const char* exts[2] = { "C", "E" };
7026   v8::ExtensionConfiguration config(2, exts);
7027   LocalContext context(&config);
7028   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7029 }
7030
7031
7032 static const char* kExtensionTestScript =
7033   "native function A();"
7034   "native function B();"
7035   "native function C();"
7036   "function Foo(i) {"
7037   "  if (i == 0) return A();"
7038   "  if (i == 1) return B();"
7039   "  if (i == 2) return C();"
7040   "}";
7041
7042
7043 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7044   ApiTestFuzzer::Fuzz();
7045   if (args.IsConstructCall()) {
7046     args.This()->Set(v8_str("data"), args.Data());
7047     args.GetReturnValue().SetNull();
7048     return;
7049   }
7050   args.GetReturnValue().Set(args.Data());
7051 }
7052
7053
7054 class FunctionExtension : public Extension {
7055  public:
7056   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7057   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7058       v8::Isolate* isolate,
7059       v8::Handle<String> name);
7060 };
7061
7062
7063 static int lookup_count = 0;
7064 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7065     v8::Isolate* isolate, v8::Handle<String> name) {
7066   lookup_count++;
7067   if (name->Equals(v8_str("A"))) {
7068     return v8::FunctionTemplate::New(
7069         isolate, CallFun, v8::Integer::New(isolate, 8));
7070   } else if (name->Equals(v8_str("B"))) {
7071     return v8::FunctionTemplate::New(
7072         isolate, CallFun, v8::Integer::New(isolate, 7));
7073   } else if (name->Equals(v8_str("C"))) {
7074     return v8::FunctionTemplate::New(
7075         isolate, CallFun, v8::Integer::New(isolate, 6));
7076   } else {
7077     return v8::Handle<v8::FunctionTemplate>();
7078   }
7079 }
7080
7081
7082 THREADED_TEST(FunctionLookup) {
7083   v8::RegisterExtension(new FunctionExtension());
7084   v8::HandleScope handle_scope(CcTest::isolate());
7085   static const char* exts[1] = { "functiontest" };
7086   v8::ExtensionConfiguration config(1, exts);
7087   LocalContext context(&config);
7088   CHECK_EQ(3, lookup_count);
7089   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7090            CompileRun("Foo(0)"));
7091   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7092            CompileRun("Foo(1)"));
7093   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7094            CompileRun("Foo(2)"));
7095 }
7096
7097
7098 THREADED_TEST(NativeFunctionConstructCall) {
7099   v8::RegisterExtension(new FunctionExtension());
7100   v8::HandleScope handle_scope(CcTest::isolate());
7101   static const char* exts[1] = { "functiontest" };
7102   v8::ExtensionConfiguration config(1, exts);
7103   LocalContext context(&config);
7104   for (int i = 0; i < 10; i++) {
7105     // Run a few times to ensure that allocation of objects doesn't
7106     // change behavior of a constructor function.
7107     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7108              CompileRun("(new A()).data"));
7109     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7110              CompileRun("(new B()).data"));
7111     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7112              CompileRun("(new C()).data"));
7113   }
7114 }
7115
7116
7117 static const char* last_location;
7118 static const char* last_message;
7119 void StoringErrorCallback(const char* location, const char* message) {
7120   if (last_location == NULL) {
7121     last_location = location;
7122     last_message = message;
7123   }
7124 }
7125
7126
7127 // ErrorReporting creates a circular extensions configuration and
7128 // tests that the fatal error handler gets called.  This renders V8
7129 // unusable and therefore this test cannot be run in parallel.
7130 TEST(ErrorReporting) {
7131   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7132   static const char* aDeps[] = { "B" };
7133   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7134   static const char* bDeps[] = { "A" };
7135   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7136   last_location = NULL;
7137   v8::ExtensionConfiguration config(1, bDeps);
7138   v8::Handle<Context> context =
7139       Context::New(CcTest::isolate(), &config);
7140   CHECK(context.IsEmpty());
7141   CHECK_NE(last_location, NULL);
7142 }
7143
7144
7145 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7146                                              v8::Handle<Value> data) {
7147   CHECK(message->GetScriptResourceName()->IsUndefined());
7148   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7149   message->GetLineNumber();
7150   message->GetSourceLine();
7151 }
7152
7153
7154 THREADED_TEST(ErrorWithMissingScriptInfo) {
7155   LocalContext context;
7156   v8::HandleScope scope(context->GetIsolate());
7157   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7158   CompileRun("throw Error()");
7159   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7160 }
7161
7162
7163 struct FlagAndPersistent {
7164   bool flag;
7165   v8::Persistent<v8::Object> handle;
7166 };
7167
7168
7169 static void DisposeAndSetFlag(
7170     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7171   data.GetParameter()->handle.Reset();
7172   data.GetParameter()->flag = true;
7173 }
7174
7175
7176 THREADED_TEST(IndependentWeakHandle) {
7177   v8::Isolate* iso = CcTest::isolate();
7178   v8::HandleScope scope(iso);
7179   v8::Handle<Context> context = Context::New(iso);
7180   Context::Scope context_scope(context);
7181
7182   FlagAndPersistent object_a, object_b;
7183
7184   {
7185     v8::HandleScope handle_scope(iso);
7186     object_a.handle.Reset(iso, v8::Object::New(iso));
7187     object_b.handle.Reset(iso, v8::Object::New(iso));
7188   }
7189
7190   object_a.flag = false;
7191   object_b.flag = false;
7192   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7193   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7194   CHECK(!object_b.handle.IsIndependent());
7195   object_a.handle.MarkIndependent();
7196   object_b.handle.MarkIndependent();
7197   CHECK(object_b.handle.IsIndependent());
7198   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7199   CHECK(object_a.flag);
7200   CHECK(object_b.flag);
7201 }
7202
7203
7204 static void InvokeScavenge() {
7205   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7206 }
7207
7208
7209 static void InvokeMarkSweep() {
7210   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7211 }
7212
7213
7214 static void ForceScavenge(
7215     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7216   data.GetParameter()->handle.Reset();
7217   data.GetParameter()->flag = true;
7218   InvokeScavenge();
7219 }
7220
7221
7222 static void ForceMarkSweep(
7223     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7224   data.GetParameter()->handle.Reset();
7225   data.GetParameter()->flag = true;
7226   InvokeMarkSweep();
7227 }
7228
7229
7230 THREADED_TEST(GCFromWeakCallbacks) {
7231   v8::Isolate* isolate = CcTest::isolate();
7232   v8::HandleScope scope(isolate);
7233   v8::Handle<Context> context = Context::New(isolate);
7234   Context::Scope context_scope(context);
7235
7236   static const int kNumberOfGCTypes = 2;
7237   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7238       Callback;
7239   Callback gc_forcing_callback[kNumberOfGCTypes] =
7240       {&ForceScavenge, &ForceMarkSweep};
7241
7242   typedef void (*GCInvoker)();
7243   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7244
7245   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7246     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7247       FlagAndPersistent object;
7248       {
7249         v8::HandleScope handle_scope(isolate);
7250         object.handle.Reset(isolate, v8::Object::New(isolate));
7251       }
7252       object.flag = false;
7253       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7254       object.handle.MarkIndependent();
7255       invoke_gc[outer_gc]();
7256       CHECK(object.flag);
7257     }
7258   }
7259 }
7260
7261
7262 static void RevivingCallback(
7263     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7264   data.GetParameter()->handle.ClearWeak();
7265   data.GetParameter()->flag = true;
7266 }
7267
7268
7269 THREADED_TEST(IndependentHandleRevival) {
7270   v8::Isolate* isolate = CcTest::isolate();
7271   v8::HandleScope scope(isolate);
7272   v8::Handle<Context> context = Context::New(isolate);
7273   Context::Scope context_scope(context);
7274
7275   FlagAndPersistent object;
7276   {
7277     v8::HandleScope handle_scope(isolate);
7278     v8::Local<v8::Object> o = v8::Object::New(isolate);
7279     object.handle.Reset(isolate, o);
7280     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7281     v8::Local<String> y_str = v8_str("y");
7282     o->Set(y_str, y_str);
7283   }
7284   object.flag = false;
7285   object.handle.SetWeak(&object, &RevivingCallback);
7286   object.handle.MarkIndependent();
7287   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7288   CHECK(object.flag);
7289   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7290   {
7291     v8::HandleScope handle_scope(isolate);
7292     v8::Local<v8::Object> o =
7293         v8::Local<v8::Object>::New(isolate, object.handle);
7294     v8::Local<String> y_str = v8_str("y");
7295     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7296     CHECK(o->Get(y_str)->Equals(y_str));
7297   }
7298 }
7299
7300
7301 v8::Handle<Function> args_fun;
7302
7303
7304 static void ArgumentsTestCallback(
7305     const v8::FunctionCallbackInfo<v8::Value>& args) {
7306   ApiTestFuzzer::Fuzz();
7307   v8::Isolate* isolate = args.GetIsolate();
7308   CHECK_EQ(args_fun, args.Callee());
7309   CHECK_EQ(3, args.Length());
7310   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7311   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7312   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7313   CHECK_EQ(v8::Undefined(isolate), args[3]);
7314   v8::HandleScope scope(args.GetIsolate());
7315   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7316 }
7317
7318
7319 THREADED_TEST(Arguments) {
7320   v8::Isolate* isolate = CcTest::isolate();
7321   v8::HandleScope scope(isolate);
7322   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7323   global->Set(v8_str("f"),
7324               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7325   LocalContext context(NULL, global);
7326   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7327   v8_compile("f(1, 2, 3)")->Run();
7328 }
7329
7330
7331 static void NoBlockGetterX(Local<String> name,
7332                            const v8::PropertyCallbackInfo<v8::Value>&) {
7333 }
7334
7335
7336 static void NoBlockGetterI(uint32_t index,
7337                            const v8::PropertyCallbackInfo<v8::Value>&) {
7338 }
7339
7340
7341 static void PDeleter(Local<String> name,
7342                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7343   if (!name->Equals(v8_str("foo"))) {
7344     return;  // not intercepted
7345   }
7346
7347   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7348 }
7349
7350
7351 static void IDeleter(uint32_t index,
7352                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7353   if (index != 2) {
7354     return;  // not intercepted
7355   }
7356
7357   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7358 }
7359
7360
7361 THREADED_TEST(Deleter) {
7362   v8::Isolate* isolate = CcTest::isolate();
7363   v8::HandleScope scope(isolate);
7364   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7365   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7366   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7367   LocalContext context;
7368   context->Global()->Set(v8_str("k"), obj->NewInstance());
7369   CompileRun(
7370     "k.foo = 'foo';"
7371     "k.bar = 'bar';"
7372     "k[2] = 2;"
7373     "k[4] = 4;");
7374   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7375   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7376
7377   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7378   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7379
7380   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7381   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7382
7383   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7384   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7385 }
7386
7387
7388 static void GetK(Local<String> name,
7389                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7390   ApiTestFuzzer::Fuzz();
7391   if (name->Equals(v8_str("foo")) ||
7392       name->Equals(v8_str("bar")) ||
7393       name->Equals(v8_str("baz"))) {
7394     info.GetReturnValue().SetUndefined();
7395   }
7396 }
7397
7398
7399 static void IndexedGetK(uint32_t index,
7400                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7401   ApiTestFuzzer::Fuzz();
7402   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7403 }
7404
7405
7406 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7407   ApiTestFuzzer::Fuzz();
7408   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7409   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7410   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7411   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7412   info.GetReturnValue().Set(result);
7413 }
7414
7415
7416 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7417   ApiTestFuzzer::Fuzz();
7418   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7419   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7420   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7421   info.GetReturnValue().Set(result);
7422 }
7423
7424
7425 THREADED_TEST(Enumerators) {
7426   v8::Isolate* isolate = CcTest::isolate();
7427   v8::HandleScope scope(isolate);
7428   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7429   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7430   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7431   LocalContext context;
7432   context->Global()->Set(v8_str("k"), obj->NewInstance());
7433   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7434     "k[10] = 0;"
7435     "k.a = 0;"
7436     "k[5] = 0;"
7437     "k.b = 0;"
7438     "k[4294967295] = 0;"
7439     "k.c = 0;"
7440     "k[4294967296] = 0;"
7441     "k.d = 0;"
7442     "k[140000] = 0;"
7443     "k.e = 0;"
7444     "k[30000000000] = 0;"
7445     "k.f = 0;"
7446     "var result = [];"
7447     "for (var prop in k) {"
7448     "  result.push(prop);"
7449     "}"
7450     "result"));
7451   // Check that we get all the property names returned including the
7452   // ones from the enumerators in the right order: indexed properties
7453   // in numerical order, indexed interceptor properties, named
7454   // properties in insertion order, named interceptor properties.
7455   // This order is not mandated by the spec, so this test is just
7456   // documenting our behavior.
7457   CHECK_EQ(17, result->Length());
7458   // Indexed properties in numerical order.
7459   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7460   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7461   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7462   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7463   // Indexed interceptor properties in the order they are returned
7464   // from the enumerator interceptor.
7465   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7466   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7467   // Named properties in insertion order.
7468   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7469   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7470   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7471   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7472   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7473   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7474   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7475   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7476   // Named interceptor properties.
7477   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7478   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7479   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7480 }
7481
7482
7483 int p_getter_count;
7484 int p_getter_count2;
7485
7486
7487 static void PGetter(Local<String> name,
7488                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7489   ApiTestFuzzer::Fuzz();
7490   p_getter_count++;
7491   v8::Handle<v8::Object> global =
7492       info.GetIsolate()->GetCurrentContext()->Global();
7493   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7494   if (name->Equals(v8_str("p1"))) {
7495     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7496   } else if (name->Equals(v8_str("p2"))) {
7497     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7498   } else if (name->Equals(v8_str("p3"))) {
7499     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7500   } else if (name->Equals(v8_str("p4"))) {
7501     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7502   }
7503 }
7504
7505
7506 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7507   ApiTestFuzzer::Fuzz();
7508   LocalContext context;
7509   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7510   CompileRun(
7511     "o1.__proto__ = { };"
7512     "var o2 = { __proto__: o1 };"
7513     "var o3 = { __proto__: o2 };"
7514     "var o4 = { __proto__: o3 };"
7515     "for (var i = 0; i < 10; i++) o4.p4;"
7516     "for (var i = 0; i < 10; i++) o3.p3;"
7517     "for (var i = 0; i < 10; i++) o2.p2;"
7518     "for (var i = 0; i < 10; i++) o1.p1;");
7519 }
7520
7521
7522 static void PGetter2(Local<String> name,
7523                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7524   ApiTestFuzzer::Fuzz();
7525   p_getter_count2++;
7526   v8::Handle<v8::Object> global =
7527       info.GetIsolate()->GetCurrentContext()->Global();
7528   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7529   if (name->Equals(v8_str("p1"))) {
7530     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7531   } else if (name->Equals(v8_str("p2"))) {
7532     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7533   } else if (name->Equals(v8_str("p3"))) {
7534     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7535   } else if (name->Equals(v8_str("p4"))) {
7536     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7537   }
7538 }
7539
7540
7541 THREADED_TEST(GetterHolders) {
7542   v8::Isolate* isolate = CcTest::isolate();
7543   v8::HandleScope scope(isolate);
7544   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7545   obj->SetAccessor(v8_str("p1"), PGetter);
7546   obj->SetAccessor(v8_str("p2"), PGetter);
7547   obj->SetAccessor(v8_str("p3"), PGetter);
7548   obj->SetAccessor(v8_str("p4"), PGetter);
7549   p_getter_count = 0;
7550   RunHolderTest(obj);
7551   CHECK_EQ(40, p_getter_count);
7552 }
7553
7554
7555 THREADED_TEST(PreInterceptorHolders) {
7556   v8::Isolate* isolate = CcTest::isolate();
7557   v8::HandleScope scope(isolate);
7558   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7559   obj->SetNamedPropertyHandler(PGetter2);
7560   p_getter_count2 = 0;
7561   RunHolderTest(obj);
7562   CHECK_EQ(40, p_getter_count2);
7563 }
7564
7565
7566 THREADED_TEST(ObjectInstantiation) {
7567   v8::Isolate* isolate = CcTest::isolate();
7568   v8::HandleScope scope(isolate);
7569   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7570   templ->SetAccessor(v8_str("t"), PGetter2);
7571   LocalContext context;
7572   context->Global()->Set(v8_str("o"), templ->NewInstance());
7573   for (int i = 0; i < 100; i++) {
7574     v8::HandleScope inner_scope(CcTest::isolate());
7575     v8::Handle<v8::Object> obj = templ->NewInstance();
7576     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7577     context->Global()->Set(v8_str("o2"), obj);
7578     v8::Handle<Value> value =
7579         CompileRun("o.__proto__ === o2.__proto__");
7580     CHECK_EQ(v8::True(isolate), value);
7581     context->Global()->Set(v8_str("o"), obj);
7582   }
7583 }
7584
7585
7586 static int StrCmp16(uint16_t* a, uint16_t* b) {
7587   while (true) {
7588     if (*a == 0 && *b == 0) return 0;
7589     if (*a != *b) return 0 + *a - *b;
7590     a++;
7591     b++;
7592   }
7593 }
7594
7595
7596 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7597   while (true) {
7598     if (n-- == 0) return 0;
7599     if (*a == 0 && *b == 0) return 0;
7600     if (*a != *b) return 0 + *a - *b;
7601     a++;
7602     b++;
7603   }
7604 }
7605
7606
7607 int GetUtf8Length(Handle<String> str) {
7608   int len = str->Utf8Length();
7609   if (len < 0) {
7610     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7611     i::String::Flatten(istr);
7612     len = str->Utf8Length();
7613   }
7614   return len;
7615 }
7616
7617
7618 THREADED_TEST(StringWrite) {
7619   LocalContext context;
7620   v8::HandleScope scope(context->GetIsolate());
7621   v8::Handle<String> str = v8_str("abcde");
7622   // abc<Icelandic eth><Unicode snowman>.
7623   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7624   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7625       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7626   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7627   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7628   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7629       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7630   // single lead surrogate
7631   uint16_t lead[1] = { 0xd800 };
7632   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7633       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7634   // single trail surrogate
7635   uint16_t trail[1] = { 0xdc00 };
7636   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7637       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7638   // surrogate pair
7639   uint16_t pair[2] = { 0xd800,  0xdc00 };
7640   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7641       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7642   const int kStride = 4;  // Must match stride in for loops in JS below.
7643   CompileRun(
7644       "var left = '';"
7645       "for (var i = 0; i < 0xd800; i += 4) {"
7646       "  left = left + String.fromCharCode(i);"
7647       "}");
7648   CompileRun(
7649       "var right = '';"
7650       "for (var i = 0; i < 0xd800; i += 4) {"
7651       "  right = String.fromCharCode(i) + right;"
7652       "}");
7653   v8::Handle<v8::Object> global = context->Global();
7654   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7655   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7656
7657   CHECK_EQ(5, str2->Length());
7658   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7659   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7660
7661   char buf[100];
7662   char utf8buf[0xd800 * 3];
7663   uint16_t wbuf[100];
7664   int len;
7665   int charlen;
7666
7667   memset(utf8buf, 0x1, 1000);
7668   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7669   CHECK_EQ(9, len);
7670   CHECK_EQ(5, charlen);
7671   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7672
7673   memset(utf8buf, 0x1, 1000);
7674   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7675   CHECK_EQ(8, len);
7676   CHECK_EQ(5, charlen);
7677   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7678
7679   memset(utf8buf, 0x1, 1000);
7680   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7681   CHECK_EQ(5, len);
7682   CHECK_EQ(4, charlen);
7683   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7684
7685   memset(utf8buf, 0x1, 1000);
7686   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7687   CHECK_EQ(5, len);
7688   CHECK_EQ(4, charlen);
7689   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7690
7691   memset(utf8buf, 0x1, 1000);
7692   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7693   CHECK_EQ(5, len);
7694   CHECK_EQ(4, charlen);
7695   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7696
7697   memset(utf8buf, 0x1, 1000);
7698   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7699   CHECK_EQ(3, len);
7700   CHECK_EQ(3, charlen);
7701   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7702
7703   memset(utf8buf, 0x1, 1000);
7704   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7705   CHECK_EQ(3, len);
7706   CHECK_EQ(3, charlen);
7707   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7708
7709   memset(utf8buf, 0x1, 1000);
7710   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7711   CHECK_EQ(2, len);
7712   CHECK_EQ(2, charlen);
7713   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7714
7715   // allow orphan surrogates by default
7716   memset(utf8buf, 0x1, 1000);
7717   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7718   CHECK_EQ(13, len);
7719   CHECK_EQ(8, charlen);
7720   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7721
7722   // replace orphan surrogates with unicode replacement character
7723   memset(utf8buf, 0x1, 1000);
7724   len = orphans_str->WriteUtf8(utf8buf,
7725                                sizeof(utf8buf),
7726                                &charlen,
7727                                String::REPLACE_INVALID_UTF8);
7728   CHECK_EQ(13, len);
7729   CHECK_EQ(8, charlen);
7730   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7731
7732   // replace single lead surrogate with unicode replacement character
7733   memset(utf8buf, 0x1, 1000);
7734   len = lead_str->WriteUtf8(utf8buf,
7735                             sizeof(utf8buf),
7736                             &charlen,
7737                             String::REPLACE_INVALID_UTF8);
7738   CHECK_EQ(4, len);
7739   CHECK_EQ(1, charlen);
7740   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7741
7742   // replace single trail surrogate with unicode replacement character
7743   memset(utf8buf, 0x1, 1000);
7744   len = trail_str->WriteUtf8(utf8buf,
7745                              sizeof(utf8buf),
7746                              &charlen,
7747                              String::REPLACE_INVALID_UTF8);
7748   CHECK_EQ(4, len);
7749   CHECK_EQ(1, charlen);
7750   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7751
7752   // do not replace / write anything if surrogate pair does not fit the buffer
7753   // space
7754   memset(utf8buf, 0x1, 1000);
7755   len = pair_str->WriteUtf8(utf8buf,
7756                              3,
7757                              &charlen,
7758                              String::REPLACE_INVALID_UTF8);
7759   CHECK_EQ(0, len);
7760   CHECK_EQ(0, charlen);
7761
7762   memset(utf8buf, 0x1, sizeof(utf8buf));
7763   len = GetUtf8Length(left_tree);
7764   int utf8_expected =
7765       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7766   CHECK_EQ(utf8_expected, len);
7767   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7768   CHECK_EQ(utf8_expected, len);
7769   CHECK_EQ(0xd800 / kStride, charlen);
7770   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7771   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7772   CHECK_EQ(0xc0 - kStride,
7773            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7774   CHECK_EQ(1, utf8buf[utf8_expected]);
7775
7776   memset(utf8buf, 0x1, sizeof(utf8buf));
7777   len = GetUtf8Length(right_tree);
7778   CHECK_EQ(utf8_expected, len);
7779   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7780   CHECK_EQ(utf8_expected, len);
7781   CHECK_EQ(0xd800 / kStride, charlen);
7782   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7783   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7784   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7785   CHECK_EQ(1, utf8buf[utf8_expected]);
7786
7787   memset(buf, 0x1, sizeof(buf));
7788   memset(wbuf, 0x1, sizeof(wbuf));
7789   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7790   CHECK_EQ(5, len);
7791   len = str->Write(wbuf);
7792   CHECK_EQ(5, len);
7793   CHECK_EQ(0, strcmp("abcde", buf));
7794   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7795   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7796
7797   memset(buf, 0x1, sizeof(buf));
7798   memset(wbuf, 0x1, sizeof(wbuf));
7799   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7800   CHECK_EQ(4, len);
7801   len = str->Write(wbuf, 0, 4);
7802   CHECK_EQ(4, len);
7803   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7804   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7805   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7806
7807   memset(buf, 0x1, sizeof(buf));
7808   memset(wbuf, 0x1, sizeof(wbuf));
7809   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7810   CHECK_EQ(5, len);
7811   len = str->Write(wbuf, 0, 5);
7812   CHECK_EQ(5, len);
7813   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7814   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7815   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7816
7817   memset(buf, 0x1, sizeof(buf));
7818   memset(wbuf, 0x1, sizeof(wbuf));
7819   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7820   CHECK_EQ(5, len);
7821   len = str->Write(wbuf, 0, 6);
7822   CHECK_EQ(5, len);
7823   CHECK_EQ(0, strcmp("abcde", buf));
7824   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7825   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7826
7827   memset(buf, 0x1, sizeof(buf));
7828   memset(wbuf, 0x1, sizeof(wbuf));
7829   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7830   CHECK_EQ(1, len);
7831   len = str->Write(wbuf, 4, -1);
7832   CHECK_EQ(1, len);
7833   CHECK_EQ(0, strcmp("e", buf));
7834   uint16_t answer5[] = {'e', '\0'};
7835   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7836
7837   memset(buf, 0x1, sizeof(buf));
7838   memset(wbuf, 0x1, sizeof(wbuf));
7839   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7840   CHECK_EQ(1, len);
7841   len = str->Write(wbuf, 4, 6);
7842   CHECK_EQ(1, len);
7843   CHECK_EQ(0, strcmp("e", buf));
7844   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7845
7846   memset(buf, 0x1, sizeof(buf));
7847   memset(wbuf, 0x1, sizeof(wbuf));
7848   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7849   CHECK_EQ(1, len);
7850   len = str->Write(wbuf, 4, 1);
7851   CHECK_EQ(1, len);
7852   CHECK_EQ(0, strncmp("e\1", buf, 2));
7853   uint16_t answer6[] = {'e', 0x101};
7854   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7855
7856   memset(buf, 0x1, sizeof(buf));
7857   memset(wbuf, 0x1, sizeof(wbuf));
7858   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7859   CHECK_EQ(1, len);
7860   len = str->Write(wbuf, 3, 1);
7861   CHECK_EQ(1, len);
7862   CHECK_EQ(0, strncmp("d\1", buf, 2));
7863   uint16_t answer7[] = {'d', 0x101};
7864   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7865
7866   memset(wbuf, 0x1, sizeof(wbuf));
7867   wbuf[5] = 'X';
7868   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7869   CHECK_EQ(5, len);
7870   CHECK_EQ('X', wbuf[5]);
7871   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7872   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7873   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7874   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7875   wbuf[5] = '\0';
7876   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7877
7878   memset(buf, 0x1, sizeof(buf));
7879   buf[5] = 'X';
7880   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7881                           0,
7882                           6,
7883                           String::NO_NULL_TERMINATION);
7884   CHECK_EQ(5, len);
7885   CHECK_EQ('X', buf[5]);
7886   CHECK_EQ(0, strncmp("abcde", buf, 5));
7887   CHECK_NE(0, strcmp("abcde", buf));
7888   buf[5] = '\0';
7889   CHECK_EQ(0, strcmp("abcde", buf));
7890
7891   memset(utf8buf, 0x1, sizeof(utf8buf));
7892   utf8buf[8] = 'X';
7893   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7894                         String::NO_NULL_TERMINATION);
7895   CHECK_EQ(8, len);
7896   CHECK_EQ('X', utf8buf[8]);
7897   CHECK_EQ(5, charlen);
7898   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7899   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7900   utf8buf[8] = '\0';
7901   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7902
7903   memset(utf8buf, 0x1, sizeof(utf8buf));
7904   utf8buf[5] = 'X';
7905   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7906                         String::NO_NULL_TERMINATION);
7907   CHECK_EQ(5, len);
7908   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7909   CHECK_EQ(5, charlen);
7910   utf8buf[5] = '\0';
7911   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7912
7913   memset(buf, 0x1, sizeof(buf));
7914   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7915   CHECK_EQ(7, len);
7916   CHECK_EQ(0, strcmp("abc", buf));
7917   CHECK_EQ(0, buf[3]);
7918   CHECK_EQ(0, strcmp("def", buf + 4));
7919
7920   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7921   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7922   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7923 }
7924
7925
7926 static void Utf16Helper(
7927     LocalContext& context,
7928     const char* name,
7929     const char* lengths_name,
7930     int len) {
7931   Local<v8::Array> a =
7932       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7933   Local<v8::Array> alens =
7934       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7935   for (int i = 0; i < len; i++) {
7936     Local<v8::String> string =
7937       Local<v8::String>::Cast(a->Get(i));
7938     Local<v8::Number> expected_len =
7939       Local<v8::Number>::Cast(alens->Get(i));
7940     int length = GetUtf8Length(string);
7941     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7942   }
7943 }
7944
7945
7946 static uint16_t StringGet(Handle<String> str, int index) {
7947   i::Handle<i::String> istring =
7948       v8::Utils::OpenHandle(String::Cast(*str));
7949   return istring->Get(index);
7950 }
7951
7952
7953 static void WriteUtf8Helper(
7954     LocalContext& context,
7955     const char* name,
7956     const char* lengths_name,
7957     int len) {
7958   Local<v8::Array> b =
7959       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7960   Local<v8::Array> alens =
7961       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7962   char buffer[1000];
7963   char buffer2[1000];
7964   for (int i = 0; i < len; i++) {
7965     Local<v8::String> string =
7966       Local<v8::String>::Cast(b->Get(i));
7967     Local<v8::Number> expected_len =
7968       Local<v8::Number>::Cast(alens->Get(i));
7969     int utf8_length = static_cast<int>(expected_len->Value());
7970     for (int j = utf8_length + 1; j >= 0; j--) {
7971       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7972       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7973       int nchars;
7974       int utf8_written =
7975           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7976       int utf8_written2 =
7977           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7978       CHECK_GE(utf8_length + 1, utf8_written);
7979       CHECK_GE(utf8_length, utf8_written2);
7980       for (int k = 0; k < utf8_written2; k++) {
7981         CHECK_EQ(buffer[k], buffer2[k]);
7982       }
7983       CHECK(nchars * 3 >= utf8_written - 1);
7984       CHECK(nchars <= utf8_written);
7985       if (j == utf8_length + 1) {
7986         CHECK_EQ(utf8_written2, utf8_length);
7987         CHECK_EQ(utf8_written2 + 1, utf8_written);
7988       }
7989       CHECK_EQ(buffer[utf8_written], 42);
7990       if (j > utf8_length) {
7991         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7992         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7993         Handle<String> roundtrip = v8_str(buffer);
7994         CHECK(roundtrip->Equals(string));
7995       } else {
7996         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7997       }
7998       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7999       if (nchars >= 2) {
8000         uint16_t trail = StringGet(string, nchars - 1);
8001         uint16_t lead = StringGet(string, nchars - 2);
8002         if (((lead & 0xfc00) == 0xd800) &&
8003             ((trail & 0xfc00) == 0xdc00)) {
8004           unsigned char u1 = buffer2[utf8_written2 - 4];
8005           unsigned char u2 = buffer2[utf8_written2 - 3];
8006           unsigned char u3 = buffer2[utf8_written2 - 2];
8007           unsigned char u4 = buffer2[utf8_written2 - 1];
8008           CHECK_EQ((u1 & 0xf8), 0xf0);
8009           CHECK_EQ((u2 & 0xc0), 0x80);
8010           CHECK_EQ((u3 & 0xc0), 0x80);
8011           CHECK_EQ((u4 & 0xc0), 0x80);
8012           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8013           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8014           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8015           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8016           CHECK_EQ((u1 & 0x3), c >> 18);
8017         }
8018       }
8019     }
8020   }
8021 }
8022
8023
8024 THREADED_TEST(Utf16) {
8025   LocalContext context;
8026   v8::HandleScope scope(context->GetIsolate());
8027   CompileRun(
8028       "var pad = '01234567890123456789';"
8029       "var p = [];"
8030       "var plens = [20, 3, 3];"
8031       "p.push('01234567890123456789');"
8032       "var lead = 0xd800;"
8033       "var trail = 0xdc00;"
8034       "p.push(String.fromCharCode(0xd800));"
8035       "p.push(String.fromCharCode(0xdc00));"
8036       "var a = [];"
8037       "var b = [];"
8038       "var c = [];"
8039       "var alens = [];"
8040       "for (var i = 0; i < 3; i++) {"
8041       "  p[1] = String.fromCharCode(lead++);"
8042       "  for (var j = 0; j < 3; j++) {"
8043       "    p[2] = String.fromCharCode(trail++);"
8044       "    a.push(p[i] + p[j]);"
8045       "    b.push(p[i] + p[j]);"
8046       "    c.push(p[i] + p[j]);"
8047       "    alens.push(plens[i] + plens[j]);"
8048       "  }"
8049       "}"
8050       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8051       "var a2 = [];"
8052       "var b2 = [];"
8053       "var c2 = [];"
8054       "var a2lens = [];"
8055       "for (var m = 0; m < 9; m++) {"
8056       "  for (var n = 0; n < 9; n++) {"
8057       "    a2.push(a[m] + a[n]);"
8058       "    b2.push(b[m] + b[n]);"
8059       "    var newc = 'x' + c[m] + c[n] + 'y';"
8060       "    c2.push(newc.substring(1, newc.length - 1));"
8061       "    var utf = alens[m] + alens[n];"  // And here.
8062            // The 'n's that start with 0xdc.. are 6-8
8063            // The 'm's that end with 0xd8.. are 1, 4 and 7
8064       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8065       "    a2lens.push(utf);"
8066       "  }"
8067       "}");
8068   Utf16Helper(context, "a", "alens", 9);
8069   Utf16Helper(context, "a2", "a2lens", 81);
8070   WriteUtf8Helper(context, "b", "alens", 9);
8071   WriteUtf8Helper(context, "b2", "a2lens", 81);
8072   WriteUtf8Helper(context, "c2", "a2lens", 81);
8073 }
8074
8075
8076 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8077   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8078   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8079   return *is1 == *is2;
8080 }
8081
8082 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8083                              const char* b) {
8084   Handle<String> symbol1 =
8085       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8086   Handle<String> symbol2 =
8087       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8088   CHECK(SameSymbol(symbol1, symbol2));
8089 }
8090
8091
8092 THREADED_TEST(Utf16Symbol) {
8093   LocalContext context;
8094   v8::HandleScope scope(context->GetIsolate());
8095
8096   Handle<String> symbol1 = v8::String::NewFromUtf8(
8097       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8098   Handle<String> symbol2 = v8::String::NewFromUtf8(
8099       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8100   CHECK(SameSymbol(symbol1, symbol2));
8101
8102   SameSymbolHelper(context->GetIsolate(),
8103                    "\360\220\220\205",  // 4 byte encoding.
8104                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8105   SameSymbolHelper(context->GetIsolate(),
8106                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8107                    "\360\220\220\206");  // 4 byte encoding.
8108   SameSymbolHelper(context->GetIsolate(),
8109                    "x\360\220\220\205",  // 4 byte encoding.
8110                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8111   SameSymbolHelper(context->GetIsolate(),
8112                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8113                    "x\360\220\220\206");  // 4 byte encoding.
8114   CompileRun(
8115       "var sym0 = 'benedictus';"
8116       "var sym0b = 'S\303\270ren';"
8117       "var sym1 = '\355\240\201\355\260\207';"
8118       "var sym2 = '\360\220\220\210';"
8119       "var sym3 = 'x\355\240\201\355\260\207';"
8120       "var sym4 = 'x\360\220\220\210';"
8121       "if (sym1.length != 2) throw sym1;"
8122       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8123       "if (sym2.length != 2) throw sym2;"
8124       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8125       "if (sym3.length != 3) throw sym3;"
8126       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8127       "if (sym4.length != 3) throw sym4;"
8128       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8129   Handle<String> sym0 = v8::String::NewFromUtf8(
8130       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8131   Handle<String> sym0b = v8::String::NewFromUtf8(
8132       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8133   Handle<String> sym1 =
8134       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8135                               v8::String::kInternalizedString);
8136   Handle<String> sym2 =
8137       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8138                               v8::String::kInternalizedString);
8139   Handle<String> sym3 = v8::String::NewFromUtf8(
8140       context->GetIsolate(), "x\355\240\201\355\260\207",
8141       v8::String::kInternalizedString);
8142   Handle<String> sym4 =
8143       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8144                               v8::String::kInternalizedString);
8145   v8::Local<v8::Object> global = context->Global();
8146   Local<Value> s0 = global->Get(v8_str("sym0"));
8147   Local<Value> s0b = global->Get(v8_str("sym0b"));
8148   Local<Value> s1 = global->Get(v8_str("sym1"));
8149   Local<Value> s2 = global->Get(v8_str("sym2"));
8150   Local<Value> s3 = global->Get(v8_str("sym3"));
8151   Local<Value> s4 = global->Get(v8_str("sym4"));
8152   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8153   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8154   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8155   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8156   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8157   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8158 }
8159
8160
8161 THREADED_TEST(ToArrayIndex) {
8162   LocalContext context;
8163   v8::Isolate* isolate = context->GetIsolate();
8164   v8::HandleScope scope(isolate);
8165
8166   v8::Handle<String> str = v8_str("42");
8167   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8168   CHECK(!index.IsEmpty());
8169   CHECK_EQ(42.0, index->Uint32Value());
8170   str = v8_str("42asdf");
8171   index = str->ToArrayIndex();
8172   CHECK(index.IsEmpty());
8173   str = v8_str("-42");
8174   index = str->ToArrayIndex();
8175   CHECK(index.IsEmpty());
8176   str = v8_str("4294967295");
8177   index = str->ToArrayIndex();
8178   CHECK(!index.IsEmpty());
8179   CHECK_EQ(4294967295.0, index->Uint32Value());
8180   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8181   index = num->ToArrayIndex();
8182   CHECK(!index.IsEmpty());
8183   CHECK_EQ(1.0, index->Uint32Value());
8184   num = v8::Number::New(isolate, -1);
8185   index = num->ToArrayIndex();
8186   CHECK(index.IsEmpty());
8187   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8188   index = obj->ToArrayIndex();
8189   CHECK(index.IsEmpty());
8190 }
8191
8192
8193 THREADED_TEST(ErrorConstruction) {
8194   LocalContext context;
8195   v8::HandleScope scope(context->GetIsolate());
8196
8197   v8::Handle<String> foo = v8_str("foo");
8198   v8::Handle<String> message = v8_str("message");
8199   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8200   CHECK(range_error->IsObject());
8201   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8202   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8203   CHECK(reference_error->IsObject());
8204   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8205   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8206   CHECK(syntax_error->IsObject());
8207   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8208   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8209   CHECK(type_error->IsObject());
8210   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8211   v8::Handle<Value> error = v8::Exception::Error(foo);
8212   CHECK(error->IsObject());
8213   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8214 }
8215
8216
8217 static void YGetter(Local<String> name,
8218                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8219   ApiTestFuzzer::Fuzz();
8220   info.GetReturnValue().Set(v8_num(10));
8221 }
8222
8223
8224 static void YSetter(Local<String> name,
8225                     Local<Value> value,
8226                     const v8::PropertyCallbackInfo<void>& info) {
8227   Local<Object> this_obj = Local<Object>::Cast(info.This());
8228   if (this_obj->Has(name)) this_obj->Delete(name);
8229   this_obj->Set(name, value);
8230 }
8231
8232
8233 THREADED_TEST(DeleteAccessor) {
8234   v8::Isolate* isolate = CcTest::isolate();
8235   v8::HandleScope scope(isolate);
8236   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8237   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8238   LocalContext context;
8239   v8::Handle<v8::Object> holder = obj->NewInstance();
8240   context->Global()->Set(v8_str("holder"), holder);
8241   v8::Handle<Value> result = CompileRun(
8242       "holder.y = 11; holder.y = 12; holder.y");
8243   CHECK_EQ(12, result->Uint32Value());
8244 }
8245
8246
8247 THREADED_TEST(TypeSwitch) {
8248   v8::Isolate* isolate = CcTest::isolate();
8249   v8::HandleScope scope(isolate);
8250   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8251   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8252   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8253   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8254   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8255   LocalContext context;
8256   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8257   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8258   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8259   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8260   for (int i = 0; i < 10; i++) {
8261     CHECK_EQ(0, type_switch->match(obj0));
8262     CHECK_EQ(1, type_switch->match(obj1));
8263     CHECK_EQ(2, type_switch->match(obj2));
8264     CHECK_EQ(3, type_switch->match(obj3));
8265     CHECK_EQ(3, type_switch->match(obj3));
8266     CHECK_EQ(2, type_switch->match(obj2));
8267     CHECK_EQ(1, type_switch->match(obj1));
8268     CHECK_EQ(0, type_switch->match(obj0));
8269   }
8270 }
8271
8272
8273 static int trouble_nesting = 0;
8274 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8275   ApiTestFuzzer::Fuzz();
8276   trouble_nesting++;
8277
8278   // Call a JS function that throws an uncaught exception.
8279   Local<v8::Object> arg_this =
8280       args.GetIsolate()->GetCurrentContext()->Global();
8281   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8282     arg_this->Get(v8_str("trouble_callee")) :
8283     arg_this->Get(v8_str("trouble_caller"));
8284   CHECK(trouble_callee->IsFunction());
8285   args.GetReturnValue().Set(
8286       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8287 }
8288
8289
8290 static int report_count = 0;
8291 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8292                                              v8::Handle<Value>) {
8293   report_count++;
8294 }
8295
8296
8297 // Counts uncaught exceptions, but other tests running in parallel
8298 // also have uncaught exceptions.
8299 TEST(ApiUncaughtException) {
8300   report_count = 0;
8301   LocalContext env;
8302   v8::Isolate* isolate = env->GetIsolate();
8303   v8::HandleScope scope(isolate);
8304   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8305
8306   Local<v8::FunctionTemplate> fun =
8307       v8::FunctionTemplate::New(isolate, TroubleCallback);
8308   v8::Local<v8::Object> global = env->Global();
8309   global->Set(v8_str("trouble"), fun->GetFunction());
8310
8311   CompileRun(
8312       "function trouble_callee() {"
8313       "  var x = null;"
8314       "  return x.foo;"
8315       "};"
8316       "function trouble_caller() {"
8317       "  trouble();"
8318       "};");
8319   Local<Value> trouble = global->Get(v8_str("trouble"));
8320   CHECK(trouble->IsFunction());
8321   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8322   CHECK(trouble_callee->IsFunction());
8323   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8324   CHECK(trouble_caller->IsFunction());
8325   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8326   CHECK_EQ(1, report_count);
8327   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8328 }
8329
8330 static const char* script_resource_name = "ExceptionInNativeScript.js";
8331 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8332                                                 v8::Handle<Value>) {
8333   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8334   CHECK(!name_val.IsEmpty() && name_val->IsString());
8335   v8::String::Utf8Value name(message->GetScriptResourceName());
8336   CHECK_EQ(script_resource_name, *name);
8337   CHECK_EQ(3, message->GetLineNumber());
8338   v8::String::Utf8Value source_line(message->GetSourceLine());
8339   CHECK_EQ("  new o.foo();", *source_line);
8340 }
8341
8342
8343 TEST(ExceptionInNativeScript) {
8344   LocalContext env;
8345   v8::Isolate* isolate = env->GetIsolate();
8346   v8::HandleScope scope(isolate);
8347   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8348
8349   Local<v8::FunctionTemplate> fun =
8350       v8::FunctionTemplate::New(isolate, TroubleCallback);
8351   v8::Local<v8::Object> global = env->Global();
8352   global->Set(v8_str("trouble"), fun->GetFunction());
8353
8354   CompileRunWithOrigin(
8355       "function trouble() {\n"
8356       "  var o = {};\n"
8357       "  new o.foo();\n"
8358       "};",
8359       script_resource_name);
8360   Local<Value> trouble = global->Get(v8_str("trouble"));
8361   CHECK(trouble->IsFunction());
8362   Function::Cast(*trouble)->Call(global, 0, NULL);
8363   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8364 }
8365
8366
8367 TEST(CompilationErrorUsingTryCatchHandler) {
8368   LocalContext env;
8369   v8::HandleScope scope(env->GetIsolate());
8370   v8::TryCatch try_catch;
8371   v8_compile("This doesn't &*&@#$&*^ compile.");
8372   CHECK_NE(NULL, *try_catch.Exception());
8373   CHECK(try_catch.HasCaught());
8374 }
8375
8376
8377 TEST(TryCatchFinallyUsingTryCatchHandler) {
8378   LocalContext env;
8379   v8::HandleScope scope(env->GetIsolate());
8380   v8::TryCatch try_catch;
8381   CompileRun("try { throw ''; } catch (e) {}");
8382   CHECK(!try_catch.HasCaught());
8383   CompileRun("try { throw ''; } finally {}");
8384   CHECK(try_catch.HasCaught());
8385   try_catch.Reset();
8386   CompileRun(
8387       "(function() {"
8388       "try { throw ''; } finally { return; }"
8389       "})()");
8390   CHECK(!try_catch.HasCaught());
8391   CompileRun(
8392       "(function()"
8393       "  { try { throw ''; } finally { throw 0; }"
8394       "})()");
8395   CHECK(try_catch.HasCaught());
8396 }
8397
8398
8399 // For use within the TestSecurityHandler() test.
8400 static bool g_security_callback_result = false;
8401 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8402                                       Local<Value> name,
8403                                       v8::AccessType type,
8404                                       Local<Value> data) {
8405   printf("a\n");
8406   // Always allow read access.
8407   if (type == v8::ACCESS_GET)
8408     return true;
8409
8410   // Sometimes allow other access.
8411   return g_security_callback_result;
8412 }
8413
8414
8415 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8416                                         uint32_t key,
8417                                         v8::AccessType type,
8418                                         Local<Value> data) {
8419   printf("b\n");
8420   // Always allow read access.
8421   if (type == v8::ACCESS_GET)
8422     return true;
8423
8424   // Sometimes allow other access.
8425   return g_security_callback_result;
8426 }
8427
8428
8429 // SecurityHandler can't be run twice
8430 TEST(SecurityHandler) {
8431   v8::Isolate* isolate = CcTest::isolate();
8432   v8::HandleScope scope0(isolate);
8433   v8::Handle<v8::ObjectTemplate> global_template =
8434       v8::ObjectTemplate::New(isolate);
8435   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8436                                            IndexedSecurityTestCallback);
8437   // Create an environment
8438   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8439   context0->Enter();
8440
8441   v8::Handle<v8::Object> global0 = context0->Global();
8442   v8::Handle<Script> script0 = v8_compile("foo = 111");
8443   script0->Run();
8444   global0->Set(v8_str("0"), v8_num(999));
8445   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8446   CHECK_EQ(111, foo0->Int32Value());
8447   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8448   CHECK_EQ(999, z0->Int32Value());
8449
8450   // Create another environment, should fail security checks.
8451   v8::HandleScope scope1(isolate);
8452
8453   v8::Handle<Context> context1 =
8454     Context::New(isolate, NULL, global_template);
8455   context1->Enter();
8456
8457   v8::Handle<v8::Object> global1 = context1->Global();
8458   global1->Set(v8_str("othercontext"), global0);
8459   // This set will fail the security check.
8460   v8::Handle<Script> script1 =
8461     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8462   script1->Run();
8463   // This read will pass the security check.
8464   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8465   CHECK_EQ(111, foo1->Int32Value());
8466   // This read will pass the security check.
8467   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8468   CHECK_EQ(999, z1->Int32Value());
8469
8470   // Create another environment, should pass security checks.
8471   { g_security_callback_result = true;  // allow security handler to pass.
8472     v8::HandleScope scope2(isolate);
8473     LocalContext context2;
8474     v8::Handle<v8::Object> global2 = context2->Global();
8475     global2->Set(v8_str("othercontext"), global0);
8476     v8::Handle<Script> script2 =
8477         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8478     script2->Run();
8479     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8480     CHECK_EQ(333, foo2->Int32Value());
8481     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8482     CHECK_EQ(888, z2->Int32Value());
8483   }
8484
8485   context1->Exit();
8486   context0->Exit();
8487 }
8488
8489
8490 THREADED_TEST(SecurityChecks) {
8491   LocalContext env1;
8492   v8::HandleScope handle_scope(env1->GetIsolate());
8493   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8494
8495   Local<Value> foo = v8_str("foo");
8496   Local<Value> bar = v8_str("bar");
8497
8498   // Set to the same domain.
8499   env1->SetSecurityToken(foo);
8500
8501   // Create a function in env1.
8502   CompileRun("spy=function(){return spy;}");
8503   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8504   CHECK(spy->IsFunction());
8505
8506   // Create another function accessing global objects.
8507   CompileRun("spy2=function(){return new this.Array();}");
8508   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8509   CHECK(spy2->IsFunction());
8510
8511   // Switch to env2 in the same domain and invoke spy on env2.
8512   {
8513     env2->SetSecurityToken(foo);
8514     // Enter env2
8515     Context::Scope scope_env2(env2);
8516     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8517     CHECK(result->IsFunction());
8518   }
8519
8520   {
8521     env2->SetSecurityToken(bar);
8522     Context::Scope scope_env2(env2);
8523
8524     // Call cross_domain_call, it should throw an exception
8525     v8::TryCatch try_catch;
8526     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8527     CHECK(try_catch.HasCaught());
8528   }
8529 }
8530
8531
8532 // Regression test case for issue 1183439.
8533 THREADED_TEST(SecurityChecksForPrototypeChain) {
8534   LocalContext current;
8535   v8::HandleScope scope(current->GetIsolate());
8536   v8::Handle<Context> other = Context::New(current->GetIsolate());
8537
8538   // Change context to be able to get to the Object function in the
8539   // other context without hitting the security checks.
8540   v8::Local<Value> other_object;
8541   { Context::Scope scope(other);
8542     other_object = other->Global()->Get(v8_str("Object"));
8543     other->Global()->Set(v8_num(42), v8_num(87));
8544   }
8545
8546   current->Global()->Set(v8_str("other"), other->Global());
8547   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8548
8549   // Make sure the security check fails here and we get an undefined
8550   // result instead of getting the Object function. Repeat in a loop
8551   // to make sure to exercise the IC code.
8552   v8::Local<Script> access_other0 = v8_compile("other.Object");
8553   v8::Local<Script> access_other1 = v8_compile("other[42]");
8554   for (int i = 0; i < 5; i++) {
8555     CHECK(!access_other0->Run()->Equals(other_object));
8556     CHECK(access_other0->Run()->IsUndefined());
8557     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8558     CHECK(access_other1->Run()->IsUndefined());
8559   }
8560
8561   // Create an object that has 'other' in its prototype chain and make
8562   // sure we cannot access the Object function indirectly through
8563   // that. Repeat in a loop to make sure to exercise the IC code.
8564   v8_compile("function F() { };"
8565              "F.prototype = other;"
8566              "var f = new F();")->Run();
8567   v8::Local<Script> access_f0 = v8_compile("f.Object");
8568   v8::Local<Script> access_f1 = v8_compile("f[42]");
8569   for (int j = 0; j < 5; j++) {
8570     CHECK(!access_f0->Run()->Equals(other_object));
8571     CHECK(access_f0->Run()->IsUndefined());
8572     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8573     CHECK(access_f1->Run()->IsUndefined());
8574   }
8575
8576   // Now it gets hairy: Set the prototype for the other global object
8577   // to be the current global object. The prototype chain for 'f' now
8578   // goes through 'other' but ends up in the current global object.
8579   { Context::Scope scope(other);
8580     other->Global()->Set(v8_str("__proto__"), current->Global());
8581   }
8582   // Set a named and an index property on the current global
8583   // object. To force the lookup to go through the other global object,
8584   // the properties must not exist in the other global object.
8585   current->Global()->Set(v8_str("foo"), v8_num(100));
8586   current->Global()->Set(v8_num(99), v8_num(101));
8587   // Try to read the properties from f and make sure that the access
8588   // gets stopped by the security checks on the other global object.
8589   Local<Script> access_f2 = v8_compile("f.foo");
8590   Local<Script> access_f3 = v8_compile("f[99]");
8591   for (int k = 0; k < 5; k++) {
8592     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8593     CHECK(access_f2->Run()->IsUndefined());
8594     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8595     CHECK(access_f3->Run()->IsUndefined());
8596   }
8597 }
8598
8599
8600 static bool named_security_check_with_gc_called;
8601
8602 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8603                                         Local<Value> name,
8604                                         v8::AccessType type,
8605                                         Local<Value> data) {
8606   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8607   named_security_check_with_gc_called = true;
8608   return true;
8609 }
8610
8611
8612 static bool indexed_security_check_with_gc_called;
8613
8614 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8615                                               uint32_t key,
8616                                               v8::AccessType type,
8617                                               Local<Value> data) {
8618   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8619   indexed_security_check_with_gc_called = true;
8620   return true;
8621 }
8622
8623
8624 TEST(SecurityTestGCAllowed) {
8625   v8::Isolate* isolate = CcTest::isolate();
8626   v8::HandleScope handle_scope(isolate);
8627   v8::Handle<v8::ObjectTemplate> object_template =
8628       v8::ObjectTemplate::New(isolate);
8629   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8630                                            IndexedSecurityTestCallbackWithGC);
8631
8632   v8::Handle<Context> context = Context::New(isolate);
8633   v8::Context::Scope context_scope(context);
8634
8635   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8636
8637   named_security_check_with_gc_called = false;
8638   CompileRun("obj.foo = new String(1001);");
8639   CHECK(named_security_check_with_gc_called);
8640
8641   indexed_security_check_with_gc_called = false;
8642   CompileRun("obj[0] = new String(1002);");
8643   CHECK(indexed_security_check_with_gc_called);
8644
8645   named_security_check_with_gc_called = false;
8646   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8647   CHECK(named_security_check_with_gc_called);
8648
8649   indexed_security_check_with_gc_called = false;
8650   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8651   CHECK(indexed_security_check_with_gc_called);
8652 }
8653
8654
8655 THREADED_TEST(CrossDomainDelete) {
8656   LocalContext env1;
8657   v8::HandleScope handle_scope(env1->GetIsolate());
8658   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8659
8660   Local<Value> foo = v8_str("foo");
8661   Local<Value> bar = v8_str("bar");
8662
8663   // Set to the same domain.
8664   env1->SetSecurityToken(foo);
8665   env2->SetSecurityToken(foo);
8666
8667   env1->Global()->Set(v8_str("prop"), v8_num(3));
8668   env2->Global()->Set(v8_str("env1"), env1->Global());
8669
8670   // Change env2 to a different domain and delete env1.prop.
8671   env2->SetSecurityToken(bar);
8672   {
8673     Context::Scope scope_env2(env2);
8674     Local<Value> result =
8675         CompileRun("delete env1.prop");
8676     CHECK(result->IsFalse());
8677   }
8678
8679   // Check that env1.prop still exists.
8680   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8681   CHECK(v->IsNumber());
8682   CHECK_EQ(3, v->Int32Value());
8683 }
8684
8685
8686 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8687   LocalContext env1;
8688   v8::HandleScope handle_scope(env1->GetIsolate());
8689   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8690
8691   Local<Value> foo = v8_str("foo");
8692   Local<Value> bar = v8_str("bar");
8693
8694   // Set to the same domain.
8695   env1->SetSecurityToken(foo);
8696   env2->SetSecurityToken(foo);
8697
8698   env1->Global()->Set(v8_str("prop"), v8_num(3));
8699   env2->Global()->Set(v8_str("env1"), env1->Global());
8700
8701   // env1.prop is enumerable in env2.
8702   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8703   {
8704     Context::Scope scope_env2(env2);
8705     Local<Value> result = CompileRun(test);
8706     CHECK(result->IsTrue());
8707   }
8708
8709   // Change env2 to a different domain and test again.
8710   env2->SetSecurityToken(bar);
8711   {
8712     Context::Scope scope_env2(env2);
8713     Local<Value> result = CompileRun(test);
8714     CHECK(result->IsFalse());
8715   }
8716 }
8717
8718
8719 THREADED_TEST(CrossDomainForIn) {
8720   LocalContext env1;
8721   v8::HandleScope handle_scope(env1->GetIsolate());
8722   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8723
8724   Local<Value> foo = v8_str("foo");
8725   Local<Value> bar = v8_str("bar");
8726
8727   // Set to the same domain.
8728   env1->SetSecurityToken(foo);
8729   env2->SetSecurityToken(foo);
8730
8731   env1->Global()->Set(v8_str("prop"), v8_num(3));
8732   env2->Global()->Set(v8_str("env1"), env1->Global());
8733
8734   // Change env2 to a different domain and set env1's global object
8735   // as the __proto__ of an object in env2 and enumerate properties
8736   // in for-in. It shouldn't enumerate properties on env1's global
8737   // object.
8738   env2->SetSecurityToken(bar);
8739   {
8740     Context::Scope scope_env2(env2);
8741     Local<Value> result =
8742         CompileRun("(function(){var obj = {'__proto__':env1};"
8743                    "for (var p in obj)"
8744                    "   if (p == 'prop') return false;"
8745                    "return true;})()");
8746     CHECK(result->IsTrue());
8747   }
8748 }
8749
8750
8751 TEST(ContextDetachGlobal) {
8752   LocalContext env1;
8753   v8::HandleScope handle_scope(env1->GetIsolate());
8754   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8755
8756   Local<v8::Object> global1 = env1->Global();
8757
8758   Local<Value> foo = v8_str("foo");
8759
8760   // Set to the same domain.
8761   env1->SetSecurityToken(foo);
8762   env2->SetSecurityToken(foo);
8763
8764   // Enter env2
8765   env2->Enter();
8766
8767   // Create a function in env2 and add a reference to it in env1.
8768   Local<v8::Object> global2 = env2->Global();
8769   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8770   CompileRun("function getProp() {return prop;}");
8771
8772   env1->Global()->Set(v8_str("getProp"),
8773                       global2->Get(v8_str("getProp")));
8774
8775   // Detach env2's global, and reuse the global object of env2
8776   env2->Exit();
8777   env2->DetachGlobal();
8778
8779   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8780                                           0,
8781                                           v8::Handle<v8::ObjectTemplate>(),
8782                                           global2);
8783   env3->SetSecurityToken(v8_str("bar"));
8784   env3->Enter();
8785
8786   Local<v8::Object> global3 = env3->Global();
8787   CHECK_EQ(global2, global3);
8788   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8789   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8790   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8791   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8792   env3->Exit();
8793
8794   // Call getProp in env1, and it should return the value 1
8795   {
8796     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8797     CHECK(get_prop->IsFunction());
8798     v8::TryCatch try_catch;
8799     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8800     CHECK(!try_catch.HasCaught());
8801     CHECK_EQ(1, r->Int32Value());
8802   }
8803
8804   // Check that env3 is not accessible from env1
8805   {
8806     Local<Value> r = global3->Get(v8_str("prop2"));
8807     CHECK(r->IsUndefined());
8808   }
8809 }
8810
8811
8812 TEST(DetachGlobal) {
8813   LocalContext env1;
8814   v8::HandleScope scope(env1->GetIsolate());
8815
8816   // Create second environment.
8817   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8818
8819   Local<Value> foo = v8_str("foo");
8820
8821   // Set same security token for env1 and env2.
8822   env1->SetSecurityToken(foo);
8823   env2->SetSecurityToken(foo);
8824
8825   // Create a property on the global object in env2.
8826   {
8827     v8::Context::Scope scope(env2);
8828     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8829   }
8830
8831   // Create a reference to env2 global from env1 global.
8832   env1->Global()->Set(v8_str("other"), env2->Global());
8833
8834   // Check that we have access to other.p in env2 from env1.
8835   Local<Value> result = CompileRun("other.p");
8836   CHECK(result->IsInt32());
8837   CHECK_EQ(42, result->Int32Value());
8838
8839   // Hold on to global from env2 and detach global from env2.
8840   Local<v8::Object> global2 = env2->Global();
8841   env2->DetachGlobal();
8842
8843   // Check that the global has been detached. No other.p property can
8844   // be found.
8845   result = CompileRun("other.p");
8846   CHECK(result->IsUndefined());
8847
8848   // Reuse global2 for env3.
8849   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8850                                           0,
8851                                           v8::Handle<v8::ObjectTemplate>(),
8852                                           global2);
8853   CHECK_EQ(global2, env3->Global());
8854
8855   // Start by using the same security token for env3 as for env1 and env2.
8856   env3->SetSecurityToken(foo);
8857
8858   // Create a property on the global object in env3.
8859   {
8860     v8::Context::Scope scope(env3);
8861     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8862   }
8863
8864   // Check that other.p is now the property in env3 and that we have access.
8865   result = CompileRun("other.p");
8866   CHECK(result->IsInt32());
8867   CHECK_EQ(24, result->Int32Value());
8868
8869   // Change security token for env3 to something different from env1 and env2.
8870   env3->SetSecurityToken(v8_str("bar"));
8871
8872   // Check that we do not have access to other.p in env1. |other| is now
8873   // the global object for env3 which has a different security token,
8874   // so access should be blocked.
8875   result = CompileRun("other.p");
8876   CHECK(result->IsUndefined());
8877 }
8878
8879
8880 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8881   info.GetReturnValue().Set(
8882       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8883 }
8884
8885
8886 TEST(DetachedAccesses) {
8887   LocalContext env1;
8888   v8::HandleScope scope(env1->GetIsolate());
8889
8890   // Create second environment.
8891   Local<ObjectTemplate> inner_global_template =
8892       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8893   inner_global_template ->SetAccessorProperty(
8894       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8895   v8::Local<Context> env2 =
8896       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8897
8898   Local<Value> foo = v8_str("foo");
8899
8900   // Set same security token for env1 and env2.
8901   env1->SetSecurityToken(foo);
8902   env2->SetSecurityToken(foo);
8903
8904   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8905
8906   {
8907     v8::Context::Scope scope(env2);
8908     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8909     CompileRun(
8910         "function bound_x() { return x; }"
8911         "function get_x()   { return this.x; }"
8912         "function get_x_w() { return (function() {return this.x;})(); }");
8913     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8914     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8915     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8916     env1->Global()->Set(
8917         v8_str("this_x"),
8918         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8919   }
8920
8921   Local<Object> env2_global = env2->Global();
8922   env2_global->TurnOnAccessCheck();
8923   env2->DetachGlobal();
8924
8925   Local<Value> result;
8926   result = CompileRun("bound_x()");
8927   CHECK_EQ(v8_str("env2_x"), result);
8928   result = CompileRun("get_x()");
8929   CHECK(result->IsUndefined());
8930   result = CompileRun("get_x_w()");
8931   CHECK(result->IsUndefined());
8932   result = CompileRun("this_x()");
8933   CHECK_EQ(v8_str("env2_x"), result);
8934
8935   // Reattach env2's proxy
8936   env2 = Context::New(env1->GetIsolate(),
8937                       0,
8938                       v8::Handle<v8::ObjectTemplate>(),
8939                       env2_global);
8940   env2->SetSecurityToken(foo);
8941   {
8942     v8::Context::Scope scope(env2);
8943     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8944     env2->Global()->Set(v8_str("env1"), env1->Global());
8945     result = CompileRun(
8946         "results = [];"
8947         "for (var i = 0; i < 4; i++ ) {"
8948         "  results.push(env1.bound_x());"
8949         "  results.push(env1.get_x());"
8950         "  results.push(env1.get_x_w());"
8951         "  results.push(env1.this_x());"
8952         "}"
8953         "results");
8954     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8955     CHECK_EQ(16, results->Length());
8956     for (int i = 0; i < 16; i += 4) {
8957       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8958       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8959       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8960       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8961     }
8962   }
8963
8964   result = CompileRun(
8965       "results = [];"
8966       "for (var i = 0; i < 4; i++ ) {"
8967       "  results.push(bound_x());"
8968       "  results.push(get_x());"
8969       "  results.push(get_x_w());"
8970       "  results.push(this_x());"
8971       "}"
8972       "results");
8973   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8974   CHECK_EQ(16, results->Length());
8975   for (int i = 0; i < 16; i += 4) {
8976     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8977     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8978     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8979     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8980   }
8981
8982   result = CompileRun(
8983       "results = [];"
8984       "for (var i = 0; i < 4; i++ ) {"
8985       "  results.push(this.bound_x());"
8986       "  results.push(this.get_x());"
8987       "  results.push(this.get_x_w());"
8988       "  results.push(this.this_x());"
8989       "}"
8990       "results");
8991   results = Local<v8::Array>::Cast(result);
8992   CHECK_EQ(16, results->Length());
8993   for (int i = 0; i < 16; i += 4) {
8994     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8995     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8996     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8997     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8998   }
8999 }
9000
9001
9002 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9003 static bool NamedAccessBlocker(Local<v8::Object> global,
9004                                Local<Value> name,
9005                                v8::AccessType type,
9006                                Local<Value> data) {
9007   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9008       allowed_access_type[type];
9009 }
9010
9011
9012 static bool IndexedAccessBlocker(Local<v8::Object> global,
9013                                  uint32_t key,
9014                                  v8::AccessType type,
9015                                  Local<Value> data) {
9016   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9017       allowed_access_type[type];
9018 }
9019
9020
9021 static int g_echo_value_1 = -1;
9022 static int g_echo_value_2 = -1;
9023
9024
9025 static void EchoGetter(
9026     Local<String> name,
9027     const v8::PropertyCallbackInfo<v8::Value>& info) {
9028   info.GetReturnValue().Set(v8_num(g_echo_value_1));
9029 }
9030
9031
9032 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9033   info.GetReturnValue().Set(v8_num(g_echo_value_2));
9034 }
9035
9036
9037 static void EchoSetter(Local<String> name,
9038                        Local<Value> value,
9039                        const v8::PropertyCallbackInfo<void>&) {
9040   if (value->IsNumber())
9041     g_echo_value_1 = value->Int32Value();
9042 }
9043
9044
9045 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9046   v8::Handle<v8::Value> value = info[0];
9047   if (value->IsNumber())
9048     g_echo_value_2 = value->Int32Value();
9049 }
9050
9051
9052 static void UnreachableGetter(
9053     Local<String> name,
9054     const v8::PropertyCallbackInfo<v8::Value>& info) {
9055   CHECK(false);  // This function should not be called..
9056 }
9057
9058
9059 static void UnreachableSetter(Local<String>,
9060                               Local<Value>,
9061                               const v8::PropertyCallbackInfo<void>&) {
9062   CHECK(false);  // This function should nto be called.
9063 }
9064
9065
9066 static void UnreachableFunction(
9067     const v8::FunctionCallbackInfo<v8::Value>& info) {
9068   CHECK(false);  // This function should not be called..
9069 }
9070
9071
9072 TEST(AccessControl) {
9073   v8::Isolate* isolate = CcTest::isolate();
9074   v8::HandleScope handle_scope(isolate);
9075   v8::Handle<v8::ObjectTemplate> global_template =
9076       v8::ObjectTemplate::New(isolate);
9077
9078   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9079                                            IndexedAccessBlocker);
9080
9081   // Add an accessor accessible by cross-domain JS code.
9082   global_template->SetAccessor(
9083       v8_str("accessible_prop"),
9084       EchoGetter, EchoSetter,
9085       v8::Handle<Value>(),
9086       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9087
9088
9089   global_template->SetAccessorProperty(
9090       v8_str("accessible_js_prop"),
9091       v8::FunctionTemplate::New(isolate, EchoGetter),
9092       v8::FunctionTemplate::New(isolate, EchoSetter),
9093       v8::None,
9094       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9095
9096   // Add an accessor that is not accessible by cross-domain JS code.
9097   global_template->SetAccessor(v8_str("blocked_prop"),
9098                                UnreachableGetter, UnreachableSetter,
9099                                v8::Handle<Value>(),
9100                                v8::DEFAULT);
9101
9102   global_template->SetAccessorProperty(
9103       v8_str("blocked_js_prop"),
9104       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9105       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9106       v8::None,
9107       v8::DEFAULT);
9108
9109   // Create an environment
9110   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9111   context0->Enter();
9112
9113   v8::Handle<v8::Object> global0 = context0->Global();
9114
9115   // Define a property with JS getter and setter.
9116   CompileRun(
9117       "function getter() { return 'getter'; };\n"
9118       "function setter() { return 'setter'; }\n"
9119       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9120
9121   Local<Value> getter = global0->Get(v8_str("getter"));
9122   Local<Value> setter = global0->Get(v8_str("setter"));
9123
9124   // And define normal element.
9125   global0->Set(239, v8_str("239"));
9126
9127   // Define an element with JS getter and setter.
9128   CompileRun(
9129       "function el_getter() { return 'el_getter'; };\n"
9130       "function el_setter() { return 'el_setter'; };\n"
9131       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9132
9133   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9134   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9135
9136   v8::HandleScope scope1(isolate);
9137
9138   v8::Local<Context> context1 = Context::New(isolate);
9139   context1->Enter();
9140
9141   v8::Handle<v8::Object> global1 = context1->Global();
9142   global1->Set(v8_str("other"), global0);
9143
9144   // Access blocked property.
9145   CompileRun("other.blocked_prop = 1");
9146
9147   ExpectUndefined("other.blocked_prop");
9148   ExpectUndefined(
9149       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9150   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9151
9152   // Enable ACCESS_HAS
9153   allowed_access_type[v8::ACCESS_HAS] = true;
9154   ExpectUndefined("other.blocked_prop");
9155   // ... and now we can get the descriptor...
9156   ExpectUndefined(
9157       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9158   // ... and enumerate the property.
9159   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9160   allowed_access_type[v8::ACCESS_HAS] = false;
9161
9162   // Access blocked element.
9163   CompileRun("other[239] = 1");
9164
9165   ExpectUndefined("other[239]");
9166   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9167   ExpectFalse("propertyIsEnumerable.call(other, '239')");
9168
9169   // Enable ACCESS_HAS
9170   allowed_access_type[v8::ACCESS_HAS] = true;
9171   ExpectUndefined("other[239]");
9172   // ... and now we can get the descriptor...
9173   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9174   // ... and enumerate the property.
9175   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9176   allowed_access_type[v8::ACCESS_HAS] = false;
9177
9178   // Access a property with JS accessor.
9179   CompileRun("other.js_accessor_p = 2");
9180
9181   ExpectUndefined("other.js_accessor_p");
9182   ExpectUndefined(
9183       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9184
9185   // Enable ACCESS_HAS.
9186   allowed_access_type[v8::ACCESS_HAS] = true;
9187   ExpectUndefined("other.js_accessor_p");
9188   ExpectUndefined(
9189       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9190   ExpectUndefined(
9191       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9192   ExpectUndefined(
9193       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9194   allowed_access_type[v8::ACCESS_HAS] = false;
9195
9196   // Enable both ACCESS_HAS and ACCESS_GET.
9197   allowed_access_type[v8::ACCESS_HAS] = true;
9198   allowed_access_type[v8::ACCESS_GET] = true;
9199
9200   ExpectString("other.js_accessor_p", "getter");
9201   ExpectObject(
9202       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9203   ExpectUndefined(
9204       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9205   ExpectUndefined(
9206       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9207
9208   allowed_access_type[v8::ACCESS_GET] = false;
9209   allowed_access_type[v8::ACCESS_HAS] = false;
9210
9211   // Enable both ACCESS_HAS and ACCESS_SET.
9212   allowed_access_type[v8::ACCESS_HAS] = true;
9213   allowed_access_type[v8::ACCESS_SET] = true;
9214
9215   ExpectUndefined("other.js_accessor_p");
9216   ExpectUndefined(
9217       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9218   ExpectObject(
9219       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9220   ExpectUndefined(
9221       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9222
9223   allowed_access_type[v8::ACCESS_SET] = false;
9224   allowed_access_type[v8::ACCESS_HAS] = false;
9225
9226   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9227   allowed_access_type[v8::ACCESS_HAS] = true;
9228   allowed_access_type[v8::ACCESS_GET] = true;
9229   allowed_access_type[v8::ACCESS_SET] = true;
9230
9231   ExpectString("other.js_accessor_p", "getter");
9232   ExpectObject(
9233       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9234   ExpectObject(
9235       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9236   ExpectUndefined(
9237       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9238
9239   allowed_access_type[v8::ACCESS_SET] = false;
9240   allowed_access_type[v8::ACCESS_GET] = false;
9241   allowed_access_type[v8::ACCESS_HAS] = false;
9242
9243   // Access an element with JS accessor.
9244   CompileRun("other[42] = 2");
9245
9246   ExpectUndefined("other[42]");
9247   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9248
9249   // Enable ACCESS_HAS.
9250   allowed_access_type[v8::ACCESS_HAS] = true;
9251   ExpectUndefined("other[42]");
9252   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9253   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9254   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9255   allowed_access_type[v8::ACCESS_HAS] = false;
9256
9257   // Enable both ACCESS_HAS and ACCESS_GET.
9258   allowed_access_type[v8::ACCESS_HAS] = true;
9259   allowed_access_type[v8::ACCESS_GET] = true;
9260
9261   ExpectString("other[42]", "el_getter");
9262   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9263   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9264   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9265
9266   allowed_access_type[v8::ACCESS_GET] = false;
9267   allowed_access_type[v8::ACCESS_HAS] = false;
9268
9269   // Enable both ACCESS_HAS and ACCESS_SET.
9270   allowed_access_type[v8::ACCESS_HAS] = true;
9271   allowed_access_type[v8::ACCESS_SET] = true;
9272
9273   ExpectUndefined("other[42]");
9274   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9275   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9276   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9277
9278   allowed_access_type[v8::ACCESS_SET] = false;
9279   allowed_access_type[v8::ACCESS_HAS] = false;
9280
9281   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9282   allowed_access_type[v8::ACCESS_HAS] = true;
9283   allowed_access_type[v8::ACCESS_GET] = true;
9284   allowed_access_type[v8::ACCESS_SET] = true;
9285
9286   ExpectString("other[42]", "el_getter");
9287   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9288   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9289   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9290
9291   allowed_access_type[v8::ACCESS_SET] = false;
9292   allowed_access_type[v8::ACCESS_GET] = false;
9293   allowed_access_type[v8::ACCESS_HAS] = false;
9294
9295   v8::Handle<Value> value;
9296
9297   // Access accessible property
9298   value = CompileRun("other.accessible_prop = 3");
9299   CHECK(value->IsNumber());
9300   CHECK_EQ(3, value->Int32Value());
9301   CHECK_EQ(3, g_echo_value_1);
9302
9303   // Access accessible js property
9304   value = CompileRun("other.accessible_js_prop = 3");
9305   CHECK(value->IsNumber());
9306   CHECK_EQ(3, value->Int32Value());
9307   CHECK_EQ(3, g_echo_value_2);
9308
9309   value = CompileRun("other.accessible_prop");
9310   CHECK(value->IsNumber());
9311   CHECK_EQ(3, value->Int32Value());
9312
9313   value = CompileRun("other.accessible_js_prop");
9314   CHECK(value->IsNumber());
9315   CHECK_EQ(3, value->Int32Value());
9316
9317   value = CompileRun(
9318       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9319   CHECK(value->IsNumber());
9320   CHECK_EQ(3, value->Int32Value());
9321
9322   value = CompileRun(
9323       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9324   CHECK(value->IsNumber());
9325   CHECK_EQ(3, value->Int32Value());
9326
9327   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9328   CHECK(value->IsTrue());
9329
9330   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9331   CHECK(value->IsTrue());
9332
9333   // Enumeration doesn't enumerate accessors from inaccessible objects in
9334   // the prototype chain even if the accessors are in themselves accessible.
9335   value =
9336       CompileRun("(function(){var obj = {'__proto__':other};"
9337                  "for (var p in obj)"
9338                  "   if (p == 'accessible_prop' ||"
9339                  "       p == 'accessible_js_prop' ||"
9340                  "       p == 'blocked_js_prop' ||"
9341                  "       p == 'blocked_js_prop') {"
9342                  "     return false;"
9343                  "   }"
9344                  "return true;})()");
9345   CHECK(value->IsTrue());
9346
9347   context1->Exit();
9348   context0->Exit();
9349 }
9350
9351
9352 TEST(AccessControlES5) {
9353   v8::Isolate* isolate = CcTest::isolate();
9354   v8::HandleScope handle_scope(isolate);
9355   v8::Handle<v8::ObjectTemplate> global_template =
9356       v8::ObjectTemplate::New(isolate);
9357
9358   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9359                                            IndexedAccessBlocker);
9360
9361   // Add accessible accessor.
9362   global_template->SetAccessor(
9363       v8_str("accessible_prop"),
9364       EchoGetter, EchoSetter,
9365       v8::Handle<Value>(),
9366       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9367
9368
9369   // Add an accessor that is not accessible by cross-domain JS code.
9370   global_template->SetAccessor(v8_str("blocked_prop"),
9371                                UnreachableGetter, UnreachableSetter,
9372                                v8::Handle<Value>(),
9373                                v8::DEFAULT);
9374
9375   // Create an environment
9376   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9377   context0->Enter();
9378
9379   v8::Handle<v8::Object> global0 = context0->Global();
9380
9381   v8::Local<Context> context1 = Context::New(isolate);
9382   context1->Enter();
9383   v8::Handle<v8::Object> global1 = context1->Global();
9384   global1->Set(v8_str("other"), global0);
9385
9386   // Regression test for issue 1154.
9387   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9388
9389   ExpectUndefined("other.blocked_prop");
9390
9391   // Regression test for issue 1027.
9392   CompileRun("Object.defineProperty(\n"
9393              "  other, 'blocked_prop', {configurable: false})");
9394   ExpectUndefined("other.blocked_prop");
9395   ExpectUndefined(
9396       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9397
9398   // Regression test for issue 1171.
9399   ExpectTrue("Object.isExtensible(other)");
9400   CompileRun("Object.preventExtensions(other)");
9401   ExpectTrue("Object.isExtensible(other)");
9402
9403   // Object.seal and Object.freeze.
9404   CompileRun("Object.freeze(other)");
9405   ExpectTrue("Object.isExtensible(other)");
9406
9407   CompileRun("Object.seal(other)");
9408   ExpectTrue("Object.isExtensible(other)");
9409
9410   // Regression test for issue 1250.
9411   // Make sure that we can set the accessible accessors value using normal
9412   // assignment.
9413   CompileRun("other.accessible_prop = 42");
9414   CHECK_EQ(42, g_echo_value_1);
9415
9416   v8::Handle<Value> value;
9417   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9418   value = CompileRun("other.accessible_prop == 42");
9419   CHECK(value->IsTrue());
9420 }
9421
9422
9423 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9424                                             Local<Value> name,
9425                                             v8::AccessType type,
9426                                             Local<Value> data) {
9427   return false;
9428 }
9429
9430
9431 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9432                                               uint32_t key,
9433                                               v8::AccessType type,
9434                                               Local<Value> data) {
9435   return false;
9436 }
9437
9438
9439 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9440   v8::Isolate* isolate = CcTest::isolate();
9441   v8::HandleScope handle_scope(isolate);
9442   v8::Handle<v8::ObjectTemplate> obj_template =
9443       v8::ObjectTemplate::New(isolate);
9444
9445   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9446   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9447                                         GetOwnPropertyNamesIndexedBlocker);
9448
9449   // Create an environment
9450   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9451   context0->Enter();
9452
9453   v8::Handle<v8::Object> global0 = context0->Global();
9454
9455   v8::HandleScope scope1(CcTest::isolate());
9456
9457   v8::Local<Context> context1 = Context::New(isolate);
9458   context1->Enter();
9459
9460   v8::Handle<v8::Object> global1 = context1->Global();
9461   global1->Set(v8_str("other"), global0);
9462   global1->Set(v8_str("object"), obj_template->NewInstance());
9463
9464   v8::Handle<Value> value;
9465
9466   // Attempt to get the property names of the other global object and
9467   // of an object that requires access checks.  Accessing the other
9468   // global object should be blocked by access checks on the global
9469   // proxy object.  Accessing the object that requires access checks
9470   // is blocked by the access checks on the object itself.
9471   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9472   CHECK(value->IsTrue());
9473
9474   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9475   CHECK(value->IsTrue());
9476
9477   context1->Exit();
9478   context0->Exit();
9479 }
9480
9481
9482 static void IndexedPropertyEnumerator(
9483     const v8::PropertyCallbackInfo<v8::Array>& info) {
9484   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9485   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9486   result->Set(1, v8::Object::New(info.GetIsolate()));
9487   info.GetReturnValue().Set(result);
9488 }
9489
9490
9491 static void NamedPropertyEnumerator(
9492     const v8::PropertyCallbackInfo<v8::Array>& info) {
9493   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9494   result->Set(0, v8_str("x"));
9495   result->Set(1, v8::Object::New(info.GetIsolate()));
9496   info.GetReturnValue().Set(result);
9497 }
9498
9499
9500 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9501   v8::Isolate* isolate = CcTest::isolate();
9502   v8::HandleScope handle_scope(isolate);
9503   v8::Handle<v8::ObjectTemplate> obj_template =
9504       v8::ObjectTemplate::New(isolate);
9505
9506   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9507   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9508   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9509                                           IndexedPropertyEnumerator);
9510   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9511                                         NamedPropertyEnumerator);
9512
9513   LocalContext context;
9514   v8::Handle<v8::Object> global = context->Global();
9515   global->Set(v8_str("object"), obj_template->NewInstance());
9516
9517   v8::Handle<v8::Value> result =
9518       CompileRun("Object.getOwnPropertyNames(object)");
9519   CHECK(result->IsArray());
9520   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9521   CHECK_EQ(3, result_array->Length());
9522   CHECK(result_array->Get(0)->IsString());
9523   CHECK(result_array->Get(1)->IsString());
9524   CHECK(result_array->Get(2)->IsString());
9525   CHECK_EQ(v8_str("7"), result_array->Get(0));
9526   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9527   CHECK_EQ(v8_str("x"), result_array->Get(2));
9528 }
9529
9530
9531 static void ConstTenGetter(Local<String> name,
9532                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9533   info.GetReturnValue().Set(v8_num(10));
9534 }
9535
9536
9537 THREADED_TEST(CrossDomainAccessors) {
9538   v8::Isolate* isolate = CcTest::isolate();
9539   v8::HandleScope handle_scope(isolate);
9540
9541   v8::Handle<v8::FunctionTemplate> func_template =
9542       v8::FunctionTemplate::New(isolate);
9543
9544   v8::Handle<v8::ObjectTemplate> global_template =
9545       func_template->InstanceTemplate();
9546
9547   v8::Handle<v8::ObjectTemplate> proto_template =
9548       func_template->PrototypeTemplate();
9549
9550   // Add an accessor to proto that's accessible by cross-domain JS code.
9551   proto_template->SetAccessor(v8_str("accessible"),
9552                               ConstTenGetter, 0,
9553                               v8::Handle<Value>(),
9554                               v8::ALL_CAN_READ);
9555
9556   // Add an accessor that is not accessible by cross-domain JS code.
9557   global_template->SetAccessor(v8_str("unreachable"),
9558                                UnreachableGetter, 0,
9559                                v8::Handle<Value>(),
9560                                v8::DEFAULT);
9561
9562   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9563   context0->Enter();
9564
9565   Local<v8::Object> global = context0->Global();
9566   // Add a normal property that shadows 'accessible'
9567   global->Set(v8_str("accessible"), v8_num(11));
9568
9569   // Enter a new context.
9570   v8::HandleScope scope1(CcTest::isolate());
9571   v8::Local<Context> context1 = Context::New(isolate);
9572   context1->Enter();
9573
9574   v8::Handle<v8::Object> global1 = context1->Global();
9575   global1->Set(v8_str("other"), global);
9576
9577   // Should return 10, instead of 11
9578   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9579   CHECK(value->IsNumber());
9580   CHECK_EQ(10, value->Int32Value());
9581
9582   value = v8_compile("other.unreachable")->Run();
9583   CHECK(value->IsUndefined());
9584
9585   context1->Exit();
9586   context0->Exit();
9587 }
9588
9589
9590 static int named_access_count = 0;
9591 static int indexed_access_count = 0;
9592
9593 static bool NamedAccessCounter(Local<v8::Object> global,
9594                                Local<Value> name,
9595                                v8::AccessType type,
9596                                Local<Value> data) {
9597   named_access_count++;
9598   return true;
9599 }
9600
9601
9602 static bool IndexedAccessCounter(Local<v8::Object> global,
9603                                  uint32_t key,
9604                                  v8::AccessType type,
9605                                  Local<Value> data) {
9606   indexed_access_count++;
9607   return true;
9608 }
9609
9610
9611 // This one is too easily disturbed by other tests.
9612 TEST(AccessControlIC) {
9613   named_access_count = 0;
9614   indexed_access_count = 0;
9615
9616   v8::Isolate* isolate = CcTest::isolate();
9617   v8::HandleScope handle_scope(isolate);
9618
9619   // Create an environment.
9620   v8::Local<Context> context0 = Context::New(isolate);
9621   context0->Enter();
9622
9623   // Create an object that requires access-check functions to be
9624   // called for cross-domain access.
9625   v8::Handle<v8::ObjectTemplate> object_template =
9626       v8::ObjectTemplate::New(isolate);
9627   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9628                                            IndexedAccessCounter);
9629   Local<v8::Object> object = object_template->NewInstance();
9630
9631   v8::HandleScope scope1(isolate);
9632
9633   // Create another environment.
9634   v8::Local<Context> context1 = Context::New(isolate);
9635   context1->Enter();
9636
9637   // Make easy access to the object from the other environment.
9638   v8::Handle<v8::Object> global1 = context1->Global();
9639   global1->Set(v8_str("obj"), object);
9640
9641   v8::Handle<Value> value;
9642
9643   // Check that the named access-control function is called every time.
9644   CompileRun("function testProp(obj) {"
9645              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9646              "  for (var j = 0; j < 10; j++) obj.prop;"
9647              "  return obj.prop"
9648              "}");
9649   value = CompileRun("testProp(obj)");
9650   CHECK(value->IsNumber());
9651   CHECK_EQ(1, value->Int32Value());
9652   CHECK_EQ(21, named_access_count);
9653
9654   // Check that the named access-control function is called every time.
9655   CompileRun("var p = 'prop';"
9656              "function testKeyed(obj) {"
9657              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9658              "  for (var j = 0; j < 10; j++) obj[p];"
9659              "  return obj[p];"
9660              "}");
9661   // Use obj which requires access checks.  No inline caching is used
9662   // in that case.
9663   value = CompileRun("testKeyed(obj)");
9664   CHECK(value->IsNumber());
9665   CHECK_EQ(1, value->Int32Value());
9666   CHECK_EQ(42, named_access_count);
9667   // Force the inline caches into generic state and try again.
9668   CompileRun("testKeyed({ a: 0 })");
9669   CompileRun("testKeyed({ b: 0 })");
9670   value = CompileRun("testKeyed(obj)");
9671   CHECK(value->IsNumber());
9672   CHECK_EQ(1, value->Int32Value());
9673   CHECK_EQ(63, named_access_count);
9674
9675   // Check that the indexed access-control function is called every time.
9676   CompileRun("function testIndexed(obj) {"
9677              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9678              "  for (var j = 0; j < 10; j++) obj[0];"
9679              "  return obj[0]"
9680              "}");
9681   value = CompileRun("testIndexed(obj)");
9682   CHECK(value->IsNumber());
9683   CHECK_EQ(1, value->Int32Value());
9684   CHECK_EQ(21, indexed_access_count);
9685   // Force the inline caches into generic state.
9686   CompileRun("testIndexed(new Array(1))");
9687   // Test that the indexed access check is called.
9688   value = CompileRun("testIndexed(obj)");
9689   CHECK(value->IsNumber());
9690   CHECK_EQ(1, value->Int32Value());
9691   CHECK_EQ(42, indexed_access_count);
9692
9693   // Check that the named access check is called when invoking
9694   // functions on an object that requires access checks.
9695   CompileRun("obj.f = function() {}");
9696   CompileRun("function testCallNormal(obj) {"
9697              "  for (var i = 0; i < 10; i++) obj.f();"
9698              "}");
9699   CompileRun("testCallNormal(obj)");
9700   CHECK_EQ(74, named_access_count);
9701
9702   // Force obj into slow case.
9703   value = CompileRun("delete obj.prop");
9704   CHECK(value->BooleanValue());
9705   // Force inline caches into dictionary probing mode.
9706   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9707   // Test that the named access check is called.
9708   value = CompileRun("testProp(obj);");
9709   CHECK(value->IsNumber());
9710   CHECK_EQ(1, value->Int32Value());
9711   CHECK_EQ(96, named_access_count);
9712
9713   // Force the call inline cache into dictionary probing mode.
9714   CompileRun("o.f = function() {}; testCallNormal(o)");
9715   // Test that the named access check is still called for each
9716   // invocation of the function.
9717   value = CompileRun("testCallNormal(obj)");
9718   CHECK_EQ(106, named_access_count);
9719
9720   context1->Exit();
9721   context0->Exit();
9722 }
9723
9724
9725 static bool NamedAccessFlatten(Local<v8::Object> global,
9726                                Local<Value> name,
9727                                v8::AccessType type,
9728                                Local<Value> data) {
9729   char buf[100];
9730   int len;
9731
9732   CHECK(name->IsString());
9733
9734   memset(buf, 0x1, sizeof(buf));
9735   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9736   CHECK_EQ(4, len);
9737
9738   uint16_t buf2[100];
9739
9740   memset(buf, 0x1, sizeof(buf));
9741   len = name.As<String>()->Write(buf2);
9742   CHECK_EQ(4, len);
9743
9744   return true;
9745 }
9746
9747
9748 static bool IndexedAccessFlatten(Local<v8::Object> global,
9749                                  uint32_t key,
9750                                  v8::AccessType type,
9751                                  Local<Value> data) {
9752   return true;
9753 }
9754
9755
9756 // Regression test.  In access checks, operations that may cause
9757 // garbage collection are not allowed.  It used to be the case that
9758 // using the Write operation on a string could cause a garbage
9759 // collection due to flattening of the string.  This is no longer the
9760 // case.
9761 THREADED_TEST(AccessControlFlatten) {
9762   named_access_count = 0;
9763   indexed_access_count = 0;
9764
9765   v8::Isolate* isolate = CcTest::isolate();
9766   v8::HandleScope handle_scope(isolate);
9767
9768   // Create an environment.
9769   v8::Local<Context> context0 = Context::New(isolate);
9770   context0->Enter();
9771
9772   // Create an object that requires access-check functions to be
9773   // called for cross-domain access.
9774   v8::Handle<v8::ObjectTemplate> object_template =
9775       v8::ObjectTemplate::New(isolate);
9776   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9777                                            IndexedAccessFlatten);
9778   Local<v8::Object> object = object_template->NewInstance();
9779
9780   v8::HandleScope scope1(isolate);
9781
9782   // Create another environment.
9783   v8::Local<Context> context1 = Context::New(isolate);
9784   context1->Enter();
9785
9786   // Make easy access to the object from the other environment.
9787   v8::Handle<v8::Object> global1 = context1->Global();
9788   global1->Set(v8_str("obj"), object);
9789
9790   v8::Handle<Value> value;
9791
9792   value = v8_compile("var p = 'as' + 'df';")->Run();
9793   value = v8_compile("obj[p];")->Run();
9794
9795   context1->Exit();
9796   context0->Exit();
9797 }
9798
9799
9800 static void AccessControlNamedGetter(
9801     Local<String>,
9802     const v8::PropertyCallbackInfo<v8::Value>& info) {
9803   info.GetReturnValue().Set(42);
9804 }
9805
9806
9807 static void AccessControlNamedSetter(
9808     Local<String>,
9809     Local<Value> value,
9810     const v8::PropertyCallbackInfo<v8::Value>& info) {
9811   info.GetReturnValue().Set(value);
9812 }
9813
9814
9815 static void AccessControlIndexedGetter(
9816       uint32_t index,
9817       const v8::PropertyCallbackInfo<v8::Value>& info) {
9818   info.GetReturnValue().Set(v8_num(42));
9819 }
9820
9821
9822 static void AccessControlIndexedSetter(
9823     uint32_t,
9824     Local<Value> value,
9825     const v8::PropertyCallbackInfo<v8::Value>& info) {
9826   info.GetReturnValue().Set(value);
9827 }
9828
9829
9830 THREADED_TEST(AccessControlInterceptorIC) {
9831   named_access_count = 0;
9832   indexed_access_count = 0;
9833
9834   v8::Isolate* isolate = CcTest::isolate();
9835   v8::HandleScope handle_scope(isolate);
9836
9837   // Create an environment.
9838   v8::Local<Context> context0 = Context::New(isolate);
9839   context0->Enter();
9840
9841   // Create an object that requires access-check functions to be
9842   // called for cross-domain access.  The object also has interceptors
9843   // interceptor.
9844   v8::Handle<v8::ObjectTemplate> object_template =
9845       v8::ObjectTemplate::New(isolate);
9846   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9847                                            IndexedAccessCounter);
9848   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9849                                            AccessControlNamedSetter);
9850   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9851                                              AccessControlIndexedSetter);
9852   Local<v8::Object> object = object_template->NewInstance();
9853
9854   v8::HandleScope scope1(isolate);
9855
9856   // Create another environment.
9857   v8::Local<Context> context1 = Context::New(isolate);
9858   context1->Enter();
9859
9860   // Make easy access to the object from the other environment.
9861   v8::Handle<v8::Object> global1 = context1->Global();
9862   global1->Set(v8_str("obj"), object);
9863
9864   v8::Handle<Value> value;
9865
9866   // Check that the named access-control function is called every time
9867   // eventhough there is an interceptor on the object.
9868   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9869   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9870                      "obj.x")->Run();
9871   CHECK(value->IsNumber());
9872   CHECK_EQ(42, value->Int32Value());
9873   CHECK_EQ(21, named_access_count);
9874
9875   value = v8_compile("var p = 'x';")->Run();
9876   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9877   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9878                      "obj[p]")->Run();
9879   CHECK(value->IsNumber());
9880   CHECK_EQ(42, value->Int32Value());
9881   CHECK_EQ(42, named_access_count);
9882
9883   // Check that the indexed access-control function is called every
9884   // time eventhough there is an interceptor on the object.
9885   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9886   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9887                      "obj[0]")->Run();
9888   CHECK(value->IsNumber());
9889   CHECK_EQ(42, value->Int32Value());
9890   CHECK_EQ(21, indexed_access_count);
9891
9892   context1->Exit();
9893   context0->Exit();
9894 }
9895
9896
9897 THREADED_TEST(Version) {
9898   v8::V8::GetVersion();
9899 }
9900
9901
9902 static void InstanceFunctionCallback(
9903     const v8::FunctionCallbackInfo<v8::Value>& args) {
9904   ApiTestFuzzer::Fuzz();
9905   args.GetReturnValue().Set(v8_num(12));
9906 }
9907
9908
9909 THREADED_TEST(InstanceProperties) {
9910   LocalContext context;
9911   v8::Isolate* isolate = context->GetIsolate();
9912   v8::HandleScope handle_scope(isolate);
9913
9914   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9915   Local<ObjectTemplate> instance = t->InstanceTemplate();
9916
9917   instance->Set(v8_str("x"), v8_num(42));
9918   instance->Set(v8_str("f"),
9919                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9920
9921   Local<Value> o = t->GetFunction()->NewInstance();
9922
9923   context->Global()->Set(v8_str("i"), o);
9924   Local<Value> value = CompileRun("i.x");
9925   CHECK_EQ(42, value->Int32Value());
9926
9927   value = CompileRun("i.f()");
9928   CHECK_EQ(12, value->Int32Value());
9929 }
9930
9931
9932 static void GlobalObjectInstancePropertiesGet(
9933     Local<String> key,
9934     const v8::PropertyCallbackInfo<v8::Value>&) {
9935   ApiTestFuzzer::Fuzz();
9936 }
9937
9938
9939 THREADED_TEST(GlobalObjectInstanceProperties) {
9940   v8::Isolate* isolate = CcTest::isolate();
9941   v8::HandleScope handle_scope(isolate);
9942
9943   Local<Value> global_object;
9944
9945   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9946   t->InstanceTemplate()->SetNamedPropertyHandler(
9947       GlobalObjectInstancePropertiesGet);
9948   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9949   instance_template->Set(v8_str("x"), v8_num(42));
9950   instance_template->Set(v8_str("f"),
9951                          v8::FunctionTemplate::New(isolate,
9952                                                    InstanceFunctionCallback));
9953
9954   // The script to check how Crankshaft compiles missing global function
9955   // invocations.  function g is not defined and should throw on call.
9956   const char* script =
9957       "function wrapper(call) {"
9958       "  var x = 0, y = 1;"
9959       "  for (var i = 0; i < 1000; i++) {"
9960       "    x += i * 100;"
9961       "    y += i * 100;"
9962       "  }"
9963       "  if (call) g();"
9964       "}"
9965       "for (var i = 0; i < 17; i++) wrapper(false);"
9966       "var thrown = 0;"
9967       "try { wrapper(true); } catch (e) { thrown = 1; };"
9968       "thrown";
9969
9970   {
9971     LocalContext env(NULL, instance_template);
9972     // Hold on to the global object so it can be used again in another
9973     // environment initialization.
9974     global_object = env->Global();
9975
9976     Local<Value> value = CompileRun("x");
9977     CHECK_EQ(42, value->Int32Value());
9978     value = CompileRun("f()");
9979     CHECK_EQ(12, value->Int32Value());
9980     value = CompileRun(script);
9981     CHECK_EQ(1, value->Int32Value());
9982   }
9983
9984   {
9985     // Create new environment reusing the global object.
9986     LocalContext env(NULL, instance_template, global_object);
9987     Local<Value> value = CompileRun("x");
9988     CHECK_EQ(42, value->Int32Value());
9989     value = CompileRun("f()");
9990     CHECK_EQ(12, value->Int32Value());
9991     value = CompileRun(script);
9992     CHECK_EQ(1, value->Int32Value());
9993   }
9994 }
9995
9996
9997 THREADED_TEST(CallKnownGlobalReceiver) {
9998   v8::Isolate* isolate = CcTest::isolate();
9999   v8::HandleScope handle_scope(isolate);
10000
10001   Local<Value> global_object;
10002
10003   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10004   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10005
10006   // The script to check that we leave global object not
10007   // global object proxy on stack when we deoptimize from inside
10008   // arguments evaluation.
10009   // To provoke error we need to both force deoptimization
10010   // from arguments evaluation and to force CallIC to take
10011   // CallIC_Miss code path that can't cope with global proxy.
10012   const char* script =
10013       "function bar(x, y) { try { } finally { } }"
10014       "function baz(x) { try { } finally { } }"
10015       "function bom(x) { try { } finally { } }"
10016       "function foo(x) { bar([x], bom(2)); }"
10017       "for (var i = 0; i < 10000; i++) foo(1);"
10018       "foo";
10019
10020   Local<Value> foo;
10021   {
10022     LocalContext env(NULL, instance_template);
10023     // Hold on to the global object so it can be used again in another
10024     // environment initialization.
10025     global_object = env->Global();
10026     foo = CompileRun(script);
10027   }
10028
10029   {
10030     // Create new environment reusing the global object.
10031     LocalContext env(NULL, instance_template, global_object);
10032     env->Global()->Set(v8_str("foo"), foo);
10033     CompileRun("foo()");
10034   }
10035 }
10036
10037
10038 static void ShadowFunctionCallback(
10039     const v8::FunctionCallbackInfo<v8::Value>& args) {
10040   ApiTestFuzzer::Fuzz();
10041   args.GetReturnValue().Set(v8_num(42));
10042 }
10043
10044
10045 static int shadow_y;
10046 static int shadow_y_setter_call_count;
10047 static int shadow_y_getter_call_count;
10048
10049
10050 static void ShadowYSetter(Local<String>,
10051                           Local<Value>,
10052                           const v8::PropertyCallbackInfo<void>&) {
10053   shadow_y_setter_call_count++;
10054   shadow_y = 42;
10055 }
10056
10057
10058 static void ShadowYGetter(Local<String> name,
10059                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10060   ApiTestFuzzer::Fuzz();
10061   shadow_y_getter_call_count++;
10062   info.GetReturnValue().Set(v8_num(shadow_y));
10063 }
10064
10065
10066 static void ShadowIndexedGet(uint32_t index,
10067                              const v8::PropertyCallbackInfo<v8::Value>&) {
10068 }
10069
10070
10071 static void ShadowNamedGet(Local<String> key,
10072                            const v8::PropertyCallbackInfo<v8::Value>&) {
10073 }
10074
10075
10076 THREADED_TEST(ShadowObject) {
10077   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10078   v8::Isolate* isolate = CcTest::isolate();
10079   v8::HandleScope handle_scope(isolate);
10080
10081   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10082   LocalContext context(NULL, global_template);
10083
10084   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10085   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10086   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10087   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10088   Local<ObjectTemplate> instance = t->InstanceTemplate();
10089
10090   proto->Set(v8_str("f"),
10091              v8::FunctionTemplate::New(isolate,
10092                                        ShadowFunctionCallback,
10093                                        Local<Value>()));
10094   proto->Set(v8_str("x"), v8_num(12));
10095
10096   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10097
10098   Local<Value> o = t->GetFunction()->NewInstance();
10099   context->Global()->Set(v8_str("__proto__"), o);
10100
10101   Local<Value> value =
10102       CompileRun("this.propertyIsEnumerable(0)");
10103   CHECK(value->IsBoolean());
10104   CHECK(!value->BooleanValue());
10105
10106   value = CompileRun("x");
10107   CHECK_EQ(12, value->Int32Value());
10108
10109   value = CompileRun("f()");
10110   CHECK_EQ(42, value->Int32Value());
10111
10112   CompileRun("y = 43");
10113   CHECK_EQ(1, shadow_y_setter_call_count);
10114   value = CompileRun("y");
10115   CHECK_EQ(1, shadow_y_getter_call_count);
10116   CHECK_EQ(42, value->Int32Value());
10117 }
10118
10119
10120 THREADED_TEST(HiddenPrototype) {
10121   LocalContext context;
10122   v8::Isolate* isolate = context->GetIsolate();
10123   v8::HandleScope handle_scope(isolate);
10124
10125   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10126   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10127   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10128   t1->SetHiddenPrototype(true);
10129   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10130   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10131   t2->SetHiddenPrototype(true);
10132   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10133   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10134   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10135
10136   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10137   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10138   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10139   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10140
10141   // Setting the prototype on an object skips hidden prototypes.
10142   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10143   o0->Set(v8_str("__proto__"), o1);
10144   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10145   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10146   o0->Set(v8_str("__proto__"), o2);
10147   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10148   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10149   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10150   o0->Set(v8_str("__proto__"), o3);
10151   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10152   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10153   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10154   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10155
10156   // Getting the prototype of o0 should get the first visible one
10157   // which is o3.  Therefore, z should not be defined on the prototype
10158   // object.
10159   Local<Value> proto = o0->Get(v8_str("__proto__"));
10160   CHECK(proto->IsObject());
10161   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10162 }
10163
10164
10165 THREADED_TEST(HiddenPrototypeSet) {
10166   LocalContext context;
10167   v8::Isolate* isolate = context->GetIsolate();
10168   v8::HandleScope handle_scope(isolate);
10169
10170   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10171   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10172   ht->SetHiddenPrototype(true);
10173   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10174   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10175
10176   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10177   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10178   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10179   o->Set(v8_str("__proto__"), h);
10180   h->Set(v8_str("__proto__"), p);
10181
10182   // Setting a property that exists on the hidden prototype goes there.
10183   o->Set(v8_str("x"), v8_num(7));
10184   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10185   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10186   CHECK(p->Get(v8_str("x"))->IsUndefined());
10187
10188   // Setting a new property should not be forwarded to the hidden prototype.
10189   o->Set(v8_str("y"), v8_num(6));
10190   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10191   CHECK(h->Get(v8_str("y"))->IsUndefined());
10192   CHECK(p->Get(v8_str("y"))->IsUndefined());
10193
10194   // Setting a property that only exists on a prototype of the hidden prototype
10195   // is treated normally again.
10196   p->Set(v8_str("z"), v8_num(8));
10197   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10198   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10199   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10200   o->Set(v8_str("z"), v8_num(9));
10201   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10202   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10203   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10204 }
10205
10206
10207 // Regression test for issue 2457.
10208 THREADED_TEST(HiddenPrototypeIdentityHash) {
10209   LocalContext context;
10210   v8::HandleScope handle_scope(context->GetIsolate());
10211
10212   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10213   t->SetHiddenPrototype(true);
10214   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10215   Handle<Object> p = t->GetFunction()->NewInstance();
10216   Handle<Object> o = Object::New(context->GetIsolate());
10217   o->SetPrototype(p);
10218
10219   int hash = o->GetIdentityHash();
10220   USE(hash);
10221   o->Set(v8_str("foo"), v8_num(42));
10222   ASSERT_EQ(hash, o->GetIdentityHash());
10223 }
10224
10225
10226 THREADED_TEST(SetPrototype) {
10227   LocalContext context;
10228   v8::Isolate* isolate = context->GetIsolate();
10229   v8::HandleScope handle_scope(isolate);
10230
10231   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10232   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10233   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10234   t1->SetHiddenPrototype(true);
10235   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10236   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10237   t2->SetHiddenPrototype(true);
10238   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10239   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10240   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10241
10242   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10243   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10244   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10245   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10246
10247   // Setting the prototype on an object does not skip hidden prototypes.
10248   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10249   CHECK(o0->SetPrototype(o1));
10250   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10251   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10252   CHECK(o1->SetPrototype(o2));
10253   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10254   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10255   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10256   CHECK(o2->SetPrototype(o3));
10257   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10258   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10259   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10260   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10261
10262   // Getting the prototype of o0 should get the first visible one
10263   // which is o3.  Therefore, z should not be defined on the prototype
10264   // object.
10265   Local<Value> proto = o0->Get(v8_str("__proto__"));
10266   CHECK(proto->IsObject());
10267   CHECK_EQ(proto.As<v8::Object>(), o3);
10268
10269   // However, Object::GetPrototype ignores hidden prototype.
10270   Local<Value> proto0 = o0->GetPrototype();
10271   CHECK(proto0->IsObject());
10272   CHECK_EQ(proto0.As<v8::Object>(), o1);
10273
10274   Local<Value> proto1 = o1->GetPrototype();
10275   CHECK(proto1->IsObject());
10276   CHECK_EQ(proto1.As<v8::Object>(), o2);
10277
10278   Local<Value> proto2 = o2->GetPrototype();
10279   CHECK(proto2->IsObject());
10280   CHECK_EQ(proto2.As<v8::Object>(), o3);
10281 }
10282
10283
10284 // Getting property names of an object with a prototype chain that
10285 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10286 // crash the runtime.
10287 THREADED_TEST(Regress91517) {
10288   i::FLAG_allow_natives_syntax = true;
10289   LocalContext context;
10290   v8::Isolate* isolate = context->GetIsolate();
10291   v8::HandleScope handle_scope(isolate);
10292
10293   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10294   t1->SetHiddenPrototype(true);
10295   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10296   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10297   t2->SetHiddenPrototype(true);
10298   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10299   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10300   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10301   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10302   t3->SetHiddenPrototype(true);
10303   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10304   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10305   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10306
10307   // Force dictionary-based properties.
10308   i::ScopedVector<char> name_buf(1024);
10309   for (int i = 1; i <= 1000; i++) {
10310     i::OS::SNPrintF(name_buf, "sdf%d", i);
10311     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10312   }
10313
10314   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10315   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10316   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10317   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10318
10319   // Create prototype chain of hidden prototypes.
10320   CHECK(o4->SetPrototype(o3));
10321   CHECK(o3->SetPrototype(o2));
10322   CHECK(o2->SetPrototype(o1));
10323
10324   // Call the runtime version of GetLocalPropertyNames() on the natively
10325   // created object through JavaScript.
10326   context->Global()->Set(v8_str("obj"), o4);
10327   // PROPERTY_ATTRIBUTES_NONE = 0
10328   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10329
10330   ExpectInt32("names.length", 1006);
10331   ExpectTrue("names.indexOf(\"baz\") >= 0");
10332   ExpectTrue("names.indexOf(\"boo\") >= 0");
10333   ExpectTrue("names.indexOf(\"foo\") >= 0");
10334   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10335   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10336   ExpectFalse("names[1005] == undefined");
10337 }
10338
10339
10340 // Getting property names of an object with a hidden and inherited
10341 // prototype should not duplicate the accessor properties inherited.
10342 THREADED_TEST(Regress269562) {
10343   i::FLAG_allow_natives_syntax = true;
10344   LocalContext context;
10345   v8::HandleScope handle_scope(context->GetIsolate());
10346
10347   Local<v8::FunctionTemplate> t1 =
10348       v8::FunctionTemplate::New(context->GetIsolate());
10349   t1->SetHiddenPrototype(true);
10350
10351   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10352   i1->SetAccessor(v8_str("foo"),
10353                   SimpleAccessorGetter, SimpleAccessorSetter);
10354   i1->SetAccessor(v8_str("bar"),
10355                   SimpleAccessorGetter, SimpleAccessorSetter);
10356   i1->SetAccessor(v8_str("baz"),
10357                   SimpleAccessorGetter, SimpleAccessorSetter);
10358   i1->Set(v8_str("n1"), v8_num(1));
10359   i1->Set(v8_str("n2"), v8_num(2));
10360
10361   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10362   Local<v8::FunctionTemplate> t2 =
10363       v8::FunctionTemplate::New(context->GetIsolate());
10364   t2->SetHiddenPrototype(true);
10365
10366   // Inherit from t1 and mark prototype as hidden.
10367   t2->Inherit(t1);
10368   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10369
10370   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10371   CHECK(o2->SetPrototype(o1));
10372
10373   v8::Local<v8::Symbol> sym =
10374       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10375   o1->Set(sym, v8_num(3));
10376   o1->SetHiddenValue(
10377       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10378
10379   // Call the runtime version of GetLocalPropertyNames() on
10380   // the natively created object through JavaScript.
10381   context->Global()->Set(v8_str("obj"), o2);
10382   context->Global()->Set(v8_str("sym"), sym);
10383   // PROPERTY_ATTRIBUTES_NONE = 0
10384   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10385
10386   ExpectInt32("names.length", 7);
10387   ExpectTrue("names.indexOf(\"foo\") >= 0");
10388   ExpectTrue("names.indexOf(\"bar\") >= 0");
10389   ExpectTrue("names.indexOf(\"baz\") >= 0");
10390   ExpectTrue("names.indexOf(\"n1\") >= 0");
10391   ExpectTrue("names.indexOf(\"n2\") >= 0");
10392   ExpectTrue("names.indexOf(sym) >= 0");
10393   ExpectTrue("names.indexOf(\"mine\") >= 0");
10394 }
10395
10396
10397 THREADED_TEST(FunctionReadOnlyPrototype) {
10398   LocalContext context;
10399   v8::Isolate* isolate = context->GetIsolate();
10400   v8::HandleScope handle_scope(isolate);
10401
10402   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10403   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10404   t1->ReadOnlyPrototype();
10405   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10406   // Configured value of ReadOnly flag.
10407   CHECK(CompileRun(
10408       "(function() {"
10409       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10410       "  return (descriptor['writable'] == false);"
10411       "})()")->BooleanValue());
10412   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10413   CHECK_EQ(42,
10414            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10415
10416   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10417   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10418   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10419   // Default value of ReadOnly flag.
10420   CHECK(CompileRun(
10421       "(function() {"
10422       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10423       "  return (descriptor['writable'] == true);"
10424       "})()")->BooleanValue());
10425   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10426 }
10427
10428
10429 THREADED_TEST(SetPrototypeThrows) {
10430   LocalContext context;
10431   v8::Isolate* isolate = context->GetIsolate();
10432   v8::HandleScope handle_scope(isolate);
10433
10434   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10435
10436   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10437   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10438
10439   CHECK(o0->SetPrototype(o1));
10440   // If setting the prototype leads to the cycle, SetPrototype should
10441   // return false and keep VM in sane state.
10442   v8::TryCatch try_catch;
10443   CHECK(!o1->SetPrototype(o0));
10444   CHECK(!try_catch.HasCaught());
10445   ASSERT(!CcTest::i_isolate()->has_pending_exception());
10446
10447   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10448 }
10449
10450
10451 THREADED_TEST(FunctionRemovePrototype) {
10452   LocalContext context;
10453   v8::Isolate* isolate = context->GetIsolate();
10454   v8::HandleScope handle_scope(isolate);
10455
10456   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10457   t1->RemovePrototype();
10458   Local<v8::Function> fun = t1->GetFunction();
10459   context->Global()->Set(v8_str("fun"), fun);
10460   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10461
10462   v8::TryCatch try_catch;
10463   CompileRun("new fun()");
10464   CHECK(try_catch.HasCaught());
10465
10466   try_catch.Reset();
10467   fun->NewInstance();
10468   CHECK(try_catch.HasCaught());
10469 }
10470
10471
10472 THREADED_TEST(GetterSetterExceptions) {
10473   LocalContext context;
10474   v8::Isolate* isolate = context->GetIsolate();
10475   v8::HandleScope handle_scope(isolate);
10476   CompileRun(
10477     "function Foo() { };"
10478     "function Throw() { throw 5; };"
10479     "var x = { };"
10480     "x.__defineSetter__('set', Throw);"
10481     "x.__defineGetter__('get', Throw);");
10482   Local<v8::Object> x =
10483       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10484   v8::TryCatch try_catch;
10485   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10486   x->Get(v8_str("get"));
10487   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10488   x->Get(v8_str("get"));
10489   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10490   x->Get(v8_str("get"));
10491   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10492   x->Get(v8_str("get"));
10493 }
10494
10495
10496 THREADED_TEST(Constructor) {
10497   LocalContext context;
10498   v8::Isolate* isolate = context->GetIsolate();
10499   v8::HandleScope handle_scope(isolate);
10500   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10501   templ->SetClassName(v8_str("Fun"));
10502   Local<Function> cons = templ->GetFunction();
10503   context->Global()->Set(v8_str("Fun"), cons);
10504   Local<v8::Object> inst = cons->NewInstance();
10505   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10506   CHECK(obj->IsJSObject());
10507   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10508   CHECK(value->BooleanValue());
10509 }
10510
10511
10512 static void ConstructorCallback(
10513     const v8::FunctionCallbackInfo<v8::Value>& args) {
10514   ApiTestFuzzer::Fuzz();
10515   Local<Object> This;
10516
10517   if (args.IsConstructCall()) {
10518     Local<Object> Holder = args.Holder();
10519     This = Object::New(args.GetIsolate());
10520     Local<Value> proto = Holder->GetPrototype();
10521     if (proto->IsObject()) {
10522       This->SetPrototype(proto);
10523     }
10524   } else {
10525     This = args.This();
10526   }
10527
10528   This->Set(v8_str("a"), args[0]);
10529   args.GetReturnValue().Set(This);
10530 }
10531
10532
10533 static void FakeConstructorCallback(
10534     const v8::FunctionCallbackInfo<v8::Value>& args) {
10535   ApiTestFuzzer::Fuzz();
10536   args.GetReturnValue().Set(args[0]);
10537 }
10538
10539
10540 THREADED_TEST(ConstructorForObject) {
10541   LocalContext context;
10542   v8::Isolate* isolate = context->GetIsolate();
10543   v8::HandleScope handle_scope(isolate);
10544
10545   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10546     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10547     Local<Object> instance = instance_template->NewInstance();
10548     context->Global()->Set(v8_str("obj"), instance);
10549     v8::TryCatch try_catch;
10550     Local<Value> value;
10551     CHECK(!try_catch.HasCaught());
10552
10553     // Call the Object's constructor with a 32-bit signed integer.
10554     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10555     CHECK(!try_catch.HasCaught());
10556     CHECK(value->IsInt32());
10557     CHECK_EQ(28, value->Int32Value());
10558
10559     Local<Value> args1[] = { v8_num(28) };
10560     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10561     CHECK(value_obj1->IsObject());
10562     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10563     value = object1->Get(v8_str("a"));
10564     CHECK(value->IsInt32());
10565     CHECK(!try_catch.HasCaught());
10566     CHECK_EQ(28, value->Int32Value());
10567
10568     // Call the Object's constructor with a String.
10569     value = CompileRun(
10570         "(function() { var o = new obj('tipli'); return o.a; })()");
10571     CHECK(!try_catch.HasCaught());
10572     CHECK(value->IsString());
10573     String::Utf8Value string_value1(value->ToString());
10574     CHECK_EQ("tipli", *string_value1);
10575
10576     Local<Value> args2[] = { v8_str("tipli") };
10577     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10578     CHECK(value_obj2->IsObject());
10579     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10580     value = object2->Get(v8_str("a"));
10581     CHECK(!try_catch.HasCaught());
10582     CHECK(value->IsString());
10583     String::Utf8Value string_value2(value->ToString());
10584     CHECK_EQ("tipli", *string_value2);
10585
10586     // Call the Object's constructor with a Boolean.
10587     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10588     CHECK(!try_catch.HasCaught());
10589     CHECK(value->IsBoolean());
10590     CHECK_EQ(true, value->BooleanValue());
10591
10592     Handle<Value> args3[] = { v8::True(isolate) };
10593     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10594     CHECK(value_obj3->IsObject());
10595     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10596     value = object3->Get(v8_str("a"));
10597     CHECK(!try_catch.HasCaught());
10598     CHECK(value->IsBoolean());
10599     CHECK_EQ(true, value->BooleanValue());
10600
10601     // Call the Object's constructor with undefined.
10602     Handle<Value> args4[] = { v8::Undefined(isolate) };
10603     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10604     CHECK(value_obj4->IsObject());
10605     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10606     value = object4->Get(v8_str("a"));
10607     CHECK(!try_catch.HasCaught());
10608     CHECK(value->IsUndefined());
10609
10610     // Call the Object's constructor with null.
10611     Handle<Value> args5[] = { v8::Null(isolate) };
10612     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10613     CHECK(value_obj5->IsObject());
10614     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10615     value = object5->Get(v8_str("a"));
10616     CHECK(!try_catch.HasCaught());
10617     CHECK(value->IsNull());
10618   }
10619
10620   // Check exception handling when there is no constructor set for the Object.
10621   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10622     Local<Object> instance = instance_template->NewInstance();
10623     context->Global()->Set(v8_str("obj2"), instance);
10624     v8::TryCatch try_catch;
10625     Local<Value> value;
10626     CHECK(!try_catch.HasCaught());
10627
10628     value = CompileRun("new obj2(28)");
10629     CHECK(try_catch.HasCaught());
10630     String::Utf8Value exception_value1(try_catch.Exception());
10631     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10632     try_catch.Reset();
10633
10634     Local<Value> args[] = { v8_num(29) };
10635     value = instance->CallAsConstructor(1, args);
10636     CHECK(try_catch.HasCaught());
10637     String::Utf8Value exception_value2(try_catch.Exception());
10638     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10639     try_catch.Reset();
10640   }
10641
10642   // Check the case when constructor throws exception.
10643   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10644     instance_template->SetCallAsFunctionHandler(ThrowValue);
10645     Local<Object> instance = instance_template->NewInstance();
10646     context->Global()->Set(v8_str("obj3"), instance);
10647     v8::TryCatch try_catch;
10648     Local<Value> value;
10649     CHECK(!try_catch.HasCaught());
10650
10651     value = CompileRun("new obj3(22)");
10652     CHECK(try_catch.HasCaught());
10653     String::Utf8Value exception_value1(try_catch.Exception());
10654     CHECK_EQ("22", *exception_value1);
10655     try_catch.Reset();
10656
10657     Local<Value> args[] = { v8_num(23) };
10658     value = instance->CallAsConstructor(1, args);
10659     CHECK(try_catch.HasCaught());
10660     String::Utf8Value exception_value2(try_catch.Exception());
10661     CHECK_EQ("23", *exception_value2);
10662     try_catch.Reset();
10663   }
10664
10665   // Check whether constructor returns with an object or non-object.
10666   { Local<FunctionTemplate> function_template =
10667         FunctionTemplate::New(isolate, FakeConstructorCallback);
10668     Local<Function> function = function_template->GetFunction();
10669     Local<Object> instance1 = function;
10670     context->Global()->Set(v8_str("obj4"), instance1);
10671     v8::TryCatch try_catch;
10672     Local<Value> value;
10673     CHECK(!try_catch.HasCaught());
10674
10675     CHECK(instance1->IsObject());
10676     CHECK(instance1->IsFunction());
10677
10678     value = CompileRun("new obj4(28)");
10679     CHECK(!try_catch.HasCaught());
10680     CHECK(value->IsObject());
10681
10682     Local<Value> args1[] = { v8_num(28) };
10683     value = instance1->CallAsConstructor(1, args1);
10684     CHECK(!try_catch.HasCaught());
10685     CHECK(value->IsObject());
10686
10687     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10688     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10689     Local<Object> instance2 = instance_template->NewInstance();
10690     context->Global()->Set(v8_str("obj5"), instance2);
10691     CHECK(!try_catch.HasCaught());
10692
10693     CHECK(instance2->IsObject());
10694     CHECK(!instance2->IsFunction());
10695
10696     value = CompileRun("new obj5(28)");
10697     CHECK(!try_catch.HasCaught());
10698     CHECK(!value->IsObject());
10699
10700     Local<Value> args2[] = { v8_num(28) };
10701     value = instance2->CallAsConstructor(1, args2);
10702     CHECK(!try_catch.HasCaught());
10703     CHECK(!value->IsObject());
10704   }
10705 }
10706
10707
10708 THREADED_TEST(FunctionDescriptorException) {
10709   LocalContext context;
10710   v8::Isolate* isolate = context->GetIsolate();
10711   v8::HandleScope handle_scope(isolate);
10712   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10713   templ->SetClassName(v8_str("Fun"));
10714   Local<Function> cons = templ->GetFunction();
10715   context->Global()->Set(v8_str("Fun"), cons);
10716   Local<Value> value = CompileRun(
10717     "function test() {"
10718     "  try {"
10719     "    (new Fun()).blah()"
10720     "  } catch (e) {"
10721     "    var str = String(e);"
10722     // "    if (str.indexOf('TypeError') == -1) return 1;"
10723     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10724     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10725     "    return 0;"
10726     "  }"
10727     "  return 4;"
10728     "}"
10729     "test();");
10730   CHECK_EQ(0, value->Int32Value());
10731 }
10732
10733
10734 THREADED_TEST(EvalAliasedDynamic) {
10735   LocalContext current;
10736   v8::HandleScope scope(current->GetIsolate());
10737
10738   // Tests where aliased eval can only be resolved dynamically.
10739   Local<Script> script = v8_compile(
10740       "function f(x) { "
10741       "  var foo = 2;"
10742       "  with (x) { return eval('foo'); }"
10743       "}"
10744       "foo = 0;"
10745       "result1 = f(new Object());"
10746       "result2 = f(this);"
10747       "var x = new Object();"
10748       "x.eval = function(x) { return 1; };"
10749       "result3 = f(x);");
10750   script->Run();
10751   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10752   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10753   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10754
10755   v8::TryCatch try_catch;
10756   script = v8_compile(
10757       "function f(x) { "
10758       "  var bar = 2;"
10759       "  with (x) { return eval('bar'); }"
10760       "}"
10761       "result4 = f(this)");
10762   script->Run();
10763   CHECK(!try_catch.HasCaught());
10764   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10765
10766   try_catch.Reset();
10767 }
10768
10769
10770 THREADED_TEST(CrossEval) {
10771   v8::HandleScope scope(CcTest::isolate());
10772   LocalContext other;
10773   LocalContext current;
10774
10775   Local<String> token = v8_str("<security token>");
10776   other->SetSecurityToken(token);
10777   current->SetSecurityToken(token);
10778
10779   // Set up reference from current to other.
10780   current->Global()->Set(v8_str("other"), other->Global());
10781
10782   // Check that new variables are introduced in other context.
10783   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10784   script->Run();
10785   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10786   CHECK_EQ(1234, foo->Int32Value());
10787   CHECK(!current->Global()->Has(v8_str("foo")));
10788
10789   // Check that writing to non-existing properties introduces them in
10790   // the other context.
10791   script = v8_compile("other.eval('na = 1234')");
10792   script->Run();
10793   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10794   CHECK(!current->Global()->Has(v8_str("na")));
10795
10796   // Check that global variables in current context are not visible in other
10797   // context.
10798   v8::TryCatch try_catch;
10799   script = v8_compile("var bar = 42; other.eval('bar');");
10800   Local<Value> result = script->Run();
10801   CHECK(try_catch.HasCaught());
10802   try_catch.Reset();
10803
10804   // Check that local variables in current context are not visible in other
10805   // context.
10806   script = v8_compile(
10807       "(function() { "
10808       "  var baz = 87;"
10809       "  return other.eval('baz');"
10810       "})();");
10811   result = script->Run();
10812   CHECK(try_catch.HasCaught());
10813   try_catch.Reset();
10814
10815   // Check that global variables in the other environment are visible
10816   // when evaluting code.
10817   other->Global()->Set(v8_str("bis"), v8_num(1234));
10818   script = v8_compile("other.eval('bis')");
10819   CHECK_EQ(1234, script->Run()->Int32Value());
10820   CHECK(!try_catch.HasCaught());
10821
10822   // Check that the 'this' pointer points to the global object evaluating
10823   // code.
10824   other->Global()->Set(v8_str("t"), other->Global());
10825   script = v8_compile("other.eval('this == t')");
10826   result = script->Run();
10827   CHECK(result->IsTrue());
10828   CHECK(!try_catch.HasCaught());
10829
10830   // Check that variables introduced in with-statement are not visible in
10831   // other context.
10832   script = v8_compile("with({x:2}){other.eval('x')}");
10833   result = script->Run();
10834   CHECK(try_catch.HasCaught());
10835   try_catch.Reset();
10836
10837   // Check that you cannot use 'eval.call' with another object than the
10838   // current global object.
10839   script = v8_compile("other.y = 1; eval.call(other, 'y')");
10840   result = script->Run();
10841   CHECK(try_catch.HasCaught());
10842 }
10843
10844
10845 // Test that calling eval in a context which has been detached from
10846 // its global throws an exception.  This behavior is consistent with
10847 // other JavaScript implementations.
10848 THREADED_TEST(EvalInDetachedGlobal) {
10849   v8::Isolate* isolate = CcTest::isolate();
10850   v8::HandleScope scope(isolate);
10851
10852   v8::Local<Context> context0 = Context::New(isolate);
10853   v8::Local<Context> context1 = Context::New(isolate);
10854
10855   // Set up function in context0 that uses eval from context0.
10856   context0->Enter();
10857   v8::Handle<v8::Value> fun =
10858       CompileRun("var x = 42;"
10859                  "(function() {"
10860                  "  var e = eval;"
10861                  "  return function(s) { return e(s); }"
10862                  "})()");
10863   context0->Exit();
10864
10865   // Put the function into context1 and call it before and after
10866   // detaching the global.  Before detaching, the call succeeds and
10867   // after detaching and exception is thrown.
10868   context1->Enter();
10869   context1->Global()->Set(v8_str("fun"), fun);
10870   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10871   CHECK_EQ(42, x_value->Int32Value());
10872   context0->DetachGlobal();
10873   v8::TryCatch catcher;
10874   x_value = CompileRun("fun('x')");
10875   CHECK(x_value.IsEmpty());
10876   CHECK(catcher.HasCaught());
10877   context1->Exit();
10878 }
10879
10880
10881 THREADED_TEST(CrossLazyLoad) {
10882   v8::HandleScope scope(CcTest::isolate());
10883   LocalContext other;
10884   LocalContext current;
10885
10886   Local<String> token = v8_str("<security token>");
10887   other->SetSecurityToken(token);
10888   current->SetSecurityToken(token);
10889
10890   // Set up reference from current to other.
10891   current->Global()->Set(v8_str("other"), other->Global());
10892
10893   // Trigger lazy loading in other context.
10894   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10895   Local<Value> value = script->Run();
10896   CHECK_EQ(42.0, value->NumberValue());
10897 }
10898
10899
10900 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10901   ApiTestFuzzer::Fuzz();
10902   if (args.IsConstructCall()) {
10903     if (args[0]->IsInt32()) {
10904       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10905       return;
10906     }
10907   }
10908
10909   args.GetReturnValue().Set(args[0]);
10910 }
10911
10912
10913 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10914   args.GetReturnValue().Set(args.This());
10915 }
10916
10917
10918 // Test that a call handler can be set for objects which will allow
10919 // non-function objects created through the API to be called as
10920 // functions.
10921 THREADED_TEST(CallAsFunction) {
10922   LocalContext context;
10923   v8::Isolate* isolate = context->GetIsolate();
10924   v8::HandleScope scope(isolate);
10925
10926   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10927     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10928     instance_template->SetCallAsFunctionHandler(call_as_function);
10929     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10930     context->Global()->Set(v8_str("obj"), instance);
10931     v8::TryCatch try_catch;
10932     Local<Value> value;
10933     CHECK(!try_catch.HasCaught());
10934
10935     value = CompileRun("obj(42)");
10936     CHECK(!try_catch.HasCaught());
10937     CHECK_EQ(42, value->Int32Value());
10938
10939     value = CompileRun("(function(o){return o(49)})(obj)");
10940     CHECK(!try_catch.HasCaught());
10941     CHECK_EQ(49, value->Int32Value());
10942
10943     // test special case of call as function
10944     value = CompileRun("[obj]['0'](45)");
10945     CHECK(!try_catch.HasCaught());
10946     CHECK_EQ(45, value->Int32Value());
10947
10948     value = CompileRun("obj.call = Function.prototype.call;"
10949                        "obj.call(null, 87)");
10950     CHECK(!try_catch.HasCaught());
10951     CHECK_EQ(87, value->Int32Value());
10952
10953     // Regression tests for bug #1116356: Calling call through call/apply
10954     // must work for non-function receivers.
10955     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10956     value = CompileRun(apply_99);
10957     CHECK(!try_catch.HasCaught());
10958     CHECK_EQ(99, value->Int32Value());
10959
10960     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10961     value = CompileRun(call_17);
10962     CHECK(!try_catch.HasCaught());
10963     CHECK_EQ(17, value->Int32Value());
10964
10965     // Check that the call-as-function handler can be called through
10966     // new.
10967     value = CompileRun("new obj(43)");
10968     CHECK(!try_catch.HasCaught());
10969     CHECK_EQ(-43, value->Int32Value());
10970
10971     // Check that the call-as-function handler can be called through
10972     // the API.
10973     v8::Handle<Value> args[] = { v8_num(28) };
10974     value = instance->CallAsFunction(instance, 1, args);
10975     CHECK(!try_catch.HasCaught());
10976     CHECK_EQ(28, value->Int32Value());
10977   }
10978
10979   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10980     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10981     USE(instance_template);
10982     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10983     context->Global()->Set(v8_str("obj2"), instance);
10984     v8::TryCatch try_catch;
10985     Local<Value> value;
10986     CHECK(!try_catch.HasCaught());
10987
10988     // Call an object without call-as-function handler through the JS
10989     value = CompileRun("obj2(28)");
10990     CHECK(value.IsEmpty());
10991     CHECK(try_catch.HasCaught());
10992     String::Utf8Value exception_value1(try_catch.Exception());
10993     // TODO(verwaest): Better message
10994     CHECK_EQ("TypeError: object is not a function",
10995              *exception_value1);
10996     try_catch.Reset();
10997
10998     // Call an object without call-as-function handler through the API
10999     value = CompileRun("obj2(28)");
11000     v8::Handle<Value> args[] = { v8_num(28) };
11001     value = instance->CallAsFunction(instance, 1, args);
11002     CHECK(value.IsEmpty());
11003     CHECK(try_catch.HasCaught());
11004     String::Utf8Value exception_value2(try_catch.Exception());
11005     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11006     try_catch.Reset();
11007   }
11008
11009   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11010     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11011     instance_template->SetCallAsFunctionHandler(ThrowValue);
11012     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11013     context->Global()->Set(v8_str("obj3"), instance);
11014     v8::TryCatch try_catch;
11015     Local<Value> value;
11016     CHECK(!try_catch.HasCaught());
11017
11018     // Catch the exception which is thrown by call-as-function handler
11019     value = CompileRun("obj3(22)");
11020     CHECK(try_catch.HasCaught());
11021     String::Utf8Value exception_value1(try_catch.Exception());
11022     CHECK_EQ("22", *exception_value1);
11023     try_catch.Reset();
11024
11025     v8::Handle<Value> args[] = { v8_num(23) };
11026     value = instance->CallAsFunction(instance, 1, args);
11027     CHECK(try_catch.HasCaught());
11028     String::Utf8Value exception_value2(try_catch.Exception());
11029     CHECK_EQ("23", *exception_value2);
11030     try_catch.Reset();
11031   }
11032
11033   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11034     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11035     instance_template->SetCallAsFunctionHandler(ReturnThis);
11036     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11037
11038     Local<v8::Value> a1 =
11039         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11040     CHECK(a1->StrictEquals(instance));
11041     Local<v8::Value> a2 =
11042         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11043     CHECK(a2->StrictEquals(instance));
11044     Local<v8::Value> a3 =
11045         instance->CallAsFunction(v8_num(42), 0, NULL);
11046     CHECK(a3->StrictEquals(instance));
11047     Local<v8::Value> a4 =
11048         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11049     CHECK(a4->StrictEquals(instance));
11050     Local<v8::Value> a5 =
11051         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11052     CHECK(a5->StrictEquals(instance));
11053   }
11054
11055   { CompileRun(
11056       "function ReturnThisSloppy() {"
11057       "  return this;"
11058       "}"
11059       "function ReturnThisStrict() {"
11060       "  'use strict';"
11061       "  return this;"
11062       "}");
11063     Local<Function> ReturnThisSloppy =
11064         Local<Function>::Cast(
11065             context->Global()->Get(v8_str("ReturnThisSloppy")));
11066     Local<Function> ReturnThisStrict =
11067         Local<Function>::Cast(
11068             context->Global()->Get(v8_str("ReturnThisStrict")));
11069
11070     Local<v8::Value> a1 =
11071         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11072     CHECK(a1->StrictEquals(context->Global()));
11073     Local<v8::Value> a2 =
11074         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11075     CHECK(a2->StrictEquals(context->Global()));
11076     Local<v8::Value> a3 =
11077         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11078     CHECK(a3->IsNumberObject());
11079     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11080     Local<v8::Value> a4 =
11081         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11082     CHECK(a4->IsStringObject());
11083     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11084     Local<v8::Value> a5 =
11085         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11086     CHECK(a5->IsBooleanObject());
11087     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11088
11089     Local<v8::Value> a6 =
11090         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11091     CHECK(a6->IsUndefined());
11092     Local<v8::Value> a7 =
11093         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11094     CHECK(a7->IsNull());
11095     Local<v8::Value> a8 =
11096         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11097     CHECK(a8->StrictEquals(v8_num(42)));
11098     Local<v8::Value> a9 =
11099         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11100     CHECK(a9->StrictEquals(v8_str("hello")));
11101     Local<v8::Value> a10 =
11102         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11103     CHECK(a10->StrictEquals(v8::True(isolate)));
11104   }
11105 }
11106
11107
11108 // Check whether a non-function object is callable.
11109 THREADED_TEST(CallableObject) {
11110   LocalContext context;
11111   v8::Isolate* isolate = context->GetIsolate();
11112   v8::HandleScope scope(isolate);
11113
11114   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11115     instance_template->SetCallAsFunctionHandler(call_as_function);
11116     Local<Object> instance = instance_template->NewInstance();
11117     v8::TryCatch try_catch;
11118
11119     CHECK(instance->IsCallable());
11120     CHECK(!try_catch.HasCaught());
11121   }
11122
11123   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11124     Local<Object> instance = instance_template->NewInstance();
11125     v8::TryCatch try_catch;
11126
11127     CHECK(!instance->IsCallable());
11128     CHECK(!try_catch.HasCaught());
11129   }
11130
11131   { Local<FunctionTemplate> function_template =
11132         FunctionTemplate::New(isolate, call_as_function);
11133     Local<Function> function = function_template->GetFunction();
11134     Local<Object> instance = function;
11135     v8::TryCatch try_catch;
11136
11137     CHECK(instance->IsCallable());
11138     CHECK(!try_catch.HasCaught());
11139   }
11140
11141   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11142     Local<Function> function = function_template->GetFunction();
11143     Local<Object> instance = function;
11144     v8::TryCatch try_catch;
11145
11146     CHECK(instance->IsCallable());
11147     CHECK(!try_catch.HasCaught());
11148   }
11149 }
11150
11151
11152 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11153   v8::HandleScope scope(isolate);
11154   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11155   for (int i = 0; i < iterations; i++) {
11156     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11157   }
11158   return Recurse(isolate, depth - 1, iterations);
11159 }
11160
11161
11162 THREADED_TEST(HandleIteration) {
11163   static const int kIterations = 500;
11164   static const int kNesting = 200;
11165   LocalContext context;
11166   v8::Isolate* isolate = context->GetIsolate();
11167   v8::HandleScope scope0(isolate);
11168   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11169   {
11170     v8::HandleScope scope1(isolate);
11171     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11172     for (int i = 0; i < kIterations; i++) {
11173       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11174       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11175     }
11176
11177     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11178     {
11179       v8::HandleScope scope2(CcTest::isolate());
11180       for (int j = 0; j < kIterations; j++) {
11181         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11182         CHECK_EQ(j + 1 + kIterations,
11183                  v8::HandleScope::NumberOfHandles(isolate));
11184       }
11185     }
11186     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11187   }
11188   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11189   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11190 }
11191
11192
11193 static void InterceptorHasOwnPropertyGetter(
11194     Local<String> name,
11195     const v8::PropertyCallbackInfo<v8::Value>& info) {
11196   ApiTestFuzzer::Fuzz();
11197 }
11198
11199
11200 THREADED_TEST(InterceptorHasOwnProperty) {
11201   LocalContext context;
11202   v8::Isolate* isolate = context->GetIsolate();
11203   v8::HandleScope scope(isolate);
11204   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11205   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11206   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11207   Local<Function> function = fun_templ->GetFunction();
11208   context->Global()->Set(v8_str("constructor"), function);
11209   v8::Handle<Value> value = CompileRun(
11210       "var o = new constructor();"
11211       "o.hasOwnProperty('ostehaps');");
11212   CHECK_EQ(false, value->BooleanValue());
11213   value = CompileRun(
11214       "o.ostehaps = 42;"
11215       "o.hasOwnProperty('ostehaps');");
11216   CHECK_EQ(true, value->BooleanValue());
11217   value = CompileRun(
11218       "var p = new constructor();"
11219       "p.hasOwnProperty('ostehaps');");
11220   CHECK_EQ(false, value->BooleanValue());
11221 }
11222
11223
11224 static void InterceptorHasOwnPropertyGetterGC(
11225     Local<String> name,
11226     const v8::PropertyCallbackInfo<v8::Value>& info) {
11227   ApiTestFuzzer::Fuzz();
11228   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11229 }
11230
11231
11232 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11233   LocalContext context;
11234   v8::Isolate* isolate = context->GetIsolate();
11235   v8::HandleScope scope(isolate);
11236   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11237   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11238   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11239   Local<Function> function = fun_templ->GetFunction();
11240   context->Global()->Set(v8_str("constructor"), function);
11241   // Let's first make some stuff so we can be sure to get a good GC.
11242   CompileRun(
11243       "function makestr(size) {"
11244       "  switch (size) {"
11245       "    case 1: return 'f';"
11246       "    case 2: return 'fo';"
11247       "    case 3: return 'foo';"
11248       "  }"
11249       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11250       "}"
11251       "var x = makestr(12345);"
11252       "x = makestr(31415);"
11253       "x = makestr(23456);");
11254   v8::Handle<Value> value = CompileRun(
11255       "var o = new constructor();"
11256       "o.__proto__ = new String(x);"
11257       "o.hasOwnProperty('ostehaps');");
11258   CHECK_EQ(false, value->BooleanValue());
11259 }
11260
11261
11262 typedef void (*NamedPropertyGetter)(
11263     Local<String> property,
11264     const v8::PropertyCallbackInfo<v8::Value>& info);
11265
11266
11267 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11268                                    const char* source,
11269                                    int expected) {
11270   v8::Isolate* isolate = CcTest::isolate();
11271   v8::HandleScope scope(isolate);
11272   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11273   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11274   LocalContext context;
11275   context->Global()->Set(v8_str("o"), templ->NewInstance());
11276   v8::Handle<Value> value = CompileRun(source);
11277   CHECK_EQ(expected, value->Int32Value());
11278 }
11279
11280
11281 static void InterceptorLoadICGetter(
11282     Local<String> name,
11283     const v8::PropertyCallbackInfo<v8::Value>& info) {
11284   ApiTestFuzzer::Fuzz();
11285   v8::Isolate* isolate = CcTest::isolate();
11286   CHECK_EQ(isolate, info.GetIsolate());
11287   CHECK_EQ(v8_str("data"), info.Data());
11288   CHECK_EQ(v8_str("x"), name);
11289   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11290 }
11291
11292
11293 // This test should hit the load IC for the interceptor case.
11294 THREADED_TEST(InterceptorLoadIC) {
11295   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11296     "var result = 0;"
11297     "for (var i = 0; i < 1000; i++) {"
11298     "  result = o.x;"
11299     "}",
11300     42);
11301 }
11302
11303
11304 // Below go several tests which verify that JITing for various
11305 // configurations of interceptor and explicit fields works fine
11306 // (those cases are special cased to get better performance).
11307
11308 static void InterceptorLoadXICGetter(
11309     Local<String> name,
11310     const v8::PropertyCallbackInfo<v8::Value>& info) {
11311   ApiTestFuzzer::Fuzz();
11312   info.GetReturnValue().Set(
11313       v8_str("x")->Equals(name) ?
11314           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11315           v8::Handle<v8::Value>());
11316 }
11317
11318
11319 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11320   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11321     "var result = 0;"
11322     "o.y = 239;"
11323     "for (var i = 0; i < 1000; i++) {"
11324     "  result = o.y;"
11325     "}",
11326     239);
11327 }
11328
11329
11330 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11331   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11332     "var result = 0;"
11333     "o.__proto__ = { 'y': 239 };"
11334     "for (var i = 0; i < 1000; i++) {"
11335     "  result = o.y + o.x;"
11336     "}",
11337     239 + 42);
11338 }
11339
11340
11341 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11342   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11343     "var result = 0;"
11344     "o.__proto__.y = 239;"
11345     "for (var i = 0; i < 1000; i++) {"
11346     "  result = o.y + o.x;"
11347     "}",
11348     239 + 42);
11349 }
11350
11351
11352 THREADED_TEST(InterceptorLoadICUndefined) {
11353   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11354     "var result = 0;"
11355     "for (var i = 0; i < 1000; i++) {"
11356     "  result = (o.y == undefined) ? 239 : 42;"
11357     "}",
11358     239);
11359 }
11360
11361
11362 THREADED_TEST(InterceptorLoadICWithOverride) {
11363   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11364     "fst = new Object();  fst.__proto__ = o;"
11365     "snd = new Object();  snd.__proto__ = fst;"
11366     "var result1 = 0;"
11367     "for (var i = 0; i < 1000;  i++) {"
11368     "  result1 = snd.x;"
11369     "}"
11370     "fst.x = 239;"
11371     "var result = 0;"
11372     "for (var i = 0; i < 1000; i++) {"
11373     "  result = snd.x;"
11374     "}"
11375     "result + result1",
11376     239 + 42);
11377 }
11378
11379
11380 // Test the case when we stored field into
11381 // a stub, but interceptor produced value on its own.
11382 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11383   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11384     "proto = new Object();"
11385     "o.__proto__ = proto;"
11386     "proto.x = 239;"
11387     "for (var i = 0; i < 1000; i++) {"
11388     "  o.x;"
11389     // Now it should be ICed and keep a reference to x defined on proto
11390     "}"
11391     "var result = 0;"
11392     "for (var i = 0; i < 1000; i++) {"
11393     "  result += o.x;"
11394     "}"
11395     "result;",
11396     42 * 1000);
11397 }
11398
11399
11400 // Test the case when we stored field into
11401 // a stub, but it got invalidated later on.
11402 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11403   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11404     "proto1 = new Object();"
11405     "proto2 = new Object();"
11406     "o.__proto__ = proto1;"
11407     "proto1.__proto__ = proto2;"
11408     "proto2.y = 239;"
11409     "for (var i = 0; i < 1000; i++) {"
11410     "  o.y;"
11411     // Now it should be ICed and keep a reference to y defined on proto2
11412     "}"
11413     "proto1.y = 42;"
11414     "var result = 0;"
11415     "for (var i = 0; i < 1000; i++) {"
11416     "  result += o.y;"
11417     "}"
11418     "result;",
11419     42 * 1000);
11420 }
11421
11422
11423 static int interceptor_load_not_handled_calls = 0;
11424 static void InterceptorLoadNotHandled(
11425     Local<String> name,
11426     const v8::PropertyCallbackInfo<v8::Value>& info) {
11427   ++interceptor_load_not_handled_calls;
11428 }
11429
11430
11431 // Test how post-interceptor lookups are done in the non-cacheable
11432 // case: the interceptor should not be invoked during this lookup.
11433 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11434   interceptor_load_not_handled_calls = 0;
11435   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11436     "receiver = new Object();"
11437     "receiver.__proto__ = o;"
11438     "proto = new Object();"
11439     "/* Make proto a slow-case object. */"
11440     "for (var i = 0; i < 1000; i++) {"
11441     "  proto[\"xxxxxxxx\" + i] = [];"
11442     "}"
11443     "proto.x = 17;"
11444     "o.__proto__ = proto;"
11445     "var result = 0;"
11446     "for (var i = 0; i < 1000; i++) {"
11447     "  result += receiver.x;"
11448     "}"
11449     "result;",
11450     17 * 1000);
11451   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11452 }
11453
11454
11455 // Test the case when we stored field into
11456 // a stub, but it got invalidated later on due to override on
11457 // global object which is between interceptor and fields' holders.
11458 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11459   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11460     "o.__proto__ = this;"  // set a global to be a proto of o.
11461     "this.__proto__.y = 239;"
11462     "for (var i = 0; i < 10; i++) {"
11463     "  if (o.y != 239) throw 'oops: ' + o.y;"
11464     // Now it should be ICed and keep a reference to y defined on field_holder.
11465     "}"
11466     "this.y = 42;"  // Assign on a global.
11467     "var result = 0;"
11468     "for (var i = 0; i < 10; i++) {"
11469     "  result += o.y;"
11470     "}"
11471     "result;",
11472     42 * 10);
11473 }
11474
11475
11476 static void SetOnThis(Local<String> name,
11477                       Local<Value> value,
11478                       const v8::PropertyCallbackInfo<void>& info) {
11479   Local<Object>::Cast(info.This())->ForceSet(name, value);
11480 }
11481
11482
11483 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11484   v8::Isolate* isolate = CcTest::isolate();
11485   v8::HandleScope scope(isolate);
11486   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11487   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11488   templ->SetAccessor(v8_str("y"), Return239Callback);
11489   LocalContext context;
11490   context->Global()->Set(v8_str("o"), templ->NewInstance());
11491
11492   // Check the case when receiver and interceptor's holder
11493   // are the same objects.
11494   v8::Handle<Value> value = CompileRun(
11495       "var result = 0;"
11496       "for (var i = 0; i < 7; i++) {"
11497       "  result = o.y;"
11498       "}");
11499   CHECK_EQ(239, value->Int32Value());
11500
11501   // Check the case when interceptor's holder is in proto chain
11502   // of receiver.
11503   value = CompileRun(
11504       "r = { __proto__: o };"
11505       "var result = 0;"
11506       "for (var i = 0; i < 7; i++) {"
11507       "  result = r.y;"
11508       "}");
11509   CHECK_EQ(239, value->Int32Value());
11510 }
11511
11512
11513 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11514   v8::Isolate* isolate = CcTest::isolate();
11515   v8::HandleScope scope(isolate);
11516   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11517   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11518   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11519   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11520
11521   LocalContext context;
11522   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11523   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11524
11525   // Check the case when receiver and interceptor's holder
11526   // are the same objects.
11527   v8::Handle<Value> value = CompileRun(
11528       "o.__proto__ = p;"
11529       "var result = 0;"
11530       "for (var i = 0; i < 7; i++) {"
11531       "  result = o.x + o.y;"
11532       "}");
11533   CHECK_EQ(239 + 42, value->Int32Value());
11534
11535   // Check the case when interceptor's holder is in proto chain
11536   // of receiver.
11537   value = CompileRun(
11538       "r = { __proto__: o };"
11539       "var result = 0;"
11540       "for (var i = 0; i < 7; i++) {"
11541       "  result = r.x + r.y;"
11542       "}");
11543   CHECK_EQ(239 + 42, value->Int32Value());
11544 }
11545
11546
11547 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11548   v8::Isolate* isolate = CcTest::isolate();
11549   v8::HandleScope scope(isolate);
11550   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11551   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11552   templ->SetAccessor(v8_str("y"), Return239Callback);
11553
11554   LocalContext context;
11555   context->Global()->Set(v8_str("o"), templ->NewInstance());
11556
11557   v8::Handle<Value> value = CompileRun(
11558     "fst = new Object();  fst.__proto__ = o;"
11559     "snd = new Object();  snd.__proto__ = fst;"
11560     "var result1 = 0;"
11561     "for (var i = 0; i < 7;  i++) {"
11562     "  result1 = snd.x;"
11563     "}"
11564     "fst.x = 239;"
11565     "var result = 0;"
11566     "for (var i = 0; i < 7; i++) {"
11567     "  result = snd.x;"
11568     "}"
11569     "result + result1");
11570   CHECK_EQ(239 + 42, value->Int32Value());
11571 }
11572
11573
11574 // Test the case when we stored callback into
11575 // a stub, but interceptor produced value on its own.
11576 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11577   v8::Isolate* isolate = CcTest::isolate();
11578   v8::HandleScope scope(isolate);
11579   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11580   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11581   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11582   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11583
11584   LocalContext context;
11585   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11586   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11587
11588   v8::Handle<Value> value = CompileRun(
11589     "o.__proto__ = p;"
11590     "for (var i = 0; i < 7; i++) {"
11591     "  o.x;"
11592     // Now it should be ICed and keep a reference to x defined on p
11593     "}"
11594     "var result = 0;"
11595     "for (var i = 0; i < 7; i++) {"
11596     "  result += o.x;"
11597     "}"
11598     "result");
11599   CHECK_EQ(42 * 7, value->Int32Value());
11600 }
11601
11602
11603 // Test the case when we stored callback into
11604 // a stub, but it got invalidated later on.
11605 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11606   v8::Isolate* isolate = CcTest::isolate();
11607   v8::HandleScope scope(isolate);
11608   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11609   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11610   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11611   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11612
11613   LocalContext context;
11614   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11615   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11616
11617   v8::Handle<Value> value = CompileRun(
11618     "inbetween = new Object();"
11619     "o.__proto__ = inbetween;"
11620     "inbetween.__proto__ = p;"
11621     "for (var i = 0; i < 10; i++) {"
11622     "  o.y;"
11623     // Now it should be ICed and keep a reference to y defined on p
11624     "}"
11625     "inbetween.y = 42;"
11626     "var result = 0;"
11627     "for (var i = 0; i < 10; i++) {"
11628     "  result += o.y;"
11629     "}"
11630     "result");
11631   CHECK_EQ(42 * 10, value->Int32Value());
11632 }
11633
11634
11635 // Test the case when we stored callback into
11636 // a stub, but it got invalidated later on due to override on
11637 // global object which is between interceptor and callbacks' holders.
11638 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11639   v8::Isolate* isolate = CcTest::isolate();
11640   v8::HandleScope scope(isolate);
11641   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11642   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11643   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11644   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11645
11646   LocalContext context;
11647   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11648   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11649
11650   v8::Handle<Value> value = CompileRun(
11651     "o.__proto__ = this;"
11652     "this.__proto__ = p;"
11653     "for (var i = 0; i < 10; i++) {"
11654     "  if (o.y != 239) throw 'oops: ' + o.y;"
11655     // Now it should be ICed and keep a reference to y defined on p
11656     "}"
11657     "this.y = 42;"
11658     "var result = 0;"
11659     "for (var i = 0; i < 10; i++) {"
11660     "  result += o.y;"
11661     "}"
11662     "result");
11663   CHECK_EQ(42 * 10, value->Int32Value());
11664 }
11665
11666
11667 static void InterceptorLoadICGetter0(
11668     Local<String> name,
11669     const v8::PropertyCallbackInfo<v8::Value>& info) {
11670   ApiTestFuzzer::Fuzz();
11671   CHECK(v8_str("x")->Equals(name));
11672   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11673 }
11674
11675
11676 THREADED_TEST(InterceptorReturningZero) {
11677   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11678      "o.x == undefined ? 1 : 0",
11679      0);
11680 }
11681
11682
11683 static void InterceptorStoreICSetter(
11684     Local<String> key,
11685     Local<Value> value,
11686     const v8::PropertyCallbackInfo<v8::Value>& info) {
11687   CHECK(v8_str("x")->Equals(key));
11688   CHECK_EQ(42, value->Int32Value());
11689   info.GetReturnValue().Set(value);
11690 }
11691
11692
11693 // This test should hit the store IC for the interceptor case.
11694 THREADED_TEST(InterceptorStoreIC) {
11695   v8::Isolate* isolate = CcTest::isolate();
11696   v8::HandleScope scope(isolate);
11697   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11698   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11699                                  InterceptorStoreICSetter,
11700                                  0, 0, 0, v8_str("data"));
11701   LocalContext context;
11702   context->Global()->Set(v8_str("o"), templ->NewInstance());
11703   CompileRun(
11704       "for (var i = 0; i < 1000; i++) {"
11705       "  o.x = 42;"
11706       "}");
11707 }
11708
11709
11710 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11711   v8::Isolate* isolate = CcTest::isolate();
11712   v8::HandleScope scope(isolate);
11713   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11714   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11715   LocalContext context;
11716   context->Global()->Set(v8_str("o"), templ->NewInstance());
11717   v8::Handle<Value> value = CompileRun(
11718     "for (var i = 0; i < 1000; i++) {"
11719     "  o.y = 239;"
11720     "}"
11721     "42 + o.y");
11722   CHECK_EQ(239 + 42, value->Int32Value());
11723 }
11724
11725
11726
11727
11728 v8::Handle<Value> call_ic_function;
11729 v8::Handle<Value> call_ic_function2;
11730 v8::Handle<Value> call_ic_function3;
11731
11732 static void InterceptorCallICGetter(
11733     Local<String> name,
11734     const v8::PropertyCallbackInfo<v8::Value>& info) {
11735   ApiTestFuzzer::Fuzz();
11736   CHECK(v8_str("x")->Equals(name));
11737   info.GetReturnValue().Set(call_ic_function);
11738 }
11739
11740
11741 // This test should hit the call IC for the interceptor case.
11742 THREADED_TEST(InterceptorCallIC) {
11743   v8::Isolate* isolate = CcTest::isolate();
11744   v8::HandleScope scope(isolate);
11745   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11746   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11747   LocalContext context;
11748   context->Global()->Set(v8_str("o"), templ->NewInstance());
11749   call_ic_function =
11750       v8_compile("function f(x) { return x + 1; }; f")->Run();
11751   v8::Handle<Value> value = CompileRun(
11752     "var result = 0;"
11753     "for (var i = 0; i < 1000; i++) {"
11754     "  result = o.x(41);"
11755     "}");
11756   CHECK_EQ(42, value->Int32Value());
11757 }
11758
11759
11760 // This test checks that if interceptor doesn't provide
11761 // a value, we can fetch regular value.
11762 THREADED_TEST(InterceptorCallICSeesOthers) {
11763   v8::Isolate* isolate = CcTest::isolate();
11764   v8::HandleScope scope(isolate);
11765   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11766   templ->SetNamedPropertyHandler(NoBlockGetterX);
11767   LocalContext context;
11768   context->Global()->Set(v8_str("o"), templ->NewInstance());
11769   v8::Handle<Value> value = CompileRun(
11770     "o.x = function f(x) { return x + 1; };"
11771     "var result = 0;"
11772     "for (var i = 0; i < 7; i++) {"
11773     "  result = o.x(41);"
11774     "}");
11775   CHECK_EQ(42, value->Int32Value());
11776 }
11777
11778
11779 static v8::Handle<Value> call_ic_function4;
11780 static void InterceptorCallICGetter4(
11781     Local<String> name,
11782     const v8::PropertyCallbackInfo<v8::Value>& info) {
11783   ApiTestFuzzer::Fuzz();
11784   CHECK(v8_str("x")->Equals(name));
11785   info.GetReturnValue().Set(call_ic_function4);
11786 }
11787
11788
11789 // This test checks that if interceptor provides a function,
11790 // even if we cached shadowed variant, interceptor's function
11791 // is invoked
11792 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11793   v8::Isolate* isolate = CcTest::isolate();
11794   v8::HandleScope scope(isolate);
11795   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11796   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11797   LocalContext context;
11798   context->Global()->Set(v8_str("o"), templ->NewInstance());
11799   call_ic_function4 =
11800       v8_compile("function f(x) { return x - 1; }; f")->Run();
11801   v8::Handle<Value> value = CompileRun(
11802     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11803     "var result = 0;"
11804     "for (var i = 0; i < 1000; i++) {"
11805     "  result = o.x(42);"
11806     "}");
11807   CHECK_EQ(41, value->Int32Value());
11808 }
11809
11810
11811 // Test the case when we stored cacheable lookup into
11812 // a stub, but it got invalidated later on
11813 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11814   v8::Isolate* isolate = CcTest::isolate();
11815   v8::HandleScope scope(isolate);
11816   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11817   templ->SetNamedPropertyHandler(NoBlockGetterX);
11818   LocalContext context;
11819   context->Global()->Set(v8_str("o"), templ->NewInstance());
11820   v8::Handle<Value> value = CompileRun(
11821     "proto1 = new Object();"
11822     "proto2 = new Object();"
11823     "o.__proto__ = proto1;"
11824     "proto1.__proto__ = proto2;"
11825     "proto2.y = function(x) { return x + 1; };"
11826     // Invoke it many times to compile a stub
11827     "for (var i = 0; i < 7; i++) {"
11828     "  o.y(42);"
11829     "}"
11830     "proto1.y = function(x) { return x - 1; };"
11831     "var result = 0;"
11832     "for (var i = 0; i < 7; i++) {"
11833     "  result += o.y(42);"
11834     "}");
11835   CHECK_EQ(41 * 7, value->Int32Value());
11836 }
11837
11838
11839 // This test checks that if interceptor doesn't provide a function,
11840 // cached constant function is used
11841 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11842   v8::Isolate* isolate = CcTest::isolate();
11843   v8::HandleScope scope(isolate);
11844   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11845   templ->SetNamedPropertyHandler(NoBlockGetterX);
11846   LocalContext context;
11847   context->Global()->Set(v8_str("o"), templ->NewInstance());
11848   v8::Handle<Value> value = CompileRun(
11849     "function inc(x) { return x + 1; };"
11850     "inc(1);"
11851     "o.x = inc;"
11852     "var result = 0;"
11853     "for (var i = 0; i < 1000; i++) {"
11854     "  result = o.x(42);"
11855     "}");
11856   CHECK_EQ(43, value->Int32Value());
11857 }
11858
11859
11860 static v8::Handle<Value> call_ic_function5;
11861 static void InterceptorCallICGetter5(
11862     Local<String> name,
11863     const v8::PropertyCallbackInfo<v8::Value>& info) {
11864   ApiTestFuzzer::Fuzz();
11865   if (v8_str("x")->Equals(name))
11866     info.GetReturnValue().Set(call_ic_function5);
11867 }
11868
11869
11870 // This test checks that if interceptor provides a function,
11871 // even if we cached constant function, interceptor's function
11872 // is invoked
11873 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11874   v8::Isolate* isolate = CcTest::isolate();
11875   v8::HandleScope scope(isolate);
11876   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11877   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11878   LocalContext context;
11879   context->Global()->Set(v8_str("o"), templ->NewInstance());
11880   call_ic_function5 =
11881       v8_compile("function f(x) { return x - 1; }; f")->Run();
11882   v8::Handle<Value> value = CompileRun(
11883     "function inc(x) { return x + 1; };"
11884     "inc(1);"
11885     "o.x = inc;"
11886     "var result = 0;"
11887     "for (var i = 0; i < 1000; i++) {"
11888     "  result = o.x(42);"
11889     "}");
11890   CHECK_EQ(41, value->Int32Value());
11891 }
11892
11893
11894 static v8::Handle<Value> call_ic_function6;
11895 static void InterceptorCallICGetter6(
11896     Local<String> name,
11897     const v8::PropertyCallbackInfo<v8::Value>& info) {
11898   ApiTestFuzzer::Fuzz();
11899   if (v8_str("x")->Equals(name))
11900     info.GetReturnValue().Set(call_ic_function6);
11901 }
11902
11903
11904 // Same test as above, except the code is wrapped in a function
11905 // to test the optimized compiler.
11906 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11907   i::FLAG_allow_natives_syntax = true;
11908   v8::Isolate* isolate = CcTest::isolate();
11909   v8::HandleScope scope(isolate);
11910   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11911   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11912   LocalContext context;
11913   context->Global()->Set(v8_str("o"), templ->NewInstance());
11914   call_ic_function6 =
11915       v8_compile("function f(x) { return x - 1; }; f")->Run();
11916   v8::Handle<Value> value = CompileRun(
11917     "function inc(x) { return x + 1; };"
11918     "inc(1);"
11919     "o.x = inc;"
11920     "function test() {"
11921     "  var result = 0;"
11922     "  for (var i = 0; i < 1000; i++) {"
11923     "    result = o.x(42);"
11924     "  }"
11925     "  return result;"
11926     "};"
11927     "test();"
11928     "test();"
11929     "test();"
11930     "%OptimizeFunctionOnNextCall(test);"
11931     "test()");
11932   CHECK_EQ(41, value->Int32Value());
11933 }
11934
11935
11936 // Test the case when we stored constant function into
11937 // a stub, but it got invalidated later on
11938 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11939   v8::Isolate* isolate = CcTest::isolate();
11940   v8::HandleScope scope(isolate);
11941   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11942   templ->SetNamedPropertyHandler(NoBlockGetterX);
11943   LocalContext context;
11944   context->Global()->Set(v8_str("o"), templ->NewInstance());
11945   v8::Handle<Value> value = CompileRun(
11946     "function inc(x) { return x + 1; };"
11947     "inc(1);"
11948     "proto1 = new Object();"
11949     "proto2 = new Object();"
11950     "o.__proto__ = proto1;"
11951     "proto1.__proto__ = proto2;"
11952     "proto2.y = inc;"
11953     // Invoke it many times to compile a stub
11954     "for (var i = 0; i < 7; i++) {"
11955     "  o.y(42);"
11956     "}"
11957     "proto1.y = function(x) { return x - 1; };"
11958     "var result = 0;"
11959     "for (var i = 0; i < 7; i++) {"
11960     "  result += o.y(42);"
11961     "}");
11962   CHECK_EQ(41 * 7, value->Int32Value());
11963 }
11964
11965
11966 // Test the case when we stored constant function into
11967 // a stub, but it got invalidated later on due to override on
11968 // global object which is between interceptor and constant function' holders.
11969 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11970   v8::Isolate* isolate = CcTest::isolate();
11971   v8::HandleScope scope(isolate);
11972   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11973   templ->SetNamedPropertyHandler(NoBlockGetterX);
11974   LocalContext context;
11975   context->Global()->Set(v8_str("o"), templ->NewInstance());
11976   v8::Handle<Value> value = CompileRun(
11977     "function inc(x) { return x + 1; };"
11978     "inc(1);"
11979     "o.__proto__ = this;"
11980     "this.__proto__.y = inc;"
11981     // Invoke it many times to compile a stub
11982     "for (var i = 0; i < 7; i++) {"
11983     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11984     "}"
11985     "this.y = function(x) { return x - 1; };"
11986     "var result = 0;"
11987     "for (var i = 0; i < 7; i++) {"
11988     "  result += o.y(42);"
11989     "}");
11990   CHECK_EQ(41 * 7, value->Int32Value());
11991 }
11992
11993
11994 // Test the case when actual function to call sits on global object.
11995 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11996   v8::Isolate* isolate = CcTest::isolate();
11997   v8::HandleScope scope(isolate);
11998   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11999   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12000
12001   LocalContext context;
12002   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12003
12004   v8::Handle<Value> value = CompileRun(
12005     "try {"
12006     "  o.__proto__ = this;"
12007     "  for (var i = 0; i < 10; i++) {"
12008     "    var v = o.parseFloat('239');"
12009     "    if (v != 239) throw v;"
12010       // Now it should be ICed and keep a reference to parseFloat.
12011     "  }"
12012     "  var result = 0;"
12013     "  for (var i = 0; i < 10; i++) {"
12014     "    result += o.parseFloat('239');"
12015     "  }"
12016     "  result"
12017     "} catch(e) {"
12018     "  e"
12019     "};");
12020   CHECK_EQ(239 * 10, value->Int32Value());
12021 }
12022
12023 static void InterceptorCallICFastApi(
12024     Local<String> name,
12025     const v8::PropertyCallbackInfo<v8::Value>& info) {
12026   ApiTestFuzzer::Fuzz();
12027   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12028   int* call_count =
12029       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12030   ++(*call_count);
12031   if ((*call_count) % 20 == 0) {
12032     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12033   }
12034 }
12035
12036 static void FastApiCallback_TrivialSignature(
12037     const v8::FunctionCallbackInfo<v8::Value>& args) {
12038   ApiTestFuzzer::Fuzz();
12039   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12040   v8::Isolate* isolate = CcTest::isolate();
12041   CHECK_EQ(isolate, args.GetIsolate());
12042   CHECK_EQ(args.This(), args.Holder());
12043   CHECK(args.Data()->Equals(v8_str("method_data")));
12044   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12045 }
12046
12047 static void FastApiCallback_SimpleSignature(
12048     const v8::FunctionCallbackInfo<v8::Value>& args) {
12049   ApiTestFuzzer::Fuzz();
12050   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12051   v8::Isolate* isolate = CcTest::isolate();
12052   CHECK_EQ(isolate, args.GetIsolate());
12053   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12054   CHECK(args.Data()->Equals(v8_str("method_data")));
12055   // Note, we're using HasRealNamedProperty instead of Has to avoid
12056   // invoking the interceptor again.
12057   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12058   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12059 }
12060
12061
12062 // Helper to maximize the odds of object moving.
12063 static void GenerateSomeGarbage() {
12064   CompileRun(
12065       "var garbage;"
12066       "for (var i = 0; i < 1000; i++) {"
12067       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12068       "}"
12069       "garbage = undefined;");
12070 }
12071
12072
12073 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12074   static int count = 0;
12075   if (count++ % 3 == 0) {
12076     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12077         // This should move the stub
12078     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12079   }
12080 }
12081
12082
12083 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12084   LocalContext context;
12085   v8::Isolate* isolate = context->GetIsolate();
12086   v8::HandleScope scope(isolate);
12087   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12088       v8::ObjectTemplate::New(isolate);
12089   nativeobject_templ->Set(isolate, "callback",
12090                           v8::FunctionTemplate::New(isolate,
12091                                                     DirectApiCallback));
12092   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12093   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12094   // call the api function multiple times to ensure direct call stub creation.
12095   CompileRun(
12096         "function f() {"
12097         "  for (var i = 1; i <= 30; i++) {"
12098         "    nativeobject.callback();"
12099         "  }"
12100         "}"
12101         "f();");
12102 }
12103
12104
12105 void ThrowingDirectApiCallback(
12106     const v8::FunctionCallbackInfo<v8::Value>& args) {
12107   args.GetIsolate()->ThrowException(v8_str("g"));
12108 }
12109
12110
12111 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12112   LocalContext context;
12113   v8::Isolate* isolate = context->GetIsolate();
12114   v8::HandleScope scope(isolate);
12115   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12116       v8::ObjectTemplate::New(isolate);
12117   nativeobject_templ->Set(isolate, "callback",
12118                           v8::FunctionTemplate::New(isolate,
12119                                                     ThrowingDirectApiCallback));
12120   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12121   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12122   // call the api function multiple times to ensure direct call stub creation.
12123   v8::Handle<Value> result = CompileRun(
12124       "var result = '';"
12125       "function f() {"
12126       "  for (var i = 1; i <= 5; i++) {"
12127       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12128       "  }"
12129       "}"
12130       "f(); result;");
12131   CHECK_EQ(v8_str("ggggg"), result);
12132 }
12133
12134
12135 static Handle<Value> DoDirectGetter() {
12136   if (++p_getter_count % 3 == 0) {
12137     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12138     GenerateSomeGarbage();
12139   }
12140   return v8_str("Direct Getter Result");
12141 }
12142
12143 static void DirectGetterCallback(
12144     Local<String> name,
12145     const v8::PropertyCallbackInfo<v8::Value>& info) {
12146   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12147   info.GetReturnValue().Set(DoDirectGetter());
12148 }
12149
12150
12151 template<typename Accessor>
12152 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12153   LocalContext context;
12154   v8::Isolate* isolate = context->GetIsolate();
12155   v8::HandleScope scope(isolate);
12156   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12157   obj->SetAccessor(v8_str("p1"), accessor);
12158   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12159   p_getter_count = 0;
12160   v8::Handle<v8::Value> result = CompileRun(
12161       "function f() {"
12162       "  for (var i = 0; i < 30; i++) o1.p1;"
12163       "  return o1.p1"
12164       "}"
12165       "f();");
12166   CHECK_EQ(v8_str("Direct Getter Result"), result);
12167   CHECK_EQ(31, p_getter_count);
12168 }
12169
12170
12171 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12172   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12173 }
12174
12175
12176 void ThrowingDirectGetterCallback(
12177     Local<String> name,
12178     const v8::PropertyCallbackInfo<v8::Value>& info) {
12179   info.GetIsolate()->ThrowException(v8_str("g"));
12180 }
12181
12182
12183 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12184   LocalContext context;
12185   v8::Isolate* isolate = context->GetIsolate();
12186   v8::HandleScope scope(isolate);
12187   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12188   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12189   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12190   v8::Handle<Value> result = CompileRun(
12191       "var result = '';"
12192       "for (var i = 0; i < 5; i++) {"
12193       "    try { o1.p1; } catch (e) { result += e; }"
12194       "}"
12195       "result;");
12196   CHECK_EQ(v8_str("ggggg"), result);
12197 }
12198
12199
12200 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12201   int interceptor_call_count = 0;
12202   v8::Isolate* isolate = CcTest::isolate();
12203   v8::HandleScope scope(isolate);
12204   v8::Handle<v8::FunctionTemplate> fun_templ =
12205       v8::FunctionTemplate::New(isolate);
12206   v8::Handle<v8::FunctionTemplate> method_templ =
12207       v8::FunctionTemplate::New(isolate,
12208                                 FastApiCallback_TrivialSignature,
12209                                 v8_str("method_data"),
12210                                 v8::Handle<v8::Signature>());
12211   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12212   proto_templ->Set(v8_str("method"), method_templ);
12213   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12214   templ->SetNamedPropertyHandler(
12215       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12216       v8::External::New(isolate, &interceptor_call_count));
12217   LocalContext context;
12218   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12219   GenerateSomeGarbage();
12220   context->Global()->Set(v8_str("o"), fun->NewInstance());
12221   CompileRun(
12222       "var result = 0;"
12223       "for (var i = 0; i < 100; i++) {"
12224       "  result = o.method(41);"
12225       "}");
12226   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12227   CHECK_EQ(100, interceptor_call_count);
12228 }
12229
12230
12231 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12232   int interceptor_call_count = 0;
12233   v8::Isolate* isolate = CcTest::isolate();
12234   v8::HandleScope scope(isolate);
12235   v8::Handle<v8::FunctionTemplate> fun_templ =
12236       v8::FunctionTemplate::New(isolate);
12237   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12238       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12239       v8::Signature::New(isolate, fun_templ));
12240   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12241   proto_templ->Set(v8_str("method"), method_templ);
12242   fun_templ->SetHiddenPrototype(true);
12243   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12244   templ->SetNamedPropertyHandler(
12245       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12246       v8::External::New(isolate, &interceptor_call_count));
12247   LocalContext context;
12248   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12249   GenerateSomeGarbage();
12250   context->Global()->Set(v8_str("o"), fun->NewInstance());
12251   CompileRun(
12252       "o.foo = 17;"
12253       "var receiver = {};"
12254       "receiver.__proto__ = o;"
12255       "var result = 0;"
12256       "for (var i = 0; i < 100; i++) {"
12257       "  result = receiver.method(41);"
12258       "}");
12259   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12260   CHECK_EQ(100, interceptor_call_count);
12261 }
12262
12263
12264 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12265   int interceptor_call_count = 0;
12266   v8::Isolate* isolate = CcTest::isolate();
12267   v8::HandleScope scope(isolate);
12268   v8::Handle<v8::FunctionTemplate> fun_templ =
12269       v8::FunctionTemplate::New(isolate);
12270   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12271       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12272       v8::Signature::New(isolate, fun_templ));
12273   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12274   proto_templ->Set(v8_str("method"), method_templ);
12275   fun_templ->SetHiddenPrototype(true);
12276   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12277   templ->SetNamedPropertyHandler(
12278       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12279       v8::External::New(isolate, &interceptor_call_count));
12280   LocalContext context;
12281   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12282   GenerateSomeGarbage();
12283   context->Global()->Set(v8_str("o"), fun->NewInstance());
12284   CompileRun(
12285       "o.foo = 17;"
12286       "var receiver = {};"
12287       "receiver.__proto__ = o;"
12288       "var result = 0;"
12289       "var saved_result = 0;"
12290       "for (var i = 0; i < 100; i++) {"
12291       "  result = receiver.method(41);"
12292       "  if (i == 50) {"
12293       "    saved_result = result;"
12294       "    receiver = {method: function(x) { return x - 1 }};"
12295       "  }"
12296       "}");
12297   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12298   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12299   CHECK_GE(interceptor_call_count, 50);
12300 }
12301
12302
12303 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12304   int interceptor_call_count = 0;
12305   v8::Isolate* isolate = CcTest::isolate();
12306   v8::HandleScope scope(isolate);
12307   v8::Handle<v8::FunctionTemplate> fun_templ =
12308       v8::FunctionTemplate::New(isolate);
12309   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12310       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12311       v8::Signature::New(isolate, fun_templ));
12312   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12313   proto_templ->Set(v8_str("method"), method_templ);
12314   fun_templ->SetHiddenPrototype(true);
12315   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12316   templ->SetNamedPropertyHandler(
12317       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12318       v8::External::New(isolate, &interceptor_call_count));
12319   LocalContext context;
12320   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12321   GenerateSomeGarbage();
12322   context->Global()->Set(v8_str("o"), fun->NewInstance());
12323   CompileRun(
12324       "o.foo = 17;"
12325       "var receiver = {};"
12326       "receiver.__proto__ = o;"
12327       "var result = 0;"
12328       "var saved_result = 0;"
12329       "for (var i = 0; i < 100; i++) {"
12330       "  result = receiver.method(41);"
12331       "  if (i == 50) {"
12332       "    saved_result = result;"
12333       "    o.method = function(x) { return x - 1 };"
12334       "  }"
12335       "}");
12336   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12337   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12338   CHECK_GE(interceptor_call_count, 50);
12339 }
12340
12341
12342 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12343   int interceptor_call_count = 0;
12344   v8::Isolate* isolate = CcTest::isolate();
12345   v8::HandleScope scope(isolate);
12346   v8::Handle<v8::FunctionTemplate> fun_templ =
12347       v8::FunctionTemplate::New(isolate);
12348   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12349       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12350       v8::Signature::New(isolate, fun_templ));
12351   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12352   proto_templ->Set(v8_str("method"), method_templ);
12353   fun_templ->SetHiddenPrototype(true);
12354   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12355   templ->SetNamedPropertyHandler(
12356       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12357       v8::External::New(isolate, &interceptor_call_count));
12358   LocalContext context;
12359   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12360   GenerateSomeGarbage();
12361   context->Global()->Set(v8_str("o"), fun->NewInstance());
12362   v8::TryCatch try_catch;
12363   CompileRun(
12364       "o.foo = 17;"
12365       "var receiver = {};"
12366       "receiver.__proto__ = o;"
12367       "var result = 0;"
12368       "var saved_result = 0;"
12369       "for (var i = 0; i < 100; i++) {"
12370       "  result = receiver.method(41);"
12371       "  if (i == 50) {"
12372       "    saved_result = result;"
12373       "    receiver = 333;"
12374       "  }"
12375       "}");
12376   CHECK(try_catch.HasCaught());
12377   // TODO(verwaest): Adjust message.
12378   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12379            try_catch.Exception()->ToString());
12380   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12381   CHECK_GE(interceptor_call_count, 50);
12382 }
12383
12384
12385 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12386   int interceptor_call_count = 0;
12387   v8::Isolate* isolate = CcTest::isolate();
12388   v8::HandleScope scope(isolate);
12389   v8::Handle<v8::FunctionTemplate> fun_templ =
12390       v8::FunctionTemplate::New(isolate);
12391   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12392       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12393       v8::Signature::New(isolate, fun_templ));
12394   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12395   proto_templ->Set(v8_str("method"), method_templ);
12396   fun_templ->SetHiddenPrototype(true);
12397   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12398   templ->SetNamedPropertyHandler(
12399       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12400       v8::External::New(isolate, &interceptor_call_count));
12401   LocalContext context;
12402   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12403   GenerateSomeGarbage();
12404   context->Global()->Set(v8_str("o"), fun->NewInstance());
12405   v8::TryCatch try_catch;
12406   CompileRun(
12407       "o.foo = 17;"
12408       "var receiver = {};"
12409       "receiver.__proto__ = o;"
12410       "var result = 0;"
12411       "var saved_result = 0;"
12412       "for (var i = 0; i < 100; i++) {"
12413       "  result = receiver.method(41);"
12414       "  if (i == 50) {"
12415       "    saved_result = result;"
12416       "    receiver = {method: receiver.method};"
12417       "  }"
12418       "}");
12419   CHECK(try_catch.HasCaught());
12420   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12421            try_catch.Exception()->ToString());
12422   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12423   CHECK_GE(interceptor_call_count, 50);
12424 }
12425
12426
12427 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12428   v8::Isolate* isolate = CcTest::isolate();
12429   v8::HandleScope scope(isolate);
12430   v8::Handle<v8::FunctionTemplate> fun_templ =
12431       v8::FunctionTemplate::New(isolate);
12432   v8::Handle<v8::FunctionTemplate> method_templ =
12433       v8::FunctionTemplate::New(isolate,
12434                                 FastApiCallback_TrivialSignature,
12435                                 v8_str("method_data"),
12436                                 v8::Handle<v8::Signature>());
12437   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12438   proto_templ->Set(v8_str("method"), method_templ);
12439   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12440   USE(templ);
12441   LocalContext context;
12442   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12443   GenerateSomeGarbage();
12444   context->Global()->Set(v8_str("o"), fun->NewInstance());
12445   CompileRun(
12446       "var result = 0;"
12447       "for (var i = 0; i < 100; i++) {"
12448       "  result = o.method(41);"
12449       "}");
12450
12451   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12452 }
12453
12454
12455 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12456   v8::Isolate* isolate = CcTest::isolate();
12457   v8::HandleScope scope(isolate);
12458   v8::Handle<v8::FunctionTemplate> fun_templ =
12459       v8::FunctionTemplate::New(isolate);
12460   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12461       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12462       v8::Signature::New(isolate, fun_templ));
12463   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12464   proto_templ->Set(v8_str("method"), method_templ);
12465   fun_templ->SetHiddenPrototype(true);
12466   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12467   CHECK(!templ.IsEmpty());
12468   LocalContext context;
12469   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12470   GenerateSomeGarbage();
12471   context->Global()->Set(v8_str("o"), fun->NewInstance());
12472   CompileRun(
12473       "o.foo = 17;"
12474       "var receiver = {};"
12475       "receiver.__proto__ = o;"
12476       "var result = 0;"
12477       "for (var i = 0; i < 100; i++) {"
12478       "  result = receiver.method(41);"
12479       "}");
12480
12481   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12482 }
12483
12484
12485 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12486   v8::Isolate* isolate = CcTest::isolate();
12487   v8::HandleScope scope(isolate);
12488   v8::Handle<v8::FunctionTemplate> fun_templ =
12489       v8::FunctionTemplate::New(isolate);
12490   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12491       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12492       v8::Signature::New(isolate, fun_templ));
12493   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12494   proto_templ->Set(v8_str("method"), method_templ);
12495   fun_templ->SetHiddenPrototype(true);
12496   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12497   CHECK(!templ.IsEmpty());
12498   LocalContext context;
12499   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12500   GenerateSomeGarbage();
12501   context->Global()->Set(v8_str("o"), fun->NewInstance());
12502   CompileRun(
12503       "o.foo = 17;"
12504       "var receiver = {};"
12505       "receiver.__proto__ = o;"
12506       "var result = 0;"
12507       "var saved_result = 0;"
12508       "for (var i = 0; i < 100; i++) {"
12509       "  result = receiver.method(41);"
12510       "  if (i == 50) {"
12511       "    saved_result = result;"
12512       "    receiver = {method: function(x) { return x - 1 }};"
12513       "  }"
12514       "}");
12515   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12516   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12517 }
12518
12519
12520 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12521   v8::Isolate* isolate = CcTest::isolate();
12522   v8::HandleScope scope(isolate);
12523   v8::Handle<v8::FunctionTemplate> fun_templ =
12524       v8::FunctionTemplate::New(isolate);
12525   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12526       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12527       v8::Signature::New(isolate, fun_templ));
12528   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12529   proto_templ->Set(v8_str("method"), method_templ);
12530   fun_templ->SetHiddenPrototype(true);
12531   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12532   CHECK(!templ.IsEmpty());
12533   LocalContext context;
12534   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12535   GenerateSomeGarbage();
12536   context->Global()->Set(v8_str("o"), fun->NewInstance());
12537   v8::TryCatch try_catch;
12538   CompileRun(
12539       "o.foo = 17;"
12540       "var receiver = {};"
12541       "receiver.__proto__ = o;"
12542       "var result = 0;"
12543       "var saved_result = 0;"
12544       "for (var i = 0; i < 100; i++) {"
12545       "  result = receiver.method(41);"
12546       "  if (i == 50) {"
12547       "    saved_result = result;"
12548       "    receiver = 333;"
12549       "  }"
12550       "}");
12551   CHECK(try_catch.HasCaught());
12552   // TODO(verwaest): Adjust message.
12553   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12554            try_catch.Exception()->ToString());
12555   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12556 }
12557
12558
12559 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12560   v8::Isolate* isolate = CcTest::isolate();
12561   v8::HandleScope scope(isolate);
12562   v8::Handle<v8::FunctionTemplate> fun_templ =
12563       v8::FunctionTemplate::New(isolate);
12564   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12565       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12566       v8::Signature::New(isolate, fun_templ));
12567   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12568   proto_templ->Set(v8_str("method"), method_templ);
12569   fun_templ->SetHiddenPrototype(true);
12570   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12571   CHECK(!templ.IsEmpty());
12572   LocalContext context;
12573   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12574   GenerateSomeGarbage();
12575   context->Global()->Set(v8_str("o"), fun->NewInstance());
12576   v8::TryCatch try_catch;
12577   CompileRun(
12578       "o.foo = 17;"
12579       "var receiver = {};"
12580       "receiver.__proto__ = o;"
12581       "var result = 0;"
12582       "var saved_result = 0;"
12583       "for (var i = 0; i < 100; i++) {"
12584       "  result = receiver.method(41);"
12585       "  if (i == 50) {"
12586       "    saved_result = result;"
12587       "    receiver = Object.create(receiver);"
12588       "  }"
12589       "}");
12590   CHECK(try_catch.HasCaught());
12591   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12592            try_catch.Exception()->ToString());
12593   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12594 }
12595
12596
12597 v8::Handle<Value> keyed_call_ic_function;
12598
12599 static void InterceptorKeyedCallICGetter(
12600     Local<String> name,
12601     const v8::PropertyCallbackInfo<v8::Value>& info) {
12602   ApiTestFuzzer::Fuzz();
12603   if (v8_str("x")->Equals(name)) {
12604     info.GetReturnValue().Set(keyed_call_ic_function);
12605   }
12606 }
12607
12608
12609 // Test the case when we stored cacheable lookup into
12610 // a stub, but the function name changed (to another cacheable function).
12611 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12612   v8::Isolate* isolate = CcTest::isolate();
12613   v8::HandleScope scope(isolate);
12614   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12615   templ->SetNamedPropertyHandler(NoBlockGetterX);
12616   LocalContext context;
12617   context->Global()->Set(v8_str("o"), templ->NewInstance());
12618   CompileRun(
12619     "proto = new Object();"
12620     "proto.y = function(x) { return x + 1; };"
12621     "proto.z = function(x) { return x - 1; };"
12622     "o.__proto__ = proto;"
12623     "var result = 0;"
12624     "var method = 'y';"
12625     "for (var i = 0; i < 10; i++) {"
12626     "  if (i == 5) { method = 'z'; };"
12627     "  result += o[method](41);"
12628     "}");
12629   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12630 }
12631
12632
12633 // Test the case when we stored cacheable lookup into
12634 // a stub, but the function name changed (and the new function is present
12635 // both before and after the interceptor in the prototype chain).
12636 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12637   v8::Isolate* isolate = CcTest::isolate();
12638   v8::HandleScope scope(isolate);
12639   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12640   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12641   LocalContext context;
12642   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12643   keyed_call_ic_function =
12644       v8_compile("function f(x) { return x - 1; }; f")->Run();
12645   CompileRun(
12646     "o = new Object();"
12647     "proto2 = new Object();"
12648     "o.y = function(x) { return x + 1; };"
12649     "proto2.y = function(x) { return x + 2; };"
12650     "o.__proto__ = proto1;"
12651     "proto1.__proto__ = proto2;"
12652     "var result = 0;"
12653     "var method = 'x';"
12654     "for (var i = 0; i < 10; i++) {"
12655     "  if (i == 5) { method = 'y'; };"
12656     "  result += o[method](41);"
12657     "}");
12658   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12659 }
12660
12661
12662 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12663 // on the global object.
12664 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12665   v8::Isolate* isolate = CcTest::isolate();
12666   v8::HandleScope scope(isolate);
12667   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12668   templ->SetNamedPropertyHandler(NoBlockGetterX);
12669   LocalContext context;
12670   context->Global()->Set(v8_str("o"), templ->NewInstance());
12671   CompileRun(
12672     "function inc(x) { return x + 1; };"
12673     "inc(1);"
12674     "function dec(x) { return x - 1; };"
12675     "dec(1);"
12676     "o.__proto__ = this;"
12677     "this.__proto__.x = inc;"
12678     "this.__proto__.y = dec;"
12679     "var result = 0;"
12680     "var method = 'x';"
12681     "for (var i = 0; i < 10; i++) {"
12682     "  if (i == 5) { method = 'y'; };"
12683     "  result += o[method](41);"
12684     "}");
12685   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12686 }
12687
12688
12689 // Test the case when actual function to call sits on global object.
12690 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12691   v8::Isolate* isolate = CcTest::isolate();
12692   v8::HandleScope scope(isolate);
12693   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12694   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12695   LocalContext context;
12696   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12697
12698   CompileRun(
12699     "function len(x) { return x.length; };"
12700     "o.__proto__ = this;"
12701     "var m = 'parseFloat';"
12702     "var result = 0;"
12703     "for (var i = 0; i < 10; i++) {"
12704     "  if (i == 5) {"
12705     "    m = 'len';"
12706     "    saved_result = result;"
12707     "  };"
12708     "  result = o[m]('239');"
12709     "}");
12710   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12711   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12712 }
12713
12714
12715 // Test the map transition before the interceptor.
12716 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12717   v8::Isolate* isolate = CcTest::isolate();
12718   v8::HandleScope scope(isolate);
12719   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12720   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12721   LocalContext context;
12722   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12723
12724   CompileRun(
12725     "var o = new Object();"
12726     "o.__proto__ = proto;"
12727     "o.method = function(x) { return x + 1; };"
12728     "var m = 'method';"
12729     "var result = 0;"
12730     "for (var i = 0; i < 10; i++) {"
12731     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12732     "  result += o[m](41);"
12733     "}");
12734   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12735 }
12736
12737
12738 // Test the map transition after the interceptor.
12739 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12740   v8::Isolate* isolate = CcTest::isolate();
12741   v8::HandleScope scope(isolate);
12742   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12743   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12744   LocalContext context;
12745   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12746
12747   CompileRun(
12748     "var proto = new Object();"
12749     "o.__proto__ = proto;"
12750     "proto.method = function(x) { return x + 1; };"
12751     "var m = 'method';"
12752     "var result = 0;"
12753     "for (var i = 0; i < 10; i++) {"
12754     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12755     "  result += o[m](41);"
12756     "}");
12757   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12758 }
12759
12760
12761 static int interceptor_call_count = 0;
12762
12763 static void InterceptorICRefErrorGetter(
12764     Local<String> name,
12765     const v8::PropertyCallbackInfo<v8::Value>& info) {
12766   ApiTestFuzzer::Fuzz();
12767   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12768     info.GetReturnValue().Set(call_ic_function2);
12769   }
12770 }
12771
12772
12773 // This test should hit load and call ICs for the interceptor case.
12774 // Once in a while, the interceptor will reply that a property was not
12775 // found in which case we should get a reference error.
12776 THREADED_TEST(InterceptorICReferenceErrors) {
12777   v8::Isolate* isolate = CcTest::isolate();
12778   v8::HandleScope scope(isolate);
12779   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12780   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12781   LocalContext context(0, templ, v8::Handle<Value>());
12782   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12783   v8::Handle<Value> value = CompileRun(
12784     "function f() {"
12785     "  for (var i = 0; i < 1000; i++) {"
12786     "    try { x; } catch(e) { return true; }"
12787     "  }"
12788     "  return false;"
12789     "};"
12790     "f();");
12791   CHECK_EQ(true, value->BooleanValue());
12792   interceptor_call_count = 0;
12793   value = CompileRun(
12794     "function g() {"
12795     "  for (var i = 0; i < 1000; i++) {"
12796     "    try { x(42); } catch(e) { return true; }"
12797     "  }"
12798     "  return false;"
12799     "};"
12800     "g();");
12801   CHECK_EQ(true, value->BooleanValue());
12802 }
12803
12804
12805 static int interceptor_ic_exception_get_count = 0;
12806
12807 static void InterceptorICExceptionGetter(
12808     Local<String> name,
12809     const v8::PropertyCallbackInfo<v8::Value>& info) {
12810   ApiTestFuzzer::Fuzz();
12811   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12812     info.GetReturnValue().Set(call_ic_function3);
12813   }
12814   if (interceptor_ic_exception_get_count == 20) {
12815     info.GetIsolate()->ThrowException(v8_num(42));
12816     return;
12817   }
12818 }
12819
12820
12821 // Test interceptor load/call IC where the interceptor throws an
12822 // exception once in a while.
12823 THREADED_TEST(InterceptorICGetterExceptions) {
12824   interceptor_ic_exception_get_count = 0;
12825   v8::Isolate* isolate = CcTest::isolate();
12826   v8::HandleScope scope(isolate);
12827   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12828   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12829   LocalContext context(0, templ, v8::Handle<Value>());
12830   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12831   v8::Handle<Value> value = CompileRun(
12832     "function f() {"
12833     "  for (var i = 0; i < 100; i++) {"
12834     "    try { x; } catch(e) { return true; }"
12835     "  }"
12836     "  return false;"
12837     "};"
12838     "f();");
12839   CHECK_EQ(true, value->BooleanValue());
12840   interceptor_ic_exception_get_count = 0;
12841   value = CompileRun(
12842     "function f() {"
12843     "  for (var i = 0; i < 100; i++) {"
12844     "    try { x(42); } catch(e) { return true; }"
12845     "  }"
12846     "  return false;"
12847     "};"
12848     "f();");
12849   CHECK_EQ(true, value->BooleanValue());
12850 }
12851
12852
12853 static int interceptor_ic_exception_set_count = 0;
12854
12855 static void InterceptorICExceptionSetter(
12856       Local<String> key,
12857       Local<Value> value,
12858       const v8::PropertyCallbackInfo<v8::Value>& info) {
12859   ApiTestFuzzer::Fuzz();
12860   if (++interceptor_ic_exception_set_count > 20) {
12861     info.GetIsolate()->ThrowException(v8_num(42));
12862   }
12863 }
12864
12865
12866 // Test interceptor store IC where the interceptor throws an exception
12867 // once in a while.
12868 THREADED_TEST(InterceptorICSetterExceptions) {
12869   interceptor_ic_exception_set_count = 0;
12870   v8::Isolate* isolate = CcTest::isolate();
12871   v8::HandleScope scope(isolate);
12872   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12873   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12874   LocalContext context(0, templ, v8::Handle<Value>());
12875   v8::Handle<Value> value = CompileRun(
12876     "function f() {"
12877     "  for (var i = 0; i < 100; i++) {"
12878     "    try { x = 42; } catch(e) { return true; }"
12879     "  }"
12880     "  return false;"
12881     "};"
12882     "f();");
12883   CHECK_EQ(true, value->BooleanValue());
12884 }
12885
12886
12887 // Test that we ignore null interceptors.
12888 THREADED_TEST(NullNamedInterceptor) {
12889   v8::Isolate* isolate = CcTest::isolate();
12890   v8::HandleScope scope(isolate);
12891   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12892   templ->SetNamedPropertyHandler(
12893       static_cast<v8::NamedPropertyGetterCallback>(0));
12894   LocalContext context;
12895   templ->Set(CcTest::isolate(), "x", v8_num(42));
12896   v8::Handle<v8::Object> obj = templ->NewInstance();
12897   context->Global()->Set(v8_str("obj"), obj);
12898   v8::Handle<Value> value = CompileRun("obj.x");
12899   CHECK(value->IsInt32());
12900   CHECK_EQ(42, value->Int32Value());
12901 }
12902
12903
12904 // Test that we ignore null interceptors.
12905 THREADED_TEST(NullIndexedInterceptor) {
12906   v8::Isolate* isolate = CcTest::isolate();
12907   v8::HandleScope scope(isolate);
12908   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12909   templ->SetIndexedPropertyHandler(
12910       static_cast<v8::IndexedPropertyGetterCallback>(0));
12911   LocalContext context;
12912   templ->Set(CcTest::isolate(), "42", v8_num(42));
12913   v8::Handle<v8::Object> obj = templ->NewInstance();
12914   context->Global()->Set(v8_str("obj"), obj);
12915   v8::Handle<Value> value = CompileRun("obj[42]");
12916   CHECK(value->IsInt32());
12917   CHECK_EQ(42, value->Int32Value());
12918 }
12919
12920
12921 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12922   v8::Isolate* isolate = CcTest::isolate();
12923   v8::HandleScope scope(isolate);
12924   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12925   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12926   LocalContext env;
12927   env->Global()->Set(v8_str("obj"),
12928                      templ->GetFunction()->NewInstance());
12929   ExpectTrue("obj.x === 42");
12930   ExpectTrue("!obj.propertyIsEnumerable('x')");
12931 }
12932
12933
12934 static void ThrowingGetter(Local<String> name,
12935                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12936   ApiTestFuzzer::Fuzz();
12937   info.GetIsolate()->ThrowException(Handle<Value>());
12938   info.GetReturnValue().SetUndefined();
12939 }
12940
12941
12942 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12943   LocalContext context;
12944   HandleScope scope(context->GetIsolate());
12945
12946   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12947   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12948   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12949
12950   Local<Object> instance = templ->GetFunction()->NewInstance();
12951
12952   Local<Object> another = Object::New(context->GetIsolate());
12953   another->SetPrototype(instance);
12954
12955   Local<Object> with_js_getter = CompileRun(
12956       "o = {};\n"
12957       "o.__defineGetter__('f', function() { throw undefined; });\n"
12958       "o\n").As<Object>();
12959   CHECK(!with_js_getter.IsEmpty());
12960
12961   TryCatch try_catch;
12962
12963   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12964   CHECK(try_catch.HasCaught());
12965   try_catch.Reset();
12966   CHECK(result.IsEmpty());
12967
12968   result = another->GetRealNamedProperty(v8_str("f"));
12969   CHECK(try_catch.HasCaught());
12970   try_catch.Reset();
12971   CHECK(result.IsEmpty());
12972
12973   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12974   CHECK(try_catch.HasCaught());
12975   try_catch.Reset();
12976   CHECK(result.IsEmpty());
12977
12978   result = another->Get(v8_str("f"));
12979   CHECK(try_catch.HasCaught());
12980   try_catch.Reset();
12981   CHECK(result.IsEmpty());
12982
12983   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12984   CHECK(try_catch.HasCaught());
12985   try_catch.Reset();
12986   CHECK(result.IsEmpty());
12987
12988   result = with_js_getter->Get(v8_str("f"));
12989   CHECK(try_catch.HasCaught());
12990   try_catch.Reset();
12991   CHECK(result.IsEmpty());
12992 }
12993
12994
12995 static void ThrowingCallbackWithTryCatch(
12996     const v8::FunctionCallbackInfo<v8::Value>& args) {
12997   TryCatch try_catch;
12998   // Verboseness is important: it triggers message delivery which can call into
12999   // external code.
13000   try_catch.SetVerbose(true);
13001   CompileRun("throw 'from JS';");
13002   CHECK(try_catch.HasCaught());
13003   CHECK(!CcTest::i_isolate()->has_pending_exception());
13004   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13005 }
13006
13007
13008 static int call_depth;
13009
13010
13011 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13012   TryCatch try_catch;
13013 }
13014
13015
13016 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13017   if (--call_depth) CompileRun("throw 'ThrowInJS';");
13018 }
13019
13020
13021 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13022   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13023 }
13024
13025
13026 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13027   Handle<String> errorMessageString = message->Get();
13028   CHECK(!errorMessageString.IsEmpty());
13029   message->GetStackTrace();
13030   message->GetScriptResourceName();
13031 }
13032
13033
13034 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13035   LocalContext context;
13036   v8::Isolate* isolate = context->GetIsolate();
13037   HandleScope scope(isolate);
13038
13039   Local<Function> func =
13040       FunctionTemplate::New(isolate,
13041                             ThrowingCallbackWithTryCatch)->GetFunction();
13042   context->Global()->Set(v8_str("func"), func);
13043
13044   MessageCallback callbacks[] =
13045       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13046   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13047     MessageCallback callback = callbacks[i];
13048     if (callback != NULL) {
13049       V8::AddMessageListener(callback);
13050     }
13051     // Some small number to control number of times message handler should
13052     // throw an exception.
13053     call_depth = 5;
13054     ExpectFalse(
13055         "var thrown = false;\n"
13056         "try { func(); } catch(e) { thrown = true; }\n"
13057         "thrown\n");
13058     if (callback != NULL) {
13059       V8::RemoveMessageListeners(callback);
13060     }
13061   }
13062 }
13063
13064
13065 static void ParentGetter(Local<String> name,
13066                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13067   ApiTestFuzzer::Fuzz();
13068   info.GetReturnValue().Set(v8_num(1));
13069 }
13070
13071
13072 static void ChildGetter(Local<String> name,
13073                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13074   ApiTestFuzzer::Fuzz();
13075   info.GetReturnValue().Set(v8_num(42));
13076 }
13077
13078
13079 THREADED_TEST(Overriding) {
13080   LocalContext context;
13081   v8::Isolate* isolate = context->GetIsolate();
13082   v8::HandleScope scope(isolate);
13083
13084   // Parent template.
13085   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13086   Local<ObjectTemplate> parent_instance_templ =
13087       parent_templ->InstanceTemplate();
13088   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13089
13090   // Template that inherits from the parent template.
13091   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13092   Local<ObjectTemplate> child_instance_templ =
13093       child_templ->InstanceTemplate();
13094   child_templ->Inherit(parent_templ);
13095   // Override 'f'.  The child version of 'f' should get called for child
13096   // instances.
13097   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13098   // Add 'g' twice.  The 'g' added last should get called for instances.
13099   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13100   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13101
13102   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13103   // so 'h' can be shadowed on the instance object.
13104   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13105   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13106       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13107
13108   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13109   // but the attribute does not have effect because it is duplicated with
13110   // NULL setter.
13111   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13112       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13113
13114
13115
13116   // Instantiate the child template.
13117   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13118
13119   // Check that the child function overrides the parent one.
13120   context->Global()->Set(v8_str("o"), instance);
13121   Local<Value> value = v8_compile("o.f")->Run();
13122   // Check that the 'g' that was added last is hit.
13123   CHECK_EQ(42, value->Int32Value());
13124   value = v8_compile("o.g")->Run();
13125   CHECK_EQ(42, value->Int32Value());
13126
13127   // Check that 'h' cannot be shadowed.
13128   value = v8_compile("o.h = 3; o.h")->Run();
13129   CHECK_EQ(1, value->Int32Value());
13130
13131   // Check that 'i' cannot be shadowed or changed.
13132   value = v8_compile("o.i = 3; o.i")->Run();
13133   CHECK_EQ(42, value->Int32Value());
13134 }
13135
13136
13137 static void IsConstructHandler(
13138     const v8::FunctionCallbackInfo<v8::Value>& args) {
13139   ApiTestFuzzer::Fuzz();
13140   args.GetReturnValue().Set(args.IsConstructCall());
13141 }
13142
13143
13144 THREADED_TEST(IsConstructCall) {
13145   v8::Isolate* isolate = CcTest::isolate();
13146   v8::HandleScope scope(isolate);
13147
13148   // Function template with call handler.
13149   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13150   templ->SetCallHandler(IsConstructHandler);
13151
13152   LocalContext context;
13153
13154   context->Global()->Set(v8_str("f"), templ->GetFunction());
13155   Local<Value> value = v8_compile("f()")->Run();
13156   CHECK(!value->BooleanValue());
13157   value = v8_compile("new f()")->Run();
13158   CHECK(value->BooleanValue());
13159 }
13160
13161
13162 THREADED_TEST(ObjectProtoToString) {
13163   v8::Isolate* isolate = CcTest::isolate();
13164   v8::HandleScope scope(isolate);
13165   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13166   templ->SetClassName(v8_str("MyClass"));
13167
13168   LocalContext context;
13169
13170   Local<String> customized_tostring = v8_str("customized toString");
13171
13172   // Replace Object.prototype.toString
13173   v8_compile("Object.prototype.toString = function() {"
13174                   "  return 'customized toString';"
13175                   "}")->Run();
13176
13177   // Normal ToString call should call replaced Object.prototype.toString
13178   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13179   Local<String> value = instance->ToString();
13180   CHECK(value->IsString() && value->Equals(customized_tostring));
13181
13182   // ObjectProtoToString should not call replace toString function.
13183   value = instance->ObjectProtoToString();
13184   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13185
13186   // Check global
13187   value = context->Global()->ObjectProtoToString();
13188   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13189
13190   // Check ordinary object
13191   Local<Value> object = v8_compile("new Object()")->Run();
13192   value = object.As<v8::Object>()->ObjectProtoToString();
13193   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13194 }
13195
13196
13197 THREADED_TEST(ObjectGetConstructorName) {
13198   LocalContext context;
13199   v8::HandleScope scope(context->GetIsolate());
13200   v8_compile("function Parent() {};"
13201              "function Child() {};"
13202              "Child.prototype = new Parent();"
13203              "var outer = { inner: function() { } };"
13204              "var p = new Parent();"
13205              "var c = new Child();"
13206              "var x = new outer.inner();")->Run();
13207
13208   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13209   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13210       v8_str("Parent")));
13211
13212   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13213   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13214       v8_str("Child")));
13215
13216   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13217   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13218       v8_str("outer.inner")));
13219 }
13220
13221
13222 bool ApiTestFuzzer::fuzzing_ = false;
13223 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13224 int ApiTestFuzzer::active_tests_;
13225 int ApiTestFuzzer::tests_being_run_;
13226 int ApiTestFuzzer::current_;
13227
13228
13229 // We are in a callback and want to switch to another thread (if we
13230 // are currently running the thread fuzzing test).
13231 void ApiTestFuzzer::Fuzz() {
13232   if (!fuzzing_) return;
13233   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13234   test->ContextSwitch();
13235 }
13236
13237
13238 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13239 // not start immediately.
13240 bool ApiTestFuzzer::NextThread() {
13241   int test_position = GetNextTestNumber();
13242   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13243   if (test_position == current_) {
13244     if (kLogThreading)
13245       printf("Stay with %s\n", test_name);
13246     return false;
13247   }
13248   if (kLogThreading) {
13249     printf("Switch from %s to %s\n",
13250            test_name,
13251            RegisterThreadedTest::nth(test_position)->name());
13252   }
13253   current_ = test_position;
13254   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13255   return true;
13256 }
13257
13258
13259 void ApiTestFuzzer::Run() {
13260   // When it is our turn...
13261   gate_.Wait();
13262   {
13263     // ... get the V8 lock and start running the test.
13264     v8::Locker locker(CcTest::isolate());
13265     CallTest();
13266   }
13267   // This test finished.
13268   active_ = false;
13269   active_tests_--;
13270   // If it was the last then signal that fact.
13271   if (active_tests_ == 0) {
13272     all_tests_done_.Signal();
13273   } else {
13274     // Otherwise select a new test and start that.
13275     NextThread();
13276   }
13277 }
13278
13279
13280 static unsigned linear_congruential_generator;
13281
13282
13283 void ApiTestFuzzer::SetUp(PartOfTest part) {
13284   linear_congruential_generator = i::FLAG_testing_prng_seed;
13285   fuzzing_ = true;
13286   int count = RegisterThreadedTest::count();
13287   int start =  count * part / (LAST_PART + 1);
13288   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13289   active_tests_ = tests_being_run_ = end - start + 1;
13290   for (int i = 0; i < tests_being_run_; i++) {
13291     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13292   }
13293   for (int i = 0; i < active_tests_; i++) {
13294     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13295   }
13296 }
13297
13298
13299 static void CallTestNumber(int test_number) {
13300   (RegisterThreadedTest::nth(test_number)->callback())();
13301 }
13302
13303
13304 void ApiTestFuzzer::RunAllTests() {
13305   // Set off the first test.
13306   current_ = -1;
13307   NextThread();
13308   // Wait till they are all done.
13309   all_tests_done_.Wait();
13310 }
13311
13312
13313 int ApiTestFuzzer::GetNextTestNumber() {
13314   int next_test;
13315   do {
13316     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13317     linear_congruential_generator *= 1664525u;
13318     linear_congruential_generator += 1013904223u;
13319   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13320   return next_test;
13321 }
13322
13323
13324 void ApiTestFuzzer::ContextSwitch() {
13325   // If the new thread is the same as the current thread there is nothing to do.
13326   if (NextThread()) {
13327     // Now it can start.
13328     v8::Unlocker unlocker(CcTest::isolate());
13329     // Wait till someone starts us again.
13330     gate_.Wait();
13331     // And we're off.
13332   }
13333 }
13334
13335
13336 void ApiTestFuzzer::TearDown() {
13337   fuzzing_ = false;
13338   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13339     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13340     if (fuzzer != NULL) fuzzer->Join();
13341   }
13342 }
13343
13344
13345 // Lets not be needlessly self-referential.
13346 TEST(Threading1) {
13347   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13348   ApiTestFuzzer::RunAllTests();
13349   ApiTestFuzzer::TearDown();
13350 }
13351
13352
13353 TEST(Threading2) {
13354   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13355   ApiTestFuzzer::RunAllTests();
13356   ApiTestFuzzer::TearDown();
13357 }
13358
13359
13360 TEST(Threading3) {
13361   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13362   ApiTestFuzzer::RunAllTests();
13363   ApiTestFuzzer::TearDown();
13364 }
13365
13366
13367 TEST(Threading4) {
13368   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13369   ApiTestFuzzer::RunAllTests();
13370   ApiTestFuzzer::TearDown();
13371 }
13372
13373
13374 void ApiTestFuzzer::CallTest() {
13375   v8::Isolate::Scope scope(CcTest::isolate());
13376   if (kLogThreading)
13377     printf("Start test %d\n", test_number_);
13378   CallTestNumber(test_number_);
13379   if (kLogThreading)
13380     printf("End test %d\n", test_number_);
13381 }
13382
13383
13384 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13385   v8::Isolate* isolate = args.GetIsolate();
13386   CHECK(v8::Locker::IsLocked(isolate));
13387   ApiTestFuzzer::Fuzz();
13388   v8::Unlocker unlocker(isolate);
13389   const char* code = "throw 7;";
13390   {
13391     v8::Locker nested_locker(isolate);
13392     v8::HandleScope scope(isolate);
13393     v8::Handle<Value> exception;
13394     { v8::TryCatch try_catch;
13395       v8::Handle<Value> value = CompileRun(code);
13396       CHECK(value.IsEmpty());
13397       CHECK(try_catch.HasCaught());
13398       // Make sure to wrap the exception in a new handle because
13399       // the handle returned from the TryCatch is destroyed
13400       // when the TryCatch is destroyed.
13401       exception = Local<Value>::New(isolate, try_catch.Exception());
13402     }
13403     args.GetIsolate()->ThrowException(exception);
13404   }
13405 }
13406
13407
13408 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13409   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13410   ApiTestFuzzer::Fuzz();
13411   v8::Unlocker unlocker(CcTest::isolate());
13412   const char* code = "throw 7;";
13413   {
13414     v8::Locker nested_locker(CcTest::isolate());
13415     v8::HandleScope scope(args.GetIsolate());
13416     v8::Handle<Value> value = CompileRun(code);
13417     CHECK(value.IsEmpty());
13418     args.GetReturnValue().Set(v8_str("foo"));
13419   }
13420 }
13421
13422
13423 // These are locking tests that don't need to be run again
13424 // as part of the locking aggregation tests.
13425 TEST(NestedLockers) {
13426   v8::Isolate* isolate = CcTest::isolate();
13427   v8::Locker locker(isolate);
13428   CHECK(v8::Locker::IsLocked(isolate));
13429   LocalContext env;
13430   v8::HandleScope scope(env->GetIsolate());
13431   Local<v8::FunctionTemplate> fun_templ =
13432       v8::FunctionTemplate::New(isolate, ThrowInJS);
13433   Local<Function> fun = fun_templ->GetFunction();
13434   env->Global()->Set(v8_str("throw_in_js"), fun);
13435   Local<Script> script = v8_compile("(function () {"
13436                                     "  try {"
13437                                     "    throw_in_js();"
13438                                     "    return 42;"
13439                                     "  } catch (e) {"
13440                                     "    return e * 13;"
13441                                     "  }"
13442                                     "})();");
13443   CHECK_EQ(91, script->Run()->Int32Value());
13444 }
13445
13446
13447 // These are locking tests that don't need to be run again
13448 // as part of the locking aggregation tests.
13449 TEST(NestedLockersNoTryCatch) {
13450   v8::Locker locker(CcTest::isolate());
13451   LocalContext env;
13452   v8::HandleScope scope(env->GetIsolate());
13453   Local<v8::FunctionTemplate> fun_templ =
13454       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13455   Local<Function> fun = fun_templ->GetFunction();
13456   env->Global()->Set(v8_str("throw_in_js"), fun);
13457   Local<Script> script = v8_compile("(function () {"
13458                                     "  try {"
13459                                     "    throw_in_js();"
13460                                     "    return 42;"
13461                                     "  } catch (e) {"
13462                                     "    return e * 13;"
13463                                     "  }"
13464                                     "})();");
13465   CHECK_EQ(91, script->Run()->Int32Value());
13466 }
13467
13468
13469 THREADED_TEST(RecursiveLocking) {
13470   v8::Locker locker(CcTest::isolate());
13471   {
13472     v8::Locker locker2(CcTest::isolate());
13473     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13474   }
13475 }
13476
13477
13478 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13479   ApiTestFuzzer::Fuzz();
13480   v8::Unlocker unlocker(CcTest::isolate());
13481 }
13482
13483
13484 THREADED_TEST(LockUnlockLock) {
13485   {
13486     v8::Locker locker(CcTest::isolate());
13487     v8::HandleScope scope(CcTest::isolate());
13488     LocalContext env;
13489     Local<v8::FunctionTemplate> fun_templ =
13490         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13491     Local<Function> fun = fun_templ->GetFunction();
13492     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13493     Local<Script> script = v8_compile("(function () {"
13494                                       "  unlock_for_a_moment();"
13495                                       "  return 42;"
13496                                       "})();");
13497     CHECK_EQ(42, script->Run()->Int32Value());
13498   }
13499   {
13500     v8::Locker locker(CcTest::isolate());
13501     v8::HandleScope scope(CcTest::isolate());
13502     LocalContext env;
13503     Local<v8::FunctionTemplate> fun_templ =
13504         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13505     Local<Function> fun = fun_templ->GetFunction();
13506     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13507     Local<Script> script = v8_compile("(function () {"
13508                                       "  unlock_for_a_moment();"
13509                                       "  return 42;"
13510                                       "})();");
13511     CHECK_EQ(42, script->Run()->Int32Value());
13512   }
13513 }
13514
13515
13516 static int GetGlobalObjectsCount() {
13517   CcTest::heap()->EnsureHeapIsIterable();
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::OS::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   i::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   i::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   i::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::OS::SNPrintF(test_buf,
16320                   boundary_program,
16321                   low);
16322   result = CompileRun(test_buf.start());
16323   CHECK_EQ(low, result->IntegerValue());
16324
16325   i::OS::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::OS::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::OS::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::OS::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::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17545   CHECK(CompileRun(code.start())->IsUndefined());
17546   i::OS::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->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::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17628   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17629   i::OS::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::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17674   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17675   i::OS::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::OS::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::OS::MemCopy(&target, &value, sizeof(target));
18097   return target;
18098 }
18099
18100
18101 static uint64_t DoubleToBits(double value) {
18102   uint64_t target;
18103   i::OS::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->GetId(), foo->ScriptId());
18515   CHECK_EQ(script->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   // HasLocalElement.
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(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19273   CHECK(current_isolate != isolate);
19274   CHECK(current_isolate == CcTest::isolate());
19275
19276   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19277   last_location = last_message = NULL;
19278   isolate->Dispose();
19279   CHECK_EQ(last_location, NULL);
19280   CHECK_EQ(last_message, NULL);
19281 }
19282
19283
19284 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19285   v8::Isolate* isolate = v8::Isolate::New();
19286   {
19287     v8::Isolate::Scope i_scope(isolate);
19288     v8::HandleScope scope(isolate);
19289     LocalContext context(isolate);
19290     // Run something in this isolate.
19291     ExpectTrue("true");
19292     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19293     last_location = last_message = NULL;
19294     // Still entered, should fail.
19295     isolate->Dispose();
19296     CHECK_NE(last_location, NULL);
19297     CHECK_NE(last_message, NULL);
19298   }
19299   isolate->Dispose();
19300 }
19301
19302
19303 TEST(RunTwoIsolatesOnSingleThread) {
19304   // Run isolate 1.
19305   v8::Isolate* isolate1 = v8::Isolate::New();
19306   isolate1->Enter();
19307   v8::Persistent<v8::Context> context1;
19308   {
19309     v8::HandleScope scope(isolate1);
19310     context1.Reset(isolate1, Context::New(isolate1));
19311   }
19312
19313   {
19314     v8::HandleScope scope(isolate1);
19315     v8::Local<v8::Context> context =
19316         v8::Local<v8::Context>::New(isolate1, context1);
19317     v8::Context::Scope context_scope(context);
19318     // Run something in new isolate.
19319     CompileRun("var foo = 'isolate 1';");
19320     ExpectString("function f() { return foo; }; f()", "isolate 1");
19321   }
19322
19323   // Run isolate 2.
19324   v8::Isolate* isolate2 = v8::Isolate::New();
19325   v8::Persistent<v8::Context> context2;
19326
19327   {
19328     v8::Isolate::Scope iscope(isolate2);
19329     v8::HandleScope scope(isolate2);
19330     context2.Reset(isolate2, Context::New(isolate2));
19331     v8::Local<v8::Context> context =
19332         v8::Local<v8::Context>::New(isolate2, context2);
19333     v8::Context::Scope context_scope(context);
19334
19335     // Run something in new isolate.
19336     CompileRun("var foo = 'isolate 2';");
19337     ExpectString("function f() { return foo; }; f()", "isolate 2");
19338   }
19339
19340   {
19341     v8::HandleScope scope(isolate1);
19342     v8::Local<v8::Context> context =
19343         v8::Local<v8::Context>::New(isolate1, context1);
19344     v8::Context::Scope context_scope(context);
19345     // Now again in isolate 1
19346     ExpectString("function f() { return foo; }; f()", "isolate 1");
19347   }
19348
19349   isolate1->Exit();
19350
19351   // Run some stuff in default isolate.
19352   v8::Persistent<v8::Context> context_default;
19353   {
19354     v8::Isolate* isolate = CcTest::isolate();
19355     v8::Isolate::Scope iscope(isolate);
19356     v8::HandleScope scope(isolate);
19357     context_default.Reset(isolate, Context::New(isolate));
19358   }
19359
19360   {
19361     v8::HandleScope scope(CcTest::isolate());
19362     v8::Local<v8::Context> context =
19363         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19364     v8::Context::Scope context_scope(context);
19365     // Variables in other isolates should be not available, verify there
19366     // is an exception.
19367     ExpectTrue("function f() {"
19368                "  try {"
19369                "    foo;"
19370                "    return false;"
19371                "  } catch(e) {"
19372                "    return true;"
19373                "  }"
19374                "};"
19375                "var isDefaultIsolate = true;"
19376                "f()");
19377   }
19378
19379   isolate1->Enter();
19380
19381   {
19382     v8::Isolate::Scope iscope(isolate2);
19383     v8::HandleScope scope(isolate2);
19384     v8::Local<v8::Context> context =
19385         v8::Local<v8::Context>::New(isolate2, context2);
19386     v8::Context::Scope context_scope(context);
19387     ExpectString("function f() { return foo; }; f()", "isolate 2");
19388   }
19389
19390   {
19391     v8::HandleScope scope(v8::Isolate::GetCurrent());
19392     v8::Local<v8::Context> context =
19393         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19394     v8::Context::Scope context_scope(context);
19395     ExpectString("function f() { return foo; }; f()", "isolate 1");
19396   }
19397
19398   {
19399     v8::Isolate::Scope iscope(isolate2);
19400     context2.Reset();
19401   }
19402
19403   context1.Reset();
19404   isolate1->Exit();
19405
19406   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19407   last_location = last_message = NULL;
19408
19409   isolate1->Dispose();
19410   CHECK_EQ(last_location, NULL);
19411   CHECK_EQ(last_message, NULL);
19412
19413   isolate2->Dispose();
19414   CHECK_EQ(last_location, NULL);
19415   CHECK_EQ(last_message, NULL);
19416
19417   // Check that default isolate still runs.
19418   {
19419     v8::HandleScope scope(CcTest::isolate());
19420     v8::Local<v8::Context> context =
19421         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19422     v8::Context::Scope context_scope(context);
19423     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19424   }
19425 }
19426
19427
19428 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19429   v8::Isolate::Scope isolate_scope(isolate);
19430   v8::HandleScope scope(isolate);
19431   LocalContext context(isolate);
19432   i::ScopedVector<char> code(1024);
19433   i::OS::SNPrintF(code, "function fib(n) {"
19434                         "  if (n <= 2) return 1;"
19435                         "  return fib(n-1) + fib(n-2);"
19436                         "}"
19437                         "fib(%d)", limit);
19438   Local<Value> value = CompileRun(code.start());
19439   CHECK(value->IsNumber());
19440   return static_cast<int>(value->NumberValue());
19441 }
19442
19443 class IsolateThread : public v8::internal::Thread {
19444  public:
19445   IsolateThread(v8::Isolate* isolate, int fib_limit)
19446       : Thread("IsolateThread"),
19447         isolate_(isolate),
19448         fib_limit_(fib_limit),
19449         result_(0) { }
19450
19451   void Run() {
19452     result_ = CalcFibonacci(isolate_, fib_limit_);
19453   }
19454
19455   int result() { return result_; }
19456
19457  private:
19458   v8::Isolate* isolate_;
19459   int fib_limit_;
19460   int result_;
19461 };
19462
19463
19464 TEST(MultipleIsolatesOnIndividualThreads) {
19465   v8::Isolate* isolate1 = v8::Isolate::New();
19466   v8::Isolate* isolate2 = v8::Isolate::New();
19467
19468   IsolateThread thread1(isolate1, 21);
19469   IsolateThread thread2(isolate2, 12);
19470
19471   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19472   thread1.Start();
19473   thread2.Start();
19474
19475   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19476   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19477
19478   thread1.Join();
19479   thread2.Join();
19480
19481   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19482   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19483   CHECK_EQ(result1, 10946);
19484   CHECK_EQ(result2, 144);
19485   CHECK_EQ(result1, thread1.result());
19486   CHECK_EQ(result2, thread2.result());
19487
19488   isolate1->Dispose();
19489   isolate2->Dispose();
19490 }
19491
19492
19493 TEST(IsolateDifferentContexts) {
19494   v8::Isolate* isolate = v8::Isolate::New();
19495   Local<v8::Context> context;
19496   {
19497     v8::Isolate::Scope isolate_scope(isolate);
19498     v8::HandleScope handle_scope(isolate);
19499     context = v8::Context::New(isolate);
19500     v8::Context::Scope context_scope(context);
19501     Local<Value> v = CompileRun("2");
19502     CHECK(v->IsNumber());
19503     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19504   }
19505   {
19506     v8::Isolate::Scope isolate_scope(isolate);
19507     v8::HandleScope handle_scope(isolate);
19508     context = v8::Context::New(isolate);
19509     v8::Context::Scope context_scope(context);
19510     Local<Value> v = CompileRun("22");
19511     CHECK(v->IsNumber());
19512     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19513   }
19514   isolate->Dispose();
19515 }
19516
19517 class InitDefaultIsolateThread : public v8::internal::Thread {
19518  public:
19519   enum TestCase {
19520     SetResourceConstraints,
19521     SetFatalHandler,
19522     SetCounterFunction,
19523     SetCreateHistogramFunction,
19524     SetAddHistogramSampleFunction
19525   };
19526
19527   explicit InitDefaultIsolateThread(TestCase testCase)
19528       : Thread("InitDefaultIsolateThread"),
19529         testCase_(testCase),
19530         result_(false) { }
19531
19532   void Run() {
19533     v8::Isolate* isolate = v8::Isolate::New();
19534     isolate->Enter();
19535     switch (testCase_) {
19536       case SetResourceConstraints: {
19537         static const int K = 1024;
19538         v8::ResourceConstraints constraints;
19539         constraints.set_max_new_space_size(2 * K * K);
19540         constraints.set_max_old_space_size(4 * K * K);
19541         v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19542         break;
19543       }
19544
19545       case SetFatalHandler:
19546         v8::V8::SetFatalErrorHandler(NULL);
19547         break;
19548
19549       case SetCounterFunction:
19550         v8::V8::SetCounterFunction(NULL);
19551         break;
19552
19553       case SetCreateHistogramFunction:
19554         v8::V8::SetCreateHistogramFunction(NULL);
19555         break;
19556
19557       case SetAddHistogramSampleFunction:
19558         v8::V8::SetAddHistogramSampleFunction(NULL);
19559         break;
19560     }
19561     isolate->Exit();
19562     isolate->Dispose();
19563     result_ = true;
19564   }
19565
19566   bool result() { return result_; }
19567
19568  private:
19569   TestCase testCase_;
19570   bool result_;
19571 };
19572
19573
19574 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19575   InitDefaultIsolateThread thread(testCase);
19576   thread.Start();
19577   thread.Join();
19578   CHECK_EQ(thread.result(), true);
19579 }
19580
19581
19582 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19583   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19584 }
19585
19586
19587 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19588   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19589 }
19590
19591
19592 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19593   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19594 }
19595
19596
19597 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19598   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19599 }
19600
19601
19602 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19603   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19604 }
19605
19606
19607 TEST(StringCheckMultipleContexts) {
19608   const char* code =
19609       "(function() { return \"a\".charAt(0); })()";
19610
19611   {
19612     // Run the code twice in the first context to initialize the call IC.
19613     LocalContext context1;
19614     v8::HandleScope scope(context1->GetIsolate());
19615     ExpectString(code, "a");
19616     ExpectString(code, "a");
19617   }
19618
19619   {
19620     // Change the String.prototype in the second context and check
19621     // that the right function gets called.
19622     LocalContext context2;
19623     v8::HandleScope scope(context2->GetIsolate());
19624     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19625     ExpectString(code, "not a");
19626   }
19627 }
19628
19629
19630 TEST(NumberCheckMultipleContexts) {
19631   const char* code =
19632       "(function() { return (42).toString(); })()";
19633
19634   {
19635     // Run the code twice in the first context to initialize the call IC.
19636     LocalContext context1;
19637     v8::HandleScope scope(context1->GetIsolate());
19638     ExpectString(code, "42");
19639     ExpectString(code, "42");
19640   }
19641
19642   {
19643     // Change the Number.prototype in the second context and check
19644     // that the right function gets called.
19645     LocalContext context2;
19646     v8::HandleScope scope(context2->GetIsolate());
19647     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19648     ExpectString(code, "not 42");
19649   }
19650 }
19651
19652
19653 TEST(BooleanCheckMultipleContexts) {
19654   const char* code =
19655       "(function() { return true.toString(); })()";
19656
19657   {
19658     // Run the code twice in the first context to initialize the call IC.
19659     LocalContext context1;
19660     v8::HandleScope scope(context1->GetIsolate());
19661     ExpectString(code, "true");
19662     ExpectString(code, "true");
19663   }
19664
19665   {
19666     // Change the Boolean.prototype in the second context and check
19667     // that the right function gets called.
19668     LocalContext context2;
19669     v8::HandleScope scope(context2->GetIsolate());
19670     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19671     ExpectString(code, "");
19672   }
19673 }
19674
19675
19676 TEST(DontDeleteCellLoadIC) {
19677   const char* function_code =
19678       "function readCell() { while (true) { return cell; } }";
19679
19680   {
19681     // Run the code twice in the first context to initialize the load
19682     // IC for a don't delete cell.
19683     LocalContext context1;
19684     v8::HandleScope scope(context1->GetIsolate());
19685     CompileRun("var cell = \"first\";");
19686     ExpectBoolean("delete cell", false);
19687     CompileRun(function_code);
19688     ExpectString("readCell()", "first");
19689     ExpectString("readCell()", "first");
19690   }
19691
19692   {
19693     // Use a deletable cell in the second context.
19694     LocalContext context2;
19695     v8::HandleScope scope(context2->GetIsolate());
19696     CompileRun("cell = \"second\";");
19697     CompileRun(function_code);
19698     ExpectString("readCell()", "second");
19699     ExpectBoolean("delete cell", true);
19700     ExpectString("(function() {"
19701                  "  try {"
19702                  "    return readCell();"
19703                  "  } catch(e) {"
19704                  "    return e.toString();"
19705                  "  }"
19706                  "})()",
19707                  "ReferenceError: cell is not defined");
19708     CompileRun("cell = \"new_second\";");
19709     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19710     ExpectString("readCell()", "new_second");
19711     ExpectString("readCell()", "new_second");
19712   }
19713 }
19714
19715
19716 TEST(DontDeleteCellLoadICForceDelete) {
19717   const char* function_code =
19718       "function readCell() { while (true) { return cell; } }";
19719
19720   // Run the code twice to initialize the load IC for a don't delete
19721   // cell.
19722   LocalContext context;
19723   v8::HandleScope scope(context->GetIsolate());
19724   CompileRun("var cell = \"value\";");
19725   ExpectBoolean("delete cell", false);
19726   CompileRun(function_code);
19727   ExpectString("readCell()", "value");
19728   ExpectString("readCell()", "value");
19729
19730   // Delete the cell using the API and check the inlined code works
19731   // correctly.
19732   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19733   ExpectString("(function() {"
19734                "  try {"
19735                "    return readCell();"
19736                "  } catch(e) {"
19737                "    return e.toString();"
19738                "  }"
19739                "})()",
19740                "ReferenceError: cell is not defined");
19741 }
19742
19743
19744 TEST(DontDeleteCellLoadICAPI) {
19745   const char* function_code =
19746       "function readCell() { while (true) { return cell; } }";
19747
19748   // Run the code twice to initialize the load IC for a don't delete
19749   // cell created using the API.
19750   LocalContext context;
19751   v8::HandleScope scope(context->GetIsolate());
19752   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19753   ExpectBoolean("delete cell", false);
19754   CompileRun(function_code);
19755   ExpectString("readCell()", "value");
19756   ExpectString("readCell()", "value");
19757
19758   // Delete the cell using the API and check the inlined code works
19759   // correctly.
19760   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19761   ExpectString("(function() {"
19762                "  try {"
19763                "    return readCell();"
19764                "  } catch(e) {"
19765                "    return e.toString();"
19766                "  }"
19767                "})()",
19768                "ReferenceError: cell is not defined");
19769 }
19770
19771
19772 class Visitor42 : public v8::PersistentHandleVisitor {
19773  public:
19774   explicit Visitor42(v8::Persistent<v8::Object>* object)
19775       : counter_(0), object_(object) { }
19776
19777   virtual void VisitPersistentHandle(Persistent<Value>* value,
19778                                      uint16_t class_id) {
19779     if (class_id != 42) return;
19780     CHECK_EQ(42, value->WrapperClassId());
19781     v8::Isolate* isolate = CcTest::isolate();
19782     v8::HandleScope handle_scope(isolate);
19783     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19784     v8::Handle<v8::Value> object =
19785         v8::Local<v8::Object>::New(isolate, *object_);
19786     CHECK(handle->IsObject());
19787     CHECK_EQ(Handle<Object>::Cast(handle), object);
19788     ++counter_;
19789   }
19790
19791   int counter_;
19792   v8::Persistent<v8::Object>* object_;
19793 };
19794
19795
19796 TEST(PersistentHandleVisitor) {
19797   LocalContext context;
19798   v8::Isolate* isolate = context->GetIsolate();
19799   v8::HandleScope scope(isolate);
19800   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19801   CHECK_EQ(0, object.WrapperClassId());
19802   object.SetWrapperClassId(42);
19803   CHECK_EQ(42, object.WrapperClassId());
19804
19805   Visitor42 visitor(&object);
19806   v8::V8::VisitHandlesWithClassIds(&visitor);
19807   CHECK_EQ(1, visitor.counter_);
19808
19809   object.Reset();
19810 }
19811
19812
19813 TEST(WrapperClassId) {
19814   LocalContext context;
19815   v8::Isolate* isolate = context->GetIsolate();
19816   v8::HandleScope scope(isolate);
19817   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19818   CHECK_EQ(0, object.WrapperClassId());
19819   object.SetWrapperClassId(65535);
19820   CHECK_EQ(65535, object.WrapperClassId());
19821   object.Reset();
19822 }
19823
19824
19825 TEST(PersistentHandleInNewSpaceVisitor) {
19826   LocalContext context;
19827   v8::Isolate* isolate = context->GetIsolate();
19828   v8::HandleScope scope(isolate);
19829   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19830   CHECK_EQ(0, object1.WrapperClassId());
19831   object1.SetWrapperClassId(42);
19832   CHECK_EQ(42, object1.WrapperClassId());
19833
19834   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19835
19836   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19837   CHECK_EQ(0, object2.WrapperClassId());
19838   object2.SetWrapperClassId(42);
19839   CHECK_EQ(42, object2.WrapperClassId());
19840
19841   Visitor42 visitor(&object2);
19842   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19843   CHECK_EQ(1, visitor.counter_);
19844
19845   object1.Reset();
19846   object2.Reset();
19847 }
19848
19849
19850 TEST(RegExp) {
19851   LocalContext context;
19852   v8::HandleScope scope(context->GetIsolate());
19853
19854   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19855   CHECK(re->IsRegExp());
19856   CHECK(re->GetSource()->Equals(v8_str("foo")));
19857   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19858
19859   re = v8::RegExp::New(v8_str("bar"),
19860                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19861                                                       v8::RegExp::kGlobal));
19862   CHECK(re->IsRegExp());
19863   CHECK(re->GetSource()->Equals(v8_str("bar")));
19864   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19865            static_cast<int>(re->GetFlags()));
19866
19867   re = v8::RegExp::New(v8_str("baz"),
19868                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19869                                                       v8::RegExp::kMultiline));
19870   CHECK(re->IsRegExp());
19871   CHECK(re->GetSource()->Equals(v8_str("baz")));
19872   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19873            static_cast<int>(re->GetFlags()));
19874
19875   re = CompileRun("/quux/").As<v8::RegExp>();
19876   CHECK(re->IsRegExp());
19877   CHECK(re->GetSource()->Equals(v8_str("quux")));
19878   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19879
19880   re = CompileRun("/quux/gm").As<v8::RegExp>();
19881   CHECK(re->IsRegExp());
19882   CHECK(re->GetSource()->Equals(v8_str("quux")));
19883   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19884            static_cast<int>(re->GetFlags()));
19885
19886   // Override the RegExp constructor and check the API constructor
19887   // still works.
19888   CompileRun("RegExp = function() {}");
19889
19890   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19891   CHECK(re->IsRegExp());
19892   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19893   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19894
19895   re = v8::RegExp::New(v8_str("foobarbaz"),
19896                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19897                                                       v8::RegExp::kMultiline));
19898   CHECK(re->IsRegExp());
19899   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19900   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19901            static_cast<int>(re->GetFlags()));
19902
19903   context->Global()->Set(v8_str("re"), re);
19904   ExpectTrue("re.test('FoobarbaZ')");
19905
19906   // RegExps are objects on which you can set properties.
19907   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19908   v8::Handle<v8::Value> value(CompileRun("re.property"));
19909   CHECK_EQ(32, value->Int32Value());
19910
19911   v8::TryCatch try_catch;
19912   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19913   CHECK(re.IsEmpty());
19914   CHECK(try_catch.HasCaught());
19915   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19916   ExpectTrue("ex instanceof SyntaxError");
19917 }
19918
19919
19920 THREADED_TEST(Equals) {
19921   LocalContext localContext;
19922   v8::HandleScope handleScope(localContext->GetIsolate());
19923
19924   v8::Handle<v8::Object> globalProxy = localContext->Global();
19925   v8::Handle<Value> global = globalProxy->GetPrototype();
19926
19927   CHECK(global->StrictEquals(global));
19928   CHECK(!global->StrictEquals(globalProxy));
19929   CHECK(!globalProxy->StrictEquals(global));
19930   CHECK(globalProxy->StrictEquals(globalProxy));
19931
19932   CHECK(global->Equals(global));
19933   CHECK(!global->Equals(globalProxy));
19934   CHECK(!globalProxy->Equals(global));
19935   CHECK(globalProxy->Equals(globalProxy));
19936 }
19937
19938
19939 static void Getter(v8::Local<v8::String> property,
19940                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19941   info.GetReturnValue().Set(v8_str("42!"));
19942 }
19943
19944
19945 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19946   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19947   result->Set(0, v8_str("universalAnswer"));
19948   info.GetReturnValue().Set(result);
19949 }
19950
19951
19952 TEST(NamedEnumeratorAndForIn) {
19953   LocalContext context;
19954   v8::Isolate* isolate = context->GetIsolate();
19955   v8::HandleScope handle_scope(isolate);
19956   v8::Context::Scope context_scope(context.local());
19957
19958   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19959   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19960   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19961   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19962         "var result = []; for (var k in o) result.push(k); result"));
19963   CHECK_EQ(1, result->Length());
19964   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19965 }
19966
19967
19968 TEST(DefinePropertyPostDetach) {
19969   LocalContext context;
19970   v8::HandleScope scope(context->GetIsolate());
19971   v8::Handle<v8::Object> proxy = context->Global();
19972   v8::Handle<v8::Function> define_property =
19973       CompileRun("(function() {"
19974                  "  Object.defineProperty("
19975                  "    this,"
19976                  "    1,"
19977                  "    { configurable: true, enumerable: true, value: 3 });"
19978                  "})").As<Function>();
19979   context->DetachGlobal();
19980   define_property->Call(proxy, 0, NULL);
19981 }
19982
19983
19984 static void InstallContextId(v8::Handle<Context> context, int id) {
19985   Context::Scope scope(context);
19986   CompileRun("Object.prototype").As<Object>()->
19987       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19988 }
19989
19990
19991 static void CheckContextId(v8::Handle<Object> object, int expected) {
19992   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19993 }
19994
19995
19996 THREADED_TEST(CreationContext) {
19997   v8::Isolate* isolate = CcTest::isolate();
19998   HandleScope handle_scope(isolate);
19999   Handle<Context> context1 = Context::New(isolate);
20000   InstallContextId(context1, 1);
20001   Handle<Context> context2 = Context::New(isolate);
20002   InstallContextId(context2, 2);
20003   Handle<Context> context3 = Context::New(isolate);
20004   InstallContextId(context3, 3);
20005
20006   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20007
20008   Local<Object> object1;
20009   Local<Function> func1;
20010   {
20011     Context::Scope scope(context1);
20012     object1 = Object::New(isolate);
20013     func1 = tmpl->GetFunction();
20014   }
20015
20016   Local<Object> object2;
20017   Local<Function> func2;
20018   {
20019     Context::Scope scope(context2);
20020     object2 = Object::New(isolate);
20021     func2 = tmpl->GetFunction();
20022   }
20023
20024   Local<Object> instance1;
20025   Local<Object> instance2;
20026
20027   {
20028     Context::Scope scope(context3);
20029     instance1 = func1->NewInstance();
20030     instance2 = func2->NewInstance();
20031   }
20032
20033   CHECK(object1->CreationContext() == context1);
20034   CheckContextId(object1, 1);
20035   CHECK(func1->CreationContext() == context1);
20036   CheckContextId(func1, 1);
20037   CHECK(instance1->CreationContext() == context1);
20038   CheckContextId(instance1, 1);
20039   CHECK(object2->CreationContext() == context2);
20040   CheckContextId(object2, 2);
20041   CHECK(func2->CreationContext() == context2);
20042   CheckContextId(func2, 2);
20043   CHECK(instance2->CreationContext() == context2);
20044   CheckContextId(instance2, 2);
20045
20046   {
20047     Context::Scope scope(context1);
20048     CHECK(object1->CreationContext() == context1);
20049     CheckContextId(object1, 1);
20050     CHECK(func1->CreationContext() == context1);
20051     CheckContextId(func1, 1);
20052     CHECK(instance1->CreationContext() == context1);
20053     CheckContextId(instance1, 1);
20054     CHECK(object2->CreationContext() == context2);
20055     CheckContextId(object2, 2);
20056     CHECK(func2->CreationContext() == context2);
20057     CheckContextId(func2, 2);
20058     CHECK(instance2->CreationContext() == context2);
20059     CheckContextId(instance2, 2);
20060   }
20061
20062   {
20063     Context::Scope scope(context2);
20064     CHECK(object1->CreationContext() == context1);
20065     CheckContextId(object1, 1);
20066     CHECK(func1->CreationContext() == context1);
20067     CheckContextId(func1, 1);
20068     CHECK(instance1->CreationContext() == context1);
20069     CheckContextId(instance1, 1);
20070     CHECK(object2->CreationContext() == context2);
20071     CheckContextId(object2, 2);
20072     CHECK(func2->CreationContext() == context2);
20073     CheckContextId(func2, 2);
20074     CHECK(instance2->CreationContext() == context2);
20075     CheckContextId(instance2, 2);
20076   }
20077 }
20078
20079
20080 THREADED_TEST(CreationContextOfJsFunction) {
20081   HandleScope handle_scope(CcTest::isolate());
20082   Handle<Context> context = Context::New(CcTest::isolate());
20083   InstallContextId(context, 1);
20084
20085   Local<Object> function;
20086   {
20087     Context::Scope scope(context);
20088     function = CompileRun("function foo() {}; foo").As<Object>();
20089   }
20090
20091   CHECK(function->CreationContext() == context);
20092   CheckContextId(function, 1);
20093 }
20094
20095
20096 void HasOwnPropertyIndexedPropertyGetter(
20097     uint32_t index,
20098     const v8::PropertyCallbackInfo<v8::Value>& info) {
20099   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20100 }
20101
20102
20103 void HasOwnPropertyNamedPropertyGetter(
20104     Local<String> property,
20105     const v8::PropertyCallbackInfo<v8::Value>& info) {
20106   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20107 }
20108
20109
20110 void HasOwnPropertyIndexedPropertyQuery(
20111     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20112   if (index == 42) info.GetReturnValue().Set(1);
20113 }
20114
20115
20116 void HasOwnPropertyNamedPropertyQuery(
20117     Local<String> property,
20118     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20119   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20120 }
20121
20122
20123 void HasOwnPropertyNamedPropertyQuery2(
20124     Local<String> property,
20125     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20126   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20127 }
20128
20129
20130 void HasOwnPropertyAccessorGetter(
20131     Local<String> property,
20132     const v8::PropertyCallbackInfo<v8::Value>& info) {
20133   info.GetReturnValue().Set(v8_str("yes"));
20134 }
20135
20136
20137 TEST(HasOwnProperty) {
20138   LocalContext env;
20139   v8::Isolate* isolate = env->GetIsolate();
20140   v8::HandleScope scope(isolate);
20141   { // Check normal properties and defined getters.
20142     Handle<Value> value = CompileRun(
20143         "function Foo() {"
20144         "    this.foo = 11;"
20145         "    this.__defineGetter__('baz', function() { return 1; });"
20146         "};"
20147         "function Bar() { "
20148         "    this.bar = 13;"
20149         "    this.__defineGetter__('bla', function() { return 2; });"
20150         "};"
20151         "Bar.prototype = new Foo();"
20152         "new Bar();");
20153     CHECK(value->IsObject());
20154     Handle<Object> object = value->ToObject();
20155     CHECK(object->Has(v8_str("foo")));
20156     CHECK(!object->HasOwnProperty(v8_str("foo")));
20157     CHECK(object->HasOwnProperty(v8_str("bar")));
20158     CHECK(object->Has(v8_str("baz")));
20159     CHECK(!object->HasOwnProperty(v8_str("baz")));
20160     CHECK(object->HasOwnProperty(v8_str("bla")));
20161   }
20162   { // Check named getter interceptors.
20163     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20164     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20165     Handle<Object> instance = templ->NewInstance();
20166     CHECK(!instance->HasOwnProperty(v8_str("42")));
20167     CHECK(instance->HasOwnProperty(v8_str("foo")));
20168     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20169   }
20170   { // Check indexed getter interceptors.
20171     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20172     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20173     Handle<Object> instance = templ->NewInstance();
20174     CHECK(instance->HasOwnProperty(v8_str("42")));
20175     CHECK(!instance->HasOwnProperty(v8_str("43")));
20176     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20177   }
20178   { // Check named query interceptors.
20179     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20180     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20181     Handle<Object> instance = templ->NewInstance();
20182     CHECK(instance->HasOwnProperty(v8_str("foo")));
20183     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20184   }
20185   { // Check indexed query interceptors.
20186     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20187     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20188     Handle<Object> instance = templ->NewInstance();
20189     CHECK(instance->HasOwnProperty(v8_str("42")));
20190     CHECK(!instance->HasOwnProperty(v8_str("41")));
20191   }
20192   { // Check callbacks.
20193     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20194     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20195     Handle<Object> instance = templ->NewInstance();
20196     CHECK(instance->HasOwnProperty(v8_str("foo")));
20197     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20198   }
20199   { // Check that query wins on disagreement.
20200     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20201     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20202                                    0,
20203                                    HasOwnPropertyNamedPropertyQuery2);
20204     Handle<Object> instance = templ->NewInstance();
20205     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20206     CHECK(instance->HasOwnProperty(v8_str("bar")));
20207   }
20208 }
20209
20210
20211 TEST(IndexedInterceptorWithStringProto) {
20212   v8::Isolate* isolate = CcTest::isolate();
20213   v8::HandleScope scope(isolate);
20214   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20215   templ->SetIndexedPropertyHandler(NULL,
20216                                    NULL,
20217                                    HasOwnPropertyIndexedPropertyQuery);
20218   LocalContext context;
20219   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20220   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20221   // These should be intercepted.
20222   CHECK(CompileRun("42 in obj")->BooleanValue());
20223   CHECK(CompileRun("'42' in obj")->BooleanValue());
20224   // These should fall through to the String prototype.
20225   CHECK(CompileRun("0 in obj")->BooleanValue());
20226   CHECK(CompileRun("'0' in obj")->BooleanValue());
20227   // And these should both fail.
20228   CHECK(!CompileRun("32 in obj")->BooleanValue());
20229   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20230 }
20231
20232
20233 void CheckCodeGenerationAllowed() {
20234   Handle<Value> result = CompileRun("eval('42')");
20235   CHECK_EQ(42, result->Int32Value());
20236   result = CompileRun("(function(e) { return e('42'); })(eval)");
20237   CHECK_EQ(42, result->Int32Value());
20238   result = CompileRun("var f = new Function('return 42'); f()");
20239   CHECK_EQ(42, result->Int32Value());
20240 }
20241
20242
20243 void CheckCodeGenerationDisallowed() {
20244   TryCatch try_catch;
20245
20246   Handle<Value> result = CompileRun("eval('42')");
20247   CHECK(result.IsEmpty());
20248   CHECK(try_catch.HasCaught());
20249   try_catch.Reset();
20250
20251   result = CompileRun("(function(e) { return e('42'); })(eval)");
20252   CHECK(result.IsEmpty());
20253   CHECK(try_catch.HasCaught());
20254   try_catch.Reset();
20255
20256   result = CompileRun("var f = new Function('return 42'); f()");
20257   CHECK(result.IsEmpty());
20258   CHECK(try_catch.HasCaught());
20259 }
20260
20261
20262 bool CodeGenerationAllowed(Local<Context> context) {
20263   ApiTestFuzzer::Fuzz();
20264   return true;
20265 }
20266
20267
20268 bool CodeGenerationDisallowed(Local<Context> context) {
20269   ApiTestFuzzer::Fuzz();
20270   return false;
20271 }
20272
20273
20274 THREADED_TEST(AllowCodeGenFromStrings) {
20275   LocalContext context;
20276   v8::HandleScope scope(context->GetIsolate());
20277
20278   // eval and the Function constructor allowed by default.
20279   CHECK(context->IsCodeGenerationFromStringsAllowed());
20280   CheckCodeGenerationAllowed();
20281
20282   // Disallow eval and the Function constructor.
20283   context->AllowCodeGenerationFromStrings(false);
20284   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20285   CheckCodeGenerationDisallowed();
20286
20287   // Allow again.
20288   context->AllowCodeGenerationFromStrings(true);
20289   CheckCodeGenerationAllowed();
20290
20291   // Disallow but setting a global callback that will allow the calls.
20292   context->AllowCodeGenerationFromStrings(false);
20293   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20294   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20295   CheckCodeGenerationAllowed();
20296
20297   // Set a callback that disallows the code generation.
20298   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20299   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20300   CheckCodeGenerationDisallowed();
20301 }
20302
20303
20304 TEST(SetErrorMessageForCodeGenFromStrings) {
20305   LocalContext context;
20306   v8::HandleScope scope(context->GetIsolate());
20307   TryCatch try_catch;
20308
20309   Handle<String> message = v8_str("Message") ;
20310   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20311   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20312   context->AllowCodeGenerationFromStrings(false);
20313   context->SetErrorMessageForCodeGenerationFromStrings(message);
20314   Handle<Value> result = CompileRun("eval('42')");
20315   CHECK(result.IsEmpty());
20316   CHECK(try_catch.HasCaught());
20317   Handle<String> actual_message = try_catch.Message()->Get();
20318   CHECK(expected_message->Equals(actual_message));
20319 }
20320
20321
20322 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20323 }
20324
20325
20326 THREADED_TEST(CallAPIFunctionOnNonObject) {
20327   LocalContext context;
20328   v8::Isolate* isolate = context->GetIsolate();
20329   v8::HandleScope scope(isolate);
20330   Handle<FunctionTemplate> templ =
20331       v8::FunctionTemplate::New(isolate, NonObjectThis);
20332   Handle<Function> function = templ->GetFunction();
20333   context->Global()->Set(v8_str("f"), function);
20334   TryCatch try_catch;
20335   CompileRun("f.call(2)");
20336 }
20337
20338
20339 // Regression test for issue 1470.
20340 THREADED_TEST(ReadOnlyIndexedProperties) {
20341   v8::Isolate* isolate = CcTest::isolate();
20342   v8::HandleScope scope(isolate);
20343   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20344
20345   LocalContext context;
20346   Local<v8::Object> obj = templ->NewInstance();
20347   context->Global()->Set(v8_str("obj"), obj);
20348   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20349   obj->Set(v8_str("1"), v8_str("foobar"));
20350   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20351   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20352   obj->Set(v8_num(2), v8_str("foobar"));
20353   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20354
20355   // Test non-smi case.
20356   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20357   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20358   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20359 }
20360
20361
20362 THREADED_TEST(Regress1516) {
20363   LocalContext context;
20364   v8::HandleScope scope(context->GetIsolate());
20365
20366   { v8::HandleScope temp_scope(context->GetIsolate());
20367     CompileRun("({'a': 0})");
20368   }
20369
20370   int elements;
20371   { i::MapCache* map_cache =
20372         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20373     elements = map_cache->NumberOfElements();
20374     CHECK_LE(1, elements);
20375   }
20376
20377   CcTest::heap()->CollectAllGarbage(
20378       i::Heap::kAbortIncrementalMarkingMask);
20379   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20380     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20381       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20382       CHECK_GT(elements, map_cache->NumberOfElements());
20383     }
20384   }
20385 }
20386
20387
20388 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20389                                                 Local<Value> name,
20390                                                 v8::AccessType type,
20391                                                 Local<Value> data) {
20392   // Only block read access to __proto__.
20393   if (type == v8::ACCESS_GET &&
20394       name->IsString() &&
20395       name->ToString()->Length() == 9 &&
20396       name->ToString()->Utf8Length() == 9) {
20397     char buffer[10];
20398     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20399     return strncmp(buffer, "__proto__", 9) != 0;
20400   }
20401
20402   return true;
20403 }
20404
20405
20406 THREADED_TEST(Regress93759) {
20407   v8::Isolate* isolate = CcTest::isolate();
20408   HandleScope scope(isolate);
20409
20410   // Template for object with security check.
20411   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20412   // We don't do indexing, so any callback can be used for that.
20413   no_proto_template->SetAccessCheckCallbacks(
20414       BlockProtoNamedSecurityTestCallback,
20415       IndexedSecurityTestCallback);
20416
20417   // Templates for objects with hidden prototypes and possibly security check.
20418   Local<FunctionTemplate> hidden_proto_template =
20419       v8::FunctionTemplate::New(isolate);
20420   hidden_proto_template->SetHiddenPrototype(true);
20421
20422   Local<FunctionTemplate> protected_hidden_proto_template =
20423       v8::FunctionTemplate::New(isolate);
20424   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20425       BlockProtoNamedSecurityTestCallback,
20426       IndexedSecurityTestCallback);
20427   protected_hidden_proto_template->SetHiddenPrototype(true);
20428
20429   // Context for "foreign" objects used in test.
20430   Local<Context> context = v8::Context::New(isolate);
20431   context->Enter();
20432
20433   // Plain object, no security check.
20434   Local<Object> simple_object = Object::New(isolate);
20435
20436   // Object with explicit security check.
20437   Local<Object> protected_object =
20438       no_proto_template->NewInstance();
20439
20440   // JSGlobalProxy object, always have security check.
20441   Local<Object> proxy_object =
20442       context->Global();
20443
20444   // Global object, the  prototype of proxy_object. No security checks.
20445   Local<Object> global_object =
20446       proxy_object->GetPrototype()->ToObject();
20447
20448   // Hidden prototype without security check.
20449   Local<Object> hidden_prototype =
20450       hidden_proto_template->GetFunction()->NewInstance();
20451   Local<Object> object_with_hidden =
20452     Object::New(isolate);
20453   object_with_hidden->SetPrototype(hidden_prototype);
20454
20455   // Hidden prototype with security check on the hidden prototype.
20456   Local<Object> protected_hidden_prototype =
20457       protected_hidden_proto_template->GetFunction()->NewInstance();
20458   Local<Object> object_with_protected_hidden =
20459     Object::New(isolate);
20460   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20461
20462   context->Exit();
20463
20464   // Template for object for second context. Values to test are put on it as
20465   // properties.
20466   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20467   global_template->Set(v8_str("simple"), simple_object);
20468   global_template->Set(v8_str("protected"), protected_object);
20469   global_template->Set(v8_str("global"), global_object);
20470   global_template->Set(v8_str("proxy"), proxy_object);
20471   global_template->Set(v8_str("hidden"), object_with_hidden);
20472   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20473
20474   LocalContext context2(NULL, global_template);
20475
20476   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20477   CHECK(result1->Equals(simple_object->GetPrototype()));
20478
20479   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20480   CHECK(result2->Equals(Undefined(isolate)));
20481
20482   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20483   CHECK(result3->Equals(global_object->GetPrototype()));
20484
20485   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20486   CHECK(result4->Equals(Undefined(isolate)));
20487
20488   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20489   CHECK(result5->Equals(
20490       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20491
20492   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20493   CHECK(result6->Equals(Undefined(isolate)));
20494 }
20495
20496
20497 THREADED_TEST(Regress125988) {
20498   v8::HandleScope scope(CcTest::isolate());
20499   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20500   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20501   LocalContext env;
20502   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20503   CompileRun("var a = new Object();"
20504              "var b = new Intercept();"
20505              "var c = new Object();"
20506              "c.__proto__ = b;"
20507              "b.__proto__ = a;"
20508              "a.x = 23;"
20509              "for (var i = 0; i < 3; i++) c.x;");
20510   ExpectBoolean("c.hasOwnProperty('x')", false);
20511   ExpectInt32("c.x", 23);
20512   CompileRun("a.y = 42;"
20513              "for (var i = 0; i < 3; i++) c.x;");
20514   ExpectBoolean("c.hasOwnProperty('x')", false);
20515   ExpectInt32("c.x", 23);
20516   ExpectBoolean("c.hasOwnProperty('y')", false);
20517   ExpectInt32("c.y", 42);
20518 }
20519
20520
20521 static void TestReceiver(Local<Value> expected_result,
20522                          Local<Value> expected_receiver,
20523                          const char* code) {
20524   Local<Value> result = CompileRun(code);
20525   CHECK(result->IsObject());
20526   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20527   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20528 }
20529
20530
20531 THREADED_TEST(ForeignFunctionReceiver) {
20532   v8::Isolate* isolate = CcTest::isolate();
20533   HandleScope scope(isolate);
20534
20535   // Create two contexts with different "id" properties ('i' and 'o').
20536   // Call a function both from its own context and from a the foreign
20537   // context, and see what "this" is bound to (returning both "this"
20538   // and "this.id" for comparison).
20539
20540   Local<Context> foreign_context = v8::Context::New(isolate);
20541   foreign_context->Enter();
20542   Local<Value> foreign_function =
20543     CompileRun("function func() { return { 0: this.id, "
20544                "                           1: this, "
20545                "                           toString: function() { "
20546                "                               return this[0];"
20547                "                           }"
20548                "                         };"
20549                "}"
20550                "var id = 'i';"
20551                "func;");
20552   CHECK(foreign_function->IsFunction());
20553   foreign_context->Exit();
20554
20555   LocalContext context;
20556
20557   Local<String> password = v8_str("Password");
20558   // Don't get hit by security checks when accessing foreign_context's
20559   // global receiver (aka. global proxy).
20560   context->SetSecurityToken(password);
20561   foreign_context->SetSecurityToken(password);
20562
20563   Local<String> i = v8_str("i");
20564   Local<String> o = v8_str("o");
20565   Local<String> id = v8_str("id");
20566
20567   CompileRun("function ownfunc() { return { 0: this.id, "
20568              "                              1: this, "
20569              "                              toString: function() { "
20570              "                                  return this[0];"
20571              "                              }"
20572              "                             };"
20573              "}"
20574              "var id = 'o';"
20575              "ownfunc");
20576   context->Global()->Set(v8_str("func"), foreign_function);
20577
20578   // Sanity check the contexts.
20579   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20580   CHECK(o->Equals(context->Global()->Get(id)));
20581
20582   // Checking local function's receiver.
20583   // Calling function using its call/apply methods.
20584   TestReceiver(o, context->Global(), "ownfunc.call()");
20585   TestReceiver(o, context->Global(), "ownfunc.apply()");
20586   // Making calls through built-in functions.
20587   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20588   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20589   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20590   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20591   // Calling with environment record as base.
20592   TestReceiver(o, context->Global(), "ownfunc()");
20593   // Calling with no base.
20594   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20595
20596   // Checking foreign function return value.
20597   // Calling function using its call/apply methods.
20598   TestReceiver(i, foreign_context->Global(), "func.call()");
20599   TestReceiver(i, foreign_context->Global(), "func.apply()");
20600   // Calling function using another context's call/apply methods.
20601   TestReceiver(i, foreign_context->Global(),
20602                "Function.prototype.call.call(func)");
20603   TestReceiver(i, foreign_context->Global(),
20604                "Function.prototype.call.apply(func)");
20605   TestReceiver(i, foreign_context->Global(),
20606                "Function.prototype.apply.call(func)");
20607   TestReceiver(i, foreign_context->Global(),
20608                "Function.prototype.apply.apply(func)");
20609   // Making calls through built-in functions.
20610   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20611   // ToString(func()) is func()[0], i.e., the returned this.id.
20612   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20613   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20614   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20615
20616   // Calling with environment record as base.
20617   TestReceiver(i, foreign_context->Global(), "func()");
20618   // Calling with no base.
20619   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20620 }
20621
20622
20623 uint8_t callback_fired = 0;
20624
20625
20626 void CallCompletedCallback1() {
20627   i::OS::Print("Firing callback 1.\n");
20628   callback_fired ^= 1;  // Toggle first bit.
20629 }
20630
20631
20632 void CallCompletedCallback2() {
20633   i::OS::Print("Firing callback 2.\n");
20634   callback_fired ^= 2;  // Toggle second bit.
20635 }
20636
20637
20638 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20639   int32_t level = args[0]->Int32Value();
20640   if (level < 3) {
20641     level++;
20642     i::OS::Print("Entering recursion level %d.\n", level);
20643     char script[64];
20644     i::Vector<char> script_vector(script, sizeof(script));
20645     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20646     CompileRun(script_vector.start());
20647     i::OS::Print("Leaving recursion level %d.\n", level);
20648     CHECK_EQ(0, callback_fired);
20649   } else {
20650     i::OS::Print("Recursion ends.\n");
20651     CHECK_EQ(0, callback_fired);
20652   }
20653 }
20654
20655
20656 TEST(CallCompletedCallback) {
20657   LocalContext env;
20658   v8::HandleScope scope(env->GetIsolate());
20659   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20660       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20661   env->Global()->Set(v8_str("recursion"),
20662                      recursive_runtime->GetFunction());
20663   // Adding the same callback a second time has no effect.
20664   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20665   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20666   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20667   i::OS::Print("--- Script (1) ---\n");
20668   Local<Script> script = v8::Script::Compile(
20669       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20670   script->Run();
20671   CHECK_EQ(3, callback_fired);
20672
20673   i::OS::Print("\n--- Script (2) ---\n");
20674   callback_fired = 0;
20675   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20676   script->Run();
20677   CHECK_EQ(2, callback_fired);
20678
20679   i::OS::Print("\n--- Function ---\n");
20680   callback_fired = 0;
20681   Local<Function> recursive_function =
20682       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20683   v8::Handle<Value> args[] = { v8_num(0) };
20684   recursive_function->Call(env->Global(), 1, args);
20685   CHECK_EQ(2, callback_fired);
20686 }
20687
20688
20689 void CallCompletedCallbackNoException() {
20690   v8::HandleScope scope(CcTest::isolate());
20691   CompileRun("1+1;");
20692 }
20693
20694
20695 void CallCompletedCallbackException() {
20696   v8::HandleScope scope(CcTest::isolate());
20697   CompileRun("throw 'second exception';");
20698 }
20699
20700
20701 TEST(CallCompletedCallbackOneException) {
20702   LocalContext env;
20703   v8::HandleScope scope(env->GetIsolate());
20704   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20705   CompileRun("throw 'exception';");
20706 }
20707
20708
20709 TEST(CallCompletedCallbackTwoExceptions) {
20710   LocalContext env;
20711   v8::HandleScope scope(env->GetIsolate());
20712   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20713   CompileRun("throw 'first exception';");
20714 }
20715
20716
20717 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20718   v8::HandleScope scope(info.GetIsolate());
20719   CompileRun("ext1Calls++;");
20720 }
20721
20722
20723 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20724   v8::HandleScope scope(info.GetIsolate());
20725   CompileRun("ext2Calls++;");
20726 }
20727
20728
20729 TEST(EnqueueMicrotask) {
20730   LocalContext env;
20731   v8::HandleScope scope(env->GetIsolate());
20732   CompileRun(
20733       "var ext1Calls = 0;"
20734       "var ext2Calls = 0;");
20735   CompileRun("1+1;");
20736   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20737   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20738
20739   env->GetIsolate()->EnqueueMicrotask(
20740       Function::New(env->GetIsolate(), MicrotaskOne));
20741   CompileRun("1+1;");
20742   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20743   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20744
20745   env->GetIsolate()->EnqueueMicrotask(
20746       Function::New(env->GetIsolate(), MicrotaskOne));
20747   env->GetIsolate()->EnqueueMicrotask(
20748       Function::New(env->GetIsolate(), MicrotaskTwo));
20749   CompileRun("1+1;");
20750   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20751   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20752
20753   env->GetIsolate()->EnqueueMicrotask(
20754       Function::New(env->GetIsolate(), MicrotaskTwo));
20755   CompileRun("1+1;");
20756   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20757   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20758
20759   CompileRun("1+1;");
20760   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20761   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20762 }
20763
20764
20765 TEST(SetAutorunMicrotasks) {
20766   LocalContext env;
20767   v8::HandleScope scope(env->GetIsolate());
20768   CompileRun(
20769       "var ext1Calls = 0;"
20770       "var ext2Calls = 0;");
20771   CompileRun("1+1;");
20772   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20773   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20774
20775   env->GetIsolate()->EnqueueMicrotask(
20776       Function::New(env->GetIsolate(), MicrotaskOne));
20777   CompileRun("1+1;");
20778   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20779   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20780
20781   env->GetIsolate()->SetAutorunMicrotasks(false);
20782   env->GetIsolate()->EnqueueMicrotask(
20783       Function::New(env->GetIsolate(), MicrotaskOne));
20784   env->GetIsolate()->EnqueueMicrotask(
20785       Function::New(env->GetIsolate(), MicrotaskTwo));
20786   CompileRun("1+1;");
20787   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20788   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20789
20790   env->GetIsolate()->RunMicrotasks();
20791   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20792   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20793
20794   env->GetIsolate()->EnqueueMicrotask(
20795       Function::New(env->GetIsolate(), MicrotaskTwo));
20796   CompileRun("1+1;");
20797   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20798   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20799
20800   env->GetIsolate()->RunMicrotasks();
20801   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20802   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20803
20804   env->GetIsolate()->SetAutorunMicrotasks(true);
20805   env->GetIsolate()->EnqueueMicrotask(
20806       Function::New(env->GetIsolate(), MicrotaskTwo));
20807   CompileRun("1+1;");
20808   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20809   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20810
20811   env->GetIsolate()->EnqueueMicrotask(
20812       Function::New(env->GetIsolate(), MicrotaskTwo));
20813   {
20814     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20815     CompileRun("1+1;");
20816     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20817     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20818   }
20819
20820   CompileRun("1+1;");
20821   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20822   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20823 }
20824
20825
20826 static int probes_counter = 0;
20827 static int misses_counter = 0;
20828 static int updates_counter = 0;
20829
20830
20831 static int* LookupCounter(const char* name) {
20832   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20833     return &probes_counter;
20834   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20835     return &misses_counter;
20836   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20837     return &updates_counter;
20838   }
20839   return NULL;
20840 }
20841
20842
20843 static const char* kMegamorphicTestProgram =
20844     "function ClassA() { };"
20845     "function ClassB() { };"
20846     "ClassA.prototype.foo = function() { };"
20847     "ClassB.prototype.foo = function() { };"
20848     "function fooify(obj) { obj.foo(); };"
20849     "var a = new ClassA();"
20850     "var b = new ClassB();"
20851     "for (var i = 0; i < 10000; i++) {"
20852     "  fooify(a);"
20853     "  fooify(b);"
20854     "}";
20855
20856
20857 static void StubCacheHelper(bool primary) {
20858   V8::SetCounterFunction(LookupCounter);
20859   USE(kMegamorphicTestProgram);
20860 #ifdef DEBUG
20861   i::FLAG_native_code_counters = true;
20862   if (primary) {
20863     i::FLAG_test_primary_stub_cache = true;
20864   } else {
20865     i::FLAG_test_secondary_stub_cache = true;
20866   }
20867   i::FLAG_crankshaft = false;
20868   LocalContext env;
20869   v8::HandleScope scope(env->GetIsolate());
20870   int initial_probes = probes_counter;
20871   int initial_misses = misses_counter;
20872   int initial_updates = updates_counter;
20873   CompileRun(kMegamorphicTestProgram);
20874   int probes = probes_counter - initial_probes;
20875   int misses = misses_counter - initial_misses;
20876   int updates = updates_counter - initial_updates;
20877   CHECK_LT(updates, 10);
20878   CHECK_LT(misses, 10);
20879   // TODO(verwaest): Update this test to overflow the degree of polymorphism
20880   // before megamorphism. The number of probes will only work once we teach the
20881   // serializer to embed references to counters in the stubs, given that the
20882   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20883   CHECK_GE(probes, 0);
20884 #endif
20885 }
20886
20887
20888 TEST(SecondaryStubCache) {
20889   StubCacheHelper(true);
20890 }
20891
20892
20893 TEST(PrimaryStubCache) {
20894   StubCacheHelper(false);
20895 }
20896
20897
20898 static int cow_arrays_created_runtime = 0;
20899
20900
20901 static int* LookupCounterCOWArrays(const char* name) {
20902   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20903     return &cow_arrays_created_runtime;
20904   }
20905   return NULL;
20906 }
20907
20908
20909 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20910   V8::SetCounterFunction(LookupCounterCOWArrays);
20911 #ifdef DEBUG
20912   i::FLAG_native_code_counters = true;
20913   LocalContext env;
20914   v8::HandleScope scope(env->GetIsolate());
20915   int initial_cow_arrays = cow_arrays_created_runtime;
20916   CompileRun("var o = [1, 2, 3];");
20917   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20918   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20919   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20920   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20921   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20922 #endif
20923 }
20924
20925
20926 TEST(StaticGetters) {
20927   LocalContext context;
20928   i::Factory* factory = CcTest::i_isolate()->factory();
20929   v8::Isolate* isolate = CcTest::isolate();
20930   v8::HandleScope scope(isolate);
20931   i::Handle<i::Object> undefined_value = factory->undefined_value();
20932   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20933   i::Handle<i::Object> null_value = factory->null_value();
20934   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20935   i::Handle<i::Object> true_value = factory->true_value();
20936   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20937   i::Handle<i::Object> false_value = factory->false_value();
20938   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20939 }
20940
20941
20942 UNINITIALIZED_TEST(IsolateEmbedderData) {
20943   CcTest::DisableAutomaticDispose();
20944   v8::Isolate* isolate = v8::Isolate::New();
20945   isolate->Enter();
20946   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20947   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20948     CHECK_EQ(NULL, isolate->GetData(slot));
20949     CHECK_EQ(NULL, i_isolate->GetData(slot));
20950   }
20951   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20952     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20953     isolate->SetData(slot, data);
20954   }
20955   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20956     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20957     CHECK_EQ(data, isolate->GetData(slot));
20958     CHECK_EQ(data, i_isolate->GetData(slot));
20959   }
20960   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20961     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20962     isolate->SetData(slot, data);
20963   }
20964   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20965     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20966     CHECK_EQ(data, isolate->GetData(slot));
20967     CHECK_EQ(data, i_isolate->GetData(slot));
20968   }
20969   isolate->Exit();
20970   isolate->Dispose();
20971 }
20972
20973
20974 TEST(StringEmpty) {
20975   LocalContext context;
20976   i::Factory* factory = CcTest::i_isolate()->factory();
20977   v8::Isolate* isolate = CcTest::isolate();
20978   v8::HandleScope scope(isolate);
20979   i::Handle<i::Object> empty_string = factory->empty_string();
20980   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20981 }
20982
20983
20984 static int instance_checked_getter_count = 0;
20985 static void InstanceCheckedGetter(
20986     Local<String> name,
20987     const v8::PropertyCallbackInfo<v8::Value>& info) {
20988   CHECK_EQ(name, v8_str("foo"));
20989   instance_checked_getter_count++;
20990   info.GetReturnValue().Set(v8_num(11));
20991 }
20992
20993
20994 static int instance_checked_setter_count = 0;
20995 static void InstanceCheckedSetter(Local<String> name,
20996                       Local<Value> value,
20997                       const v8::PropertyCallbackInfo<void>& info) {
20998   CHECK_EQ(name, v8_str("foo"));
20999   CHECK_EQ(value, v8_num(23));
21000   instance_checked_setter_count++;
21001 }
21002
21003
21004 static void CheckInstanceCheckedResult(int getters,
21005                                        int setters,
21006                                        bool expects_callbacks,
21007                                        TryCatch* try_catch) {
21008   if (expects_callbacks) {
21009     CHECK(!try_catch->HasCaught());
21010     CHECK_EQ(getters, instance_checked_getter_count);
21011     CHECK_EQ(setters, instance_checked_setter_count);
21012   } else {
21013     CHECK(try_catch->HasCaught());
21014     CHECK_EQ(0, instance_checked_getter_count);
21015     CHECK_EQ(0, instance_checked_setter_count);
21016   }
21017   try_catch->Reset();
21018 }
21019
21020
21021 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21022   instance_checked_getter_count = 0;
21023   instance_checked_setter_count = 0;
21024   TryCatch try_catch;
21025
21026   // Test path through generic runtime code.
21027   CompileRun("obj.foo");
21028   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21029   CompileRun("obj.foo = 23");
21030   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21031
21032   // Test path through generated LoadIC and StoredIC.
21033   CompileRun("function test_get(o) { o.foo; }"
21034              "test_get(obj);");
21035   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21036   CompileRun("test_get(obj);");
21037   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21038   CompileRun("test_get(obj);");
21039   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21040   CompileRun("function test_set(o) { o.foo = 23; }"
21041              "test_set(obj);");
21042   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21043   CompileRun("test_set(obj);");
21044   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21045   CompileRun("test_set(obj);");
21046   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21047
21048   // Test path through optimized code.
21049   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21050              "test_get(obj);");
21051   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21052   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21053              "test_set(obj);");
21054   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21055
21056   // Cleanup so that closures start out fresh in next check.
21057   CompileRun("%DeoptimizeFunction(test_get);"
21058              "%ClearFunctionTypeFeedback(test_get);"
21059              "%DeoptimizeFunction(test_set);"
21060              "%ClearFunctionTypeFeedback(test_set);");
21061 }
21062
21063
21064 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21065   v8::internal::FLAG_allow_natives_syntax = true;
21066   LocalContext context;
21067   v8::HandleScope scope(context->GetIsolate());
21068
21069   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21070   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21071   inst->SetAccessor(v8_str("foo"),
21072                     InstanceCheckedGetter, InstanceCheckedSetter,
21073                     Handle<Value>(),
21074                     v8::DEFAULT,
21075                     v8::None,
21076                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21077   context->Global()->Set(v8_str("f"), templ->GetFunction());
21078
21079   printf("Testing positive ...\n");
21080   CompileRun("var obj = new f();");
21081   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21082   CheckInstanceCheckedAccessors(true);
21083
21084   printf("Testing negative ...\n");
21085   CompileRun("var obj = {};"
21086              "obj.__proto__ = new f();");
21087   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21088   CheckInstanceCheckedAccessors(false);
21089 }
21090
21091
21092 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21093   v8::internal::FLAG_allow_natives_syntax = true;
21094   LocalContext context;
21095   v8::HandleScope scope(context->GetIsolate());
21096
21097   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21098   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21099   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21100   inst->SetAccessor(v8_str("foo"),
21101                     InstanceCheckedGetter, InstanceCheckedSetter,
21102                     Handle<Value>(),
21103                     v8::DEFAULT,
21104                     v8::None,
21105                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21106   context->Global()->Set(v8_str("f"), templ->GetFunction());
21107
21108   printf("Testing positive ...\n");
21109   CompileRun("var obj = new f();");
21110   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21111   CheckInstanceCheckedAccessors(true);
21112
21113   printf("Testing negative ...\n");
21114   CompileRun("var obj = {};"
21115              "obj.__proto__ = new f();");
21116   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21117   CheckInstanceCheckedAccessors(false);
21118 }
21119
21120
21121 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21122   v8::internal::FLAG_allow_natives_syntax = true;
21123   LocalContext context;
21124   v8::HandleScope scope(context->GetIsolate());
21125
21126   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21127   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21128   proto->SetAccessor(v8_str("foo"),
21129                      InstanceCheckedGetter, InstanceCheckedSetter,
21130                      Handle<Value>(),
21131                      v8::DEFAULT,
21132                      v8::None,
21133                      v8::AccessorSignature::New(context->GetIsolate(), templ));
21134   context->Global()->Set(v8_str("f"), templ->GetFunction());
21135
21136   printf("Testing positive ...\n");
21137   CompileRun("var obj = new f();");
21138   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21139   CheckInstanceCheckedAccessors(true);
21140
21141   printf("Testing negative ...\n");
21142   CompileRun("var obj = {};"
21143              "obj.__proto__ = new f();");
21144   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21145   CheckInstanceCheckedAccessors(false);
21146
21147   printf("Testing positive with modified prototype chain ...\n");
21148   CompileRun("var obj = new f();"
21149              "var pro = {};"
21150              "pro.__proto__ = obj.__proto__;"
21151              "obj.__proto__ = pro;");
21152   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21153   CheckInstanceCheckedAccessors(true);
21154 }
21155
21156
21157 TEST(TryFinallyMessage) {
21158   LocalContext context;
21159   v8::HandleScope scope(context->GetIsolate());
21160   {
21161     // Test that the original error message is not lost if there is a
21162     // recursive call into Javascript is done in the finally block, e.g. to
21163     // initialize an IC. (crbug.com/129171)
21164     TryCatch try_catch;
21165     const char* trigger_ic =
21166         "try {                      \n"
21167         "  throw new Error('test'); \n"
21168         "} finally {                \n"
21169         "  var x = 0;               \n"
21170         "  x++;                     \n"  // Trigger an IC initialization here.
21171         "}                          \n";
21172     CompileRun(trigger_ic);
21173     CHECK(try_catch.HasCaught());
21174     Local<Message> message = try_catch.Message();
21175     CHECK(!message.IsEmpty());
21176     CHECK_EQ(2, message->GetLineNumber());
21177   }
21178
21179   {
21180     // Test that the original exception message is indeed overwritten if
21181     // a new error is thrown in the finally block.
21182     TryCatch try_catch;
21183     const char* throw_again =
21184         "try {                       \n"
21185         "  throw new Error('test');  \n"
21186         "} finally {                 \n"
21187         "  var x = 0;                \n"
21188         "  x++;                      \n"
21189         "  throw new Error('again'); \n"  // This is the new uncaught error.
21190         "}                           \n";
21191     CompileRun(throw_again);
21192     CHECK(try_catch.HasCaught());
21193     Local<Message> message = try_catch.Message();
21194     CHECK(!message.IsEmpty());
21195     CHECK_EQ(6, message->GetLineNumber());
21196   }
21197 }
21198
21199
21200 static void Helper137002(bool do_store,
21201                          bool polymorphic,
21202                          bool remove_accessor,
21203                          bool interceptor) {
21204   LocalContext context;
21205   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21206   if (interceptor) {
21207     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21208   } else {
21209     templ->SetAccessor(v8_str("foo"),
21210                        GetterWhichReturns42,
21211                        SetterWhichSetsYOnThisTo23);
21212   }
21213   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21214
21215   // Turn monomorphic on slow object with native accessor, then turn
21216   // polymorphic, finally optimize to create negative lookup and fail.
21217   CompileRun(do_store ?
21218              "function f(x) { x.foo = void 0; }" :
21219              "function f(x) { return x.foo; }");
21220   CompileRun("obj.y = void 0;");
21221   if (!interceptor) {
21222     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21223   }
21224   CompileRun("obj.__proto__ = null;"
21225              "f(obj); f(obj); f(obj);");
21226   if (polymorphic) {
21227     CompileRun("f({});");
21228   }
21229   CompileRun("obj.y = void 0;"
21230              "%OptimizeFunctionOnNextCall(f);");
21231   if (remove_accessor) {
21232     CompileRun("delete obj.foo;");
21233   }
21234   CompileRun("var result = f(obj);");
21235   if (do_store) {
21236     CompileRun("result = obj.y;");
21237   }
21238   if (remove_accessor && !interceptor) {
21239     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21240   } else {
21241     CHECK_EQ(do_store ? 23 : 42,
21242              context->Global()->Get(v8_str("result"))->Int32Value());
21243   }
21244 }
21245
21246
21247 THREADED_TEST(Regress137002a) {
21248   i::FLAG_allow_natives_syntax = true;
21249   i::FLAG_compilation_cache = false;
21250   v8::HandleScope scope(CcTest::isolate());
21251   for (int i = 0; i < 16; i++) {
21252     Helper137002(i & 8, i & 4, i & 2, i & 1);
21253   }
21254 }
21255
21256
21257 THREADED_TEST(Regress137002b) {
21258   i::FLAG_allow_natives_syntax = true;
21259   LocalContext context;
21260   v8::Isolate* isolate = context->GetIsolate();
21261   v8::HandleScope scope(isolate);
21262   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21263   templ->SetAccessor(v8_str("foo"),
21264                      GetterWhichReturns42,
21265                      SetterWhichSetsYOnThisTo23);
21266   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21267
21268   // Turn monomorphic on slow object with native accessor, then just
21269   // delete the property and fail.
21270   CompileRun("function load(x) { return x.foo; }"
21271              "function store(x) { x.foo = void 0; }"
21272              "function keyed_load(x, key) { return x[key]; }"
21273              // Second version of function has a different source (add void 0)
21274              // so that it does not share code with the first version.  This
21275              // ensures that the ICs are monomorphic.
21276              "function load2(x) { void 0; return x.foo; }"
21277              "function store2(x) { void 0; x.foo = void 0; }"
21278              "function keyed_load2(x, key) { void 0; return x[key]; }"
21279
21280              "obj.y = void 0;"
21281              "obj.__proto__ = null;"
21282              "var subobj = {};"
21283              "subobj.y = void 0;"
21284              "subobj.__proto__ = obj;"
21285              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21286
21287              // Make the ICs monomorphic.
21288              "load(obj); load(obj);"
21289              "load2(subobj); load2(subobj);"
21290              "store(obj); store(obj);"
21291              "store2(subobj); store2(subobj);"
21292              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21293              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21294
21295              // Actually test the shiny new ICs and better not crash. This
21296              // serves as a regression test for issue 142088 as well.
21297              "load(obj);"
21298              "load2(subobj);"
21299              "store(obj);"
21300              "store2(subobj);"
21301              "keyed_load(obj, 'foo');"
21302              "keyed_load2(subobj, 'foo');"
21303
21304              // Delete the accessor.  It better not be called any more now.
21305              "delete obj.foo;"
21306              "obj.y = void 0;"
21307              "subobj.y = void 0;"
21308
21309              "var load_result = load(obj);"
21310              "var load_result2 = load2(subobj);"
21311              "var keyed_load_result = keyed_load(obj, 'foo');"
21312              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21313              "store(obj);"
21314              "store2(subobj);"
21315              "var y_from_obj = obj.y;"
21316              "var y_from_subobj = subobj.y;");
21317   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21318   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21319   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21320   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21321   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21322   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21323 }
21324
21325
21326 THREADED_TEST(Regress142088) {
21327   i::FLAG_allow_natives_syntax = true;
21328   LocalContext context;
21329   v8::Isolate* isolate = context->GetIsolate();
21330   v8::HandleScope scope(isolate);
21331   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21332   templ->SetAccessor(v8_str("foo"),
21333                      GetterWhichReturns42,
21334                      SetterWhichSetsYOnThisTo23);
21335   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21336
21337   CompileRun("function load(x) { return x.foo; }"
21338              "var o = Object.create(obj);"
21339              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21340              "load(o); load(o); load(o); load(o);");
21341 }
21342
21343
21344 THREADED_TEST(Regress137496) {
21345   i::FLAG_expose_gc = true;
21346   LocalContext context;
21347   v8::HandleScope scope(context->GetIsolate());
21348
21349   // Compile a try-finally clause where the finally block causes a GC
21350   // while there still is a message pending for external reporting.
21351   TryCatch try_catch;
21352   try_catch.SetVerbose(true);
21353   CompileRun("try { throw new Error(); } finally { gc(); }");
21354   CHECK(try_catch.HasCaught());
21355 }
21356
21357
21358 THREADED_TEST(Regress149912) {
21359   LocalContext context;
21360   v8::HandleScope scope(context->GetIsolate());
21361   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21362   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21363   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21364   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21365 }
21366
21367
21368 THREADED_TEST(Regress157124) {
21369   LocalContext context;
21370   v8::Isolate* isolate = context->GetIsolate();
21371   v8::HandleScope scope(isolate);
21372   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21373   Local<Object> obj = templ->NewInstance();
21374   obj->GetIdentityHash();
21375   obj->DeleteHiddenValue(v8_str("Bug"));
21376 }
21377
21378
21379 THREADED_TEST(Regress2535) {
21380   i::FLAG_harmony_collections = true;
21381   LocalContext context;
21382   v8::HandleScope scope(context->GetIsolate());
21383   Local<Value> set_value = CompileRun("new Set();");
21384   Local<Object> set_object(Local<Object>::Cast(set_value));
21385   CHECK_EQ(0, set_object->InternalFieldCount());
21386   Local<Value> map_value = CompileRun("new Map();");
21387   Local<Object> map_object(Local<Object>::Cast(map_value));
21388   CHECK_EQ(0, map_object->InternalFieldCount());
21389 }
21390
21391
21392 THREADED_TEST(Regress2746) {
21393   LocalContext context;
21394   v8::Isolate* isolate = context->GetIsolate();
21395   v8::HandleScope scope(isolate);
21396   Local<Object> obj = Object::New(isolate);
21397   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21398   obj->SetHiddenValue(key, v8::Undefined(isolate));
21399   Local<Value> value = obj->GetHiddenValue(key);
21400   CHECK(!value.IsEmpty());
21401   CHECK(value->IsUndefined());
21402 }
21403
21404
21405 THREADED_TEST(Regress260106) {
21406   LocalContext context;
21407   v8::Isolate* isolate = context->GetIsolate();
21408   v8::HandleScope scope(isolate);
21409   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21410                                                         DummyCallHandler);
21411   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21412   Local<Function> function = templ->GetFunction();
21413   CHECK(!function.IsEmpty());
21414   CHECK(function->IsFunction());
21415 }
21416
21417
21418 THREADED_TEST(JSONParseObject) {
21419   LocalContext context;
21420   HandleScope scope(context->GetIsolate());
21421   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21422   Handle<Object> global = context->Global();
21423   global->Set(v8_str("obj"), obj);
21424   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21425 }
21426
21427
21428 THREADED_TEST(JSONParseNumber) {
21429   LocalContext context;
21430   HandleScope scope(context->GetIsolate());
21431   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21432   Handle<Object> global = context->Global();
21433   global->Set(v8_str("obj"), obj);
21434   ExpectString("JSON.stringify(obj)", "42");
21435 }
21436
21437
21438 #if V8_OS_POSIX
21439 class ThreadInterruptTest {
21440  public:
21441   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21442   ~ThreadInterruptTest() {}
21443
21444   void RunTest() {
21445     InterruptThread i_thread(this);
21446     i_thread.Start();
21447
21448     sem_.Wait();
21449     CHECK_EQ(kExpectedValue, sem_value_);
21450   }
21451
21452  private:
21453   static const int kExpectedValue = 1;
21454
21455   class InterruptThread : public i::Thread {
21456    public:
21457     explicit InterruptThread(ThreadInterruptTest* test)
21458         : Thread("InterruptThread"), test_(test) {}
21459
21460     virtual void Run() {
21461       struct sigaction action;
21462
21463       // Ensure that we'll enter waiting condition
21464       i::OS::Sleep(100);
21465
21466       // Setup signal handler
21467       memset(&action, 0, sizeof(action));
21468       action.sa_handler = SignalHandler;
21469       sigaction(SIGCHLD, &action, NULL);
21470
21471       // Send signal
21472       kill(getpid(), SIGCHLD);
21473
21474       // Ensure that if wait has returned because of error
21475       i::OS::Sleep(100);
21476
21477       // Set value and signal semaphore
21478       test_->sem_value_ = 1;
21479       test_->sem_.Signal();
21480     }
21481
21482     static void SignalHandler(int signal) {
21483     }
21484
21485    private:
21486      ThreadInterruptTest* test_;
21487   };
21488
21489   i::Semaphore sem_;
21490   volatile int sem_value_;
21491 };
21492
21493
21494 THREADED_TEST(SemaphoreInterruption) {
21495   ThreadInterruptTest().RunTest();
21496 }
21497
21498
21499 #endif  // V8_OS_POSIX
21500
21501
21502 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21503                                      Local<Value> name,
21504                                      v8::AccessType type,
21505                                      Local<Value> data) {
21506   i::PrintF("Named access blocked.\n");
21507   return false;
21508 }
21509
21510
21511 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21512                                      uint32_t key,
21513                                      v8::AccessType type,
21514                                      Local<Value> data) {
21515   i::PrintF("Indexed access blocked.\n");
21516   return false;
21517 }
21518
21519
21520 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21521   CHECK(false);
21522 }
21523
21524
21525 TEST(JSONStringifyAccessCheck) {
21526   v8::V8::Initialize();
21527   v8::Isolate* isolate = CcTest::isolate();
21528   v8::HandleScope scope(isolate);
21529
21530   // Create an ObjectTemplate for global objects and install access
21531   // check callbacks that will block access.
21532   v8::Handle<v8::ObjectTemplate> global_template =
21533       v8::ObjectTemplate::New(isolate);
21534   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21535                                            IndexAccessAlwaysBlocked);
21536
21537   // Create a context and set an x property on it's global object.
21538   LocalContext context0(NULL, global_template);
21539   v8::Handle<v8::Object> global0 = context0->Global();
21540   global0->Set(v8_str("x"), v8_num(42));
21541   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21542
21543   for (int i = 0; i < 2; i++) {
21544     if (i == 1) {
21545       // Install a toJSON function on the second run.
21546       v8::Handle<v8::FunctionTemplate> toJSON =
21547           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21548
21549       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21550     }
21551     // Create a context with a different security token so that the
21552     // failed access check callback will be called on each access.
21553     LocalContext context1(NULL, global_template);
21554     context1->Global()->Set(v8_str("other"), global0);
21555
21556     ExpectString("JSON.stringify(other)", "{}");
21557     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21558                  "{\"a\":{},\"b\":[\"c\"]}");
21559     ExpectString("JSON.stringify([other, 'b', 'c'])",
21560                  "[{},\"b\",\"c\"]");
21561
21562     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21563     array->Set(0, v8_str("a"));
21564     array->Set(1, v8_str("b"));
21565     context1->Global()->Set(v8_str("array"), array);
21566     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21567     array->TurnOnAccessCheck();
21568     ExpectString("JSON.stringify(array)", "[]");
21569     ExpectString("JSON.stringify([array])", "[[]]");
21570     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21571   }
21572 }
21573
21574
21575 bool access_check_fail_thrown = false;
21576 bool catch_callback_called = false;
21577
21578
21579 // Failed access check callback that performs a GC on each invocation.
21580 void FailedAccessCheckThrows(Local<v8::Object> target,
21581                              v8::AccessType type,
21582                              Local<v8::Value> data) {
21583   access_check_fail_thrown = true;
21584   i::PrintF("Access check failed. Error thrown.\n");
21585   CcTest::isolate()->ThrowException(
21586       v8::Exception::Error(v8_str("cross context")));
21587 }
21588
21589
21590 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21591   for (int i = 0; i < args.Length(); i++) {
21592     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21593   }
21594   catch_callback_called = true;
21595 }
21596
21597
21598 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21599   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21600 }
21601
21602
21603 void CheckCorrectThrow(const char* script) {
21604   // Test that the script, when wrapped into a try-catch, triggers the catch
21605   // clause due to failed access check throwing an exception.
21606   // The subsequent try-catch should run without any exception.
21607   access_check_fail_thrown = false;
21608   catch_callback_called = false;
21609   i::ScopedVector<char> source(1024);
21610   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21611   CompileRun(source.start());
21612   CHECK(access_check_fail_thrown);
21613   CHECK(catch_callback_called);
21614
21615   access_check_fail_thrown = false;
21616   catch_callback_called = false;
21617   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21618   CHECK(!access_check_fail_thrown);
21619   CHECK(!catch_callback_called);
21620 }
21621
21622
21623 TEST(AccessCheckThrows) {
21624   i::FLAG_allow_natives_syntax = true;
21625   v8::V8::Initialize();
21626   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21627   v8::Isolate* isolate = CcTest::isolate();
21628   v8::HandleScope scope(isolate);
21629
21630   // Create an ObjectTemplate for global objects and install access
21631   // check callbacks that will block access.
21632   v8::Handle<v8::ObjectTemplate> global_template =
21633       v8::ObjectTemplate::New(isolate);
21634   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21635                                            IndexAccessAlwaysBlocked);
21636
21637   // Create a context and set an x property on it's global object.
21638   LocalContext context0(NULL, global_template);
21639   context0->Global()->Set(v8_str("x"), v8_num(42));
21640   v8::Handle<v8::Object> global0 = context0->Global();
21641
21642   // Create a context with a different security token so that the
21643   // failed access check callback will be called on each access.
21644   LocalContext context1(NULL, global_template);
21645   context1->Global()->Set(v8_str("other"), global0);
21646
21647   v8::Handle<v8::FunctionTemplate> catcher_fun =
21648       v8::FunctionTemplate::New(isolate, CatcherCallback);
21649   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21650
21651   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21652       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21653   context1->Global()->Set(v8_str("has_own_property"),
21654                           has_own_property_fun->GetFunction());
21655
21656   { v8::TryCatch try_catch;
21657     access_check_fail_thrown = false;
21658     CompileRun("other.x;");
21659     CHECK(access_check_fail_thrown);
21660     CHECK(try_catch.HasCaught());
21661   }
21662
21663   CheckCorrectThrow("other.x");
21664   CheckCorrectThrow("other[1]");
21665   CheckCorrectThrow("JSON.stringify(other)");
21666   CheckCorrectThrow("has_own_property(other, 'x')");
21667   CheckCorrectThrow("%GetProperty(other, 'x')");
21668   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21669   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21670   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21671   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21672   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21673   CheckCorrectThrow("%HasProperty(other, 'x')");
21674   CheckCorrectThrow("%HasElement(other, 1)");
21675   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21676   CheckCorrectThrow("%GetPropertyNames(other)");
21677   // PROPERTY_ATTRIBUTES_NONE = 0
21678   CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21679   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21680                         "other, 'x', null, null, 1)");
21681
21682   // Reset the failed access check callback so it does not influence
21683   // the other tests.
21684   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21685 }
21686
21687
21688 THREADED_TEST(Regress256330) {
21689   i::FLAG_allow_natives_syntax = true;
21690   LocalContext context;
21691   v8::HandleScope scope(context->GetIsolate());
21692   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21693   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21694   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21695   CompileRun("\"use strict\"; var o = new Bug;"
21696              "function f(o) { o.x = 10; };"
21697              "f(o); f(o); f(o);"
21698              "%OptimizeFunctionOnNextCall(f);"
21699              "f(o);");
21700   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21701 }
21702
21703
21704 THREADED_TEST(CrankshaftInterceptorSetter) {
21705   i::FLAG_allow_natives_syntax = true;
21706   v8::HandleScope scope(CcTest::isolate());
21707   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21708   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21709   LocalContext env;
21710   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21711   CompileRun("var obj = new Obj;"
21712              // Initialize fields to avoid transitions later.
21713              "obj.age = 0;"
21714              "obj.accessor_age = 42;"
21715              "function setter(i) { this.accessor_age = i; };"
21716              "function getter() { return this.accessor_age; };"
21717              "function setAge(i) { obj.age = i; };"
21718              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21719              "setAge(1);"
21720              "setAge(2);"
21721              "setAge(3);"
21722              "%OptimizeFunctionOnNextCall(setAge);"
21723              "setAge(4);");
21724   // All stores went through the interceptor.
21725   ExpectInt32("obj.interceptor_age", 4);
21726   ExpectInt32("obj.accessor_age", 42);
21727 }
21728
21729
21730 THREADED_TEST(CrankshaftInterceptorGetter) {
21731   i::FLAG_allow_natives_syntax = true;
21732   v8::HandleScope scope(CcTest::isolate());
21733   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21734   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21735   LocalContext env;
21736   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21737   CompileRun("var obj = new Obj;"
21738              // Initialize fields to avoid transitions later.
21739              "obj.age = 1;"
21740              "obj.accessor_age = 42;"
21741              "function getter() { return this.accessor_age; };"
21742              "function getAge() { return obj.interceptor_age; };"
21743              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21744              "getAge();"
21745              "getAge();"
21746              "getAge();"
21747              "%OptimizeFunctionOnNextCall(getAge);");
21748   // Access through interceptor.
21749   ExpectInt32("getAge()", 1);
21750 }
21751
21752
21753 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21754   i::FLAG_allow_natives_syntax = true;
21755   v8::HandleScope scope(CcTest::isolate());
21756   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21757   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21758   LocalContext env;
21759   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21760   CompileRun("var obj = new Obj;"
21761              "obj.__proto__.interceptor_age = 42;"
21762              "obj.age = 100;"
21763              "function getAge() { return obj.interceptor_age; };");
21764   ExpectInt32("getAge();", 100);
21765   ExpectInt32("getAge();", 100);
21766   ExpectInt32("getAge();", 100);
21767   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21768   // Access through interceptor.
21769   ExpectInt32("getAge();", 100);
21770 }
21771
21772
21773 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21774   i::FLAG_allow_natives_syntax = true;
21775   v8::HandleScope scope(CcTest::isolate());
21776   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21777   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21778   LocalContext env;
21779   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21780   CompileRun("var obj = new Obj;"
21781              "obj.age = 100000;"
21782              "function setAge(i) { obj.age = i };"
21783              "setAge(100);"
21784              "setAge(101);"
21785              "setAge(102);"
21786              "%OptimizeFunctionOnNextCall(setAge);"
21787              "setAge(103);");
21788   ExpectInt32("obj.age", 100000);
21789   ExpectInt32("obj.interceptor_age", 103);
21790 }
21791
21792
21793 class RequestInterruptTestBase {
21794  public:
21795   RequestInterruptTestBase()
21796       : env_(),
21797         isolate_(env_->GetIsolate()),
21798         sem_(0),
21799         warmup_(20000),
21800         should_continue_(true) {
21801   }
21802
21803   virtual ~RequestInterruptTestBase() { }
21804
21805   virtual void TestBody() = 0;
21806
21807   void RunTest() {
21808     InterruptThread i_thread(this);
21809     i_thread.Start();
21810
21811     v8::HandleScope handle_scope(isolate_);
21812
21813     TestBody();
21814
21815     isolate_->ClearInterrupt();
21816
21817     // Verify we arrived here because interruptor was called
21818     // not due to a bug causing us to exit the loop too early.
21819     CHECK(!should_continue());
21820   }
21821
21822   void WakeUpInterruptor() {
21823     sem_.Signal();
21824   }
21825
21826   bool should_continue() const { return should_continue_; }
21827
21828   bool ShouldContinue() {
21829     if (warmup_ > 0) {
21830       if (--warmup_ == 0) {
21831         WakeUpInterruptor();
21832       }
21833     }
21834
21835     return should_continue_;
21836   }
21837
21838  protected:
21839   static void ShouldContinueCallback(
21840       const v8::FunctionCallbackInfo<Value>& info) {
21841     RequestInterruptTestBase* test =
21842         reinterpret_cast<RequestInterruptTestBase*>(
21843             info.Data().As<v8::External>()->Value());
21844     info.GetReturnValue().Set(test->ShouldContinue());
21845   }
21846
21847   class InterruptThread : public i::Thread {
21848    public:
21849     explicit InterruptThread(RequestInterruptTestBase* test)
21850         : Thread("RequestInterruptTest"), test_(test) {}
21851
21852     virtual void Run() {
21853       test_->sem_.Wait();
21854       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21855     }
21856
21857     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21858       reinterpret_cast<RequestInterruptTestBase*>(data)->
21859           should_continue_ = false;
21860     }
21861
21862    private:
21863      RequestInterruptTestBase* test_;
21864   };
21865
21866   LocalContext env_;
21867   v8::Isolate* isolate_;
21868   i::Semaphore sem_;
21869   int warmup_;
21870   bool should_continue_;
21871 };
21872
21873
21874 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21875  public:
21876   virtual void TestBody() {
21877     Local<Function> func = Function::New(
21878         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21879     env_->Global()->Set(v8_str("ShouldContinue"), func);
21880
21881     CompileRun("while (ShouldContinue()) { }");
21882   }
21883 };
21884
21885
21886 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21887  public:
21888   virtual void TestBody() {
21889     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21890     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21891     proto->Set(v8_str("shouldContinue"), Function::New(
21892         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21893     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21894
21895     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21896   }
21897 };
21898
21899
21900 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21901  public:
21902   virtual void TestBody() {
21903     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21904     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21905     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21906         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21907     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21908
21909     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21910   }
21911 };
21912
21913
21914 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21915  public:
21916   virtual void TestBody() {
21917     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21918     t->InstanceTemplate()->SetNativeDataProperty(
21919         v8_str("shouldContinue"),
21920         &ShouldContinueNativeGetter,
21921         NULL,
21922         v8::External::New(isolate_, this));
21923     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21924
21925     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21926   }
21927
21928  private:
21929   static void ShouldContinueNativeGetter(
21930       Local<String> property,
21931       const v8::PropertyCallbackInfo<v8::Value>& info) {
21932     RequestInterruptTestBase* test =
21933         reinterpret_cast<RequestInterruptTestBase*>(
21934             info.Data().As<v8::External>()->Value());
21935     info.GetReturnValue().Set(test->ShouldContinue());
21936   }
21937 };
21938
21939
21940 class RequestInterruptTestWithMethodCallAndInterceptor
21941     : public RequestInterruptTestBase {
21942  public:
21943   virtual void TestBody() {
21944     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21945     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21946     proto->Set(v8_str("shouldContinue"), Function::New(
21947         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21948     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21949     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21950
21951     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21952
21953     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21954   }
21955
21956  private:
21957   static void EmptyInterceptor(
21958       Local<String> property,
21959       const v8::PropertyCallbackInfo<v8::Value>& info) {
21960   }
21961 };
21962
21963
21964 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21965  public:
21966   virtual void TestBody() {
21967     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21968         isolate_,
21969         WakeUpInterruptorCallback,
21970         v8::External::New(isolate_, this)));
21971
21972     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21973         isolate_,
21974         ShouldContinueCallback,
21975         v8::External::New(isolate_, this)));
21976
21977     i::FLAG_allow_natives_syntax = true;
21978     CompileRun("function loopish(o) {"
21979                "  var pre = 10;"
21980                "  while (o.abs(1) > 0) {"
21981                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21982                "    if (pre > 0) {"
21983                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
21984                "    }"
21985                "  }"
21986                "}"
21987                "var i = 50;"
21988                "var obj = {abs: function () { return i-- }, x: null};"
21989                "delete obj.x;"
21990                "loopish(obj);"
21991                "%OptimizeFunctionOnNextCall(loopish);"
21992                "loopish(Math);");
21993
21994     i::FLAG_allow_natives_syntax = false;
21995   }
21996
21997  private:
21998   static void WakeUpInterruptorCallback(
21999       const v8::FunctionCallbackInfo<Value>& info) {
22000     if (!info[0]->BooleanValue()) return;
22001
22002     RequestInterruptTestBase* test =
22003         reinterpret_cast<RequestInterruptTestBase*>(
22004             info.Data().As<v8::External>()->Value());
22005     test->WakeUpInterruptor();
22006   }
22007
22008   static void ShouldContinueCallback(
22009       const v8::FunctionCallbackInfo<Value>& info) {
22010     RequestInterruptTestBase* test =
22011         reinterpret_cast<RequestInterruptTestBase*>(
22012             info.Data().As<v8::External>()->Value());
22013     info.GetReturnValue().Set(test->should_continue());
22014   }
22015 };
22016
22017
22018 TEST(RequestInterruptTestWithFunctionCall) {
22019   RequestInterruptTestWithFunctionCall().RunTest();
22020 }
22021
22022
22023 TEST(RequestInterruptTestWithMethodCall) {
22024   RequestInterruptTestWithMethodCall().RunTest();
22025 }
22026
22027
22028 TEST(RequestInterruptTestWithAccessor) {
22029   RequestInterruptTestWithAccessor().RunTest();
22030 }
22031
22032
22033 TEST(RequestInterruptTestWithNativeAccessor) {
22034   RequestInterruptTestWithNativeAccessor().RunTest();
22035 }
22036
22037
22038 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22039   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22040 }
22041
22042
22043 TEST(RequestInterruptTestWithMathAbs) {
22044   RequestInterruptTestWithMathAbs().RunTest();
22045 }
22046
22047
22048 static Local<Value> function_new_expected_env;
22049 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22050   CHECK_EQ(function_new_expected_env, info.Data());
22051   info.GetReturnValue().Set(17);
22052 }
22053
22054
22055 THREADED_TEST(FunctionNew) {
22056   LocalContext env;
22057   v8::Isolate* isolate = env->GetIsolate();
22058   v8::HandleScope scope(isolate);
22059   Local<Object> data = v8::Object::New(isolate);
22060   function_new_expected_env = data;
22061   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22062   env->Global()->Set(v8_str("func"), func);
22063   Local<Value> result = CompileRun("func();");
22064   CHECK_EQ(v8::Integer::New(isolate, 17), result);
22065   // Verify function not cached
22066   int serial_number =
22067       i::Smi::cast(v8::Utils::OpenHandle(*func)
22068           ->shared()->get_api_func_data()->serial_number())->value();
22069   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22070   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22071   i::Handle<i::Object> elm =
22072       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22073   CHECK(elm->IsUndefined());
22074   // Verify that each Function::New creates a new function instance
22075   Local<Object> data2 = v8::Object::New(isolate);
22076   function_new_expected_env = data2;
22077   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22078   CHECK(!func2->IsNull());
22079   CHECK_NE(func, func2);
22080   env->Global()->Set(v8_str("func2"), func2);
22081   Local<Value> result2 = CompileRun("func2();");
22082   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22083 }
22084
22085
22086 TEST(EscapeableHandleScope) {
22087   HandleScope outer_scope(CcTest::isolate());
22088   LocalContext context;
22089   const int runs = 10;
22090   Local<String> values[runs];
22091   for (int i = 0; i < runs; i++) {
22092     v8::EscapableHandleScope inner_scope(CcTest::isolate());
22093     Local<String> value;
22094     if (i != 0) value = v8_str("escape value");
22095     values[i] = inner_scope.Escape(value);
22096   }
22097   for (int i = 0; i < runs; i++) {
22098     Local<String> expected;
22099     if (i != 0) {
22100       CHECK_EQ(v8_str("escape value"), values[i]);
22101     } else {
22102       CHECK(values[i].IsEmpty());
22103     }
22104   }
22105 }
22106
22107
22108 static void SetterWhichExpectsThisAndHolderToDiffer(
22109     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22110   CHECK(info.Holder() != info.This());
22111 }
22112
22113
22114 TEST(Regress239669) {
22115   LocalContext context;
22116   v8::Isolate* isolate = context->GetIsolate();
22117   v8::HandleScope scope(isolate);
22118   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22119   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22120   context->Global()->Set(v8_str("P"), templ->NewInstance());
22121   CompileRun(
22122       "function C1() {"
22123       "  this.x = 23;"
22124       "};"
22125       "C1.prototype = P;"
22126       "for (var i = 0; i < 4; i++ ) {"
22127       "  new C1();"
22128       "}");
22129 }
22130
22131
22132 class ApiCallOptimizationChecker {
22133  private:
22134   static Local<Object> data;
22135   static Local<Object> receiver;
22136   static Local<Object> holder;
22137   static Local<Object> callee;
22138   static int count;
22139
22140   static void OptimizationCallback(
22141       const v8::FunctionCallbackInfo<v8::Value>& info) {
22142     CHECK(callee == info.Callee());
22143     CHECK(data == info.Data());
22144     CHECK(receiver == info.This());
22145     if (info.Length() == 1) {
22146       CHECK_EQ(v8_num(1), info[0]);
22147     }
22148     CHECK(holder == info.Holder());
22149     count++;
22150     info.GetReturnValue().Set(v8_str("returned"));
22151   }
22152
22153   public:
22154     enum SignatureType {
22155       kNoSignature,
22156       kSignatureOnReceiver,
22157       kSignatureOnPrototype
22158     };
22159
22160     void RunAll() {
22161       SignatureType signature_types[] =
22162         {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22163       for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22164         SignatureType signature_type = signature_types[i];
22165         for (int j = 0; j < 2; j++) {
22166           bool global = j == 0;
22167           int key = signature_type +
22168               ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22169           Run(signature_type, global, key);
22170         }
22171       }
22172     }
22173
22174     void Run(SignatureType signature_type, bool global, int key) {
22175       v8::Isolate* isolate = CcTest::isolate();
22176       v8::HandleScope scope(isolate);
22177       // Build a template for signature checks.
22178       Local<v8::ObjectTemplate> signature_template;
22179       Local<v8::Signature> signature;
22180       {
22181         Local<v8::FunctionTemplate> parent_template =
22182           FunctionTemplate::New(isolate);
22183         parent_template->SetHiddenPrototype(true);
22184         Local<v8::FunctionTemplate> function_template
22185             = FunctionTemplate::New(isolate);
22186         function_template->Inherit(parent_template);
22187         switch (signature_type) {
22188           case kNoSignature:
22189             break;
22190           case kSignatureOnReceiver:
22191             signature = v8::Signature::New(isolate, function_template);
22192             break;
22193           case kSignatureOnPrototype:
22194             signature = v8::Signature::New(isolate, parent_template);
22195             break;
22196         }
22197         signature_template = function_template->InstanceTemplate();
22198       }
22199       // Global object must pass checks.
22200       Local<v8::Context> context =
22201           v8::Context::New(isolate, NULL, signature_template);
22202       v8::Context::Scope context_scope(context);
22203       // Install regular object that can pass signature checks.
22204       Local<Object> function_receiver = signature_template->NewInstance();
22205       context->Global()->Set(v8_str("function_receiver"), function_receiver);
22206       // Get the holder objects.
22207       Local<Object> inner_global =
22208           Local<Object>::Cast(context->Global()->GetPrototype());
22209       // Install functions on hidden prototype object if there is one.
22210       data = Object::New(isolate);
22211       Local<FunctionTemplate> function_template = FunctionTemplate::New(
22212           isolate, OptimizationCallback, data, signature);
22213       Local<Function> function = function_template->GetFunction();
22214       Local<Object> global_holder = inner_global;
22215       Local<Object> function_holder = function_receiver;
22216       if (signature_type == kSignatureOnPrototype) {
22217         function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22218         global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22219       }
22220       global_holder->Set(v8_str("g_f"), function);
22221       global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22222       function_holder->Set(v8_str("f"), function);
22223       function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22224       // Initialize expected values.
22225       callee = function;
22226       count = 0;
22227       if (global) {
22228         receiver = context->Global();
22229         holder = inner_global;
22230       } else {
22231         holder = function_receiver;
22232         // If not using a signature, add something else to the prototype chain
22233         // to test the case that holder != receiver
22234         if (signature_type == kNoSignature) {
22235           receiver = Local<Object>::Cast(CompileRun(
22236               "var receiver_subclass = {};\n"
22237               "receiver_subclass.__proto__ = function_receiver;\n"
22238               "receiver_subclass"));
22239         } else {
22240           receiver = Local<Object>::Cast(CompileRun(
22241             "var receiver_subclass = function_receiver;\n"
22242             "receiver_subclass"));
22243         }
22244       }
22245       // With no signature, the holder is not set.
22246       if (signature_type == kNoSignature) holder = receiver;
22247       // build wrap_function
22248       i::ScopedVector<char> wrap_function(200);
22249       if (global) {
22250         i::OS::SNPrintF(
22251             wrap_function,
22252             "function wrap_f_%d() { var f = g_f; return f(); }\n"
22253             "function wrap_get_%d() { return this.g_acc; }\n"
22254             "function wrap_set_%d() { return this.g_acc = 1; }\n",
22255             key, key, key);
22256       } else {
22257         i::OS::SNPrintF(
22258             wrap_function,
22259             "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22260             "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22261             "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22262             key, key, key);
22263       }
22264       // build source string
22265       i::ScopedVector<char> source(1000);
22266       i::OS::SNPrintF(
22267           source,
22268           "%s\n"  // wrap functions
22269           "function wrap_f() { return wrap_f_%d(); }\n"
22270           "function wrap_get() { return wrap_get_%d(); }\n"
22271           "function wrap_set() { return wrap_set_%d(); }\n"
22272           "check = function(returned) {\n"
22273           "  if (returned !== 'returned') { throw returned; }\n"
22274           "}\n"
22275           "\n"
22276           "check(wrap_f());\n"
22277           "check(wrap_f());\n"
22278           "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22279           "check(wrap_f());\n"
22280           "\n"
22281           "check(wrap_get());\n"
22282           "check(wrap_get());\n"
22283           "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22284           "check(wrap_get());\n"
22285           "\n"
22286           "check = function(returned) {\n"
22287           "  if (returned !== 1) { throw returned; }\n"
22288           "}\n"
22289           "check(wrap_set());\n"
22290           "check(wrap_set());\n"
22291           "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22292           "check(wrap_set());\n",
22293           wrap_function.start(), key, key, key, key, key, key);
22294       v8::TryCatch try_catch;
22295       CompileRun(source.start());
22296       ASSERT(!try_catch.HasCaught());
22297       CHECK_EQ(9, count);
22298     }
22299 };
22300
22301
22302 Local<Object> ApiCallOptimizationChecker::data;
22303 Local<Object> ApiCallOptimizationChecker::receiver;
22304 Local<Object> ApiCallOptimizationChecker::holder;
22305 Local<Object> ApiCallOptimizationChecker::callee;
22306 int ApiCallOptimizationChecker::count = 0;
22307
22308
22309 TEST(TestFunctionCallOptimization) {
22310   i::FLAG_allow_natives_syntax = true;
22311   ApiCallOptimizationChecker checker;
22312   checker.RunAll();
22313 }
22314
22315
22316 static const char* last_event_message;
22317 static int last_event_status;
22318 void StoringEventLoggerCallback(const char* message, int status) {
22319     last_event_message = message;
22320     last_event_status = status;
22321 }
22322
22323
22324 TEST(EventLogging) {
22325   v8::Isolate* isolate = CcTest::isolate();
22326   isolate->SetEventLogger(StoringEventLoggerCallback);
22327   v8::internal::HistogramTimer* histogramTimer =
22328       new v8::internal::HistogramTimer(
22329           "V8.Test", 0, 10000, 50,
22330           reinterpret_cast<v8::internal::Isolate*>(isolate));
22331   histogramTimer->Start();
22332   CHECK_EQ("V8.Test", last_event_message);
22333   CHECK_EQ(0, last_event_status);
22334   histogramTimer->Stop();
22335   CHECK_EQ("V8.Test", last_event_message);
22336   CHECK_EQ(1, last_event_status);
22337 }
22338
22339
22340 TEST(Promises) {
22341   LocalContext context;
22342   v8::Isolate* isolate = context->GetIsolate();
22343   v8::HandleScope scope(isolate);
22344   Handle<Object> global = context->Global();
22345
22346   // Creation.
22347   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22348   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22349   Handle<v8::Promise> p = pr->GetPromise();
22350   Handle<v8::Promise> r = rr->GetPromise();
22351
22352   // IsPromise predicate.
22353   CHECK(p->IsPromise());
22354   CHECK(r->IsPromise());
22355   Handle<Value> o = v8::Object::New(isolate);
22356   CHECK(!o->IsPromise());
22357
22358   // Resolution and rejection.
22359   pr->Resolve(v8::Integer::New(isolate, 1));
22360   CHECK(p->IsPromise());
22361   rr->Reject(v8::Integer::New(isolate, 2));
22362   CHECK(r->IsPromise());
22363
22364   // Chaining non-pending promises.
22365   CompileRun(
22366       "var x1 = 0;\n"
22367       "var x2 = 0;\n"
22368       "function f1(x) { x1 = x; return x+1 };\n"
22369       "function f2(x) { x2 = x; return x+1 };\n");
22370   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22371   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22372
22373   p->Chain(f1);
22374   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22375   isolate->RunMicrotasks();
22376   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22377
22378   p->Catch(f2);
22379   isolate->RunMicrotasks();
22380   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22381
22382   r->Catch(f2);
22383   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22384   isolate->RunMicrotasks();
22385   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22386
22387   r->Chain(f1);
22388   isolate->RunMicrotasks();
22389   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22390
22391   // Chaining pending promises.
22392   CompileRun("x1 = x2 = 0;");
22393   pr = v8::Promise::Resolver::New(isolate);
22394   rr = v8::Promise::Resolver::New(isolate);
22395
22396   pr->GetPromise()->Chain(f1);
22397   rr->GetPromise()->Catch(f2);
22398   isolate->RunMicrotasks();
22399   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22400   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22401
22402   pr->Resolve(v8::Integer::New(isolate, 1));
22403   rr->Reject(v8::Integer::New(isolate, 2));
22404   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22405   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22406
22407   isolate->RunMicrotasks();
22408   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22409   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22410
22411   // Multi-chaining.
22412   CompileRun("x1 = x2 = 0;");
22413   pr = v8::Promise::Resolver::New(isolate);
22414   pr->GetPromise()->Chain(f1)->Chain(f2);
22415   pr->Resolve(v8::Integer::New(isolate, 3));
22416   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22417   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22418   isolate->RunMicrotasks();
22419   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22420   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22421
22422   CompileRun("x1 = x2 = 0;");
22423   rr = v8::Promise::Resolver::New(isolate);
22424   rr->GetPromise()->Catch(f1)->Chain(f2);
22425   rr->Reject(v8::Integer::New(isolate, 3));
22426   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22427   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22428   isolate->RunMicrotasks();
22429   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22430   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22431 }
22432
22433
22434 TEST(DisallowJavascriptExecutionScope) {
22435   LocalContext context;
22436   v8::Isolate* isolate = context->GetIsolate();
22437   v8::HandleScope scope(isolate);
22438   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22439       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22440   CompileRun("2+2");
22441 }
22442
22443
22444 TEST(AllowJavascriptExecutionScope) {
22445   LocalContext context;
22446   v8::Isolate* isolate = context->GetIsolate();
22447   v8::HandleScope scope(isolate);
22448   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22449       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22450   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22451       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22452   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22453     CompileRun("1+1");
22454   }
22455 }
22456
22457
22458 TEST(ThrowOnJavascriptExecution) {
22459   LocalContext context;
22460   v8::Isolate* isolate = context->GetIsolate();
22461   v8::HandleScope scope(isolate);
22462   v8::TryCatch try_catch;
22463   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22464       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22465   CompileRun("1+1");
22466   CHECK(try_catch.HasCaught());
22467 }
22468
22469
22470 TEST(Regress354123) {
22471   LocalContext current;
22472   v8::Isolate* isolate = current->GetIsolate();
22473   v8::HandleScope scope(isolate);
22474
22475   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22476   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22477   current->Global()->Set(v8_str("friend"), templ->NewInstance());
22478
22479   // Test access using __proto__ from the prototype chain.
22480   named_access_count = 0;
22481   CompileRun("friend.__proto__ = {};");
22482   CHECK_EQ(2, named_access_count);
22483   CompileRun("friend.__proto__;");
22484   CHECK_EQ(4, named_access_count);
22485
22486   // Test access using __proto__ as a hijacked function (A).
22487   named_access_count = 0;
22488   CompileRun("var p = Object.prototype;"
22489              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22490              "f.call(friend, {});");
22491   CHECK_EQ(1, named_access_count);
22492   CompileRun("var p = Object.prototype;"
22493              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22494              "f.call(friend);");
22495   CHECK_EQ(2, named_access_count);
22496
22497   // Test access using __proto__ as a hijacked function (B).
22498   named_access_count = 0;
22499   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22500              "f.call(friend, {});");
22501   CHECK_EQ(1, named_access_count);
22502   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22503              "f.call(friend);");
22504   CHECK_EQ(2, named_access_count);
22505
22506   // Test access using Object.setPrototypeOf reflective method.
22507   named_access_count = 0;
22508   CompileRun("Object.setPrototypeOf(friend, {});");
22509   CHECK_EQ(1, named_access_count);
22510   CompileRun("Object.getPrototypeOf(friend);");
22511   CHECK_EQ(2, named_access_count);
22512 }
22513
22514
22515 TEST(CaptureStackTraceForStackOverflow) {
22516   v8::internal::FLAG_stack_size = 150;
22517   LocalContext current;
22518   v8::Isolate* isolate = current->GetIsolate();
22519   v8::HandleScope scope(isolate);
22520   V8::SetCaptureStackTraceForUncaughtExceptions(
22521       true, 10, v8::StackTrace::kDetailed);
22522   v8::TryCatch try_catch;
22523   CompileRun("(function f(x) { f(x+1); })(0)");
22524   CHECK(try_catch.HasCaught());
22525 }