deps: update v8 to 3.29.93.1
[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 <map>
31 #include <string>
32
33 #include "src/v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "include/v8-util.h"
40 #include "src/api.h"
41 #include "src/arguments.h"
42 #include "src/base/platform/platform.h"
43 #include "src/compilation-cache.h"
44 #include "src/cpu-profiler.h"
45 #include "src/execution.h"
46 #include "src/isolate.h"
47 #include "src/objects.h"
48 #include "src/parser.h"
49 #include "src/snapshot.h"
50 #include "src/unicode-inl.h"
51 #include "src/utils.h"
52 #include "src/vm-state.h"
53 #include "test/cctest/cctest.h"
54
55 static const bool kLogThreading = false;
56
57 using ::v8::Boolean;
58 using ::v8::BooleanObject;
59 using ::v8::Context;
60 using ::v8::Extension;
61 using ::v8::Function;
62 using ::v8::FunctionTemplate;
63 using ::v8::Handle;
64 using ::v8::HandleScope;
65 using ::v8::Local;
66 using ::v8::Name;
67 using ::v8::Message;
68 using ::v8::MessageCallback;
69 using ::v8::Object;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::Script;
73 using ::v8::StackTrace;
74 using ::v8::String;
75 using ::v8::Symbol;
76 using ::v8::TryCatch;
77 using ::v8::Undefined;
78 using ::v8::UniqueId;
79 using ::v8::V8;
80 using ::v8::Value;
81
82
83 #define THREADED_PROFILED_TEST(Name)                                 \
84   static void Test##Name();                                          \
85   TEST(Name##WithProfiler) {                                         \
86     RunWithProfiler(&Test##Name);                                    \
87   }                                                                  \
88   THREADED_TEST(Name)
89
90
91 void RunWithProfiler(void (*test)()) {
92   LocalContext env;
93   v8::HandleScope scope(env->GetIsolate());
94   v8::Local<v8::String> profile_name =
95       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
97
98   cpu_profiler->StartProfiling(profile_name);
99   (*test)();
100   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
101 }
102
103
104 static int signature_callback_count;
105 static Local<Value> signature_expected_receiver;
106 static void IncrementingSignatureCallback(
107     const v8::FunctionCallbackInfo<v8::Value>& args) {
108   ApiTestFuzzer::Fuzz();
109   signature_callback_count++;
110   CHECK_EQ(signature_expected_receiver, args.Holder());
111   CHECK_EQ(signature_expected_receiver, args.This());
112   v8::Handle<v8::Array> result =
113       v8::Array::New(args.GetIsolate(), args.Length());
114   for (int i = 0; i < args.Length(); i++)
115     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116   args.GetReturnValue().Set(result);
117 }
118
119
120 static void SignatureCallback(
121     const v8::FunctionCallbackInfo<v8::Value>& args) {
122   ApiTestFuzzer::Fuzz();
123   v8::Handle<v8::Array> result =
124       v8::Array::New(args.GetIsolate(), args.Length());
125   for (int i = 0; i < args.Length(); i++) {
126     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
127   }
128   args.GetReturnValue().Set(result);
129 }
130
131
132 // Tests that call v8::V8::Dispose() cannot be threaded.
133 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
134   CHECK(v8::V8::Initialize());
135   CHECK(v8::V8::Dispose());
136 }
137
138
139 // Tests that call v8::V8::Dispose() cannot be threaded.
140 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
143   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
145   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
146 }
147
148
149 THREADED_TEST(Handles) {
150   v8::HandleScope scope(CcTest::isolate());
151   Local<Context> local_env;
152   {
153     LocalContext env;
154     local_env = env.local();
155   }
156
157   // Local context should still be live.
158   CHECK(!local_env.IsEmpty());
159   local_env->Enter();
160
161   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
162   CHECK(!undef.IsEmpty());
163   CHECK(undef->IsUndefined());
164
165   const char* source = "1 + 2 + 3";
166   Local<Script> script = v8_compile(source);
167   CHECK_EQ(6, script->Run()->Int32Value());
168
169   local_env->Exit();
170 }
171
172
173 THREADED_TEST(IsolateOfContext) {
174   v8::HandleScope scope(CcTest::isolate());
175   v8::Handle<Context> env = Context::New(CcTest::isolate());
176
177   CHECK(!env->GetIsolate()->InContext());
178   CHECK(env->GetIsolate() == CcTest::isolate());
179   env->Enter();
180   CHECK(env->GetIsolate()->InContext());
181   CHECK(env->GetIsolate() == CcTest::isolate());
182   env->Exit();
183   CHECK(!env->GetIsolate()->InContext());
184   CHECK(env->GetIsolate() == CcTest::isolate());
185 }
186
187
188 static void TestSignature(const char* loop_js, Local<Value> receiver) {
189   i::ScopedVector<char> source(200);
190   i::SNPrintF(source,
191               "for (var i = 0; i < 10; i++) {"
192               "  %s"
193               "}",
194               loop_js);
195   signature_callback_count = 0;
196   signature_expected_receiver = receiver;
197   bool expected_to_throw = receiver.IsEmpty();
198   v8::TryCatch try_catch;
199   CompileRun(source.start());
200   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
201   if (!expected_to_throw) {
202     CHECK_EQ(10, signature_callback_count);
203   } else {
204     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
205              try_catch.Exception()->ToString());
206   }
207 }
208
209
210 THREADED_TEST(ReceiverSignature) {
211   LocalContext env;
212   v8::Isolate* isolate = env->GetIsolate();
213   v8::HandleScope scope(isolate);
214   // Setup templates.
215   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
216   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
217   v8::Handle<v8::FunctionTemplate> callback_sig =
218       v8::FunctionTemplate::New(
219           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
220   v8::Handle<v8::FunctionTemplate> callback =
221       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
222   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
223   sub_fun->Inherit(fun);
224   v8::Handle<v8::FunctionTemplate> unrel_fun =
225       v8::FunctionTemplate::New(isolate);
226   // Install properties.
227   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
228   fun_proto->Set(v8_str("prop_sig"), callback_sig);
229   fun_proto->Set(v8_str("prop"), callback);
230   fun_proto->SetAccessorProperty(
231       v8_str("accessor_sig"), callback_sig, callback_sig);
232   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
233   // Instantiate templates.
234   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
235   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
236   // Setup global variables.
237   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
238   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
239   env->Global()->Set(v8_str("fun_instance"), fun_instance);
240   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
241   CompileRun(
242       "var accessor_sig_key = 'accessor_sig';"
243       "var accessor_key = 'accessor';"
244       "var prop_sig_key = 'prop_sig';"
245       "var prop_key = 'prop';"
246       ""
247       "function copy_props(obj) {"
248       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
249       "  var source = Fun.prototype;"
250       "  for (var i in keys) {"
251       "    var key = keys[i];"
252       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
253       "    Object.defineProperty(obj, key, desc);"
254       "  }"
255       "}"
256       ""
257       "var obj = {};"
258       "copy_props(obj);"
259       "var unrel = new UnrelFun();"
260       "copy_props(unrel);");
261   // Test with and without ICs
262   const char* test_objects[] = {
263       "fun_instance", "sub_fun_instance", "obj", "unrel" };
264   unsigned bad_signature_start_offset = 2;
265   for (unsigned i = 0; i < arraysize(test_objects); i++) {
266     i::ScopedVector<char> source(200);
267     i::SNPrintF(
268         source, "var test_object = %s; test_object", test_objects[i]);
269     Local<Value> test_object = CompileRun(source.start());
270     TestSignature("test_object.prop();", test_object);
271     TestSignature("test_object.accessor;", test_object);
272     TestSignature("test_object[accessor_key];", test_object);
273     TestSignature("test_object.accessor = 1;", test_object);
274     TestSignature("test_object[accessor_key] = 1;", test_object);
275     if (i >= bad_signature_start_offset) test_object = Local<Value>();
276     TestSignature("test_object.prop_sig();", test_object);
277     TestSignature("test_object.accessor_sig;", test_object);
278     TestSignature("test_object[accessor_sig_key];", test_object);
279     TestSignature("test_object.accessor_sig = 1;", test_object);
280     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
281   }
282 }
283
284
285 THREADED_TEST(ArgumentSignature) {
286   LocalContext env;
287   v8::Isolate* isolate = env->GetIsolate();
288   v8::HandleScope scope(isolate);
289   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
290   cons->SetClassName(v8_str("Cons"));
291   v8::Handle<v8::Signature> sig = v8::Signature::New(
292       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
293   v8::Handle<v8::FunctionTemplate> fun =
294       v8::FunctionTemplate::New(isolate,
295                                 SignatureCallback,
296                                 v8::Handle<Value>(),
297                                 sig);
298   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
299   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
300
301   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
302   CHECK(value1->IsTrue());
303
304   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
305   CHECK(value2->IsTrue());
306
307   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
308   CHECK(value3->IsTrue());
309
310   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
311   cons1->SetClassName(v8_str("Cons1"));
312   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
313   cons2->SetClassName(v8_str("Cons2"));
314   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
315   cons3->SetClassName(v8_str("Cons3"));
316
317   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
318   v8::Handle<v8::Signature> wsig = v8::Signature::New(
319       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
320   v8::Handle<v8::FunctionTemplate> fun2 =
321       v8::FunctionTemplate::New(isolate,
322                                 SignatureCallback,
323                                 v8::Handle<Value>(),
324                                 wsig);
325
326   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
327   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
328   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
329   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
330   v8::Handle<Value> value4 = CompileRun(
331       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
332       "'[object Cons1],[object Cons2],[object Cons3]'");
333   CHECK(value4->IsTrue());
334
335   v8::Handle<Value> value5 = CompileRun(
336       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
337   CHECK(value5->IsTrue());
338
339   v8::Handle<Value> value6 = CompileRun(
340       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
341   CHECK(value6->IsTrue());
342
343   v8::Handle<Value> value7 = CompileRun(
344       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
345       "'[object Cons1],[object Cons2],[object Cons3],d';");
346   CHECK(value7->IsTrue());
347
348   v8::Handle<Value> value8 = CompileRun(
349       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
350   CHECK(value8->IsTrue());
351 }
352
353
354 THREADED_TEST(HulIgennem) {
355   LocalContext env;
356   v8::Isolate* isolate = env->GetIsolate();
357   v8::HandleScope scope(isolate);
358   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
359   Local<String> undef_str = undef->ToString();
360   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
361   undef_str->WriteUtf8(value);
362   CHECK_EQ(0, strcmp(value, "undefined"));
363   i::DeleteArray(value);
364 }
365
366
367 THREADED_TEST(Access) {
368   LocalContext env;
369   v8::Isolate* isolate = env->GetIsolate();
370   v8::HandleScope scope(isolate);
371   Local<v8::Object> obj = v8::Object::New(isolate);
372   Local<Value> foo_before = obj->Get(v8_str("foo"));
373   CHECK(foo_before->IsUndefined());
374   Local<String> bar_str = v8_str("bar");
375   obj->Set(v8_str("foo"), bar_str);
376   Local<Value> foo_after = obj->Get(v8_str("foo"));
377   CHECK(!foo_after->IsUndefined());
378   CHECK(foo_after->IsString());
379   CHECK_EQ(bar_str, foo_after);
380 }
381
382
383 THREADED_TEST(AccessElement) {
384   LocalContext env;
385   v8::HandleScope scope(env->GetIsolate());
386   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
387   Local<Value> before = obj->Get(1);
388   CHECK(before->IsUndefined());
389   Local<String> bar_str = v8_str("bar");
390   obj->Set(1, bar_str);
391   Local<Value> after = obj->Get(1);
392   CHECK(!after->IsUndefined());
393   CHECK(after->IsString());
394   CHECK_EQ(bar_str, after);
395
396   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
397   CHECK_EQ(v8_str("a"), value->Get(0));
398   CHECK_EQ(v8_str("b"), value->Get(1));
399 }
400
401
402 THREADED_TEST(Script) {
403   LocalContext env;
404   v8::HandleScope scope(env->GetIsolate());
405   const char* source = "1 + 2 + 3";
406   Local<Script> script = v8_compile(source);
407   CHECK_EQ(6, script->Run()->Int32Value());
408 }
409
410
411 class TestResource: public String::ExternalStringResource {
412  public:
413   explicit TestResource(uint16_t* data, int* counter = NULL,
414                         bool owning_data = true)
415       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
416     while (data[length_]) ++length_;
417   }
418
419   ~TestResource() {
420     if (owning_data_) i::DeleteArray(data_);
421     if (counter_ != NULL) ++*counter_;
422   }
423
424   const uint16_t* data() const {
425     return data_;
426   }
427
428   size_t length() const {
429     return length_;
430   }
431
432  private:
433   uint16_t* data_;
434   size_t length_;
435   int* counter_;
436   bool owning_data_;
437 };
438
439
440 class TestOneByteResource : public String::ExternalOneByteStringResource {
441  public:
442   explicit TestOneByteResource(const char* data, int* counter = NULL,
443                                size_t offset = 0)
444       : orig_data_(data),
445         data_(data + offset),
446         length_(strlen(data) - offset),
447         counter_(counter) {}
448
449   ~TestOneByteResource() {
450     i::DeleteArray(orig_data_);
451     if (counter_ != NULL) ++*counter_;
452   }
453
454   const char* data() const {
455     return data_;
456   }
457
458   size_t length() const {
459     return length_;
460   }
461
462  private:
463   const char* orig_data_;
464   const char* data_;
465   size_t length_;
466   int* counter_;
467 };
468
469
470 THREADED_TEST(ScriptUsingStringResource) {
471   int dispose_count = 0;
472   const char* c_source = "1 + 2 * 3";
473   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
474   {
475     LocalContext env;
476     v8::HandleScope scope(env->GetIsolate());
477     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
478     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
479     Local<Script> script = v8_compile(source);
480     Local<Value> value = script->Run();
481     CHECK(value->IsNumber());
482     CHECK_EQ(7, value->Int32Value());
483     CHECK(source->IsExternal());
484     CHECK_EQ(resource,
485              static_cast<TestResource*>(source->GetExternalStringResource()));
486     String::Encoding encoding = String::UNKNOWN_ENCODING;
487     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
488              source->GetExternalStringResourceBase(&encoding));
489     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
490     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
491     CHECK_EQ(0, dispose_count);
492   }
493   CcTest::i_isolate()->compilation_cache()->Clear();
494   CcTest::heap()->CollectAllAvailableGarbage();
495   CHECK_EQ(1, dispose_count);
496 }
497
498
499 THREADED_TEST(ScriptUsingOneByteStringResource) {
500   int dispose_count = 0;
501   const char* c_source = "1 + 2 * 3";
502   {
503     LocalContext env;
504     v8::HandleScope scope(env->GetIsolate());
505     TestOneByteResource* resource =
506         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
507     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
508     CHECK(source->IsExternalOneByte());
509     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510              source->GetExternalOneByteStringResource());
511     String::Encoding encoding = String::UNKNOWN_ENCODING;
512     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
513              source->GetExternalStringResourceBase(&encoding));
514     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
515     Local<Script> script = v8_compile(source);
516     Local<Value> value = script->Run();
517     CHECK(value->IsNumber());
518     CHECK_EQ(7, value->Int32Value());
519     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
520     CHECK_EQ(0, dispose_count);
521   }
522   CcTest::i_isolate()->compilation_cache()->Clear();
523   CcTest::heap()->CollectAllAvailableGarbage();
524   CHECK_EQ(1, dispose_count);
525 }
526
527
528 THREADED_TEST(ScriptMakingExternalString) {
529   int dispose_count = 0;
530   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
531   {
532     LocalContext env;
533     v8::HandleScope scope(env->GetIsolate());
534     Local<String> source =
535         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
536     // Trigger GCs so that the newly allocated string moves to old gen.
537     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
538     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
539     CHECK_EQ(source->IsExternal(), false);
540     CHECK_EQ(source->IsExternalOneByte(), false);
541     String::Encoding encoding = String::UNKNOWN_ENCODING;
542     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
543     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
544     bool success = source->MakeExternal(new TestResource(two_byte_source,
545                                                          &dispose_count));
546     CHECK(success);
547     Local<Script> script = v8_compile(source);
548     Local<Value> value = script->Run();
549     CHECK(value->IsNumber());
550     CHECK_EQ(7, value->Int32Value());
551     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
552     CHECK_EQ(0, dispose_count);
553   }
554   CcTest::i_isolate()->compilation_cache()->Clear();
555   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
556   CHECK_EQ(1, dispose_count);
557 }
558
559
560 THREADED_TEST(ScriptMakingExternalOneByteString) {
561   int dispose_count = 0;
562   const char* c_source = "1 + 2 * 3";
563   {
564     LocalContext env;
565     v8::HandleScope scope(env->GetIsolate());
566     Local<String> source = v8_str(c_source);
567     // Trigger GCs so that the newly allocated string moves to old gen.
568     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
569     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
570     bool success = source->MakeExternal(
571         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
572     CHECK(success);
573     Local<Script> script = v8_compile(source);
574     Local<Value> value = script->Run();
575     CHECK(value->IsNumber());
576     CHECK_EQ(7, value->Int32Value());
577     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
578     CHECK_EQ(0, dispose_count);
579   }
580   CcTest::i_isolate()->compilation_cache()->Clear();
581   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
582   CHECK_EQ(1, dispose_count);
583 }
584
585
586 TEST(MakingExternalStringConditions) {
587   LocalContext env;
588   v8::HandleScope scope(env->GetIsolate());
589
590   // Free some space in the new space so that we can check freshness.
591   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593
594   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
595   Local<String> small_string =
596       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
597   i::DeleteArray(two_byte_string);
598
599   // We should refuse to externalize newly created small string.
600   CHECK(!small_string->CanMakeExternal());
601   // Trigger GCs so that the newly allocated string moves to old gen.
602   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
603   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
604   // Old space strings should be accepted.
605   CHECK(small_string->CanMakeExternal());
606
607   two_byte_string = AsciiToTwoByteString("small string 2");
608   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
609   i::DeleteArray(two_byte_string);
610
611   // We should refuse externalizing newly created small string.
612   CHECK(!small_string->CanMakeExternal());
613   for (int i = 0; i < 100; i++) {
614     String::Value value(small_string);
615   }
616   // Frequently used strings should be accepted.
617   CHECK(small_string->CanMakeExternal());
618
619   const int buf_size = 10 * 1024;
620   char* buf = i::NewArray<char>(buf_size);
621   memset(buf, 'a', buf_size);
622   buf[buf_size - 1] = '\0';
623
624   two_byte_string = AsciiToTwoByteString(buf);
625   Local<String> large_string =
626       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
627   i::DeleteArray(buf);
628   i::DeleteArray(two_byte_string);
629   // Large strings should be immediately accepted.
630   CHECK(large_string->CanMakeExternal());
631 }
632
633
634 TEST(MakingExternalOneByteStringConditions) {
635   LocalContext env;
636   v8::HandleScope scope(env->GetIsolate());
637
638   // Free some space in the new space so that we can check freshness.
639   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641
642   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
643   // We should refuse to externalize newly created small string.
644   CHECK(!small_string->CanMakeExternal());
645   // Trigger GCs so that the newly allocated string moves to old gen.
646   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
647   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
648   // Old space strings should be accepted.
649   CHECK(small_string->CanMakeExternal());
650
651   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
652   // We should refuse externalizing newly created small string.
653   CHECK(!small_string->CanMakeExternal());
654   for (int i = 0; i < 100; i++) {
655     String::Value value(small_string);
656   }
657   // Frequently used strings should be accepted.
658   CHECK(small_string->CanMakeExternal());
659
660   const int buf_size = 10 * 1024;
661   char* buf = i::NewArray<char>(buf_size);
662   memset(buf, 'a', buf_size);
663   buf[buf_size - 1] = '\0';
664   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
665   i::DeleteArray(buf);
666   // Large strings should be immediately accepted.
667   CHECK(large_string->CanMakeExternal());
668 }
669
670
671 TEST(MakingExternalUnalignedOneByteString) {
672   LocalContext env;
673   v8::HandleScope scope(env->GetIsolate());
674
675   CompileRun("function cons(a, b) { return a + b; }"
676              "function slice(a) { return a.substring(1); }");
677   // Create a cons string that will land in old pointer space.
678   Local<String> cons = Local<String>::Cast(CompileRun(
679       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
680   // Create a sliced string that will land in old pointer space.
681   Local<String> slice = Local<String>::Cast(CompileRun(
682       "slice('abcdefghijklmnopqrstuvwxyz');"));
683
684   // Trigger GCs so that the newly allocated string moves to old gen.
685   SimulateFullSpace(CcTest::heap()->old_pointer_space());
686   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
687   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
688
689   // Turn into external string with unaligned resource data.
690   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
691   bool success =
692       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
693   CHECK(success);
694   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
695   success =
696       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
697   CHECK(success);
698
699   // Trigger GCs and force evacuation.
700   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
701   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
702 }
703
704
705 THREADED_TEST(UsingExternalString) {
706   i::Factory* factory = CcTest::i_isolate()->factory();
707   {
708     v8::HandleScope scope(CcTest::isolate());
709     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
710     Local<String> string = String::NewExternal(
711         CcTest::isolate(), new TestResource(two_byte_string));
712     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713     // Trigger GCs so that the newly allocated string moves to old gen.
714     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
715     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
716     i::Handle<i::String> isymbol =
717         factory->InternalizeString(istring);
718     CHECK(isymbol->IsInternalizedString());
719   }
720   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722 }
723
724
725 THREADED_TEST(UsingExternalOneByteString) {
726   i::Factory* factory = CcTest::i_isolate()->factory();
727   {
728     v8::HandleScope scope(CcTest::isolate());
729     const char* one_byte_string = "test string";
730     Local<String> string = String::NewExternal(
731         CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
732     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
733     // Trigger GCs so that the newly allocated string moves to old gen.
734     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
735     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
736     i::Handle<i::String> isymbol =
737         factory->InternalizeString(istring);
738     CHECK(isymbol->IsInternalizedString());
739   }
740   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
741   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742 }
743
744
745 class DummyResource : public v8::String::ExternalStringResource {
746  public:
747   virtual const uint16_t* data() const { return string_; }
748   virtual size_t length() const { return 1 << 30; }
749
750  private:
751   uint16_t string_[10];
752 };
753
754
755 class DummyOneByteResource : public v8::String::ExternalOneByteStringResource {
756  public:
757   virtual const char* data() const { return string_; }
758   virtual size_t length() const { return 1 << 30; }
759
760  private:
761   char string_[10];
762 };
763
764
765 THREADED_TEST(NewExternalForVeryLongString) {
766   {
767     LocalContext env;
768     v8::HandleScope scope(env->GetIsolate());
769     v8::TryCatch try_catch;
770     DummyOneByteResource r;
771     v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
772     CHECK(str.IsEmpty());
773     CHECK(try_catch.HasCaught());
774     String::Utf8Value exception_value(try_catch.Exception());
775     CHECK_EQ("RangeError: Invalid string length", *exception_value);
776   }
777
778   {
779     LocalContext env;
780     v8::HandleScope scope(env->GetIsolate());
781     v8::TryCatch try_catch;
782     DummyResource r;
783     v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
784     CHECK(str.IsEmpty());
785     CHECK(try_catch.HasCaught());
786     String::Utf8Value exception_value(try_catch.Exception());
787     CHECK_EQ("RangeError: Invalid string length", *exception_value);
788   }
789 }
790
791
792 THREADED_TEST(ScavengeExternalString) {
793   i::FLAG_stress_compaction = false;
794   i::FLAG_gc_global = false;
795   int dispose_count = 0;
796   bool in_new_space = false;
797   {
798     v8::HandleScope scope(CcTest::isolate());
799     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
800     Local<String> string = String::NewExternal(
801         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
802     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
803     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
804     in_new_space = CcTest::heap()->InNewSpace(*istring);
805     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
806     CHECK_EQ(0, dispose_count);
807   }
808   CcTest::heap()->CollectGarbage(
809       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
810   CHECK_EQ(1, dispose_count);
811 }
812
813
814 THREADED_TEST(ScavengeExternalOneByteString) {
815   i::FLAG_stress_compaction = false;
816   i::FLAG_gc_global = false;
817   int dispose_count = 0;
818   bool in_new_space = false;
819   {
820     v8::HandleScope scope(CcTest::isolate());
821     const char* one_byte_string = "test string";
822     Local<String> string = String::NewExternal(
823         CcTest::isolate(),
824         new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
825     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
826     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
827     in_new_space = CcTest::heap()->InNewSpace(*istring);
828     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
829     CHECK_EQ(0, dispose_count);
830   }
831   CcTest::heap()->CollectGarbage(
832       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
833   CHECK_EQ(1, dispose_count);
834 }
835
836
837 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
838  public:
839   // Only used by non-threaded tests, so it can use static fields.
840   static int dispose_calls;
841   static int dispose_count;
842
843   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
844       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
845
846   void Dispose() {
847     ++dispose_calls;
848     if (dispose_) delete this;
849   }
850  private:
851   bool dispose_;
852 };
853
854
855 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
856 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
857
858
859 TEST(ExternalStringWithDisposeHandling) {
860   const char* c_source = "1 + 2 * 3";
861
862   // Use a stack allocated external string resource allocated object.
863   TestOneByteResourceWithDisposeControl::dispose_count = 0;
864   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
865   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
866   {
867     LocalContext env;
868     v8::HandleScope scope(env->GetIsolate());
869     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
870     Local<Script> script = v8_compile(source);
871     Local<Value> value = script->Run();
872     CHECK(value->IsNumber());
873     CHECK_EQ(7, value->Int32Value());
874     CcTest::heap()->CollectAllAvailableGarbage();
875     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
876   }
877   CcTest::i_isolate()->compilation_cache()->Clear();
878   CcTest::heap()->CollectAllAvailableGarbage();
879   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
880   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
881
882   // Use a heap allocated external string resource allocated object.
883   TestOneByteResourceWithDisposeControl::dispose_count = 0;
884   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
885   TestOneByteResource* res_heap =
886       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
887   {
888     LocalContext env;
889     v8::HandleScope scope(env->GetIsolate());
890     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
891     Local<Script> script = v8_compile(source);
892     Local<Value> value = script->Run();
893     CHECK(value->IsNumber());
894     CHECK_EQ(7, value->Int32Value());
895     CcTest::heap()->CollectAllAvailableGarbage();
896     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
897   }
898   CcTest::i_isolate()->compilation_cache()->Clear();
899   CcTest::heap()->CollectAllAvailableGarbage();
900   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
901   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
902 }
903
904
905 THREADED_TEST(StringConcat) {
906   {
907     LocalContext env;
908     v8::HandleScope scope(env->GetIsolate());
909     const char* one_byte_string_1 = "function a_times_t";
910     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
911     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
912     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
913     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
914     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
915     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
916     Local<String> left = v8_str(one_byte_string_1);
917
918     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
919     Local<String> right =
920         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
921     i::DeleteArray(two_byte_source);
922
923     Local<String> source = String::Concat(left, right);
924     right = String::NewExternal(
925         env->GetIsolate(),
926         new TestOneByteResource(i::StrDup(one_byte_extern_1)));
927     source = String::Concat(source, right);
928     right = String::NewExternal(
929         env->GetIsolate(),
930         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
931     source = String::Concat(source, right);
932     right = v8_str(one_byte_string_2);
933     source = String::Concat(source, right);
934
935     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
936     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
937     i::DeleteArray(two_byte_source);
938
939     source = String::Concat(source, right);
940     right = String::NewExternal(
941         env->GetIsolate(),
942         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
943     source = String::Concat(source, right);
944     Local<Script> script = v8_compile(source);
945     Local<Value> value = script->Run();
946     CHECK(value->IsNumber());
947     CHECK_EQ(68, value->Int32Value());
948   }
949   CcTest::i_isolate()->compilation_cache()->Clear();
950   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
951   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
952 }
953
954
955 THREADED_TEST(GlobalProperties) {
956   LocalContext env;
957   v8::HandleScope scope(env->GetIsolate());
958   v8::Handle<v8::Object> global = env->Global();
959   global->Set(v8_str("pi"), v8_num(3.1415926));
960   Local<Value> pi = global->Get(v8_str("pi"));
961   CHECK_EQ(3.1415926, pi->NumberValue());
962 }
963
964
965 template<typename T>
966 static void CheckReturnValue(const T& t, i::Address callback) {
967   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
968   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
969   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
970   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
971   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
972   // Verify reset
973   bool is_runtime = (*o)->IsTheHole();
974   rv.Set(true);
975   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
976   rv.Set(v8::Handle<v8::Object>());
977   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
978   CHECK_EQ(is_runtime, (*o)->IsTheHole());
979
980   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
981   // If CPU profiler is active check that when API callback is invoked
982   // VMState is set to EXTERNAL.
983   if (isolate->cpu_profiler()->is_profiling()) {
984     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
985     CHECK(isolate->external_callback_scope());
986     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
987   }
988 }
989
990
991 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
992                                  i::Address callback) {
993   ApiTestFuzzer::Fuzz();
994   CheckReturnValue(info, callback);
995   info.GetReturnValue().Set(v8_str("bad value"));
996   info.GetReturnValue().Set(v8_num(102));
997 }
998
999
1000 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1001   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1002 }
1003
1004
1005 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1006   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1007 }
1008
1009 static void construct_callback(
1010     const v8::FunctionCallbackInfo<Value>& info) {
1011   ApiTestFuzzer::Fuzz();
1012   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1013   info.This()->Set(v8_str("x"), v8_num(1));
1014   info.This()->Set(v8_str("y"), v8_num(2));
1015   info.GetReturnValue().Set(v8_str("bad value"));
1016   info.GetReturnValue().Set(info.This());
1017 }
1018
1019
1020 static void Return239Callback(
1021     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1022   ApiTestFuzzer::Fuzz();
1023   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1024   info.GetReturnValue().Set(v8_str("bad value"));
1025   info.GetReturnValue().Set(v8_num(239));
1026 }
1027
1028
1029 template<typename Handler>
1030 static void TestFunctionTemplateInitializer(Handler handler,
1031                                             Handler handler_2) {
1032   // Test constructor calls.
1033   {
1034     LocalContext env;
1035     v8::Isolate* isolate = env->GetIsolate();
1036     v8::HandleScope scope(isolate);
1037
1038     Local<v8::FunctionTemplate> fun_templ =
1039         v8::FunctionTemplate::New(isolate, handler);
1040     Local<Function> fun = fun_templ->GetFunction();
1041     env->Global()->Set(v8_str("obj"), fun);
1042     Local<Script> script = v8_compile("obj()");
1043     for (int i = 0; i < 30; i++) {
1044       CHECK_EQ(102, script->Run()->Int32Value());
1045     }
1046   }
1047   // Use SetCallHandler to initialize a function template, should work like
1048   // the previous one.
1049   {
1050     LocalContext env;
1051     v8::Isolate* isolate = env->GetIsolate();
1052     v8::HandleScope scope(isolate);
1053
1054     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1055     fun_templ->SetCallHandler(handler_2);
1056     Local<Function> fun = fun_templ->GetFunction();
1057     env->Global()->Set(v8_str("obj"), fun);
1058     Local<Script> script = v8_compile("obj()");
1059     for (int i = 0; i < 30; i++) {
1060       CHECK_EQ(102, script->Run()->Int32Value());
1061     }
1062   }
1063 }
1064
1065
1066 template<typename Constructor, typename Accessor>
1067 static void TestFunctionTemplateAccessor(Constructor constructor,
1068                                          Accessor accessor) {
1069   LocalContext env;
1070   v8::HandleScope scope(env->GetIsolate());
1071
1072   Local<v8::FunctionTemplate> fun_templ =
1073       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1074   fun_templ->SetClassName(v8_str("funky"));
1075   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1076   Local<Function> fun = fun_templ->GetFunction();
1077   env->Global()->Set(v8_str("obj"), fun);
1078   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1079   CHECK_EQ(v8_str("[object funky]"), result);
1080   CompileRun("var obj_instance = new obj();");
1081   Local<Script> script;
1082   script = v8_compile("obj_instance.x");
1083   for (int i = 0; i < 30; i++) {
1084     CHECK_EQ(1, script->Run()->Int32Value());
1085   }
1086   script = v8_compile("obj_instance.m");
1087   for (int i = 0; i < 30; i++) {
1088     CHECK_EQ(239, script->Run()->Int32Value());
1089   }
1090 }
1091
1092
1093 THREADED_PROFILED_TEST(FunctionTemplate) {
1094   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1095   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1096 }
1097
1098
1099 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1100   ApiTestFuzzer::Fuzz();
1101   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1102   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1103 }
1104
1105
1106 template<typename Callback>
1107 static void TestSimpleCallback(Callback callback) {
1108   LocalContext env;
1109   v8::Isolate* isolate = env->GetIsolate();
1110   v8::HandleScope scope(isolate);
1111
1112   v8::Handle<v8::ObjectTemplate> object_template =
1113       v8::ObjectTemplate::New(isolate);
1114   object_template->Set(isolate, "callback",
1115                        v8::FunctionTemplate::New(isolate, callback));
1116   v8::Local<v8::Object> object = object_template->NewInstance();
1117   (*env)->Global()->Set(v8_str("callback_object"), object);
1118   v8::Handle<v8::Script> script;
1119   script = v8_compile("callback_object.callback(17)");
1120   for (int i = 0; i < 30; i++) {
1121     CHECK_EQ(51424, script->Run()->Int32Value());
1122   }
1123   script = v8_compile("callback_object.callback(17, 24)");
1124   for (int i = 0; i < 30; i++) {
1125     CHECK_EQ(51425, script->Run()->Int32Value());
1126   }
1127 }
1128
1129
1130 THREADED_PROFILED_TEST(SimpleCallback) {
1131   TestSimpleCallback(SimpleCallback);
1132 }
1133
1134
1135 template<typename T>
1136 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1137
1138 // constant return values
1139 static int32_t fast_return_value_int32 = 471;
1140 static uint32_t fast_return_value_uint32 = 571;
1141 static const double kFastReturnValueDouble = 2.7;
1142 // variable return values
1143 static bool fast_return_value_bool = false;
1144 enum ReturnValueOddball {
1145   kNullReturnValue,
1146   kUndefinedReturnValue,
1147   kEmptyStringReturnValue
1148 };
1149 static ReturnValueOddball fast_return_value_void;
1150 static bool fast_return_value_object_is_empty = false;
1151
1152 // Helper function to avoid compiler error: insufficient contextual information
1153 // to determine type when applying FUNCTION_ADDR to a template function.
1154 static i::Address address_of(v8::FunctionCallback callback) {
1155   return FUNCTION_ADDR(callback);
1156 }
1157
1158 template<>
1159 void FastReturnValueCallback<int32_t>(
1160     const v8::FunctionCallbackInfo<v8::Value>& info) {
1161   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1162   info.GetReturnValue().Set(fast_return_value_int32);
1163 }
1164
1165 template<>
1166 void FastReturnValueCallback<uint32_t>(
1167     const v8::FunctionCallbackInfo<v8::Value>& info) {
1168   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1169   info.GetReturnValue().Set(fast_return_value_uint32);
1170 }
1171
1172 template<>
1173 void FastReturnValueCallback<double>(
1174     const v8::FunctionCallbackInfo<v8::Value>& info) {
1175   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1176   info.GetReturnValue().Set(kFastReturnValueDouble);
1177 }
1178
1179 template<>
1180 void FastReturnValueCallback<bool>(
1181     const v8::FunctionCallbackInfo<v8::Value>& info) {
1182   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1183   info.GetReturnValue().Set(fast_return_value_bool);
1184 }
1185
1186 template<>
1187 void FastReturnValueCallback<void>(
1188     const v8::FunctionCallbackInfo<v8::Value>& info) {
1189   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1190   switch (fast_return_value_void) {
1191     case kNullReturnValue:
1192       info.GetReturnValue().SetNull();
1193       break;
1194     case kUndefinedReturnValue:
1195       info.GetReturnValue().SetUndefined();
1196       break;
1197     case kEmptyStringReturnValue:
1198       info.GetReturnValue().SetEmptyString();
1199       break;
1200   }
1201 }
1202
1203 template<>
1204 void FastReturnValueCallback<Object>(
1205     const v8::FunctionCallbackInfo<v8::Value>& info) {
1206   v8::Handle<v8::Object> object;
1207   if (!fast_return_value_object_is_empty) {
1208     object = Object::New(info.GetIsolate());
1209   }
1210   info.GetReturnValue().Set(object);
1211 }
1212
1213 template<typename T>
1214 Handle<Value> TestFastReturnValues() {
1215   LocalContext env;
1216   v8::Isolate* isolate = env->GetIsolate();
1217   v8::EscapableHandleScope scope(isolate);
1218   v8::Handle<v8::ObjectTemplate> object_template =
1219       v8::ObjectTemplate::New(isolate);
1220   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1221   object_template->Set(isolate, "callback",
1222                        v8::FunctionTemplate::New(isolate, callback));
1223   v8::Local<v8::Object> object = object_template->NewInstance();
1224   (*env)->Global()->Set(v8_str("callback_object"), object);
1225   return scope.Escape(CompileRun("callback_object.callback()"));
1226 }
1227
1228
1229 THREADED_PROFILED_TEST(FastReturnValues) {
1230   LocalContext env;
1231   v8::HandleScope scope(CcTest::isolate());
1232   v8::Handle<v8::Value> value;
1233   // check int32_t and uint32_t
1234   int32_t int_values[] = {
1235       0, 234, -723,
1236       i::Smi::kMinValue, i::Smi::kMaxValue
1237   };
1238   for (size_t i = 0; i < arraysize(int_values); i++) {
1239     for (int modifier = -1; modifier <= 1; modifier++) {
1240       int int_value = int_values[i] + modifier;
1241       // check int32_t
1242       fast_return_value_int32 = int_value;
1243       value = TestFastReturnValues<int32_t>();
1244       CHECK(value->IsInt32());
1245       CHECK(fast_return_value_int32 == value->Int32Value());
1246       // check uint32_t
1247       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1248       value = TestFastReturnValues<uint32_t>();
1249       CHECK(value->IsUint32());
1250       CHECK(fast_return_value_uint32 == value->Uint32Value());
1251     }
1252   }
1253   // check double
1254   value = TestFastReturnValues<double>();
1255   CHECK(value->IsNumber());
1256   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1257   // check bool values
1258   for (int i = 0; i < 2; i++) {
1259     fast_return_value_bool = i == 0;
1260     value = TestFastReturnValues<bool>();
1261     CHECK(value->IsBoolean());
1262     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1263   }
1264   // check oddballs
1265   ReturnValueOddball oddballs[] = {
1266       kNullReturnValue,
1267       kUndefinedReturnValue,
1268       kEmptyStringReturnValue
1269   };
1270   for (size_t i = 0; i < arraysize(oddballs); i++) {
1271     fast_return_value_void = oddballs[i];
1272     value = TestFastReturnValues<void>();
1273     switch (fast_return_value_void) {
1274       case kNullReturnValue:
1275         CHECK(value->IsNull());
1276         break;
1277       case kUndefinedReturnValue:
1278         CHECK(value->IsUndefined());
1279         break;
1280       case kEmptyStringReturnValue:
1281         CHECK(value->IsString());
1282         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1283         break;
1284     }
1285   }
1286   // check handles
1287   fast_return_value_object_is_empty = false;
1288   value = TestFastReturnValues<Object>();
1289   CHECK(value->IsObject());
1290   fast_return_value_object_is_empty = true;
1291   value = TestFastReturnValues<Object>();
1292   CHECK(value->IsUndefined());
1293 }
1294
1295
1296 THREADED_TEST(FunctionTemplateSetLength) {
1297   LocalContext env;
1298   v8::Isolate* isolate = env->GetIsolate();
1299   v8::HandleScope scope(isolate);
1300   {
1301     Local<v8::FunctionTemplate> fun_templ =
1302         v8::FunctionTemplate::New(isolate,
1303                                   handle_callback,
1304                                   Handle<v8::Value>(),
1305                                   Handle<v8::Signature>(),
1306                                   23);
1307     Local<Function> fun = fun_templ->GetFunction();
1308     env->Global()->Set(v8_str("obj"), fun);
1309     Local<Script> script = v8_compile("obj.length");
1310     CHECK_EQ(23, script->Run()->Int32Value());
1311   }
1312   {
1313     Local<v8::FunctionTemplate> fun_templ =
1314         v8::FunctionTemplate::New(isolate, handle_callback);
1315     fun_templ->SetLength(22);
1316     Local<Function> fun = fun_templ->GetFunction();
1317     env->Global()->Set(v8_str("obj"), fun);
1318     Local<Script> script = v8_compile("obj.length");
1319     CHECK_EQ(22, script->Run()->Int32Value());
1320   }
1321   {
1322     // Without setting length it defaults to 0.
1323     Local<v8::FunctionTemplate> fun_templ =
1324         v8::FunctionTemplate::New(isolate, handle_callback);
1325     Local<Function> fun = fun_templ->GetFunction();
1326     env->Global()->Set(v8_str("obj"), fun);
1327     Local<Script> script = v8_compile("obj.length");
1328     CHECK_EQ(0, script->Run()->Int32Value());
1329   }
1330 }
1331
1332
1333 static void* expected_ptr;
1334 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1335   void* ptr = v8::External::Cast(*args.Data())->Value();
1336   CHECK_EQ(expected_ptr, ptr);
1337   args.GetReturnValue().Set(true);
1338 }
1339
1340
1341 static void TestExternalPointerWrapping() {
1342   LocalContext env;
1343   v8::Isolate* isolate = env->GetIsolate();
1344   v8::HandleScope scope(isolate);
1345
1346   v8::Handle<v8::Value> data =
1347       v8::External::New(isolate, expected_ptr);
1348
1349   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1350   obj->Set(v8_str("func"),
1351            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1352   env->Global()->Set(v8_str("obj"), obj);
1353
1354   CHECK(CompileRun(
1355         "function foo() {\n"
1356         "  for (var i = 0; i < 13; i++) obj.func();\n"
1357         "}\n"
1358         "foo(), true")->BooleanValue());
1359 }
1360
1361
1362 THREADED_TEST(ExternalWrap) {
1363   // Check heap allocated object.
1364   int* ptr = new int;
1365   expected_ptr = ptr;
1366   TestExternalPointerWrapping();
1367   delete ptr;
1368
1369   // Check stack allocated object.
1370   int foo;
1371   expected_ptr = &foo;
1372   TestExternalPointerWrapping();
1373
1374   // Check not aligned addresses.
1375   const int n = 100;
1376   char* s = new char[n];
1377   for (int i = 0; i < n; i++) {
1378     expected_ptr = s + i;
1379     TestExternalPointerWrapping();
1380   }
1381
1382   delete[] s;
1383
1384   // Check several invalid addresses.
1385   expected_ptr = reinterpret_cast<void*>(1);
1386   TestExternalPointerWrapping();
1387
1388   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1389   TestExternalPointerWrapping();
1390
1391   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1392   TestExternalPointerWrapping();
1393
1394 #if defined(V8_HOST_ARCH_X64)
1395   // Check a value with a leading 1 bit in x64 Smi encoding.
1396   expected_ptr = reinterpret_cast<void*>(0x400000000);
1397   TestExternalPointerWrapping();
1398
1399   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1400   TestExternalPointerWrapping();
1401
1402   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1403   TestExternalPointerWrapping();
1404 #endif
1405 }
1406
1407
1408 THREADED_TEST(FindInstanceInPrototypeChain) {
1409   LocalContext env;
1410   v8::Isolate* isolate = env->GetIsolate();
1411   v8::HandleScope scope(isolate);
1412
1413   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1414   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1415   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1416   derived->Inherit(base);
1417
1418   Local<v8::Function> base_function = base->GetFunction();
1419   Local<v8::Function> derived_function = derived->GetFunction();
1420   Local<v8::Function> other_function = other->GetFunction();
1421
1422   Local<v8::Object> base_instance = base_function->NewInstance();
1423   Local<v8::Object> derived_instance = derived_function->NewInstance();
1424   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1425   Local<v8::Object> other_instance = other_function->NewInstance();
1426   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1427   other_instance->Set(v8_str("__proto__"), derived_instance2);
1428
1429   // base_instance is only an instance of base.
1430   CHECK_EQ(base_instance,
1431            base_instance->FindInstanceInPrototypeChain(base));
1432   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1433   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1434
1435   // derived_instance is an instance of base and derived.
1436   CHECK_EQ(derived_instance,
1437            derived_instance->FindInstanceInPrototypeChain(base));
1438   CHECK_EQ(derived_instance,
1439            derived_instance->FindInstanceInPrototypeChain(derived));
1440   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1441
1442   // other_instance is an instance of other and its immediate
1443   // prototype derived_instance2 is an instance of base and derived.
1444   // Note, derived_instance is an instance of base and derived too,
1445   // but it comes after derived_instance2 in the prototype chain of
1446   // other_instance.
1447   CHECK_EQ(derived_instance2,
1448            other_instance->FindInstanceInPrototypeChain(base));
1449   CHECK_EQ(derived_instance2,
1450            other_instance->FindInstanceInPrototypeChain(derived));
1451   CHECK_EQ(other_instance,
1452            other_instance->FindInstanceInPrototypeChain(other));
1453 }
1454
1455
1456 THREADED_TEST(TinyInteger) {
1457   LocalContext env;
1458   v8::Isolate* isolate = env->GetIsolate();
1459   v8::HandleScope scope(isolate);
1460
1461   int32_t value = 239;
1462   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1463   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1464
1465   value_obj = v8::Integer::New(isolate, value);
1466   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1467 }
1468
1469
1470 THREADED_TEST(BigSmiInteger) {
1471   LocalContext env;
1472   v8::HandleScope scope(env->GetIsolate());
1473   v8::Isolate* isolate = CcTest::isolate();
1474
1475   int32_t value = i::Smi::kMaxValue;
1476   // We cannot add one to a Smi::kMaxValue without wrapping.
1477   if (i::SmiValuesAre31Bits()) {
1478     CHECK(i::Smi::IsValid(value));
1479     CHECK(!i::Smi::IsValid(value + 1));
1480
1481     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1482     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1483
1484     value_obj = v8::Integer::New(isolate, value);
1485     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1486   }
1487 }
1488
1489
1490 THREADED_TEST(BigInteger) {
1491   LocalContext env;
1492   v8::HandleScope scope(env->GetIsolate());
1493   v8::Isolate* isolate = CcTest::isolate();
1494
1495   // We cannot add one to a Smi::kMaxValue without wrapping.
1496   if (i::SmiValuesAre31Bits()) {
1497     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1498     // The code will not be run in that case, due to the "if" guard.
1499     int32_t value =
1500         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1501     CHECK(value > i::Smi::kMaxValue);
1502     CHECK(!i::Smi::IsValid(value));
1503
1504     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1505     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1506
1507     value_obj = v8::Integer::New(isolate, value);
1508     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509   }
1510 }
1511
1512
1513 THREADED_TEST(TinyUnsignedInteger) {
1514   LocalContext env;
1515   v8::HandleScope scope(env->GetIsolate());
1516   v8::Isolate* isolate = CcTest::isolate();
1517
1518   uint32_t value = 239;
1519
1520   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1521   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1522
1523   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1525 }
1526
1527
1528 THREADED_TEST(BigUnsignedSmiInteger) {
1529   LocalContext env;
1530   v8::HandleScope scope(env->GetIsolate());
1531   v8::Isolate* isolate = CcTest::isolate();
1532
1533   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1534   CHECK(i::Smi::IsValid(value));
1535   CHECK(!i::Smi::IsValid(value + 1));
1536
1537   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1538   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1539
1540   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1541   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1542 }
1543
1544
1545 THREADED_TEST(BigUnsignedInteger) {
1546   LocalContext env;
1547   v8::HandleScope scope(env->GetIsolate());
1548   v8::Isolate* isolate = CcTest::isolate();
1549
1550   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1551   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1552   CHECK(!i::Smi::IsValid(value));
1553
1554   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1555   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1556
1557   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1558   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1559 }
1560
1561
1562 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1563   LocalContext env;
1564   v8::HandleScope scope(env->GetIsolate());
1565   v8::Isolate* isolate = CcTest::isolate();
1566
1567   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1568   uint32_t value = INT32_MAX_AS_UINT + 1;
1569   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1570
1571   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1572   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1573
1574   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1575   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1576 }
1577
1578
1579 THREADED_TEST(IsNativeError) {
1580   LocalContext env;
1581   v8::HandleScope scope(env->GetIsolate());
1582   v8::Handle<Value> syntax_error = CompileRun(
1583       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1584   CHECK(syntax_error->IsNativeError());
1585   v8::Handle<Value> not_error = CompileRun("{a:42}");
1586   CHECK(!not_error->IsNativeError());
1587   v8::Handle<Value> not_object = CompileRun("42");
1588   CHECK(!not_object->IsNativeError());
1589 }
1590
1591
1592 THREADED_TEST(IsGeneratorFunctionOrObject) {
1593   LocalContext env;
1594   v8::HandleScope scope(env->GetIsolate());
1595
1596   CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1597   v8::Handle<Value> gen = CompileRun("gen");
1598   v8::Handle<Value> genObj = CompileRun("gen()");
1599   v8::Handle<Value> object = CompileRun("{a:42}");
1600   v8::Handle<Value> func = CompileRun("func");
1601
1602   CHECK(gen->IsGeneratorFunction());
1603   CHECK(gen->IsFunction());
1604   CHECK(!gen->IsGeneratorObject());
1605
1606   CHECK(!genObj->IsGeneratorFunction());
1607   CHECK(!genObj->IsFunction());
1608   CHECK(genObj->IsGeneratorObject());
1609
1610   CHECK(!object->IsGeneratorFunction());
1611   CHECK(!object->IsFunction());
1612   CHECK(!object->IsGeneratorObject());
1613
1614   CHECK(!func->IsGeneratorFunction());
1615   CHECK(func->IsFunction());
1616   CHECK(!func->IsGeneratorObject());
1617 }
1618
1619
1620 THREADED_TEST(ArgumentsObject) {
1621   LocalContext env;
1622   v8::HandleScope scope(env->GetIsolate());
1623   v8::Handle<Value> arguments_object =
1624       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1625   CHECK(arguments_object->IsArgumentsObject());
1626   v8::Handle<Value> array = CompileRun("[1,2,3]");
1627   CHECK(!array->IsArgumentsObject());
1628   v8::Handle<Value> object = CompileRun("{a:42}");
1629   CHECK(!object->IsArgumentsObject());
1630 }
1631
1632
1633 THREADED_TEST(IsMapOrSet) {
1634   LocalContext env;
1635   v8::HandleScope scope(env->GetIsolate());
1636   v8::Handle<Value> map = CompileRun("new Map()");
1637   v8::Handle<Value> set = CompileRun("new Set()");
1638   v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1639   v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1640   CHECK(map->IsMap());
1641   CHECK(set->IsSet());
1642   CHECK(weak_map->IsWeakMap());
1643   CHECK(weak_set->IsWeakSet());
1644
1645   CHECK(!map->IsSet());
1646   CHECK(!map->IsWeakMap());
1647   CHECK(!map->IsWeakSet());
1648
1649   CHECK(!set->IsMap());
1650   CHECK(!set->IsWeakMap());
1651   CHECK(!set->IsWeakSet());
1652
1653   CHECK(!weak_map->IsMap());
1654   CHECK(!weak_map->IsSet());
1655   CHECK(!weak_map->IsWeakSet());
1656
1657   CHECK(!weak_set->IsMap());
1658   CHECK(!weak_set->IsSet());
1659   CHECK(!weak_set->IsWeakMap());
1660
1661   v8::Handle<Value> object = CompileRun("{a:42}");
1662   CHECK(!object->IsMap());
1663   CHECK(!object->IsSet());
1664   CHECK(!object->IsWeakMap());
1665   CHECK(!object->IsWeakSet());
1666 }
1667
1668
1669 THREADED_TEST(StringObject) {
1670   LocalContext env;
1671   v8::HandleScope scope(env->GetIsolate());
1672   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1673   CHECK(boxed_string->IsStringObject());
1674   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1675   CHECK(!unboxed_string->IsStringObject());
1676   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1677   CHECK(!boxed_not_string->IsStringObject());
1678   v8::Handle<Value> not_object = CompileRun("0");
1679   CHECK(!not_object->IsStringObject());
1680   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1681   CHECK(!as_boxed.IsEmpty());
1682   Local<v8::String> the_string = as_boxed->ValueOf();
1683   CHECK(!the_string.IsEmpty());
1684   ExpectObject("\"test\"", the_string);
1685   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1686   CHECK(new_boxed_string->IsStringObject());
1687   as_boxed = new_boxed_string.As<v8::StringObject>();
1688   the_string = as_boxed->ValueOf();
1689   CHECK(!the_string.IsEmpty());
1690   ExpectObject("\"test\"", the_string);
1691 }
1692
1693
1694 THREADED_TEST(NumberObject) {
1695   LocalContext env;
1696   v8::HandleScope scope(env->GetIsolate());
1697   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1698   CHECK(boxed_number->IsNumberObject());
1699   v8::Handle<Value> unboxed_number = CompileRun("42");
1700   CHECK(!unboxed_number->IsNumberObject());
1701   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1702   CHECK(!boxed_not_number->IsNumberObject());
1703   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1704   CHECK(!as_boxed.IsEmpty());
1705   double the_number = as_boxed->ValueOf();
1706   CHECK_EQ(42.0, the_number);
1707   v8::Handle<v8::Value> new_boxed_number =
1708       v8::NumberObject::New(env->GetIsolate(), 43);
1709   CHECK(new_boxed_number->IsNumberObject());
1710   as_boxed = new_boxed_number.As<v8::NumberObject>();
1711   the_number = as_boxed->ValueOf();
1712   CHECK_EQ(43.0, the_number);
1713 }
1714
1715
1716 THREADED_TEST(BooleanObject) {
1717   LocalContext env;
1718   v8::HandleScope scope(env->GetIsolate());
1719   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1720   CHECK(boxed_boolean->IsBooleanObject());
1721   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1722   CHECK(!unboxed_boolean->IsBooleanObject());
1723   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1724   CHECK(!boxed_not_boolean->IsBooleanObject());
1725   v8::Handle<v8::BooleanObject> as_boxed =
1726       boxed_boolean.As<v8::BooleanObject>();
1727   CHECK(!as_boxed.IsEmpty());
1728   bool the_boolean = as_boxed->ValueOf();
1729   CHECK_EQ(true, the_boolean);
1730   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1731   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1732   CHECK(boxed_true->IsBooleanObject());
1733   CHECK(boxed_false->IsBooleanObject());
1734   as_boxed = boxed_true.As<v8::BooleanObject>();
1735   CHECK_EQ(true, as_boxed->ValueOf());
1736   as_boxed = boxed_false.As<v8::BooleanObject>();
1737   CHECK_EQ(false, as_boxed->ValueOf());
1738 }
1739
1740
1741 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1742   LocalContext env;
1743   v8::HandleScope scope(env->GetIsolate());
1744
1745   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1746   CHECK(primitive_false->IsBoolean());
1747   CHECK(!primitive_false->IsBooleanObject());
1748   CHECK(!primitive_false->BooleanValue());
1749   CHECK(!primitive_false->IsTrue());
1750   CHECK(primitive_false->IsFalse());
1751
1752   Local<Value> false_value = BooleanObject::New(false);
1753   CHECK(!false_value->IsBoolean());
1754   CHECK(false_value->IsBooleanObject());
1755   CHECK(false_value->BooleanValue());
1756   CHECK(!false_value->IsTrue());
1757   CHECK(!false_value->IsFalse());
1758
1759   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1760   CHECK(!false_boolean_object->IsBoolean());
1761   CHECK(false_boolean_object->IsBooleanObject());
1762   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1763   // CHECK(false_boolean_object->BooleanValue());
1764   CHECK(!false_boolean_object->ValueOf());
1765   CHECK(!false_boolean_object->IsTrue());
1766   CHECK(!false_boolean_object->IsFalse());
1767
1768   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1769   CHECK(primitive_true->IsBoolean());
1770   CHECK(!primitive_true->IsBooleanObject());
1771   CHECK(primitive_true->BooleanValue());
1772   CHECK(primitive_true->IsTrue());
1773   CHECK(!primitive_true->IsFalse());
1774
1775   Local<Value> true_value = BooleanObject::New(true);
1776   CHECK(!true_value->IsBoolean());
1777   CHECK(true_value->IsBooleanObject());
1778   CHECK(true_value->BooleanValue());
1779   CHECK(!true_value->IsTrue());
1780   CHECK(!true_value->IsFalse());
1781
1782   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1783   CHECK(!true_boolean_object->IsBoolean());
1784   CHECK(true_boolean_object->IsBooleanObject());
1785   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1786   // CHECK(true_boolean_object->BooleanValue());
1787   CHECK(true_boolean_object->ValueOf());
1788   CHECK(!true_boolean_object->IsTrue());
1789   CHECK(!true_boolean_object->IsFalse());
1790 }
1791
1792
1793 THREADED_TEST(Number) {
1794   LocalContext env;
1795   v8::HandleScope scope(env->GetIsolate());
1796   double PI = 3.1415926;
1797   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1798   CHECK_EQ(PI, pi_obj->NumberValue());
1799 }
1800
1801
1802 THREADED_TEST(ToNumber) {
1803   LocalContext env;
1804   v8::Isolate* isolate = CcTest::isolate();
1805   v8::HandleScope scope(isolate);
1806   Local<String> str = v8_str("3.1415926");
1807   CHECK_EQ(3.1415926, str->NumberValue());
1808   v8::Handle<v8::Boolean> t = v8::True(isolate);
1809   CHECK_EQ(1.0, t->NumberValue());
1810   v8::Handle<v8::Boolean> f = v8::False(isolate);
1811   CHECK_EQ(0.0, f->NumberValue());
1812 }
1813
1814
1815 THREADED_TEST(Date) {
1816   LocalContext env;
1817   v8::HandleScope scope(env->GetIsolate());
1818   double PI = 3.1415926;
1819   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1820   CHECK_EQ(3.0, date->NumberValue());
1821   date.As<v8::Date>()->Set(v8_str("property"),
1822                            v8::Integer::New(env->GetIsolate(), 42));
1823   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1824 }
1825
1826
1827 THREADED_TEST(Boolean) {
1828   LocalContext env;
1829   v8::Isolate* isolate = env->GetIsolate();
1830   v8::HandleScope scope(isolate);
1831   v8::Handle<v8::Boolean> t = v8::True(isolate);
1832   CHECK(t->Value());
1833   v8::Handle<v8::Boolean> f = v8::False(isolate);
1834   CHECK(!f->Value());
1835   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1836   CHECK(!u->BooleanValue());
1837   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1838   CHECK(!n->BooleanValue());
1839   v8::Handle<String> str1 = v8_str("");
1840   CHECK(!str1->BooleanValue());
1841   v8::Handle<String> str2 = v8_str("x");
1842   CHECK(str2->BooleanValue());
1843   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1844   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1845   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1846   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1847   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1848 }
1849
1850
1851 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1852   ApiTestFuzzer::Fuzz();
1853   args.GetReturnValue().Set(v8_num(13.4));
1854 }
1855
1856
1857 static void GetM(Local<String> name,
1858                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1859   ApiTestFuzzer::Fuzz();
1860   info.GetReturnValue().Set(v8_num(876));
1861 }
1862
1863
1864 THREADED_TEST(GlobalPrototype) {
1865   v8::Isolate* isolate = CcTest::isolate();
1866   v8::HandleScope scope(isolate);
1867   v8::Handle<v8::FunctionTemplate> func_templ =
1868       v8::FunctionTemplate::New(isolate);
1869   func_templ->PrototypeTemplate()->Set(
1870       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1871   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1872   templ->Set(isolate, "x", v8_num(200));
1873   templ->SetAccessor(v8_str("m"), GetM);
1874   LocalContext env(0, templ);
1875   v8::Handle<Script> script(v8_compile("dummy()"));
1876   v8::Handle<Value> result(script->Run());
1877   CHECK_EQ(13.4, result->NumberValue());
1878   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1879   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1880 }
1881
1882
1883 THREADED_TEST(ObjectTemplate) {
1884   v8::Isolate* isolate = CcTest::isolate();
1885   v8::HandleScope scope(isolate);
1886   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1887   templ1->Set(isolate, "x", v8_num(10));
1888   templ1->Set(isolate, "y", v8_num(13));
1889   LocalContext env;
1890   Local<v8::Object> instance1 = templ1->NewInstance();
1891   env->Global()->Set(v8_str("p"), instance1);
1892   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1893   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1894   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1895   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1896   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1897   templ2->Set(isolate, "a", v8_num(12));
1898   templ2->Set(isolate, "b", templ1);
1899   Local<v8::Object> instance2 = templ2->NewInstance();
1900   env->Global()->Set(v8_str("q"), instance2);
1901   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1902   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1903   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1904   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1905 }
1906
1907
1908 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1909   ApiTestFuzzer::Fuzz();
1910   args.GetReturnValue().Set(v8_num(17.2));
1911 }
1912
1913
1914 static void GetKnurd(Local<String> property,
1915                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1916   ApiTestFuzzer::Fuzz();
1917   info.GetReturnValue().Set(v8_num(15.2));
1918 }
1919
1920
1921 THREADED_TEST(DescriptorInheritance) {
1922   v8::Isolate* isolate = CcTest::isolate();
1923   v8::HandleScope scope(isolate);
1924   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1925   super->PrototypeTemplate()->Set(isolate, "flabby",
1926                                   v8::FunctionTemplate::New(isolate,
1927                                                             GetFlabby));
1928   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1929
1930   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1931
1932   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1933   base1->Inherit(super);
1934   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1935
1936   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1937   base2->Inherit(super);
1938   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1939
1940   LocalContext env;
1941
1942   env->Global()->Set(v8_str("s"), super->GetFunction());
1943   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1944   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1945
1946   // Checks right __proto__ chain.
1947   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1948   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1949
1950   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1951
1952   // Instance accessor should not be visible on function object or its prototype
1953   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1954   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1955   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1956
1957   env->Global()->Set(v8_str("obj"),
1958                      base1->GetFunction()->NewInstance());
1959   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1960   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1961   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1962   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1963   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1964
1965   env->Global()->Set(v8_str("obj2"),
1966                      base2->GetFunction()->NewInstance());
1967   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1968   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1969   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1970   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1971   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1972
1973   // base1 and base2 cannot cross reference to each's prototype
1974   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1975   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1976 }
1977
1978
1979 int echo_named_call_count;
1980
1981
1982 static void EchoNamedProperty(Local<String> name,
1983                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1984   ApiTestFuzzer::Fuzz();
1985   CHECK_EQ(v8_str("data"), info.Data());
1986   echo_named_call_count++;
1987   info.GetReturnValue().Set(name);
1988 }
1989
1990
1991 // Helper functions for Interceptor/Accessor interaction tests
1992
1993 void SimpleAccessorGetter(Local<String> name,
1994                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1995   Handle<Object> self = Handle<Object>::Cast(info.This());
1996   info.GetReturnValue().Set(
1997       self->Get(String::Concat(v8_str("accessor_"), name)));
1998 }
1999
2000 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2001                           const v8::PropertyCallbackInfo<void>& info) {
2002   Handle<Object> self = Handle<Object>::Cast(info.This());
2003   self->Set(String::Concat(v8_str("accessor_"), name), value);
2004 }
2005
2006 void SymbolAccessorGetter(Local<Name> name,
2007                           const v8::PropertyCallbackInfo<v8::Value>& info) {
2008   CHECK(name->IsSymbol());
2009   Local<Symbol> sym = Local<Symbol>::Cast(name);
2010   if (sym->Name()->IsUndefined())
2011     return;
2012   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2013 }
2014
2015 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2016                           const v8::PropertyCallbackInfo<void>& info) {
2017   CHECK(name->IsSymbol());
2018   Local<Symbol> sym = Local<Symbol>::Cast(name);
2019   if (sym->Name()->IsUndefined())
2020     return;
2021   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2022 }
2023
2024 void EmptyInterceptorGetter(Local<String> name,
2025                             const v8::PropertyCallbackInfo<v8::Value>& info) {
2026 }
2027
2028 void EmptyInterceptorSetter(Local<String> name,
2029                             Local<Value> value,
2030                             const v8::PropertyCallbackInfo<v8::Value>& info) {
2031 }
2032
2033 void InterceptorGetter(Local<String> name,
2034                        const v8::PropertyCallbackInfo<v8::Value>& info) {
2035   // Intercept names that start with 'interceptor_'.
2036   String::Utf8Value utf8(name);
2037   char* name_str = *utf8;
2038   char prefix[] = "interceptor_";
2039   int i;
2040   for (i = 0; name_str[i] && prefix[i]; ++i) {
2041     if (name_str[i] != prefix[i]) return;
2042   }
2043   Handle<Object> self = Handle<Object>::Cast(info.This());
2044   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
2045 }
2046
2047 void InterceptorSetter(Local<String> name,
2048                        Local<Value> value,
2049                        const v8::PropertyCallbackInfo<v8::Value>& info) {
2050   // Intercept accesses that set certain integer values, for which the name does
2051   // not start with 'accessor_'.
2052   String::Utf8Value utf8(name);
2053   char* name_str = *utf8;
2054   char prefix[] = "accessor_";
2055   int i;
2056   for (i = 0; name_str[i] && prefix[i]; ++i) {
2057     if (name_str[i] != prefix[i]) break;
2058   }
2059   if (!prefix[i]) return;
2060
2061   if (value->IsInt32() && value->Int32Value() < 10000) {
2062     Handle<Object> self = Handle<Object>::Cast(info.This());
2063     self->SetHiddenValue(name, value);
2064     info.GetReturnValue().Set(value);
2065   }
2066 }
2067
2068 void AddAccessor(Handle<FunctionTemplate> templ,
2069                  Handle<String> name,
2070                  v8::AccessorGetterCallback getter,
2071                  v8::AccessorSetterCallback setter) {
2072   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2073 }
2074
2075 void AddInterceptor(Handle<FunctionTemplate> templ,
2076                     v8::NamedPropertyGetterCallback getter,
2077                     v8::NamedPropertySetterCallback setter) {
2078   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2079 }
2080
2081
2082 void AddAccessor(Handle<FunctionTemplate> templ,
2083                  Handle<Name> name,
2084                  v8::AccessorNameGetterCallback getter,
2085                  v8::AccessorNameSetterCallback setter) {
2086   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2087 }
2088
2089
2090 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2091   v8::HandleScope scope(CcTest::isolate());
2092   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2093   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2094   child->Inherit(parent);
2095   AddAccessor(parent, v8_str("age"),
2096               SimpleAccessorGetter, SimpleAccessorSetter);
2097   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2098   LocalContext env;
2099   env->Global()->Set(v8_str("Child"), child->GetFunction());
2100   CompileRun("var child = new Child;"
2101              "child.age = 10;");
2102   ExpectBoolean("child.hasOwnProperty('age')", false);
2103   ExpectInt32("child.age", 10);
2104   ExpectInt32("child.accessor_age", 10);
2105 }
2106
2107
2108 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2109   v8::Isolate* isolate = CcTest::isolate();
2110   v8::HandleScope scope(isolate);
2111   LocalContext env;
2112   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2113   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2114   CHECK(a->map()->instance_descriptors()->IsFixedArray());
2115   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2116   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2117   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2118   // But we should still have an ExecutableAccessorInfo.
2119   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2120   i::LookupResult lookup(i_isolate);
2121   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2122   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2123   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2124   CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2125 }
2126
2127
2128 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2129   v8::HandleScope scope(CcTest::isolate());
2130   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2131   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2132   LocalContext env;
2133   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2134   CompileRun("var o1 = new Constructor;"
2135              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2136              "Object.defineProperty(o1, 'x', {value: 10});");
2137   CompileRun("var o2 = new Constructor;"
2138              "o2.a = 1;"
2139              "Object.defineProperty(o2, 'x', {value: 10});");
2140 }
2141
2142
2143 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2144   v8::Isolate* isolate = CcTest::isolate();
2145   v8::HandleScope scope(isolate);
2146   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2147   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2148   child->Inherit(parent);
2149   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2150   LocalContext env;
2151   env->Global()->Set(v8_str("Child"), child->GetFunction());
2152   CompileRun("var child = new Child;"
2153              "var parent = child.__proto__;"
2154              "Object.defineProperty(parent, 'age', "
2155              "  {get: function(){ return this.accessor_age; }, "
2156              "   set: function(v){ this.accessor_age = v; }, "
2157              "   enumerable: true, configurable: true});"
2158              "child.age = 10;");
2159   ExpectBoolean("child.hasOwnProperty('age')", false);
2160   ExpectInt32("child.age", 10);
2161   ExpectInt32("child.accessor_age", 10);
2162 }
2163
2164
2165 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2166   v8::Isolate* isolate = CcTest::isolate();
2167   v8::HandleScope scope(isolate);
2168   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2169   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2170   child->Inherit(parent);
2171   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2172   LocalContext env;
2173   env->Global()->Set(v8_str("Child"), child->GetFunction());
2174   CompileRun("var child = new Child;"
2175              "var parent = child.__proto__;"
2176              "parent.name = 'Alice';");
2177   ExpectBoolean("child.hasOwnProperty('name')", false);
2178   ExpectString("child.name", "Alice");
2179   CompileRun("child.name = 'Bob';");
2180   ExpectString("child.name", "Bob");
2181   ExpectBoolean("child.hasOwnProperty('name')", true);
2182   ExpectString("parent.name", "Alice");
2183 }
2184
2185
2186 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2187   v8::HandleScope scope(CcTest::isolate());
2188   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2189   AddAccessor(templ, v8_str("age"),
2190               SimpleAccessorGetter, SimpleAccessorSetter);
2191   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2192   LocalContext env;
2193   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2194   CompileRun("var obj = new Obj;"
2195              "function setAge(i){ obj.age = i; };"
2196              "for(var i = 0; i <= 10000; i++) setAge(i);");
2197   // All i < 10000 go to the interceptor.
2198   ExpectInt32("obj.interceptor_age", 9999);
2199   // The last i goes to the accessor.
2200   ExpectInt32("obj.accessor_age", 10000);
2201 }
2202
2203
2204 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2205   v8::HandleScope scope(CcTest::isolate());
2206   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2207   AddAccessor(templ, v8_str("age"),
2208               SimpleAccessorGetter, SimpleAccessorSetter);
2209   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2210   LocalContext env;
2211   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2212   CompileRun("var obj = new Obj;"
2213              "function setAge(i){ obj.age = i; };"
2214              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2215   // All i >= 10000 go to the accessor.
2216   ExpectInt32("obj.accessor_age", 10000);
2217   // The last i goes to the interceptor.
2218   ExpectInt32("obj.interceptor_age", 9999);
2219 }
2220
2221
2222 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2223   v8::HandleScope scope(CcTest::isolate());
2224   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2225   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2226   child->Inherit(parent);
2227   AddAccessor(parent, v8_str("age"),
2228               SimpleAccessorGetter, SimpleAccessorSetter);
2229   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2230   LocalContext env;
2231   env->Global()->Set(v8_str("Child"), child->GetFunction());
2232   CompileRun("var child = new Child;"
2233              "function setAge(i){ child.age = i; };"
2234              "for(var i = 0; i <= 10000; i++) setAge(i);");
2235   // All i < 10000 go to the interceptor.
2236   ExpectInt32("child.interceptor_age", 9999);
2237   // The last i goes to the accessor.
2238   ExpectInt32("child.accessor_age", 10000);
2239 }
2240
2241
2242 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2243   v8::HandleScope scope(CcTest::isolate());
2244   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2245   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2246   child->Inherit(parent);
2247   AddAccessor(parent, v8_str("age"),
2248               SimpleAccessorGetter, SimpleAccessorSetter);
2249   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2250   LocalContext env;
2251   env->Global()->Set(v8_str("Child"), child->GetFunction());
2252   CompileRun("var child = new Child;"
2253              "function setAge(i){ child.age = i; };"
2254              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2255   // All i >= 10000 go to the accessor.
2256   ExpectInt32("child.accessor_age", 10000);
2257   // The last i goes to the interceptor.
2258   ExpectInt32("child.interceptor_age", 9999);
2259 }
2260
2261
2262 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2263   v8::HandleScope scope(CcTest::isolate());
2264   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2265   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2266   LocalContext env;
2267   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2268   CompileRun("var obj = new Obj;"
2269              "function setter(i) { this.accessor_age = i; };"
2270              "function getter() { return this.accessor_age; };"
2271              "function setAge(i) { obj.age = i; };"
2272              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2273              "for(var i = 0; i <= 10000; i++) setAge(i);");
2274   // All i < 10000 go to the interceptor.
2275   ExpectInt32("obj.interceptor_age", 9999);
2276   // The last i goes to the JavaScript accessor.
2277   ExpectInt32("obj.accessor_age", 10000);
2278   // The installed JavaScript getter is still intact.
2279   // This last part is a regression test for issue 1651 and relies on the fact
2280   // that both interceptor and accessor are being installed on the same object.
2281   ExpectInt32("obj.age", 10000);
2282   ExpectBoolean("obj.hasOwnProperty('age')", true);
2283   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2284 }
2285
2286
2287 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2288   v8::HandleScope scope(CcTest::isolate());
2289   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2290   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2291   LocalContext env;
2292   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2293   CompileRun("var obj = new Obj;"
2294              "function setter(i) { this.accessor_age = i; };"
2295              "function getter() { return this.accessor_age; };"
2296              "function setAge(i) { obj.age = i; };"
2297              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2298              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2299   // All i >= 10000 go to the accessor.
2300   ExpectInt32("obj.accessor_age", 10000);
2301   // The last i goes to the interceptor.
2302   ExpectInt32("obj.interceptor_age", 9999);
2303   // The installed JavaScript getter is still intact.
2304   // This last part is a regression test for issue 1651 and relies on the fact
2305   // that both interceptor and accessor are being installed on the same object.
2306   ExpectInt32("obj.age", 10000);
2307   ExpectBoolean("obj.hasOwnProperty('age')", true);
2308   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2309 }
2310
2311
2312 THREADED_TEST(SwitchFromInterceptorToProperty) {
2313   v8::HandleScope scope(CcTest::isolate());
2314   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2315   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2316   child->Inherit(parent);
2317   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2318   LocalContext env;
2319   env->Global()->Set(v8_str("Child"), child->GetFunction());
2320   CompileRun("var child = new Child;"
2321              "function setAge(i){ child.age = i; };"
2322              "for(var i = 0; i <= 10000; i++) setAge(i);");
2323   // All i < 10000 go to the interceptor.
2324   ExpectInt32("child.interceptor_age", 9999);
2325   // The last i goes to child's own property.
2326   ExpectInt32("child.age", 10000);
2327 }
2328
2329
2330 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2331   v8::HandleScope scope(CcTest::isolate());
2332   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2333   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2334   child->Inherit(parent);
2335   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2336   LocalContext env;
2337   env->Global()->Set(v8_str("Child"), child->GetFunction());
2338   CompileRun("var child = new Child;"
2339              "function setAge(i){ child.age = i; };"
2340              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2341   // All i >= 10000 go to child's own property.
2342   ExpectInt32("child.age", 10000);
2343   // The last i goes to the interceptor.
2344   ExpectInt32("child.interceptor_age", 9999);
2345 }
2346
2347
2348 THREADED_TEST(NamedPropertyHandlerGetter) {
2349   echo_named_call_count = 0;
2350   v8::HandleScope scope(CcTest::isolate());
2351   v8::Handle<v8::FunctionTemplate> templ =
2352       v8::FunctionTemplate::New(CcTest::isolate());
2353   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2354                                                      0, 0, 0, 0,
2355                                                      v8_str("data"));
2356   LocalContext env;
2357   env->Global()->Set(v8_str("obj"),
2358                      templ->GetFunction()->NewInstance());
2359   CHECK_EQ(echo_named_call_count, 0);
2360   v8_compile("obj.x")->Run();
2361   CHECK_EQ(echo_named_call_count, 1);
2362   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2363   v8::Handle<Value> str = CompileRun(code);
2364   String::Utf8Value value(str);
2365   CHECK_EQ(*value, "oddlepoddle");
2366   // Check default behavior
2367   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2368   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2369   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2370 }
2371
2372
2373 int echo_indexed_call_count = 0;
2374
2375
2376 static void EchoIndexedProperty(
2377     uint32_t index,
2378     const v8::PropertyCallbackInfo<v8::Value>& info) {
2379   ApiTestFuzzer::Fuzz();
2380   CHECK_EQ(v8_num(637), info.Data());
2381   echo_indexed_call_count++;
2382   info.GetReturnValue().Set(v8_num(index));
2383 }
2384
2385
2386 THREADED_TEST(IndexedPropertyHandlerGetter) {
2387   v8::Isolate* isolate = CcTest::isolate();
2388   v8::HandleScope scope(isolate);
2389   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2390   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2391                                                        0, 0, 0, 0,
2392                                                        v8_num(637));
2393   LocalContext env;
2394   env->Global()->Set(v8_str("obj"),
2395                      templ->GetFunction()->NewInstance());
2396   Local<Script> script = v8_compile("obj[900]");
2397   CHECK_EQ(script->Run()->Int32Value(), 900);
2398 }
2399
2400
2401 v8::Handle<v8::Object> bottom;
2402
2403 static void CheckThisIndexedPropertyHandler(
2404     uint32_t index,
2405     const v8::PropertyCallbackInfo<v8::Value>& info) {
2406   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2407   ApiTestFuzzer::Fuzz();
2408   CHECK(info.This()->Equals(bottom));
2409 }
2410
2411 static void CheckThisNamedPropertyHandler(
2412     Local<String> name,
2413     const v8::PropertyCallbackInfo<v8::Value>& info) {
2414   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2415   ApiTestFuzzer::Fuzz();
2416   CHECK(info.This()->Equals(bottom));
2417 }
2418
2419 void CheckThisIndexedPropertySetter(
2420     uint32_t index,
2421     Local<Value> value,
2422     const v8::PropertyCallbackInfo<v8::Value>& info) {
2423   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2424   ApiTestFuzzer::Fuzz();
2425   CHECK(info.This()->Equals(bottom));
2426 }
2427
2428
2429 void CheckThisNamedPropertySetter(
2430     Local<String> property,
2431     Local<Value> value,
2432     const v8::PropertyCallbackInfo<v8::Value>& info) {
2433   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2434   ApiTestFuzzer::Fuzz();
2435   CHECK(info.This()->Equals(bottom));
2436 }
2437
2438 void CheckThisIndexedPropertyQuery(
2439     uint32_t index,
2440     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2441   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2442   ApiTestFuzzer::Fuzz();
2443   CHECK(info.This()->Equals(bottom));
2444 }
2445
2446
2447 void CheckThisNamedPropertyQuery(
2448     Local<String> property,
2449     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2450   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2451   ApiTestFuzzer::Fuzz();
2452   CHECK(info.This()->Equals(bottom));
2453 }
2454
2455
2456 void CheckThisIndexedPropertyDeleter(
2457     uint32_t index,
2458     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2459   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2460   ApiTestFuzzer::Fuzz();
2461   CHECK(info.This()->Equals(bottom));
2462 }
2463
2464
2465 void CheckThisNamedPropertyDeleter(
2466     Local<String> property,
2467     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2468   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2469   ApiTestFuzzer::Fuzz();
2470   CHECK(info.This()->Equals(bottom));
2471 }
2472
2473
2474 void CheckThisIndexedPropertyEnumerator(
2475     const v8::PropertyCallbackInfo<v8::Array>& info) {
2476   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2477   ApiTestFuzzer::Fuzz();
2478   CHECK(info.This()->Equals(bottom));
2479 }
2480
2481
2482 void CheckThisNamedPropertyEnumerator(
2483     const v8::PropertyCallbackInfo<v8::Array>& info) {
2484   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2485   ApiTestFuzzer::Fuzz();
2486   CHECK(info.This()->Equals(bottom));
2487 }
2488
2489
2490 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2491   LocalContext env;
2492   v8::Isolate* isolate = env->GetIsolate();
2493   v8::HandleScope scope(isolate);
2494
2495   // Set up a prototype chain with three interceptors.
2496   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2497   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2498       CheckThisIndexedPropertyHandler,
2499       CheckThisIndexedPropertySetter,
2500       CheckThisIndexedPropertyQuery,
2501       CheckThisIndexedPropertyDeleter,
2502       CheckThisIndexedPropertyEnumerator);
2503
2504   templ->InstanceTemplate()->SetNamedPropertyHandler(
2505       CheckThisNamedPropertyHandler,
2506       CheckThisNamedPropertySetter,
2507       CheckThisNamedPropertyQuery,
2508       CheckThisNamedPropertyDeleter,
2509       CheckThisNamedPropertyEnumerator);
2510
2511   bottom = templ->GetFunction()->NewInstance();
2512   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2513   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2514
2515   bottom->SetPrototype(middle);
2516   middle->SetPrototype(top);
2517   env->Global()->Set(v8_str("obj"), bottom);
2518
2519   // Indexed and named get.
2520   CompileRun("obj[0]");
2521   CompileRun("obj.x");
2522
2523   // Indexed and named set.
2524   CompileRun("obj[1] = 42");
2525   CompileRun("obj.y = 42");
2526
2527   // Indexed and named query.
2528   CompileRun("0 in obj");
2529   CompileRun("'x' in obj");
2530
2531   // Indexed and named deleter.
2532   CompileRun("delete obj[0]");
2533   CompileRun("delete obj.x");
2534
2535   // Enumerators.
2536   CompileRun("for (var p in obj) ;");
2537 }
2538
2539
2540 static void PrePropertyHandlerGet(
2541     Local<String> key,
2542     const v8::PropertyCallbackInfo<v8::Value>& info) {
2543   ApiTestFuzzer::Fuzz();
2544   if (v8_str("pre")->Equals(key)) {
2545     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2546   }
2547 }
2548
2549
2550 static void PrePropertyHandlerQuery(
2551     Local<String> key,
2552     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2553   if (v8_str("pre")->Equals(key)) {
2554     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2555   }
2556 }
2557
2558
2559 THREADED_TEST(PrePropertyHandler) {
2560   v8::Isolate* isolate = CcTest::isolate();
2561   v8::HandleScope scope(isolate);
2562   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2563   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2564                                                     0,
2565                                                     PrePropertyHandlerQuery);
2566   LocalContext env(NULL, desc->InstanceTemplate());
2567   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2568   v8::Handle<Value> result_pre = CompileRun("pre");
2569   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2570   v8::Handle<Value> result_on = CompileRun("on");
2571   CHECK_EQ(v8_str("Object: on"), result_on);
2572   v8::Handle<Value> result_post = CompileRun("post");
2573   CHECK(result_post.IsEmpty());
2574 }
2575
2576
2577 THREADED_TEST(UndefinedIsNotEnumerable) {
2578   LocalContext env;
2579   v8::HandleScope scope(env->GetIsolate());
2580   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2581   CHECK(result->IsFalse());
2582 }
2583
2584
2585 v8::Handle<Script> call_recursively_script;
2586 static const int kTargetRecursionDepth = 200;  // near maximum
2587
2588
2589 static void CallScriptRecursivelyCall(
2590     const v8::FunctionCallbackInfo<v8::Value>& args) {
2591   ApiTestFuzzer::Fuzz();
2592   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2593   if (depth == kTargetRecursionDepth) return;
2594   args.This()->Set(v8_str("depth"),
2595                    v8::Integer::New(args.GetIsolate(), depth + 1));
2596   args.GetReturnValue().Set(call_recursively_script->Run());
2597 }
2598
2599
2600 static void CallFunctionRecursivelyCall(
2601     const v8::FunctionCallbackInfo<v8::Value>& args) {
2602   ApiTestFuzzer::Fuzz();
2603   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2604   if (depth == kTargetRecursionDepth) {
2605     printf("[depth = %d]\n", depth);
2606     return;
2607   }
2608   args.This()->Set(v8_str("depth"),
2609                    v8::Integer::New(args.GetIsolate(), depth + 1));
2610   v8::Handle<Value> function =
2611       args.This()->Get(v8_str("callFunctionRecursively"));
2612   args.GetReturnValue().Set(
2613       function.As<Function>()->Call(args.This(), 0, NULL));
2614 }
2615
2616
2617 THREADED_TEST(DeepCrossLanguageRecursion) {
2618   v8::Isolate* isolate = CcTest::isolate();
2619   v8::HandleScope scope(isolate);
2620   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2621   global->Set(v8_str("callScriptRecursively"),
2622               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2623   global->Set(v8_str("callFunctionRecursively"),
2624               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2625   LocalContext env(NULL, global);
2626
2627   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2628   call_recursively_script = v8_compile("callScriptRecursively()");
2629   call_recursively_script->Run();
2630   call_recursively_script = v8::Handle<Script>();
2631
2632   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2633   CompileRun("callFunctionRecursively()");
2634 }
2635
2636
2637 static void ThrowingPropertyHandlerGet(
2638     Local<String> key,
2639     const v8::PropertyCallbackInfo<v8::Value>& info) {
2640   ApiTestFuzzer::Fuzz();
2641   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2642 }
2643
2644
2645 static void ThrowingPropertyHandlerSet(
2646     Local<String> key,
2647     Local<Value>,
2648     const v8::PropertyCallbackInfo<v8::Value>& info) {
2649   info.GetIsolate()->ThrowException(key);
2650   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2651 }
2652
2653
2654 THREADED_TEST(CallbackExceptionRegression) {
2655   v8::Isolate* isolate = CcTest::isolate();
2656   v8::HandleScope scope(isolate);
2657   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2658   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2659                                ThrowingPropertyHandlerSet);
2660   LocalContext env;
2661   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2662   v8::Handle<Value> otto = CompileRun(
2663       "try { with (obj) { otto; } } catch (e) { e; }");
2664   CHECK_EQ(v8_str("otto"), otto);
2665   v8::Handle<Value> netto = CompileRun(
2666       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2667   CHECK_EQ(v8_str("netto"), netto);
2668 }
2669
2670
2671 THREADED_TEST(FunctionPrototype) {
2672   v8::Isolate* isolate = CcTest::isolate();
2673   v8::HandleScope scope(isolate);
2674   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2675   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2676   LocalContext env;
2677   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2678   Local<Script> script = v8_compile("Foo.prototype.plak");
2679   CHECK_EQ(script->Run()->Int32Value(), 321);
2680 }
2681
2682
2683 THREADED_TEST(InternalFields) {
2684   LocalContext env;
2685   v8::Isolate* isolate = env->GetIsolate();
2686   v8::HandleScope scope(isolate);
2687
2688   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2689   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2690   instance_templ->SetInternalFieldCount(1);
2691   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2692   CHECK_EQ(1, obj->InternalFieldCount());
2693   CHECK(obj->GetInternalField(0)->IsUndefined());
2694   obj->SetInternalField(0, v8_num(17));
2695   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2696 }
2697
2698
2699 THREADED_TEST(GlobalObjectInternalFields) {
2700   v8::Isolate* isolate = CcTest::isolate();
2701   v8::HandleScope scope(isolate);
2702   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2703   global_template->SetInternalFieldCount(1);
2704   LocalContext env(NULL, global_template);
2705   v8::Handle<v8::Object> global_proxy = env->Global();
2706   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2707   CHECK_EQ(1, global->InternalFieldCount());
2708   CHECK(global->GetInternalField(0)->IsUndefined());
2709   global->SetInternalField(0, v8_num(17));
2710   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2711 }
2712
2713
2714 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2715   LocalContext env;
2716   v8::HandleScope scope(CcTest::isolate());
2717
2718   v8::Local<v8::Object> global = env->Global();
2719   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2720   CHECK(global->HasRealIndexedProperty(0));
2721 }
2722
2723
2724 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2725                                                void* value) {
2726   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2727   obj->SetAlignedPointerInInternalField(0, value);
2728   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2729   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2730 }
2731
2732
2733 THREADED_TEST(InternalFieldsAlignedPointers) {
2734   LocalContext env;
2735   v8::Isolate* isolate = env->GetIsolate();
2736   v8::HandleScope scope(isolate);
2737
2738   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2739   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2740   instance_templ->SetInternalFieldCount(1);
2741   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2742   CHECK_EQ(1, obj->InternalFieldCount());
2743
2744   CheckAlignedPointerInInternalField(obj, NULL);
2745
2746   int* heap_allocated = new int[100];
2747   CheckAlignedPointerInInternalField(obj, heap_allocated);
2748   delete[] heap_allocated;
2749
2750   int stack_allocated[100];
2751   CheckAlignedPointerInInternalField(obj, stack_allocated);
2752
2753   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2754   CheckAlignedPointerInInternalField(obj, huge);
2755
2756   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2757   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2758   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2759 }
2760
2761
2762 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2763                                               int index,
2764                                               void* value) {
2765   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2766   (*env)->SetAlignedPointerInEmbedderData(index, value);
2767   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2768   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2769 }
2770
2771
2772 static void* AlignedTestPointer(int i) {
2773   return reinterpret_cast<void*>(i * 1234);
2774 }
2775
2776
2777 THREADED_TEST(EmbedderDataAlignedPointers) {
2778   LocalContext env;
2779   v8::HandleScope scope(env->GetIsolate());
2780
2781   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2782
2783   int* heap_allocated = new int[100];
2784   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2785   delete[] heap_allocated;
2786
2787   int stack_allocated[100];
2788   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2789
2790   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2791   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2792
2793   // Test growing of the embedder data's backing store.
2794   for (int i = 0; i < 100; i++) {
2795     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2796   }
2797   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2798   for (int i = 0; i < 100; i++) {
2799     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2800   }
2801 }
2802
2803
2804 static void CheckEmbedderData(LocalContext* env,
2805                               int index,
2806                               v8::Handle<Value> data) {
2807   (*env)->SetEmbedderData(index, data);
2808   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2809 }
2810
2811
2812 THREADED_TEST(EmbedderData) {
2813   LocalContext env;
2814   v8::Isolate* isolate = env->GetIsolate();
2815   v8::HandleScope scope(isolate);
2816
2817   CheckEmbedderData(
2818       &env, 3,
2819       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2820   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2821                                                      "over the lazy dog."));
2822   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2823   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2824 }
2825
2826
2827 THREADED_TEST(IdentityHash) {
2828   LocalContext env;
2829   v8::Isolate* isolate = env->GetIsolate();
2830   v8::HandleScope scope(isolate);
2831
2832   // Ensure that the test starts with an fresh heap to test whether the hash
2833   // code is based on the address.
2834   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2835   Local<v8::Object> obj = v8::Object::New(isolate);
2836   int hash = obj->GetIdentityHash();
2837   int hash1 = obj->GetIdentityHash();
2838   CHECK_EQ(hash, hash1);
2839   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2840   // Since the identity hash is essentially a random number two consecutive
2841   // objects should not be assigned the same hash code. If the test below fails
2842   // the random number generator should be evaluated.
2843   CHECK_NE(hash, hash2);
2844   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2845   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2846   // Make sure that the identity hash is not based on the initial address of
2847   // the object alone. If the test below fails the random number generator
2848   // should be evaluated.
2849   CHECK_NE(hash, hash3);
2850   int hash4 = obj->GetIdentityHash();
2851   CHECK_EQ(hash, hash4);
2852
2853   // Check identity hashes behaviour in the presence of JS accessors.
2854   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2855   {
2856     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2857     Local<v8::Object> o1 = v8::Object::New(isolate);
2858     Local<v8::Object> o2 = v8::Object::New(isolate);
2859     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2860   }
2861   {
2862     CompileRun(
2863         "function cnst() { return 42; };\n"
2864         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2865     Local<v8::Object> o1 = v8::Object::New(isolate);
2866     Local<v8::Object> o2 = v8::Object::New(isolate);
2867     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2868   }
2869 }
2870
2871
2872 THREADED_TEST(GlobalProxyIdentityHash) {
2873   LocalContext env;
2874   v8::Isolate* isolate = env->GetIsolate();
2875   v8::HandleScope scope(isolate);
2876   Handle<Object> global_proxy = env->Global();
2877   int hash1 = global_proxy->GetIdentityHash();
2878   // Hash should be retained after being detached.
2879   env->DetachGlobal();
2880   int hash2 = global_proxy->GetIdentityHash();
2881   CHECK_EQ(hash1, hash2);
2882   {
2883     // Re-attach global proxy to a new context, hash should stay the same.
2884     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2885     int hash3 = global_proxy->GetIdentityHash();
2886     CHECK_EQ(hash1, hash3);
2887   }
2888 }
2889
2890
2891 THREADED_TEST(SymbolProperties) {
2892   LocalContext env;
2893   v8::Isolate* isolate = env->GetIsolate();
2894   v8::HandleScope scope(isolate);
2895
2896   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2897   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2898   v8::Local<v8::Symbol> sym2 =
2899       v8::Symbol::New(isolate, v8_str("my-symbol"));
2900   v8::Local<v8::Symbol> sym3 =
2901       v8::Symbol::New(isolate, v8_str("sym3"));
2902
2903   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2904
2905   // Check basic symbol functionality.
2906   CHECK(sym1->IsSymbol());
2907   CHECK(sym2->IsSymbol());
2908   CHECK(!obj->IsSymbol());
2909
2910   CHECK(sym1->Equals(sym1));
2911   CHECK(sym2->Equals(sym2));
2912   CHECK(!sym1->Equals(sym2));
2913   CHECK(!sym2->Equals(sym1));
2914   CHECK(sym1->StrictEquals(sym1));
2915   CHECK(sym2->StrictEquals(sym2));
2916   CHECK(!sym1->StrictEquals(sym2));
2917   CHECK(!sym2->StrictEquals(sym1));
2918
2919   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2920
2921   v8::Local<v8::Value> sym_val = sym2;
2922   CHECK(sym_val->IsSymbol());
2923   CHECK(sym_val->Equals(sym2));
2924   CHECK(sym_val->StrictEquals(sym2));
2925   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2926
2927   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2928   CHECK(sym_obj->IsSymbolObject());
2929   CHECK(!sym2->IsSymbolObject());
2930   CHECK(!obj->IsSymbolObject());
2931   CHECK(!sym_obj->Equals(sym2));
2932   CHECK(!sym_obj->StrictEquals(sym2));
2933   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2934   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2935
2936   // Make sure delete of a non-existent symbol property works.
2937   CHECK(obj->Delete(sym1));
2938   CHECK(!obj->Has(sym1));
2939
2940   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2941   CHECK(obj->Has(sym1));
2942   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2943   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2944   CHECK(obj->Has(sym1));
2945   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2946   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2947
2948   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2949   int num_props = obj->GetPropertyNames()->Length();
2950   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2951                  v8::Integer::New(isolate, 20)));
2952   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2953   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2954
2955   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2956
2957   CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2958   CHECK(obj->Get(sym3)->IsUndefined());
2959   CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2960   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2961   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2962       v8::Integer::New(isolate, 42)));
2963
2964   // Add another property and delete it afterwards to force the object in
2965   // slow case.
2966   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2967   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2968   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2969   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2970   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2971
2972   CHECK(obj->Has(sym1));
2973   CHECK(obj->Has(sym2));
2974   CHECK(obj->Has(sym3));
2975   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2976   CHECK(obj->Delete(sym2));
2977   CHECK(obj->Has(sym1));
2978   CHECK(!obj->Has(sym2));
2979   CHECK(obj->Has(sym3));
2980   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2981   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2982   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2983   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2984       v8::Integer::New(isolate, 42)));
2985   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2986
2987   // Symbol properties are inherited.
2988   v8::Local<v8::Object> child = v8::Object::New(isolate);
2989   child->SetPrototype(obj);
2990   CHECK(child->Has(sym1));
2991   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2992   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2993   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2994       v8::Integer::New(isolate, 42)));
2995   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2996 }
2997
2998
2999 THREADED_TEST(SymbolTemplateProperties) {
3000   LocalContext env;
3001   v8::Isolate* isolate = env->GetIsolate();
3002   v8::HandleScope scope(isolate);
3003   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3004   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3005   CHECK(!name.IsEmpty());
3006   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3007   v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3008   CHECK(!new_instance.IsEmpty());
3009   CHECK(new_instance->Has(name));
3010 }
3011
3012
3013 THREADED_TEST(PrivateProperties) {
3014   LocalContext env;
3015   v8::Isolate* isolate = env->GetIsolate();
3016   v8::HandleScope scope(isolate);
3017
3018   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3019   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3020   v8::Local<v8::Private> priv2 =
3021       v8::Private::New(isolate, v8_str("my-private"));
3022
3023   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3024
3025   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3026
3027   // Make sure delete of a non-existent private symbol property works.
3028   CHECK(obj->DeletePrivate(priv1));
3029   CHECK(!obj->HasPrivate(priv1));
3030
3031   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3032   CHECK(obj->HasPrivate(priv1));
3033   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3034   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3035   CHECK(obj->HasPrivate(priv1));
3036   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3037
3038   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3039   int num_props = obj->GetPropertyNames()->Length();
3040   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3041                  v8::Integer::New(isolate, 20)));
3042   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3043   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3044
3045   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3046
3047   // Add another property and delete it afterwards to force the object in
3048   // slow case.
3049   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3050   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3051   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3052   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3053   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3054
3055   CHECK(obj->HasPrivate(priv1));
3056   CHECK(obj->HasPrivate(priv2));
3057   CHECK(obj->DeletePrivate(priv2));
3058   CHECK(obj->HasPrivate(priv1));
3059   CHECK(!obj->HasPrivate(priv2));
3060   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3061   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3062
3063   // Private properties are inherited (for the time being).
3064   v8::Local<v8::Object> child = v8::Object::New(isolate);
3065   child->SetPrototype(obj);
3066   CHECK(child->HasPrivate(priv1));
3067   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3068   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3069 }
3070
3071
3072 THREADED_TEST(GlobalSymbols) {
3073   LocalContext env;
3074   v8::Isolate* isolate = env->GetIsolate();
3075   v8::HandleScope scope(isolate);
3076
3077   v8::Local<String> name = v8_str("my-symbol");
3078   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3079   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3080   CHECK(glob2->SameValue(glob));
3081
3082   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3083   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3084   CHECK(glob_api2->SameValue(glob_api));
3085   CHECK(!glob_api->SameValue(glob));
3086
3087   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3088   CHECK(!sym->SameValue(glob));
3089
3090   CompileRun("var sym2 = Symbol.for('my-symbol')");
3091   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3092   CHECK(sym2->SameValue(glob));
3093   CHECK(!sym2->SameValue(glob_api));
3094 }
3095
3096
3097 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3098                                  const char* name) {
3099   LocalContext env;
3100   v8::Isolate* isolate = env->GetIsolate();
3101   v8::HandleScope scope(isolate);
3102
3103   v8::Local<v8::Symbol> symbol = getter(isolate);
3104   std::string script = std::string("var sym = ") + name;
3105   CompileRun(script.c_str());
3106   v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3107
3108   CHECK(!value.IsEmpty());
3109   CHECK(!symbol.IsEmpty());
3110   CHECK(value->SameValue(symbol));
3111 }
3112
3113
3114 THREADED_TEST(WellKnownSymbols) {
3115   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3116   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3117 }
3118
3119
3120 THREADED_TEST(GlobalPrivates) {
3121   LocalContext env;
3122   v8::Isolate* isolate = env->GetIsolate();
3123   v8::HandleScope scope(isolate);
3124
3125   v8::Local<String> name = v8_str("my-private");
3126   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3127   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3128   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3129
3130   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3131   CHECK(obj->HasPrivate(glob2));
3132
3133   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3134   CHECK(!obj->HasPrivate(priv));
3135
3136   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3137   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3138   CHECK(!obj->Has(intern));
3139 }
3140
3141
3142 class ScopedArrayBufferContents {
3143  public:
3144   explicit ScopedArrayBufferContents(
3145       const v8::ArrayBuffer::Contents& contents)
3146     : contents_(contents) {}
3147   ~ScopedArrayBufferContents() { free(contents_.Data()); }
3148   void* Data() const { return contents_.Data(); }
3149   size_t ByteLength() const { return contents_.ByteLength(); }
3150  private:
3151   const v8::ArrayBuffer::Contents contents_;
3152 };
3153
3154 template <typename T>
3155 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3156   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3157   for (int i = 0; i < value->InternalFieldCount(); i++) {
3158     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3159   }
3160 }
3161
3162
3163 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3164   LocalContext env;
3165   v8::Isolate* isolate = env->GetIsolate();
3166   v8::HandleScope handle_scope(isolate);
3167
3168   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3169   CheckInternalFieldsAreZero(ab);
3170   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3171   CHECK(!ab->IsExternal());
3172   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3173
3174   ScopedArrayBufferContents ab_contents(ab->Externalize());
3175   CHECK(ab->IsExternal());
3176
3177   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3178   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3179   DCHECK(data != NULL);
3180   env->Global()->Set(v8_str("ab"), ab);
3181
3182   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3183   CHECK_EQ(1024, result->Int32Value());
3184
3185   result = CompileRun("var u8 = new Uint8Array(ab);"
3186                       "u8[0] = 0xFF;"
3187                       "u8[1] = 0xAA;"
3188                       "u8.length");
3189   CHECK_EQ(1024, result->Int32Value());
3190   CHECK_EQ(0xFF, data[0]);
3191   CHECK_EQ(0xAA, data[1]);
3192   data[0] = 0xCC;
3193   data[1] = 0x11;
3194   result = CompileRun("u8[0] + u8[1]");
3195   CHECK_EQ(0xDD, result->Int32Value());
3196 }
3197
3198
3199 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3200   LocalContext env;
3201   v8::Isolate* isolate = env->GetIsolate();
3202   v8::HandleScope handle_scope(isolate);
3203
3204
3205   v8::Local<v8::Value> result =
3206       CompileRun("var ab1 = new ArrayBuffer(2);"
3207                  "var u8_a = new Uint8Array(ab1);"
3208                  "u8_a[0] = 0xAA;"
3209                  "u8_a[1] = 0xFF; u8_a.buffer");
3210   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3211   CheckInternalFieldsAreZero(ab1);
3212   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3213   CHECK(!ab1->IsExternal());
3214   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3215   CHECK(ab1->IsExternal());
3216
3217   result = CompileRun("ab1.byteLength");
3218   CHECK_EQ(2, result->Int32Value());
3219   result = CompileRun("u8_a[0]");
3220   CHECK_EQ(0xAA, result->Int32Value());
3221   result = CompileRun("u8_a[1]");
3222   CHECK_EQ(0xFF, result->Int32Value());
3223   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3224                       "u8_b[0] = 0xBB;"
3225                       "u8_a[0]");
3226   CHECK_EQ(0xBB, result->Int32Value());
3227   result = CompileRun("u8_b[1]");
3228   CHECK_EQ(0xFF, result->Int32Value());
3229
3230   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3231   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3232   CHECK_EQ(0xBB, ab1_data[0]);
3233   CHECK_EQ(0xFF, ab1_data[1]);
3234   ab1_data[0] = 0xCC;
3235   ab1_data[1] = 0x11;
3236   result = CompileRun("u8_a[0] + u8_a[1]");
3237   CHECK_EQ(0xDD, result->Int32Value());
3238 }
3239
3240
3241 THREADED_TEST(ArrayBuffer_External) {
3242   LocalContext env;
3243   v8::Isolate* isolate = env->GetIsolate();
3244   v8::HandleScope handle_scope(isolate);
3245
3246   i::ScopedVector<uint8_t> my_data(100);
3247   memset(my_data.start(), 0, 100);
3248   Local<v8::ArrayBuffer> ab3 =
3249       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3250   CheckInternalFieldsAreZero(ab3);
3251   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3252   CHECK(ab3->IsExternal());
3253
3254   env->Global()->Set(v8_str("ab3"), ab3);
3255
3256   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3257   CHECK_EQ(100, result->Int32Value());
3258
3259   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3260                       "u8_b[0] = 0xBB;"
3261                       "u8_b[1] = 0xCC;"
3262                       "u8_b.length");
3263   CHECK_EQ(100, result->Int32Value());
3264   CHECK_EQ(0xBB, my_data[0]);
3265   CHECK_EQ(0xCC, my_data[1]);
3266   my_data[0] = 0xCC;
3267   my_data[1] = 0x11;
3268   result = CompileRun("u8_b[0] + u8_b[1]");
3269   CHECK_EQ(0xDD, result->Int32Value());
3270 }
3271
3272
3273 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3274   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3275   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3276 }
3277
3278
3279 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3280   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3281   CHECK_EQ(0, static_cast<int>(ta->Length()));
3282   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3283 }
3284
3285
3286 static void CheckIsTypedArrayVarNeutered(const char* name) {
3287   i::ScopedVector<char> source(1024);
3288   i::SNPrintF(source,
3289       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3290       name, name, name);
3291   CHECK(CompileRun(source.start())->IsTrue());
3292   v8::Handle<v8::TypedArray> ta =
3293     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3294   CheckIsNeutered(ta);
3295 }
3296
3297
3298 template <typename TypedArray, int kElementSize>
3299 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3300                                          int byteOffset,
3301                                          int length) {
3302   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3303   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3304   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3305   CHECK_EQ(length, static_cast<int>(ta->Length()));
3306   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3307   return ta;
3308 }
3309
3310
3311 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3312   LocalContext env;
3313   v8::Isolate* isolate = env->GetIsolate();
3314   v8::HandleScope handle_scope(isolate);
3315
3316   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3317
3318   v8::Handle<v8::Uint8Array> u8a =
3319     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3320   v8::Handle<v8::Uint8ClampedArray> u8c =
3321     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3322   v8::Handle<v8::Int8Array> i8a =
3323     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3324
3325   v8::Handle<v8::Uint16Array> u16a =
3326     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3327   v8::Handle<v8::Int16Array> i16a =
3328     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3329
3330   v8::Handle<v8::Uint32Array> u32a =
3331     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3332   v8::Handle<v8::Int32Array> i32a =
3333     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3334
3335   v8::Handle<v8::Float32Array> f32a =
3336     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3337   v8::Handle<v8::Float64Array> f64a =
3338     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3339
3340   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3341   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3342   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3343   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3344
3345   ScopedArrayBufferContents contents(buffer->Externalize());
3346   buffer->Neuter();
3347   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3348   CheckIsNeutered(u8a);
3349   CheckIsNeutered(u8c);
3350   CheckIsNeutered(i8a);
3351   CheckIsNeutered(u16a);
3352   CheckIsNeutered(i16a);
3353   CheckIsNeutered(u32a);
3354   CheckIsNeutered(i32a);
3355   CheckIsNeutered(f32a);
3356   CheckIsNeutered(f64a);
3357   CheckDataViewIsNeutered(dv);
3358 }
3359
3360
3361 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3362   LocalContext env;
3363   v8::Isolate* isolate = env->GetIsolate();
3364   v8::HandleScope handle_scope(isolate);
3365
3366   CompileRun(
3367       "var ab = new ArrayBuffer(1024);"
3368       "var u8a = new Uint8Array(ab, 1, 1023);"
3369       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3370       "var i8a = new Int8Array(ab, 1, 1023);"
3371       "var u16a = new Uint16Array(ab, 2, 511);"
3372       "var i16a = new Int16Array(ab, 2, 511);"
3373       "var u32a = new Uint32Array(ab, 4, 255);"
3374       "var i32a = new Int32Array(ab, 4, 255);"
3375       "var f32a = new Float32Array(ab, 4, 255);"
3376       "var f64a = new Float64Array(ab, 8, 127);"
3377       "var dv = new DataView(ab, 1, 1023);");
3378
3379   v8::Handle<v8::ArrayBuffer> ab =
3380       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3381
3382   v8::Handle<v8::DataView> dv =
3383     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3384
3385   ScopedArrayBufferContents contents(ab->Externalize());
3386   ab->Neuter();
3387   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3388   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3389
3390   CheckIsTypedArrayVarNeutered("u8a");
3391   CheckIsTypedArrayVarNeutered("u8c");
3392   CheckIsTypedArrayVarNeutered("i8a");
3393   CheckIsTypedArrayVarNeutered("u16a");
3394   CheckIsTypedArrayVarNeutered("i16a");
3395   CheckIsTypedArrayVarNeutered("u32a");
3396   CheckIsTypedArrayVarNeutered("i32a");
3397   CheckIsTypedArrayVarNeutered("f32a");
3398   CheckIsTypedArrayVarNeutered("f64a");
3399
3400   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3401   CheckDataViewIsNeutered(dv);
3402 }
3403
3404
3405
3406 THREADED_TEST(HiddenProperties) {
3407   LocalContext env;
3408   v8::Isolate* isolate = env->GetIsolate();
3409   v8::HandleScope scope(isolate);
3410
3411   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3412   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3413   v8::Local<v8::String> empty = v8_str("");
3414   v8::Local<v8::String> prop_name = v8_str("prop_name");
3415
3416   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3417
3418   // Make sure delete of a non-existent hidden value works
3419   CHECK(obj->DeleteHiddenValue(key));
3420
3421   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3422   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3423   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3424   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3425
3426   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3427
3428   // Make sure we do not find the hidden property.
3429   CHECK(!obj->Has(empty));
3430   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3431   CHECK(obj->Get(empty)->IsUndefined());
3432   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3433   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3434   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3435   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3436
3437   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3438
3439   // Add another property and delete it afterwards to force the object in
3440   // slow case.
3441   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3442   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3443   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3444   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3445   CHECK(obj->Delete(prop_name));
3446   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3447
3448   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3449
3450   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3451   CHECK(obj->GetHiddenValue(key).IsEmpty());
3452
3453   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3454   CHECK(obj->DeleteHiddenValue(key));
3455   CHECK(obj->GetHiddenValue(key).IsEmpty());
3456 }
3457
3458
3459 THREADED_TEST(Regress97784) {
3460   // Regression test for crbug.com/97784
3461   // Messing with the Object.prototype should not have effect on
3462   // hidden properties.
3463   LocalContext env;
3464   v8::HandleScope scope(env->GetIsolate());
3465
3466   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3467   v8::Local<v8::String> key = v8_str("hidden");
3468
3469   CompileRun(
3470       "set_called = false;"
3471       "Object.defineProperty("
3472       "    Object.prototype,"
3473       "    'hidden',"
3474       "    {get: function() { return 45; },"
3475       "     set: function() { set_called = true; }})");
3476
3477   CHECK(obj->GetHiddenValue(key).IsEmpty());
3478   // Make sure that the getter and setter from Object.prototype is not invoked.
3479   // If it did we would have full access to the hidden properties in
3480   // the accessor.
3481   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3482   ExpectFalse("set_called");
3483   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3484 }
3485
3486
3487 static bool interceptor_for_hidden_properties_called;
3488 static void InterceptorForHiddenProperties(
3489     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3490   interceptor_for_hidden_properties_called = true;
3491 }
3492
3493
3494 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3495   LocalContext context;
3496   v8::Isolate* isolate = context->GetIsolate();
3497   v8::HandleScope scope(isolate);
3498
3499   interceptor_for_hidden_properties_called = false;
3500
3501   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3502
3503   // Associate an interceptor with an object and start setting hidden values.
3504   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3505   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3506   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3507   Local<v8::Function> function = fun_templ->GetFunction();
3508   Local<v8::Object> obj = function->NewInstance();
3509   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3510   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3511   CHECK(!interceptor_for_hidden_properties_called);
3512 }
3513
3514
3515 THREADED_TEST(External) {
3516   v8::HandleScope scope(CcTest::isolate());
3517   int x = 3;
3518   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3519   LocalContext env;
3520   env->Global()->Set(v8_str("ext"), ext);
3521   Local<Value> reext_obj = CompileRun("this.ext");
3522   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3523   int* ptr = static_cast<int*>(reext->Value());
3524   CHECK_EQ(x, 3);
3525   *ptr = 10;
3526   CHECK_EQ(x, 10);
3527
3528   // Make sure unaligned pointers are wrapped properly.
3529   char* data = i::StrDup("0123456789");
3530   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3531   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3532   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3533   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3534
3535   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3536   CHECK_EQ('0', *char_ptr);
3537   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3538   CHECK_EQ('1', *char_ptr);
3539   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3540   CHECK_EQ('2', *char_ptr);
3541   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3542   CHECK_EQ('3', *char_ptr);
3543   i::DeleteArray(data);
3544 }
3545
3546
3547 THREADED_TEST(GlobalHandle) {
3548   v8::Isolate* isolate = CcTest::isolate();
3549   v8::Persistent<String> global;
3550   {
3551     v8::HandleScope scope(isolate);
3552     global.Reset(isolate, v8_str("str"));
3553   }
3554   {
3555     v8::HandleScope scope(isolate);
3556     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3557   }
3558   global.Reset();
3559   {
3560     v8::HandleScope scope(isolate);
3561     global.Reset(isolate, v8_str("str"));
3562   }
3563   {
3564     v8::HandleScope scope(isolate);
3565     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3566   }
3567   global.Reset();
3568 }
3569
3570
3571 THREADED_TEST(ResettingGlobalHandle) {
3572   v8::Isolate* isolate = CcTest::isolate();
3573   v8::Persistent<String> global;
3574   {
3575     v8::HandleScope scope(isolate);
3576     global.Reset(isolate, v8_str("str"));
3577   }
3578   v8::internal::GlobalHandles* global_handles =
3579       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3580   int initial_handle_count = global_handles->global_handles_count();
3581   {
3582     v8::HandleScope scope(isolate);
3583     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3584   }
3585   {
3586     v8::HandleScope scope(isolate);
3587     global.Reset(isolate, v8_str("longer"));
3588   }
3589   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3590   {
3591     v8::HandleScope scope(isolate);
3592     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3593   }
3594   global.Reset();
3595   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3596 }
3597
3598
3599 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3600   v8::Isolate* isolate = CcTest::isolate();
3601   v8::Persistent<String> global;
3602   {
3603     v8::HandleScope scope(isolate);
3604     global.Reset(isolate, v8_str("str"));
3605   }
3606   v8::internal::GlobalHandles* global_handles =
3607       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3608   int initial_handle_count = global_handles->global_handles_count();
3609   {
3610     v8::HandleScope scope(isolate);
3611     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3612   }
3613   {
3614     v8::HandleScope scope(isolate);
3615     Local<String> empty;
3616     global.Reset(isolate, empty);
3617   }
3618   CHECK(global.IsEmpty());
3619   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3620 }
3621
3622
3623 template<class T>
3624 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3625   return unique.Pass();
3626 }
3627
3628
3629 template<class T>
3630 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3631                                             const v8::Persistent<T> & global) {
3632   v8::UniquePersistent<String> unique(isolate, global);
3633   return unique.Pass();
3634 }
3635
3636
3637 THREADED_TEST(UniquePersistent) {
3638   v8::Isolate* isolate = CcTest::isolate();
3639   v8::Persistent<String> global;
3640   {
3641     v8::HandleScope scope(isolate);
3642     global.Reset(isolate, v8_str("str"));
3643   }
3644   v8::internal::GlobalHandles* global_handles =
3645       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3646   int initial_handle_count = global_handles->global_handles_count();
3647   {
3648     v8::UniquePersistent<String> unique(isolate, global);
3649     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3650     // Test assignment via Pass
3651     {
3652       v8::UniquePersistent<String> copy = unique.Pass();
3653       CHECK(unique.IsEmpty());
3654       CHECK(copy == global);
3655       CHECK_EQ(initial_handle_count + 1,
3656                global_handles->global_handles_count());
3657       unique = copy.Pass();
3658     }
3659     // Test ctor via Pass
3660     {
3661       v8::UniquePersistent<String> copy(unique.Pass());
3662       CHECK(unique.IsEmpty());
3663       CHECK(copy == global);
3664       CHECK_EQ(initial_handle_count + 1,
3665                global_handles->global_handles_count());
3666       unique = copy.Pass();
3667     }
3668     // Test pass through function call
3669     {
3670       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3671       CHECK(unique.IsEmpty());
3672       CHECK(copy == global);
3673       CHECK_EQ(initial_handle_count + 1,
3674                global_handles->global_handles_count());
3675       unique = copy.Pass();
3676     }
3677     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3678   }
3679   // Test pass from function call
3680   {
3681     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3682     CHECK(unique == global);
3683     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3684   }
3685   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3686   global.Reset();
3687 }
3688
3689
3690 template<typename K, typename V>
3691 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3692  public:
3693   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3694       MapType;
3695   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3696   struct WeakCallbackDataType {
3697     MapType* map;
3698     K key;
3699   };
3700   static WeakCallbackDataType* WeakCallbackParameter(
3701       MapType* map, const K& key, Local<V> value) {
3702     WeakCallbackDataType* data = new WeakCallbackDataType;
3703     data->map = map;
3704     data->key = key;
3705     return data;
3706   }
3707   static MapType* MapFromWeakCallbackData(
3708       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3709     return data.GetParameter()->map;
3710   }
3711   static K KeyFromWeakCallbackData(
3712       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3713     return data.GetParameter()->key;
3714   }
3715   static void DisposeCallbackData(WeakCallbackDataType* data) {
3716     delete data;
3717   }
3718   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3719       K key) { }
3720 };
3721
3722
3723 template<typename Map>
3724 static void TestPersistentValueMap() {
3725   LocalContext env;
3726   v8::Isolate* isolate = env->GetIsolate();
3727   Map map(isolate);
3728   v8::internal::GlobalHandles* global_handles =
3729       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3730   int initial_handle_count = global_handles->global_handles_count();
3731   CHECK_EQ(0, static_cast<int>(map.Size()));
3732   {
3733     HandleScope scope(isolate);
3734     Local<v8::Object> obj = map.Get(7);
3735     CHECK(obj.IsEmpty());
3736     Local<v8::Object> expected = v8::Object::New(isolate);
3737     map.Set(7, expected);
3738     CHECK_EQ(1, static_cast<int>(map.Size()));
3739     obj = map.Get(7);
3740     CHECK_EQ(expected, obj);
3741     {
3742       typename Map::PersistentValueReference ref = map.GetReference(7);
3743       CHECK_EQ(expected, ref.NewLocal(isolate));
3744     }
3745     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3746     CHECK_EQ(0, static_cast<int>(map.Size()));
3747     CHECK(expected == removed);
3748     removed = map.Remove(7);
3749     CHECK(removed.IsEmpty());
3750     map.Set(8, expected);
3751     CHECK_EQ(1, static_cast<int>(map.Size()));
3752     map.Set(8, expected);
3753     CHECK_EQ(1, static_cast<int>(map.Size()));
3754     {
3755       typename Map::PersistentValueReference ref;
3756       Local<v8::Object> expected2 = v8::Object::New(isolate);
3757       removed = map.Set(8,
3758           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3759       CHECK_EQ(1, static_cast<int>(map.Size()));
3760       CHECK(expected == removed);
3761       CHECK_EQ(expected2, ref.NewLocal(isolate));
3762     }
3763   }
3764   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3765   if (map.IsWeak()) {
3766     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3767         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3768   } else {
3769     map.Clear();
3770   }
3771   CHECK_EQ(0, static_cast<int>(map.Size()));
3772   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3773 }
3774
3775
3776 TEST(PersistentValueMap) {
3777   // Default case, w/o weak callbacks:
3778   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3779
3780   // Custom traits with weak callbacks:
3781   typedef v8::PersistentValueMap<int, v8::Object,
3782       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3783   TestPersistentValueMap<WeakPersistentValueMap>();
3784 }
3785
3786
3787 TEST(PersistentValueVector) {
3788   LocalContext env;
3789   v8::Isolate* isolate = env->GetIsolate();
3790   v8::internal::GlobalHandles* global_handles =
3791       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3792   int handle_count = global_handles->global_handles_count();
3793   HandleScope scope(isolate);
3794
3795   v8::PersistentValueVector<v8::Object> vector(isolate);
3796
3797   Local<v8::Object> obj1 = v8::Object::New(isolate);
3798   Local<v8::Object> obj2 = v8::Object::New(isolate);
3799   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3800
3801   CHECK(vector.IsEmpty());
3802   CHECK_EQ(0, static_cast<int>(vector.Size()));
3803
3804   vector.ReserveCapacity(3);
3805   CHECK(vector.IsEmpty());
3806
3807   vector.Append(obj1);
3808   vector.Append(obj2);
3809   vector.Append(obj1);
3810   vector.Append(obj3.Pass());
3811   vector.Append(obj1);
3812
3813   CHECK(!vector.IsEmpty());
3814   CHECK_EQ(5, static_cast<int>(vector.Size()));
3815   CHECK(obj3.IsEmpty());
3816   CHECK_EQ(obj1, vector.Get(0));
3817   CHECK_EQ(obj1, vector.Get(2));
3818   CHECK_EQ(obj1, vector.Get(4));
3819   CHECK_EQ(obj2, vector.Get(1));
3820
3821   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3822
3823   vector.Clear();
3824   CHECK(vector.IsEmpty());
3825   CHECK_EQ(0, static_cast<int>(vector.Size()));
3826   CHECK_EQ(handle_count, global_handles->global_handles_count());
3827 }
3828
3829
3830 THREADED_TEST(GlobalHandleUpcast) {
3831   v8::Isolate* isolate = CcTest::isolate();
3832   v8::HandleScope scope(isolate);
3833   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3834   v8::Persistent<String> global_string(isolate, local);
3835   v8::Persistent<Value>& global_value =
3836       v8::Persistent<Value>::Cast(global_string);
3837   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3838   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3839   global_string.Reset();
3840 }
3841
3842
3843 THREADED_TEST(HandleEquality) {
3844   v8::Isolate* isolate = CcTest::isolate();
3845   v8::Persistent<String> global1;
3846   v8::Persistent<String> global2;
3847   {
3848     v8::HandleScope scope(isolate);
3849     global1.Reset(isolate, v8_str("str"));
3850     global2.Reset(isolate, v8_str("str2"));
3851   }
3852   CHECK_EQ(global1 == global1, true);
3853   CHECK_EQ(global1 != global1, false);
3854   {
3855     v8::HandleScope scope(isolate);
3856     Local<String> local1 = Local<String>::New(isolate, global1);
3857     Local<String> local2 = Local<String>::New(isolate, global2);
3858
3859     CHECK_EQ(global1 == local1, true);
3860     CHECK_EQ(global1 != local1, false);
3861     CHECK_EQ(local1 == global1, true);
3862     CHECK_EQ(local1 != global1, false);
3863
3864     CHECK_EQ(global1 == local2, false);
3865     CHECK_EQ(global1 != local2, true);
3866     CHECK_EQ(local2 == global1, false);
3867     CHECK_EQ(local2 != global1, true);
3868
3869     CHECK_EQ(local1 == local2, false);
3870     CHECK_EQ(local1 != local2, true);
3871
3872     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3873     CHECK_EQ(local1 == anotherLocal1, true);
3874     CHECK_EQ(local1 != anotherLocal1, false);
3875   }
3876   global1.Reset();
3877   global2.Reset();
3878 }
3879
3880
3881 THREADED_TEST(LocalHandle) {
3882   v8::HandleScope scope(CcTest::isolate());
3883   v8::Local<String> local =
3884       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3885   CHECK_EQ(local->Length(), 3);
3886 }
3887
3888
3889 class WeakCallCounter {
3890  public:
3891   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3892   int id() { return id_; }
3893   void increment() { number_of_weak_calls_++; }
3894   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3895  private:
3896   int id_;
3897   int number_of_weak_calls_;
3898 };
3899
3900
3901 template<typename T>
3902 struct WeakCallCounterAndPersistent {
3903   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3904       : counter(counter) {}
3905   WeakCallCounter* counter;
3906   v8::Persistent<T> handle;
3907 };
3908
3909
3910 template <typename T>
3911 static void WeakPointerCallback(
3912     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3913   CHECK_EQ(1234, data.GetParameter()->counter->id());
3914   data.GetParameter()->counter->increment();
3915   data.GetParameter()->handle.Reset();
3916 }
3917
3918
3919 template<typename T>
3920 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3921   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3922 }
3923
3924
3925 THREADED_TEST(ApiObjectGroups) {
3926   LocalContext env;
3927   v8::Isolate* iso = env->GetIsolate();
3928   HandleScope scope(iso);
3929
3930   WeakCallCounter counter(1234);
3931
3932   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3933   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3934   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3935   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3936   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3937   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3938
3939   {
3940     HandleScope scope(iso);
3941     g1s1.handle.Reset(iso, Object::New(iso));
3942     g1s2.handle.Reset(iso, Object::New(iso));
3943     g1c1.handle.Reset(iso, Object::New(iso));
3944     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3945     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3946     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3947
3948     g2s1.handle.Reset(iso, Object::New(iso));
3949     g2s2.handle.Reset(iso, Object::New(iso));
3950     g2c1.handle.Reset(iso, Object::New(iso));
3951     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3952     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3953     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3954   }
3955
3956   WeakCallCounterAndPersistent<Value> root(&counter);
3957   root.handle.Reset(iso, g1s1.handle);  // make a root.
3958
3959   // Connect group 1 and 2, make a cycle.
3960   {
3961     HandleScope scope(iso);
3962     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3963             Set(0, Local<Value>::New(iso, g2s2.handle)));
3964     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3965             Set(0, Local<Value>::New(iso, g1s1.handle)));
3966   }
3967
3968   {
3969     UniqueId id1 = MakeUniqueId(g1s1.handle);
3970     UniqueId id2 = MakeUniqueId(g2s2.handle);
3971     iso->SetObjectGroupId(g1s1.handle, id1);
3972     iso->SetObjectGroupId(g1s2.handle, id1);
3973     iso->SetReferenceFromGroup(id1, g1c1.handle);
3974     iso->SetObjectGroupId(g2s1.handle, id2);
3975     iso->SetObjectGroupId(g2s2.handle, id2);
3976     iso->SetReferenceFromGroup(id2, g2c1.handle);
3977   }
3978   // Do a single full GC, ensure incremental marking is stopped.
3979   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3980       iso)->heap();
3981   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3982
3983   // All object should be alive.
3984   CHECK_EQ(0, counter.NumberOfWeakCalls());
3985
3986   // Weaken the root.
3987   root.handle.SetWeak(&root, &WeakPointerCallback);
3988   // But make children strong roots---all the objects (except for children)
3989   // should be collectable now.
3990   g1c1.handle.ClearWeak();
3991   g2c1.handle.ClearWeak();
3992
3993   // Groups are deleted, rebuild groups.
3994   {
3995     UniqueId id1 = MakeUniqueId(g1s1.handle);
3996     UniqueId id2 = MakeUniqueId(g2s2.handle);
3997     iso->SetObjectGroupId(g1s1.handle, id1);
3998     iso->SetObjectGroupId(g1s2.handle, id1);
3999     iso->SetReferenceFromGroup(id1, g1c1.handle);
4000     iso->SetObjectGroupId(g2s1.handle, id2);
4001     iso->SetObjectGroupId(g2s2.handle, id2);
4002     iso->SetReferenceFromGroup(id2, g2c1.handle);
4003   }
4004
4005   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4006
4007   // All objects should be gone. 5 global handles in total.
4008   CHECK_EQ(5, counter.NumberOfWeakCalls());
4009
4010   // And now make children weak again and collect them.
4011   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4012   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4013
4014   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4015   CHECK_EQ(7, counter.NumberOfWeakCalls());
4016 }
4017
4018
4019 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4020   LocalContext env;
4021   v8::Isolate* iso = env->GetIsolate();
4022   HandleScope scope(iso);
4023
4024   WeakCallCounter counter(1234);
4025
4026   WeakCallCounterAndPersistent<Object> g1s1(&counter);
4027   WeakCallCounterAndPersistent<String> g1s2(&counter);
4028   WeakCallCounterAndPersistent<String> g1c1(&counter);
4029   WeakCallCounterAndPersistent<Object> g2s1(&counter);
4030   WeakCallCounterAndPersistent<String> g2s2(&counter);
4031   WeakCallCounterAndPersistent<String> g2c1(&counter);
4032
4033   {
4034     HandleScope scope(iso);
4035     g1s1.handle.Reset(iso, Object::New(iso));
4036     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4037     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4038     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4039     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4040     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4041
4042     g2s1.handle.Reset(iso, Object::New(iso));
4043     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4044     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4045     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4046     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4047     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4048   }
4049
4050   WeakCallCounterAndPersistent<Value> root(&counter);
4051   root.handle.Reset(iso, g1s1.handle);  // make a root.
4052
4053   // Connect group 1 and 2, make a cycle.
4054   {
4055     HandleScope scope(iso);
4056     CHECK(Local<Object>::New(iso, g1s1.handle)
4057               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4058     CHECK(Local<Object>::New(iso, g2s1.handle)
4059               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
4060   }
4061
4062   {
4063     UniqueId id1 = MakeUniqueId(g1s1.handle);
4064     UniqueId id2 = MakeUniqueId(g2s2.handle);
4065     iso->SetObjectGroupId(g1s1.handle, id1);
4066     iso->SetObjectGroupId(g1s2.handle, id1);
4067     iso->SetReference(g1s1.handle, g1c1.handle);
4068     iso->SetObjectGroupId(g2s1.handle, id2);
4069     iso->SetObjectGroupId(g2s2.handle, id2);
4070     iso->SetReferenceFromGroup(id2, g2c1.handle);
4071   }
4072   // Do a single full GC, ensure incremental marking is stopped.
4073   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4074       iso)->heap();
4075   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4076
4077   // All object should be alive.
4078   CHECK_EQ(0, counter.NumberOfWeakCalls());
4079
4080   // Weaken the root.
4081   root.handle.SetWeak(&root, &WeakPointerCallback);
4082   // But make children strong roots---all the objects (except for children)
4083   // should be collectable now.
4084   g1c1.handle.ClearWeak();
4085   g2c1.handle.ClearWeak();
4086
4087   // Groups are deleted, rebuild groups.
4088   {
4089     UniqueId id1 = MakeUniqueId(g1s1.handle);
4090     UniqueId id2 = MakeUniqueId(g2s2.handle);
4091     iso->SetObjectGroupId(g1s1.handle, id1);
4092     iso->SetObjectGroupId(g1s2.handle, id1);
4093     iso->SetReference(g1s1.handle, g1c1.handle);
4094     iso->SetObjectGroupId(g2s1.handle, id2);
4095     iso->SetObjectGroupId(g2s2.handle, id2);
4096     iso->SetReferenceFromGroup(id2, g2c1.handle);
4097   }
4098
4099   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4100
4101   // All objects should be gone. 5 global handles in total.
4102   CHECK_EQ(5, counter.NumberOfWeakCalls());
4103
4104   // And now make children weak again and collect them.
4105   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4106   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4107
4108   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4109   CHECK_EQ(7, counter.NumberOfWeakCalls());
4110 }
4111
4112
4113 THREADED_TEST(ApiObjectGroupsCycle) {
4114   LocalContext env;
4115   v8::Isolate* iso = env->GetIsolate();
4116   HandleScope scope(iso);
4117
4118   WeakCallCounter counter(1234);
4119
4120   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4121   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4122   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4123   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4124   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4125   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4126   WeakCallCounterAndPersistent<Value> g4s1(&counter);
4127   WeakCallCounterAndPersistent<Value> g4s2(&counter);
4128
4129   {
4130     HandleScope scope(iso);
4131     g1s1.handle.Reset(iso, Object::New(iso));
4132     g1s2.handle.Reset(iso, Object::New(iso));
4133     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4134     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4135     CHECK(g1s1.handle.IsWeak());
4136     CHECK(g1s2.handle.IsWeak());
4137
4138     g2s1.handle.Reset(iso, Object::New(iso));
4139     g2s2.handle.Reset(iso, Object::New(iso));
4140     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4141     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4142     CHECK(g2s1.handle.IsWeak());
4143     CHECK(g2s2.handle.IsWeak());
4144
4145     g3s1.handle.Reset(iso, Object::New(iso));
4146     g3s2.handle.Reset(iso, Object::New(iso));
4147     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4148     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4149     CHECK(g3s1.handle.IsWeak());
4150     CHECK(g3s2.handle.IsWeak());
4151
4152     g4s1.handle.Reset(iso, Object::New(iso));
4153     g4s2.handle.Reset(iso, Object::New(iso));
4154     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4155     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4156     CHECK(g4s1.handle.IsWeak());
4157     CHECK(g4s2.handle.IsWeak());
4158   }
4159
4160   WeakCallCounterAndPersistent<Value> root(&counter);
4161   root.handle.Reset(iso, g1s1.handle);  // make a root.
4162
4163   // Connect groups.  We're building the following cycle:
4164   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4165   // groups.
4166   {
4167     UniqueId id1 = MakeUniqueId(g1s1.handle);
4168     UniqueId id2 = MakeUniqueId(g2s1.handle);
4169     UniqueId id3 = MakeUniqueId(g3s1.handle);
4170     UniqueId id4 = MakeUniqueId(g4s1.handle);
4171     iso->SetObjectGroupId(g1s1.handle, id1);
4172     iso->SetObjectGroupId(g1s2.handle, id1);
4173     iso->SetReferenceFromGroup(id1, g2s1.handle);
4174     iso->SetObjectGroupId(g2s1.handle, id2);
4175     iso->SetObjectGroupId(g2s2.handle, id2);
4176     iso->SetReferenceFromGroup(id2, g3s1.handle);
4177     iso->SetObjectGroupId(g3s1.handle, id3);
4178     iso->SetObjectGroupId(g3s2.handle, id3);
4179     iso->SetReferenceFromGroup(id3, g4s1.handle);
4180     iso->SetObjectGroupId(g4s1.handle, id4);
4181     iso->SetObjectGroupId(g4s2.handle, id4);
4182     iso->SetReferenceFromGroup(id4, g1s1.handle);
4183   }
4184   // Do a single full GC
4185   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4186       iso)->heap();
4187   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4188
4189   // All object should be alive.
4190   CHECK_EQ(0, counter.NumberOfWeakCalls());
4191
4192   // Weaken the root.
4193   root.handle.SetWeak(&root, &WeakPointerCallback);
4194
4195   // Groups are deleted, rebuild groups.
4196   {
4197     UniqueId id1 = MakeUniqueId(g1s1.handle);
4198     UniqueId id2 = MakeUniqueId(g2s1.handle);
4199     UniqueId id3 = MakeUniqueId(g3s1.handle);
4200     UniqueId id4 = MakeUniqueId(g4s1.handle);
4201     iso->SetObjectGroupId(g1s1.handle, id1);
4202     iso->SetObjectGroupId(g1s2.handle, id1);
4203     iso->SetReferenceFromGroup(id1, g2s1.handle);
4204     iso->SetObjectGroupId(g2s1.handle, id2);
4205     iso->SetObjectGroupId(g2s2.handle, id2);
4206     iso->SetReferenceFromGroup(id2, g3s1.handle);
4207     iso->SetObjectGroupId(g3s1.handle, id3);
4208     iso->SetObjectGroupId(g3s2.handle, id3);
4209     iso->SetReferenceFromGroup(id3, g4s1.handle);
4210     iso->SetObjectGroupId(g4s1.handle, id4);
4211     iso->SetObjectGroupId(g4s2.handle, id4);
4212     iso->SetReferenceFromGroup(id4, g1s1.handle);
4213   }
4214
4215   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4216
4217   // All objects should be gone. 9 global handles in total.
4218   CHECK_EQ(9, counter.NumberOfWeakCalls());
4219 }
4220
4221
4222 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4223 // on the buildbots, so was made non-threaded for the time being.
4224 TEST(ApiObjectGroupsCycleForScavenger) {
4225   i::FLAG_stress_compaction = false;
4226   i::FLAG_gc_global = false;
4227   LocalContext env;
4228   v8::Isolate* iso = env->GetIsolate();
4229   HandleScope scope(iso);
4230
4231   WeakCallCounter counter(1234);
4232
4233   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4234   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4235   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4236   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4237   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4238   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4239
4240   {
4241     HandleScope scope(iso);
4242     g1s1.handle.Reset(iso, Object::New(iso));
4243     g1s2.handle.Reset(iso, Object::New(iso));
4244     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4245     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4246
4247     g2s1.handle.Reset(iso, Object::New(iso));
4248     g2s2.handle.Reset(iso, Object::New(iso));
4249     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4250     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4251
4252     g3s1.handle.Reset(iso, Object::New(iso));
4253     g3s2.handle.Reset(iso, Object::New(iso));
4254     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4255     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4256   }
4257
4258   // Make a root.
4259   WeakCallCounterAndPersistent<Value> root(&counter);
4260   root.handle.Reset(iso, g1s1.handle);
4261   root.handle.MarkPartiallyDependent();
4262
4263   // Connect groups.  We're building the following cycle:
4264   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4265   // groups.
4266   {
4267     HandleScope handle_scope(iso);
4268     g1s1.handle.MarkPartiallyDependent();
4269     g1s2.handle.MarkPartiallyDependent();
4270     g2s1.handle.MarkPartiallyDependent();
4271     g2s2.handle.MarkPartiallyDependent();
4272     g3s1.handle.MarkPartiallyDependent();
4273     g3s2.handle.MarkPartiallyDependent();
4274     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4275     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4276     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4277         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4278     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4279     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4280     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4281         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4282     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4283     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4284     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4285         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4286   }
4287
4288   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4289       iso)->heap();
4290   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4291
4292   // All objects should be alive.
4293   CHECK_EQ(0, counter.NumberOfWeakCalls());
4294
4295   // Weaken the root.
4296   root.handle.SetWeak(&root, &WeakPointerCallback);
4297   root.handle.MarkPartiallyDependent();
4298
4299   // Groups are deleted, rebuild groups.
4300   {
4301     HandleScope handle_scope(iso);
4302     g1s1.handle.MarkPartiallyDependent();
4303     g1s2.handle.MarkPartiallyDependent();
4304     g2s1.handle.MarkPartiallyDependent();
4305     g2s2.handle.MarkPartiallyDependent();
4306     g3s1.handle.MarkPartiallyDependent();
4307     g3s2.handle.MarkPartiallyDependent();
4308     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4309     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4310     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4311         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4312     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4313     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4314     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4315         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4316     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4317     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4318     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4319         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4320   }
4321
4322   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4323
4324   // All objects should be gone. 7 global handles in total.
4325   CHECK_EQ(7, counter.NumberOfWeakCalls());
4326 }
4327
4328
4329 THREADED_TEST(ScriptException) {
4330   LocalContext env;
4331   v8::HandleScope scope(env->GetIsolate());
4332   Local<Script> script = v8_compile("throw 'panama!';");
4333   v8::TryCatch try_catch;
4334   Local<Value> result = script->Run();
4335   CHECK(result.IsEmpty());
4336   CHECK(try_catch.HasCaught());
4337   String::Utf8Value exception_value(try_catch.Exception());
4338   CHECK_EQ(*exception_value, "panama!");
4339 }
4340
4341
4342 TEST(TryCatchCustomException) {
4343   LocalContext env;
4344   v8::HandleScope scope(env->GetIsolate());
4345   v8::TryCatch try_catch;
4346   CompileRun("function CustomError() { this.a = 'b'; }"
4347              "(function f() { throw new CustomError(); })();");
4348   CHECK(try_catch.HasCaught());
4349   CHECK(try_catch.Exception()->ToObject()->
4350             Get(v8_str("a"))->Equals(v8_str("b")));
4351 }
4352
4353
4354 bool message_received;
4355
4356
4357 static void check_message_0(v8::Handle<v8::Message> message,
4358                             v8::Handle<Value> data) {
4359   CHECK_EQ(5.76, data->NumberValue());
4360   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4361   CHECK(!message->IsSharedCrossOrigin());
4362   message_received = true;
4363 }
4364
4365
4366 THREADED_TEST(MessageHandler0) {
4367   message_received = false;
4368   v8::HandleScope scope(CcTest::isolate());
4369   CHECK(!message_received);
4370   LocalContext context;
4371   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4372   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4373   script->Run();
4374   CHECK(message_received);
4375   // clear out the message listener
4376   v8::V8::RemoveMessageListeners(check_message_0);
4377 }
4378
4379
4380 static void check_message_1(v8::Handle<v8::Message> message,
4381                             v8::Handle<Value> data) {
4382   CHECK(data->IsNumber());
4383   CHECK_EQ(1337, data->Int32Value());
4384   CHECK(!message->IsSharedCrossOrigin());
4385   message_received = true;
4386 }
4387
4388
4389 TEST(MessageHandler1) {
4390   message_received = false;
4391   v8::HandleScope scope(CcTest::isolate());
4392   CHECK(!message_received);
4393   v8::V8::AddMessageListener(check_message_1);
4394   LocalContext context;
4395   CompileRun("throw 1337;");
4396   CHECK(message_received);
4397   // clear out the message listener
4398   v8::V8::RemoveMessageListeners(check_message_1);
4399 }
4400
4401
4402 static void check_message_2(v8::Handle<v8::Message> message,
4403                             v8::Handle<Value> data) {
4404   LocalContext context;
4405   CHECK(data->IsObject());
4406   v8::Local<v8::Value> hidden_property =
4407       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4408   CHECK(v8_str("hidden value")->Equals(hidden_property));
4409   CHECK(!message->IsSharedCrossOrigin());
4410   message_received = true;
4411 }
4412
4413
4414 TEST(MessageHandler2) {
4415   message_received = false;
4416   v8::HandleScope scope(CcTest::isolate());
4417   CHECK(!message_received);
4418   v8::V8::AddMessageListener(check_message_2);
4419   LocalContext context;
4420   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4421   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4422                                            v8_str("hidden value"));
4423   context->Global()->Set(v8_str("error"), error);
4424   CompileRun("throw error;");
4425   CHECK(message_received);
4426   // clear out the message listener
4427   v8::V8::RemoveMessageListeners(check_message_2);
4428 }
4429
4430
4431 static void check_message_3(v8::Handle<v8::Message> message,
4432                             v8::Handle<Value> data) {
4433   CHECK(message->IsSharedCrossOrigin());
4434   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4435   message_received = true;
4436 }
4437
4438
4439 TEST(MessageHandler3) {
4440   message_received = false;
4441   v8::Isolate* isolate = CcTest::isolate();
4442   v8::HandleScope scope(isolate);
4443   CHECK(!message_received);
4444   v8::V8::AddMessageListener(check_message_3);
4445   LocalContext context;
4446   v8::ScriptOrigin origin =
4447       v8::ScriptOrigin(v8_str("6.75"),
4448                        v8::Integer::New(isolate, 1),
4449                        v8::Integer::New(isolate, 2),
4450                        v8::True(isolate));
4451   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4452                                                   &origin);
4453   script->Run();
4454   CHECK(message_received);
4455   // clear out the message listener
4456   v8::V8::RemoveMessageListeners(check_message_3);
4457 }
4458
4459
4460 static void check_message_4(v8::Handle<v8::Message> message,
4461                             v8::Handle<Value> data) {
4462   CHECK(!message->IsSharedCrossOrigin());
4463   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4464   message_received = true;
4465 }
4466
4467
4468 TEST(MessageHandler4) {
4469   message_received = false;
4470   v8::Isolate* isolate = CcTest::isolate();
4471   v8::HandleScope scope(isolate);
4472   CHECK(!message_received);
4473   v8::V8::AddMessageListener(check_message_4);
4474   LocalContext context;
4475   v8::ScriptOrigin origin =
4476       v8::ScriptOrigin(v8_str("6.75"),
4477                        v8::Integer::New(isolate, 1),
4478                        v8::Integer::New(isolate, 2),
4479                        v8::False(isolate));
4480   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4481                                                   &origin);
4482   script->Run();
4483   CHECK(message_received);
4484   // clear out the message listener
4485   v8::V8::RemoveMessageListeners(check_message_4);
4486 }
4487
4488
4489 static void check_message_5a(v8::Handle<v8::Message> message,
4490                             v8::Handle<Value> data) {
4491   CHECK(message->IsSharedCrossOrigin());
4492   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4493   message_received = true;
4494 }
4495
4496
4497 static void check_message_5b(v8::Handle<v8::Message> message,
4498                             v8::Handle<Value> data) {
4499   CHECK(!message->IsSharedCrossOrigin());
4500   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4501   message_received = true;
4502 }
4503
4504
4505 TEST(MessageHandler5) {
4506   message_received = false;
4507   v8::Isolate* isolate = CcTest::isolate();
4508   v8::HandleScope scope(isolate);
4509   CHECK(!message_received);
4510   v8::V8::AddMessageListener(check_message_5a);
4511   LocalContext context;
4512   v8::ScriptOrigin origin =
4513       v8::ScriptOrigin(v8_str("6.75"),
4514                        v8::Integer::New(isolate, 1),
4515                        v8::Integer::New(isolate, 2),
4516                        v8::True(isolate));
4517   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4518                                                   &origin);
4519   script->Run();
4520   CHECK(message_received);
4521   // clear out the message listener
4522   v8::V8::RemoveMessageListeners(check_message_5a);
4523
4524   message_received = false;
4525   v8::V8::AddMessageListener(check_message_5b);
4526   origin =
4527       v8::ScriptOrigin(v8_str("6.75"),
4528                        v8::Integer::New(isolate, 1),
4529                        v8::Integer::New(isolate, 2),
4530                        v8::False(isolate));
4531   script = Script::Compile(v8_str("throw 'error'"),
4532                            &origin);
4533   script->Run();
4534   CHECK(message_received);
4535   // clear out the message listener
4536   v8::V8::RemoveMessageListeners(check_message_5b);
4537 }
4538
4539
4540 THREADED_TEST(GetSetProperty) {
4541   LocalContext context;
4542   v8::Isolate* isolate = context->GetIsolate();
4543   v8::HandleScope scope(isolate);
4544   context->Global()->Set(v8_str("foo"), v8_num(14));
4545   context->Global()->Set(v8_str("12"), v8_num(92));
4546   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4547   context->Global()->Set(v8_num(13), v8_num(56));
4548   Local<Value> foo = CompileRun("this.foo");
4549   CHECK_EQ(14, foo->Int32Value());
4550   Local<Value> twelve = CompileRun("this[12]");
4551   CHECK_EQ(92, twelve->Int32Value());
4552   Local<Value> sixteen = CompileRun("this[16]");
4553   CHECK_EQ(32, sixteen->Int32Value());
4554   Local<Value> thirteen = CompileRun("this[13]");
4555   CHECK_EQ(56, thirteen->Int32Value());
4556   CHECK_EQ(92,
4557            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4558   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4559   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4560   CHECK_EQ(32,
4561            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4562   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4563   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4564   CHECK_EQ(56,
4565            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4566   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4567   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4568 }
4569
4570
4571 THREADED_TEST(PropertyAttributes) {
4572   LocalContext context;
4573   v8::HandleScope scope(context->GetIsolate());
4574   // none
4575   Local<String> prop = v8_str("none");
4576   context->Global()->Set(prop, v8_num(7));
4577   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4578   // read-only
4579   prop = v8_str("read_only");
4580   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4581   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4582   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4583   CompileRun("read_only = 9");
4584   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4585   context->Global()->Set(prop, v8_num(10));
4586   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4587   // dont-delete
4588   prop = v8_str("dont_delete");
4589   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4590   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4591   CompileRun("delete dont_delete");
4592   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4593   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4594   // dont-enum
4595   prop = v8_str("dont_enum");
4596   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4597   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4598   // absent
4599   prop = v8_str("absent");
4600   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4601   Local<Value> fake_prop = v8_num(1);
4602   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4603   // exception
4604   TryCatch try_catch;
4605   Local<Value> exception =
4606       CompileRun("({ toString: function() { throw 'exception';} })");
4607   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4608   CHECK(try_catch.HasCaught());
4609   String::Utf8Value exception_value(try_catch.Exception());
4610   CHECK_EQ("exception", *exception_value);
4611   try_catch.Reset();
4612 }
4613
4614
4615 THREADED_TEST(Array) {
4616   LocalContext context;
4617   v8::HandleScope scope(context->GetIsolate());
4618   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4619   CHECK_EQ(0, array->Length());
4620   CHECK(array->Get(0)->IsUndefined());
4621   CHECK(!array->Has(0));
4622   CHECK(array->Get(100)->IsUndefined());
4623   CHECK(!array->Has(100));
4624   array->Set(2, v8_num(7));
4625   CHECK_EQ(3, array->Length());
4626   CHECK(!array->Has(0));
4627   CHECK(!array->Has(1));
4628   CHECK(array->Has(2));
4629   CHECK_EQ(7, array->Get(2)->Int32Value());
4630   Local<Value> obj = CompileRun("[1, 2, 3]");
4631   Local<v8::Array> arr = obj.As<v8::Array>();
4632   CHECK_EQ(3, arr->Length());
4633   CHECK_EQ(1, arr->Get(0)->Int32Value());
4634   CHECK_EQ(2, arr->Get(1)->Int32Value());
4635   CHECK_EQ(3, arr->Get(2)->Int32Value());
4636   array = v8::Array::New(context->GetIsolate(), 27);
4637   CHECK_EQ(27, array->Length());
4638   array = v8::Array::New(context->GetIsolate(), -27);
4639   CHECK_EQ(0, array->Length());
4640 }
4641
4642
4643 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4644   v8::EscapableHandleScope scope(args.GetIsolate());
4645   ApiTestFuzzer::Fuzz();
4646   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4647   for (int i = 0; i < args.Length(); i++)
4648     result->Set(i, args[i]);
4649   args.GetReturnValue().Set(scope.Escape(result));
4650 }
4651
4652
4653 THREADED_TEST(Vector) {
4654   v8::Isolate* isolate = CcTest::isolate();
4655   v8::HandleScope scope(isolate);
4656   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4657   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4658   LocalContext context(0, global);
4659
4660   const char* fun = "f()";
4661   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4662   CHECK_EQ(0, a0->Length());
4663
4664   const char* fun2 = "f(11)";
4665   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4666   CHECK_EQ(1, a1->Length());
4667   CHECK_EQ(11, a1->Get(0)->Int32Value());
4668
4669   const char* fun3 = "f(12, 13)";
4670   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4671   CHECK_EQ(2, a2->Length());
4672   CHECK_EQ(12, a2->Get(0)->Int32Value());
4673   CHECK_EQ(13, a2->Get(1)->Int32Value());
4674
4675   const char* fun4 = "f(14, 15, 16)";
4676   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4677   CHECK_EQ(3, a3->Length());
4678   CHECK_EQ(14, a3->Get(0)->Int32Value());
4679   CHECK_EQ(15, a3->Get(1)->Int32Value());
4680   CHECK_EQ(16, a3->Get(2)->Int32Value());
4681
4682   const char* fun5 = "f(17, 18, 19, 20)";
4683   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4684   CHECK_EQ(4, a4->Length());
4685   CHECK_EQ(17, a4->Get(0)->Int32Value());
4686   CHECK_EQ(18, a4->Get(1)->Int32Value());
4687   CHECK_EQ(19, a4->Get(2)->Int32Value());
4688   CHECK_EQ(20, a4->Get(3)->Int32Value());
4689 }
4690
4691
4692 THREADED_TEST(FunctionCall) {
4693   LocalContext context;
4694   v8::Isolate* isolate = context->GetIsolate();
4695   v8::HandleScope scope(isolate);
4696   CompileRun(
4697     "function Foo() {"
4698     "  var result = [];"
4699     "  for (var i = 0; i < arguments.length; i++) {"
4700     "    result.push(arguments[i]);"
4701     "  }"
4702     "  return result;"
4703     "}"
4704     "function ReturnThisSloppy() {"
4705     "  return this;"
4706     "}"
4707     "function ReturnThisStrict() {"
4708     "  'use strict';"
4709     "  return this;"
4710     "}");
4711   Local<Function> Foo =
4712       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4713   Local<Function> ReturnThisSloppy =
4714       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4715   Local<Function> ReturnThisStrict =
4716       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4717
4718   v8::Handle<Value>* args0 = NULL;
4719   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4720   CHECK_EQ(0, a0->Length());
4721
4722   v8::Handle<Value> args1[] = { v8_num(1.1) };
4723   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4724   CHECK_EQ(1, a1->Length());
4725   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4726
4727   v8::Handle<Value> args2[] = { v8_num(2.2),
4728                                 v8_num(3.3) };
4729   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4730   CHECK_EQ(2, a2->Length());
4731   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4732   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4733
4734   v8::Handle<Value> args3[] = { v8_num(4.4),
4735                                 v8_num(5.5),
4736                                 v8_num(6.6) };
4737   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4738   CHECK_EQ(3, a3->Length());
4739   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4740   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4741   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4742
4743   v8::Handle<Value> args4[] = { v8_num(7.7),
4744                                 v8_num(8.8),
4745                                 v8_num(9.9),
4746                                 v8_num(10.11) };
4747   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4748   CHECK_EQ(4, a4->Length());
4749   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4750   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4751   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4752   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4753
4754   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4755   CHECK(r1->StrictEquals(context->Global()));
4756   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4757   CHECK(r2->StrictEquals(context->Global()));
4758   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4759   CHECK(r3->IsNumberObject());
4760   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4761   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4762   CHECK(r4->IsStringObject());
4763   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4764   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4765   CHECK(r5->IsBooleanObject());
4766   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4767
4768   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4769   CHECK(r6->IsUndefined());
4770   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4771   CHECK(r7->IsNull());
4772   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4773   CHECK(r8->StrictEquals(v8_num(42)));
4774   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4775   CHECK(r9->StrictEquals(v8_str("hello")));
4776   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4777   CHECK(r10->StrictEquals(v8::True(isolate)));
4778 }
4779
4780
4781 THREADED_TEST(ConstructCall) {
4782   LocalContext context;
4783   v8::Isolate* isolate = context->GetIsolate();
4784   v8::HandleScope scope(isolate);
4785   CompileRun(
4786     "function Foo() {"
4787     "  var result = [];"
4788     "  for (var i = 0; i < arguments.length; i++) {"
4789     "    result.push(arguments[i]);"
4790     "  }"
4791     "  return result;"
4792     "}");
4793   Local<Function> Foo =
4794       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4795
4796   v8::Handle<Value>* args0 = NULL;
4797   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4798   CHECK_EQ(0, a0->Length());
4799
4800   v8::Handle<Value> args1[] = { v8_num(1.1) };
4801   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4802   CHECK_EQ(1, a1->Length());
4803   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4804
4805   v8::Handle<Value> args2[] = { v8_num(2.2),
4806                                 v8_num(3.3) };
4807   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4808   CHECK_EQ(2, a2->Length());
4809   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4810   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4811
4812   v8::Handle<Value> args3[] = { v8_num(4.4),
4813                                 v8_num(5.5),
4814                                 v8_num(6.6) };
4815   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4816   CHECK_EQ(3, a3->Length());
4817   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4818   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4819   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4820
4821   v8::Handle<Value> args4[] = { v8_num(7.7),
4822                                 v8_num(8.8),
4823                                 v8_num(9.9),
4824                                 v8_num(10.11) };
4825   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4826   CHECK_EQ(4, a4->Length());
4827   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4828   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4829   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4830   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4831 }
4832
4833
4834 static void CheckUncle(v8::TryCatch* try_catch) {
4835   CHECK(try_catch->HasCaught());
4836   String::Utf8Value str_value(try_catch->Exception());
4837   CHECK_EQ(*str_value, "uncle?");
4838   try_catch->Reset();
4839 }
4840
4841
4842 THREADED_TEST(ConversionNumber) {
4843   LocalContext env;
4844   v8::HandleScope scope(env->GetIsolate());
4845   // Very large number.
4846   CompileRun("var obj = Math.pow(2,32) * 1237;");
4847   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4848   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4849   CHECK_EQ(0, obj->ToInt32()->Value());
4850   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4851   // Large number.
4852   CompileRun("var obj = -1234567890123;");
4853   obj = env->Global()->Get(v8_str("obj"));
4854   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4855   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4856   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4857   // Small positive integer.
4858   CompileRun("var obj = 42;");
4859   obj = env->Global()->Get(v8_str("obj"));
4860   CHECK_EQ(42.0, obj->ToNumber()->Value());
4861   CHECK_EQ(42, obj->ToInt32()->Value());
4862   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4863   // Negative integer.
4864   CompileRun("var obj = -37;");
4865   obj = env->Global()->Get(v8_str("obj"));
4866   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4867   CHECK_EQ(-37, obj->ToInt32()->Value());
4868   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4869   // Positive non-int32 integer.
4870   CompileRun("var obj = 0x81234567;");
4871   obj = env->Global()->Get(v8_str("obj"));
4872   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4873   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4874   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4875   // Fraction.
4876   CompileRun("var obj = 42.3;");
4877   obj = env->Global()->Get(v8_str("obj"));
4878   CHECK_EQ(42.3, obj->ToNumber()->Value());
4879   CHECK_EQ(42, obj->ToInt32()->Value());
4880   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4881   // Large negative fraction.
4882   CompileRun("var obj = -5726623061.75;");
4883   obj = env->Global()->Get(v8_str("obj"));
4884   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4885   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4886   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4887 }
4888
4889
4890 THREADED_TEST(isNumberType) {
4891   LocalContext env;
4892   v8::HandleScope scope(env->GetIsolate());
4893   // Very large number.
4894   CompileRun("var obj = Math.pow(2,32) * 1237;");
4895   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4896   CHECK(!obj->IsInt32());
4897   CHECK(!obj->IsUint32());
4898   // Large negative number.
4899   CompileRun("var obj = -1234567890123;");
4900   obj = env->Global()->Get(v8_str("obj"));
4901   CHECK(!obj->IsInt32());
4902   CHECK(!obj->IsUint32());
4903   // Small positive integer.
4904   CompileRun("var obj = 42;");
4905   obj = env->Global()->Get(v8_str("obj"));
4906   CHECK(obj->IsInt32());
4907   CHECK(obj->IsUint32());
4908   // Negative integer.
4909   CompileRun("var obj = -37;");
4910   obj = env->Global()->Get(v8_str("obj"));
4911   CHECK(obj->IsInt32());
4912   CHECK(!obj->IsUint32());
4913   // Positive non-int32 integer.
4914   CompileRun("var obj = 0x81234567;");
4915   obj = env->Global()->Get(v8_str("obj"));
4916   CHECK(!obj->IsInt32());
4917   CHECK(obj->IsUint32());
4918   // Fraction.
4919   CompileRun("var obj = 42.3;");
4920   obj = env->Global()->Get(v8_str("obj"));
4921   CHECK(!obj->IsInt32());
4922   CHECK(!obj->IsUint32());
4923   // Large negative fraction.
4924   CompileRun("var obj = -5726623061.75;");
4925   obj = env->Global()->Get(v8_str("obj"));
4926   CHECK(!obj->IsInt32());
4927   CHECK(!obj->IsUint32());
4928   // Positive zero
4929   CompileRun("var obj = 0.0;");
4930   obj = env->Global()->Get(v8_str("obj"));
4931   CHECK(obj->IsInt32());
4932   CHECK(obj->IsUint32());
4933   // Positive zero
4934   CompileRun("var obj = -0.0;");
4935   obj = env->Global()->Get(v8_str("obj"));
4936   CHECK(!obj->IsInt32());
4937   CHECK(!obj->IsUint32());
4938 }
4939
4940
4941 THREADED_TEST(ConversionException) {
4942   LocalContext env;
4943   v8::Isolate* isolate = env->GetIsolate();
4944   v8::HandleScope scope(isolate);
4945   CompileRun(
4946     "function TestClass() { };"
4947     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4948     "var obj = new TestClass();");
4949   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4950
4951   v8::TryCatch try_catch;
4952
4953   Local<Value> to_string_result = obj->ToString();
4954   CHECK(to_string_result.IsEmpty());
4955   CheckUncle(&try_catch);
4956
4957   Local<Value> to_number_result = obj->ToNumber();
4958   CHECK(to_number_result.IsEmpty());
4959   CheckUncle(&try_catch);
4960
4961   Local<Value> to_integer_result = obj->ToInteger();
4962   CHECK(to_integer_result.IsEmpty());
4963   CheckUncle(&try_catch);
4964
4965   Local<Value> to_uint32_result = obj->ToUint32();
4966   CHECK(to_uint32_result.IsEmpty());
4967   CheckUncle(&try_catch);
4968
4969   Local<Value> to_int32_result = obj->ToInt32();
4970   CHECK(to_int32_result.IsEmpty());
4971   CheckUncle(&try_catch);
4972
4973   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4974   CHECK(to_object_result.IsEmpty());
4975   CHECK(try_catch.HasCaught());
4976   try_catch.Reset();
4977
4978   int32_t int32_value = obj->Int32Value();
4979   CHECK_EQ(0, int32_value);
4980   CheckUncle(&try_catch);
4981
4982   uint32_t uint32_value = obj->Uint32Value();
4983   CHECK_EQ(0, uint32_value);
4984   CheckUncle(&try_catch);
4985
4986   double number_value = obj->NumberValue();
4987   CHECK_NE(0, std::isnan(number_value));
4988   CheckUncle(&try_catch);
4989
4990   int64_t integer_value = obj->IntegerValue();
4991   CHECK_EQ(0.0, static_cast<double>(integer_value));
4992   CheckUncle(&try_catch);
4993 }
4994
4995
4996 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4997   ApiTestFuzzer::Fuzz();
4998   args.GetIsolate()->ThrowException(v8_str("konto"));
4999 }
5000
5001
5002 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5003   if (args.Length() < 1) {
5004     args.GetReturnValue().Set(false);
5005     return;
5006   }
5007   v8::HandleScope scope(args.GetIsolate());
5008   v8::TryCatch try_catch;
5009   Local<Value> result = CompileRun(args[0]->ToString());
5010   CHECK(!try_catch.HasCaught() || result.IsEmpty());
5011   args.GetReturnValue().Set(try_catch.HasCaught());
5012 }
5013
5014
5015 THREADED_TEST(APICatch) {
5016   v8::Isolate* isolate = CcTest::isolate();
5017   v8::HandleScope scope(isolate);
5018   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5019   templ->Set(v8_str("ThrowFromC"),
5020              v8::FunctionTemplate::New(isolate, ThrowFromC));
5021   LocalContext context(0, templ);
5022   CompileRun(
5023     "var thrown = false;"
5024     "try {"
5025     "  ThrowFromC();"
5026     "} catch (e) {"
5027     "  thrown = true;"
5028     "}");
5029   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5030   CHECK(thrown->BooleanValue());
5031 }
5032
5033
5034 THREADED_TEST(APIThrowTryCatch) {
5035   v8::Isolate* isolate = CcTest::isolate();
5036   v8::HandleScope scope(isolate);
5037   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5038   templ->Set(v8_str("ThrowFromC"),
5039              v8::FunctionTemplate::New(isolate, ThrowFromC));
5040   LocalContext context(0, templ);
5041   v8::TryCatch try_catch;
5042   CompileRun("ThrowFromC();");
5043   CHECK(try_catch.HasCaught());
5044 }
5045
5046
5047 // Test that a try-finally block doesn't shadow a try-catch block
5048 // when setting up an external handler.
5049 //
5050 // BUG(271): Some of the exception propagation does not work on the
5051 // ARM simulator because the simulator separates the C++ stack and the
5052 // JS stack.  This test therefore fails on the simulator.  The test is
5053 // not threaded to allow the threading tests to run on the simulator.
5054 TEST(TryCatchInTryFinally) {
5055   v8::Isolate* isolate = CcTest::isolate();
5056   v8::HandleScope scope(isolate);
5057   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5058   templ->Set(v8_str("CCatcher"),
5059              v8::FunctionTemplate::New(isolate, CCatcher));
5060   LocalContext context(0, templ);
5061   Local<Value> result = CompileRun("try {"
5062                                    "  try {"
5063                                    "    CCatcher('throw 7;');"
5064                                    "  } finally {"
5065                                    "  }"
5066                                    "} catch (e) {"
5067                                    "}");
5068   CHECK(result->IsTrue());
5069 }
5070
5071
5072 static void check_reference_error_message(
5073     v8::Handle<v8::Message> message,
5074     v8::Handle<v8::Value> data) {
5075   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5076   CHECK(message->Get()->Equals(v8_str(reference_error)));
5077 }
5078
5079
5080 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5081   ApiTestFuzzer::Fuzz();
5082   CHECK(false);
5083 }
5084
5085
5086 // Test that overwritten methods are not invoked on uncaught exception
5087 // formatting. However, they are invoked when performing normal error
5088 // string conversions.
5089 TEST(APIThrowMessageOverwrittenToString) {
5090   v8::Isolate* isolate = CcTest::isolate();
5091   v8::HandleScope scope(isolate);
5092   v8::V8::AddMessageListener(check_reference_error_message);
5093   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5094   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5095   LocalContext context(NULL, templ);
5096   CompileRun("asdf;");
5097   CompileRun("var limit = {};"
5098              "limit.valueOf = fail;"
5099              "Error.stackTraceLimit = limit;");
5100   CompileRun("asdf");
5101   CompileRun("Array.prototype.pop = fail;");
5102   CompileRun("Object.prototype.hasOwnProperty = fail;");
5103   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5104   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5105   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5106   CompileRun("ReferenceError.prototype.toString ="
5107              "  function() { return 'Whoops' }");
5108   CompileRun("asdf;");
5109   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5110   CompileRun("asdf;");
5111   CompileRun("ReferenceError.prototype.constructor = void 0;");
5112   CompileRun("asdf;");
5113   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5114   CompileRun("asdf;");
5115   CompileRun("ReferenceError.prototype = new Object();");
5116   CompileRun("asdf;");
5117   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5118   CHECK(string->Equals(v8_str("Whoops")));
5119   CompileRun("ReferenceError.prototype.constructor = new Object();"
5120              "ReferenceError.prototype.constructor.name = 1;"
5121              "Number.prototype.toString = function() { return 'Whoops'; };"
5122              "ReferenceError.prototype.toString = Object.prototype.toString;");
5123   CompileRun("asdf;");
5124   v8::V8::RemoveMessageListeners(check_reference_error_message);
5125 }
5126
5127
5128 static void check_custom_error_tostring(
5129     v8::Handle<v8::Message> message,
5130     v8::Handle<v8::Value> data) {
5131   const char* uncaught_error = "Uncaught MyError toString";
5132   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5133 }
5134
5135
5136 TEST(CustomErrorToString) {
5137   LocalContext context;
5138   v8::HandleScope scope(context->GetIsolate());
5139   v8::V8::AddMessageListener(check_custom_error_tostring);
5140   CompileRun(
5141     "function MyError(name, message) {                   "
5142     "  this.name = name;                                 "
5143     "  this.message = message;                           "
5144     "}                                                   "
5145     "MyError.prototype = Object.create(Error.prototype); "
5146     "MyError.prototype.toString = function() {           "
5147     "  return 'MyError toString';                        "
5148     "};                                                  "
5149     "throw new MyError('my name', 'my message');         ");
5150   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5151 }
5152
5153
5154 static void check_custom_error_message(
5155     v8::Handle<v8::Message> message,
5156     v8::Handle<v8::Value> data) {
5157   const char* uncaught_error = "Uncaught MyError: my message";
5158   printf("%s\n", *v8::String::Utf8Value(message->Get()));
5159   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5160 }
5161
5162
5163 TEST(CustomErrorMessage) {
5164   LocalContext context;
5165   v8::HandleScope scope(context->GetIsolate());
5166   v8::V8::AddMessageListener(check_custom_error_message);
5167
5168   // Handlebars.
5169   CompileRun(
5170     "function MyError(msg) {                             "
5171     "  this.name = 'MyError';                            "
5172     "  this.message = msg;                               "
5173     "}                                                   "
5174     "MyError.prototype = new Error();                    "
5175     "throw new MyError('my message');                    ");
5176
5177   // Closure.
5178   CompileRun(
5179     "function MyError(msg) {                             "
5180     "  this.name = 'MyError';                            "
5181     "  this.message = msg;                               "
5182     "}                                                   "
5183     "inherits = function(childCtor, parentCtor) {        "
5184     "    function tempCtor() {};                         "
5185     "    tempCtor.prototype = parentCtor.prototype;      "
5186     "    childCtor.superClass_ = parentCtor.prototype;   "
5187     "    childCtor.prototype = new tempCtor();           "
5188     "    childCtor.prototype.constructor = childCtor;    "
5189     "};                                                  "
5190     "inherits(MyError, Error);                           "
5191     "throw new MyError('my message');                    ");
5192
5193   // Object.create.
5194   CompileRun(
5195     "function MyError(msg) {                             "
5196     "  this.name = 'MyError';                            "
5197     "  this.message = msg;                               "
5198     "}                                                   "
5199     "MyError.prototype = Object.create(Error.prototype); "
5200     "throw new MyError('my message');                    ");
5201
5202   v8::V8::RemoveMessageListeners(check_custom_error_message);
5203 }
5204
5205
5206 static void receive_message(v8::Handle<v8::Message> message,
5207                             v8::Handle<v8::Value> data) {
5208   message->Get();
5209   message_received = true;
5210 }
5211
5212
5213 TEST(APIThrowMessage) {
5214   message_received = false;
5215   v8::Isolate* isolate = CcTest::isolate();
5216   v8::HandleScope scope(isolate);
5217   v8::V8::AddMessageListener(receive_message);
5218   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5219   templ->Set(v8_str("ThrowFromC"),
5220              v8::FunctionTemplate::New(isolate, ThrowFromC));
5221   LocalContext context(0, templ);
5222   CompileRun("ThrowFromC();");
5223   CHECK(message_received);
5224   v8::V8::RemoveMessageListeners(receive_message);
5225 }
5226
5227
5228 TEST(APIThrowMessageAndVerboseTryCatch) {
5229   message_received = false;
5230   v8::Isolate* isolate = CcTest::isolate();
5231   v8::HandleScope scope(isolate);
5232   v8::V8::AddMessageListener(receive_message);
5233   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5234   templ->Set(v8_str("ThrowFromC"),
5235              v8::FunctionTemplate::New(isolate, ThrowFromC));
5236   LocalContext context(0, templ);
5237   v8::TryCatch try_catch;
5238   try_catch.SetVerbose(true);
5239   Local<Value> result = CompileRun("ThrowFromC();");
5240   CHECK(try_catch.HasCaught());
5241   CHECK(result.IsEmpty());
5242   CHECK(message_received);
5243   v8::V8::RemoveMessageListeners(receive_message);
5244 }
5245
5246
5247 TEST(APIStackOverflowAndVerboseTryCatch) {
5248   message_received = false;
5249   LocalContext context;
5250   v8::HandleScope scope(context->GetIsolate());
5251   v8::V8::AddMessageListener(receive_message);
5252   v8::TryCatch try_catch;
5253   try_catch.SetVerbose(true);
5254   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5255   CHECK(try_catch.HasCaught());
5256   CHECK(result.IsEmpty());
5257   CHECK(message_received);
5258   v8::V8::RemoveMessageListeners(receive_message);
5259 }
5260
5261
5262 THREADED_TEST(ExternalScriptException) {
5263   v8::Isolate* isolate = CcTest::isolate();
5264   v8::HandleScope scope(isolate);
5265   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5266   templ->Set(v8_str("ThrowFromC"),
5267              v8::FunctionTemplate::New(isolate, ThrowFromC));
5268   LocalContext context(0, templ);
5269
5270   v8::TryCatch try_catch;
5271   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5272   CHECK(result.IsEmpty());
5273   CHECK(try_catch.HasCaught());
5274   String::Utf8Value exception_value(try_catch.Exception());
5275   CHECK_EQ("konto", *exception_value);
5276 }
5277
5278
5279
5280 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5281   ApiTestFuzzer::Fuzz();
5282   CHECK_EQ(4, args.Length());
5283   int count = args[0]->Int32Value();
5284   int cInterval = args[2]->Int32Value();
5285   if (count == 0) {
5286     args.GetIsolate()->ThrowException(v8_str("FromC"));
5287     return;
5288   } else {
5289     Local<v8::Object> global =
5290         args.GetIsolate()->GetCurrentContext()->Global();
5291     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5292     v8::Handle<Value> argv[] = { v8_num(count - 1),
5293                                  args[1],
5294                                  args[2],
5295                                  args[3] };
5296     if (count % cInterval == 0) {
5297       v8::TryCatch try_catch;
5298       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5299       int expected = args[3]->Int32Value();
5300       if (try_catch.HasCaught()) {
5301         CHECK_EQ(expected, count);
5302         CHECK(result.IsEmpty());
5303         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5304       } else {
5305         CHECK_NE(expected, count);
5306       }
5307       args.GetReturnValue().Set(result);
5308       return;
5309     } else {
5310       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5311       return;
5312     }
5313   }
5314 }
5315
5316
5317 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5318   ApiTestFuzzer::Fuzz();
5319   CHECK_EQ(3, args.Length());
5320   bool equality = args[0]->BooleanValue();
5321   int count = args[1]->Int32Value();
5322   int expected = args[2]->Int32Value();
5323   if (equality) {
5324     CHECK_EQ(count, expected);
5325   } else {
5326     CHECK_NE(count, expected);
5327   }
5328 }
5329
5330
5331 THREADED_TEST(EvalInTryFinally) {
5332   LocalContext context;
5333   v8::HandleScope scope(context->GetIsolate());
5334   v8::TryCatch try_catch;
5335   CompileRun("(function() {"
5336              "  try {"
5337              "    eval('asldkf (*&^&*^');"
5338              "  } finally {"
5339              "    return;"
5340              "  }"
5341              "})()");
5342   CHECK(!try_catch.HasCaught());
5343 }
5344
5345
5346 // This test works by making a stack of alternating JavaScript and C
5347 // activations.  These activations set up exception handlers with regular
5348 // intervals, one interval for C activations and another for JavaScript
5349 // activations.  When enough activations have been created an exception is
5350 // thrown and we check that the right activation catches the exception and that
5351 // no other activations do.  The right activation is always the topmost one with
5352 // a handler, regardless of whether it is in JavaScript or C.
5353 //
5354 // The notation used to describe a test case looks like this:
5355 //
5356 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5357 //
5358 // Each entry is an activation, either JS or C.  The index is the count at that
5359 // level.  Stars identify activations with exception handlers, the @ identifies
5360 // the exception handler that should catch the exception.
5361 //
5362 // BUG(271): Some of the exception propagation does not work on the
5363 // ARM simulator because the simulator separates the C++ stack and the
5364 // JS stack.  This test therefore fails on the simulator.  The test is
5365 // not threaded to allow the threading tests to run on the simulator.
5366 TEST(ExceptionOrder) {
5367   v8::Isolate* isolate = CcTest::isolate();
5368   v8::HandleScope scope(isolate);
5369   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5370   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5371   templ->Set(v8_str("CThrowCountDown"),
5372              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5373   LocalContext context(0, templ);
5374   CompileRun(
5375     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5376     "  if (count == 0) throw 'FromJS';"
5377     "  if (count % jsInterval == 0) {"
5378     "    try {"
5379     "      var value = CThrowCountDown(count - 1,"
5380     "                                  jsInterval,"
5381     "                                  cInterval,"
5382     "                                  expected);"
5383     "      check(false, count, expected);"
5384     "      return value;"
5385     "    } catch (e) {"
5386     "      check(true, count, expected);"
5387     "    }"
5388     "  } else {"
5389     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5390     "  }"
5391     "}");
5392   Local<Function> fun =
5393       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5394
5395   const int argc = 4;
5396   //                             count      jsInterval cInterval  expected
5397
5398   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5399   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5400   fun->Call(fun, argc, a0);
5401
5402   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5403   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5404   fun->Call(fun, argc, a1);
5405
5406   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5407   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5408   fun->Call(fun, argc, a2);
5409
5410   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5411   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5412   fun->Call(fun, argc, a3);
5413
5414   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5415   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5416   fun->Call(fun, argc, a4);
5417
5418   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5419   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5420   fun->Call(fun, argc, a5);
5421 }
5422
5423
5424 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5425   ApiTestFuzzer::Fuzz();
5426   CHECK_EQ(1, args.Length());
5427   args.GetIsolate()->ThrowException(args[0]);
5428 }
5429
5430
5431 THREADED_TEST(ThrowValues) {
5432   v8::Isolate* isolate = CcTest::isolate();
5433   v8::HandleScope scope(isolate);
5434   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5435   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5436   LocalContext context(0, templ);
5437   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5438     "function Run(obj) {"
5439     "  try {"
5440     "    Throw(obj);"
5441     "  } catch (e) {"
5442     "    return e;"
5443     "  }"
5444     "  return 'no exception';"
5445     "}"
5446     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5447   CHECK_EQ(5, result->Length());
5448   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5449   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5450   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5451   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5452   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5453   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5454   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5455 }
5456
5457
5458 THREADED_TEST(CatchZero) {
5459   LocalContext context;
5460   v8::HandleScope scope(context->GetIsolate());
5461   v8::TryCatch try_catch;
5462   CHECK(!try_catch.HasCaught());
5463   CompileRun("throw 10");
5464   CHECK(try_catch.HasCaught());
5465   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5466   try_catch.Reset();
5467   CHECK(!try_catch.HasCaught());
5468   CompileRun("throw 0");
5469   CHECK(try_catch.HasCaught());
5470   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5471 }
5472
5473
5474 THREADED_TEST(CatchExceptionFromWith) {
5475   LocalContext context;
5476   v8::HandleScope scope(context->GetIsolate());
5477   v8::TryCatch try_catch;
5478   CHECK(!try_catch.HasCaught());
5479   CompileRun("var o = {}; with (o) { throw 42; }");
5480   CHECK(try_catch.HasCaught());
5481 }
5482
5483
5484 THREADED_TEST(TryCatchAndFinallyHidingException) {
5485   LocalContext context;
5486   v8::HandleScope scope(context->GetIsolate());
5487   v8::TryCatch try_catch;
5488   CHECK(!try_catch.HasCaught());
5489   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5490   CompileRun("f({toString: function() { throw 42; }});");
5491   CHECK(!try_catch.HasCaught());
5492 }
5493
5494
5495 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5496   v8::TryCatch try_catch;
5497 }
5498
5499
5500 THREADED_TEST(TryCatchAndFinally) {
5501   LocalContext context;
5502   v8::Isolate* isolate = context->GetIsolate();
5503   v8::HandleScope scope(isolate);
5504   context->Global()->Set(
5505       v8_str("native_with_try_catch"),
5506       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5507   v8::TryCatch try_catch;
5508   CHECK(!try_catch.HasCaught());
5509   CompileRun(
5510       "try {\n"
5511       "  throw new Error('a');\n"
5512       "} finally {\n"
5513       "  native_with_try_catch();\n"
5514       "}\n");
5515   CHECK(try_catch.HasCaught());
5516 }
5517
5518
5519 static void TryCatchNested1Helper(int depth) {
5520   if (depth > 0) {
5521     v8::TryCatch try_catch;
5522     try_catch.SetVerbose(true);
5523     TryCatchNested1Helper(depth - 1);
5524     CHECK(try_catch.HasCaught());
5525     try_catch.ReThrow();
5526   } else {
5527     CcTest::isolate()->ThrowException(v8_str("E1"));
5528   }
5529 }
5530
5531
5532 static void TryCatchNested2Helper(int depth) {
5533   if (depth > 0) {
5534     v8::TryCatch try_catch;
5535     try_catch.SetVerbose(true);
5536     TryCatchNested2Helper(depth - 1);
5537     CHECK(try_catch.HasCaught());
5538     try_catch.ReThrow();
5539   } else {
5540     CompileRun("throw 'E2';");
5541   }
5542 }
5543
5544
5545 TEST(TryCatchNested) {
5546   v8::V8::Initialize();
5547   LocalContext context;
5548   v8::HandleScope scope(context->GetIsolate());
5549
5550   {
5551     // Test nested try-catch with a native throw in the end.
5552     v8::TryCatch try_catch;
5553     TryCatchNested1Helper(5);
5554     CHECK(try_catch.HasCaught());
5555     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5556   }
5557
5558   {
5559     // Test nested try-catch with a JavaScript throw in the end.
5560     v8::TryCatch try_catch;
5561     TryCatchNested2Helper(5);
5562     CHECK(try_catch.HasCaught());
5563     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5564   }
5565 }
5566
5567
5568 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5569   CHECK(try_catch->HasCaught());
5570   Handle<Message> message = try_catch->Message();
5571   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5572   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5573   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5574                      "Uncaught Error: a"));
5575   CHECK_EQ(1, message->GetLineNumber());
5576   CHECK_EQ(6, message->GetStartColumn());
5577 }
5578
5579
5580 void TryCatchMixedNestingHelper(
5581     const v8::FunctionCallbackInfo<v8::Value>& args) {
5582   ApiTestFuzzer::Fuzz();
5583   v8::TryCatch try_catch;
5584   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5585   CHECK(try_catch.HasCaught());
5586   TryCatchMixedNestingCheck(&try_catch);
5587   try_catch.ReThrow();
5588 }
5589
5590
5591 // This test ensures that an outer TryCatch in the following situation:
5592 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5593 // does not clobber the Message object generated for the inner TryCatch.
5594 // This exercises the ability of TryCatch.ReThrow() to restore the
5595 // inner pending Message before throwing the exception again.
5596 TEST(TryCatchMixedNesting) {
5597   v8::Isolate* isolate = CcTest::isolate();
5598   v8::HandleScope scope(isolate);
5599   v8::V8::Initialize();
5600   v8::TryCatch try_catch;
5601   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5602   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5603              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5604   LocalContext context(0, templ);
5605   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5606   TryCatchMixedNestingCheck(&try_catch);
5607 }
5608
5609
5610 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5611   ApiTestFuzzer::Fuzz();
5612   v8::TryCatch try_catch;
5613   args.GetIsolate()->ThrowException(v8_str("boom"));
5614   CHECK(try_catch.HasCaught());
5615 }
5616
5617
5618 TEST(TryCatchNative) {
5619   v8::Isolate* isolate = CcTest::isolate();
5620   v8::HandleScope scope(isolate);
5621   v8::V8::Initialize();
5622   v8::TryCatch try_catch;
5623   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5624   templ->Set(v8_str("TryCatchNativeHelper"),
5625              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5626   LocalContext context(0, templ);
5627   CompileRun("TryCatchNativeHelper();");
5628   CHECK(!try_catch.HasCaught());
5629 }
5630
5631
5632 void TryCatchNativeResetHelper(
5633     const v8::FunctionCallbackInfo<v8::Value>& args) {
5634   ApiTestFuzzer::Fuzz();
5635   v8::TryCatch try_catch;
5636   args.GetIsolate()->ThrowException(v8_str("boom"));
5637   CHECK(try_catch.HasCaught());
5638   try_catch.Reset();
5639   CHECK(!try_catch.HasCaught());
5640 }
5641
5642
5643 TEST(TryCatchNativeReset) {
5644   v8::Isolate* isolate = CcTest::isolate();
5645   v8::HandleScope scope(isolate);
5646   v8::V8::Initialize();
5647   v8::TryCatch try_catch;
5648   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5649   templ->Set(v8_str("TryCatchNativeResetHelper"),
5650              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5651   LocalContext context(0, templ);
5652   CompileRun("TryCatchNativeResetHelper();");
5653   CHECK(!try_catch.HasCaught());
5654 }
5655
5656
5657 THREADED_TEST(Equality) {
5658   LocalContext context;
5659   v8::Isolate* isolate = context->GetIsolate();
5660   v8::HandleScope scope(context->GetIsolate());
5661   // Check that equality works at all before relying on CHECK_EQ
5662   CHECK(v8_str("a")->Equals(v8_str("a")));
5663   CHECK(!v8_str("a")->Equals(v8_str("b")));
5664
5665   CHECK_EQ(v8_str("a"), v8_str("a"));
5666   CHECK_NE(v8_str("a"), v8_str("b"));
5667   CHECK_EQ(v8_num(1), v8_num(1));
5668   CHECK_EQ(v8_num(1.00), v8_num(1));
5669   CHECK_NE(v8_num(1), v8_num(2));
5670
5671   // Assume String is not internalized.
5672   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5673   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5674   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5675   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5676   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5677   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5678   Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5679   CHECK(!not_a_number->StrictEquals(not_a_number));
5680   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5681   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5682
5683   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5684   v8::Persistent<v8::Object> alias(isolate, obj);
5685   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5686   alias.Reset();
5687
5688   CHECK(v8_str("a")->SameValue(v8_str("a")));
5689   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5690   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5691   CHECK(v8_num(1)->SameValue(v8_num(1)));
5692   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5693   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5694   CHECK(not_a_number->SameValue(not_a_number));
5695   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5696   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5697 }
5698
5699
5700 THREADED_TEST(MultiRun) {
5701   LocalContext context;
5702   v8::HandleScope scope(context->GetIsolate());
5703   Local<Script> script = v8_compile("x");
5704   for (int i = 0; i < 10; i++)
5705     script->Run();
5706 }
5707
5708
5709 static void GetXValue(Local<String> name,
5710                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5711   ApiTestFuzzer::Fuzz();
5712   CHECK_EQ(info.Data(), v8_str("donut"));
5713   CHECK_EQ(name, v8_str("x"));
5714   info.GetReturnValue().Set(name);
5715 }
5716
5717
5718 THREADED_TEST(SimplePropertyRead) {
5719   LocalContext context;
5720   v8::Isolate* isolate = context->GetIsolate();
5721   v8::HandleScope scope(isolate);
5722   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5723   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5724   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5725   Local<Script> script = v8_compile("obj.x");
5726   for (int i = 0; i < 10; i++) {
5727     Local<Value> result = script->Run();
5728     CHECK_EQ(result, v8_str("x"));
5729   }
5730 }
5731
5732
5733 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5734   LocalContext context;
5735   v8::Isolate* isolate = context->GetIsolate();
5736   v8::HandleScope scope(isolate);
5737   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5738   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5739   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5740
5741   // Uses getOwnPropertyDescriptor to check the configurable status
5742   Local<Script> script_desc = v8_compile(
5743       "var prop = Object.getOwnPropertyDescriptor( "
5744       "obj, 'x');"
5745       "prop.configurable;");
5746   Local<Value> result = script_desc->Run();
5747   CHECK_EQ(result->BooleanValue(), true);
5748
5749   // Redefine get - but still configurable
5750   Local<Script> script_define = v8_compile(
5751       "var desc = { get: function(){return 42; },"
5752       "            configurable: true };"
5753       "Object.defineProperty(obj, 'x', desc);"
5754       "obj.x");
5755   result = script_define->Run();
5756   CHECK_EQ(result, v8_num(42));
5757
5758   // Check that the accessor is still configurable
5759   result = script_desc->Run();
5760   CHECK_EQ(result->BooleanValue(), true);
5761
5762   // Redefine to a non-configurable
5763   script_define = v8_compile(
5764       "var desc = { get: function(){return 43; },"
5765       "             configurable: false };"
5766       "Object.defineProperty(obj, 'x', desc);"
5767       "obj.x");
5768   result = script_define->Run();
5769   CHECK_EQ(result, v8_num(43));
5770   result = script_desc->Run();
5771   CHECK_EQ(result->BooleanValue(), false);
5772
5773   // Make sure that it is not possible to redefine again
5774   v8::TryCatch try_catch;
5775   result = script_define->Run();
5776   CHECK(try_catch.HasCaught());
5777   String::Utf8Value exception_value(try_catch.Exception());
5778   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5779 }
5780
5781
5782 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5783   v8::Isolate* isolate = CcTest::isolate();
5784   v8::HandleScope scope(isolate);
5785   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5786   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5787   LocalContext context;
5788   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5789
5790   Local<Script> script_desc = v8_compile(
5791       "var prop ="
5792       "Object.getOwnPropertyDescriptor( "
5793       "obj, 'x');"
5794       "prop.configurable;");
5795   Local<Value> result = script_desc->Run();
5796   CHECK_EQ(result->BooleanValue(), true);
5797
5798   Local<Script> script_define = v8_compile(
5799       "var desc = {get: function(){return 42; },"
5800       "            configurable: true };"
5801       "Object.defineProperty(obj, 'x', desc);"
5802       "obj.x");
5803   result = script_define->Run();
5804   CHECK_EQ(result, v8_num(42));
5805
5806
5807   result = script_desc->Run();
5808   CHECK_EQ(result->BooleanValue(), true);
5809
5810
5811   script_define = v8_compile(
5812       "var desc = {get: function(){return 43; },"
5813       "            configurable: false };"
5814       "Object.defineProperty(obj, 'x', desc);"
5815       "obj.x");
5816   result = script_define->Run();
5817   CHECK_EQ(result, v8_num(43));
5818   result = script_desc->Run();
5819
5820   CHECK_EQ(result->BooleanValue(), false);
5821
5822   v8::TryCatch try_catch;
5823   result = script_define->Run();
5824   CHECK(try_catch.HasCaught());
5825   String::Utf8Value exception_value(try_catch.Exception());
5826   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5827 }
5828
5829
5830 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5831                                                 char const* name) {
5832   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5833 }
5834
5835
5836 THREADED_TEST(DefineAPIAccessorOnObject) {
5837   v8::Isolate* isolate = CcTest::isolate();
5838   v8::HandleScope scope(isolate);
5839   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5840   LocalContext context;
5841
5842   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5843   CompileRun("var obj2 = {};");
5844
5845   CHECK(CompileRun("obj1.x")->IsUndefined());
5846   CHECK(CompileRun("obj2.x")->IsUndefined());
5847
5848   CHECK(GetGlobalProperty(&context, "obj1")->
5849       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5850
5851   ExpectString("obj1.x", "x");
5852   CHECK(CompileRun("obj2.x")->IsUndefined());
5853
5854   CHECK(GetGlobalProperty(&context, "obj2")->
5855       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5856
5857   ExpectString("obj1.x", "x");
5858   ExpectString("obj2.x", "x");
5859
5860   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5861   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5862
5863   CompileRun("Object.defineProperty(obj1, 'x',"
5864              "{ get: function() { return 'y'; }, configurable: true })");
5865
5866   ExpectString("obj1.x", "y");
5867   ExpectString("obj2.x", "x");
5868
5869   CompileRun("Object.defineProperty(obj2, 'x',"
5870              "{ get: function() { return 'y'; }, configurable: true })");
5871
5872   ExpectString("obj1.x", "y");
5873   ExpectString("obj2.x", "y");
5874
5875   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5876   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5877
5878   CHECK(GetGlobalProperty(&context, "obj1")->
5879       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5880   CHECK(GetGlobalProperty(&context, "obj2")->
5881       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5882
5883   ExpectString("obj1.x", "x");
5884   ExpectString("obj2.x", "x");
5885
5886   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5887   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5888
5889   // Define getters/setters, but now make them not configurable.
5890   CompileRun("Object.defineProperty(obj1, 'x',"
5891              "{ get: function() { return 'z'; }, configurable: false })");
5892   CompileRun("Object.defineProperty(obj2, 'x',"
5893              "{ get: function() { return 'z'; }, configurable: false })");
5894
5895   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5896   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5897
5898   ExpectString("obj1.x", "z");
5899   ExpectString("obj2.x", "z");
5900
5901   CHECK(!GetGlobalProperty(&context, "obj1")->
5902       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5903   CHECK(!GetGlobalProperty(&context, "obj2")->
5904       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5905
5906   ExpectString("obj1.x", "z");
5907   ExpectString("obj2.x", "z");
5908 }
5909
5910
5911 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5912   v8::Isolate* isolate = CcTest::isolate();
5913   v8::HandleScope scope(isolate);
5914   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5915   LocalContext context;
5916
5917   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5918   CompileRun("var obj2 = {};");
5919
5920   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5921         v8_str("x"),
5922         GetXValue, NULL,
5923         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5924   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5925         v8_str("x"),
5926         GetXValue, NULL,
5927         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5928
5929   ExpectString("obj1.x", "x");
5930   ExpectString("obj2.x", "x");
5931
5932   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5933   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5934
5935   CHECK(!GetGlobalProperty(&context, "obj1")->
5936       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5937   CHECK(!GetGlobalProperty(&context, "obj2")->
5938       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5939
5940   {
5941     v8::TryCatch try_catch;
5942     CompileRun("Object.defineProperty(obj1, 'x',"
5943         "{get: function() { return 'func'; }})");
5944     CHECK(try_catch.HasCaught());
5945     String::Utf8Value exception_value(try_catch.Exception());
5946     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5947   }
5948   {
5949     v8::TryCatch try_catch;
5950     CompileRun("Object.defineProperty(obj2, 'x',"
5951         "{get: function() { return 'func'; }})");
5952     CHECK(try_catch.HasCaught());
5953     String::Utf8Value exception_value(try_catch.Exception());
5954     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5955   }
5956 }
5957
5958
5959 static void Get239Value(Local<String> name,
5960                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5961   ApiTestFuzzer::Fuzz();
5962   CHECK_EQ(info.Data(), v8_str("donut"));
5963   CHECK_EQ(name, v8_str("239"));
5964   info.GetReturnValue().Set(name);
5965 }
5966
5967
5968 THREADED_TEST(ElementAPIAccessor) {
5969   v8::Isolate* isolate = CcTest::isolate();
5970   v8::HandleScope scope(isolate);
5971   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5972   LocalContext context;
5973
5974   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5975   CompileRun("var obj2 = {};");
5976
5977   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5978         v8_str("239"),
5979         Get239Value, NULL,
5980         v8_str("donut")));
5981   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5982         v8_str("239"),
5983         Get239Value, NULL,
5984         v8_str("donut")));
5985
5986   ExpectString("obj1[239]", "239");
5987   ExpectString("obj2[239]", "239");
5988   ExpectString("obj1['239']", "239");
5989   ExpectString("obj2['239']", "239");
5990 }
5991
5992
5993 v8::Persistent<Value> xValue;
5994
5995
5996 static void SetXValue(Local<String> name,
5997                       Local<Value> value,
5998                       const v8::PropertyCallbackInfo<void>& info) {
5999   CHECK_EQ(value, v8_num(4));
6000   CHECK_EQ(info.Data(), v8_str("donut"));
6001   CHECK_EQ(name, v8_str("x"));
6002   CHECK(xValue.IsEmpty());
6003   xValue.Reset(info.GetIsolate(), value);
6004 }
6005
6006
6007 THREADED_TEST(SimplePropertyWrite) {
6008   v8::Isolate* isolate = CcTest::isolate();
6009   v8::HandleScope scope(isolate);
6010   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6011   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6012   LocalContext context;
6013   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6014   Local<Script> script = v8_compile("obj.x = 4");
6015   for (int i = 0; i < 10; i++) {
6016     CHECK(xValue.IsEmpty());
6017     script->Run();
6018     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6019     xValue.Reset();
6020   }
6021 }
6022
6023
6024 THREADED_TEST(SetterOnly) {
6025   v8::Isolate* isolate = CcTest::isolate();
6026   v8::HandleScope scope(isolate);
6027   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6028   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6029   LocalContext context;
6030   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6031   Local<Script> script = v8_compile("obj.x = 4; obj.x");
6032   for (int i = 0; i < 10; i++) {
6033     CHECK(xValue.IsEmpty());
6034     script->Run();
6035     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6036     xValue.Reset();
6037   }
6038 }
6039
6040
6041 THREADED_TEST(NoAccessors) {
6042   v8::Isolate* isolate = CcTest::isolate();
6043   v8::HandleScope scope(isolate);
6044   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6045   templ->SetAccessor(v8_str("x"),
6046                      static_cast<v8::AccessorGetterCallback>(NULL),
6047                      NULL,
6048                      v8_str("donut"));
6049   LocalContext context;
6050   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6051   Local<Script> script = v8_compile("obj.x = 4; obj.x");
6052   for (int i = 0; i < 10; i++) {
6053     script->Run();
6054   }
6055 }
6056
6057
6058 static void XPropertyGetter(Local<String> property,
6059                             const v8::PropertyCallbackInfo<v8::Value>& info) {
6060   ApiTestFuzzer::Fuzz();
6061   CHECK(info.Data()->IsUndefined());
6062   info.GetReturnValue().Set(property);
6063 }
6064
6065
6066 THREADED_TEST(NamedInterceptorPropertyRead) {
6067   v8::Isolate* isolate = CcTest::isolate();
6068   v8::HandleScope scope(isolate);
6069   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6070   templ->SetNamedPropertyHandler(XPropertyGetter);
6071   LocalContext context;
6072   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6073   Local<Script> script = v8_compile("obj.x");
6074   for (int i = 0; i < 10; i++) {
6075     Local<Value> result = script->Run();
6076     CHECK_EQ(result, v8_str("x"));
6077   }
6078 }
6079
6080
6081 THREADED_TEST(NamedInterceptorDictionaryIC) {
6082   v8::Isolate* isolate = CcTest::isolate();
6083   v8::HandleScope scope(isolate);
6084   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6085   templ->SetNamedPropertyHandler(XPropertyGetter);
6086   LocalContext context;
6087   // Create an object with a named interceptor.
6088   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6089   Local<Script> script = v8_compile("interceptor_obj.x");
6090   for (int i = 0; i < 10; i++) {
6091     Local<Value> result = script->Run();
6092     CHECK_EQ(result, v8_str("x"));
6093   }
6094   // Create a slow case object and a function accessing a property in
6095   // that slow case object (with dictionary probing in generated
6096   // code). Then force object with a named interceptor into slow-case,
6097   // pass it to the function, and check that the interceptor is called
6098   // instead of accessing the local property.
6099   Local<Value> result =
6100       CompileRun("function get_x(o) { return o.x; };"
6101                  "var obj = { x : 42, y : 0 };"
6102                  "delete obj.y;"
6103                  "for (var i = 0; i < 10; i++) get_x(obj);"
6104                  "interceptor_obj.x = 42;"
6105                  "interceptor_obj.y = 10;"
6106                  "delete interceptor_obj.y;"
6107                  "get_x(interceptor_obj)");
6108   CHECK_EQ(result, v8_str("x"));
6109 }
6110
6111
6112 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6113   v8::Isolate* isolate = CcTest::isolate();
6114   v8::HandleScope scope(isolate);
6115   v8::Local<Context> context1 = Context::New(isolate);
6116
6117   context1->Enter();
6118   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6119   templ->SetNamedPropertyHandler(XPropertyGetter);
6120   // Create an object with a named interceptor.
6121   v8::Local<v8::Object> object = templ->NewInstance();
6122   context1->Global()->Set(v8_str("interceptor_obj"), object);
6123
6124   // Force the object into the slow case.
6125   CompileRun("interceptor_obj.y = 0;"
6126              "delete interceptor_obj.y;");
6127   context1->Exit();
6128
6129   {
6130     // Introduce the object into a different context.
6131     // Repeat named loads to exercise ICs.
6132     LocalContext context2;
6133     context2->Global()->Set(v8_str("interceptor_obj"), object);
6134     Local<Value> result =
6135       CompileRun("function get_x(o) { return o.x; }"
6136                  "interceptor_obj.x = 42;"
6137                  "for (var i=0; i != 10; i++) {"
6138                  "  get_x(interceptor_obj);"
6139                  "}"
6140                  "get_x(interceptor_obj)");
6141     // Check that the interceptor was actually invoked.
6142     CHECK_EQ(result, v8_str("x"));
6143   }
6144
6145   // Return to the original context and force some object to the slow case
6146   // to cause the NormalizedMapCache to verify.
6147   context1->Enter();
6148   CompileRun("var obj = { x : 0 }; delete obj.x;");
6149   context1->Exit();
6150 }
6151
6152
6153 static void SetXOnPrototypeGetter(
6154     Local<String> property,
6155     const v8::PropertyCallbackInfo<v8::Value>& info) {
6156   // Set x on the prototype object and do not handle the get request.
6157   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6158   proto.As<v8::Object>()->Set(v8_str("x"),
6159                               v8::Integer::New(info.GetIsolate(), 23));
6160 }
6161
6162
6163 // This is a regression test for http://crbug.com/20104. Map
6164 // transitions should not interfere with post interceptor lookup.
6165 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6166   v8::Isolate* isolate = CcTest::isolate();
6167   v8::HandleScope scope(isolate);
6168   Local<v8::FunctionTemplate> function_template =
6169       v8::FunctionTemplate::New(isolate);
6170   Local<v8::ObjectTemplate> instance_template
6171       = function_template->InstanceTemplate();
6172   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
6173   LocalContext context;
6174   context->Global()->Set(v8_str("F"), function_template->GetFunction());
6175   // Create an instance of F and introduce a map transition for x.
6176   CompileRun("var o = new F(); o.x = 23;");
6177   // Create an instance of F and invoke the getter. The result should be 23.
6178   Local<Value> result = CompileRun("o = new F(); o.x");
6179   CHECK_EQ(result->Int32Value(), 23);
6180 }
6181
6182
6183 static void IndexedPropertyGetter(
6184     uint32_t index,
6185     const v8::PropertyCallbackInfo<v8::Value>& info) {
6186   ApiTestFuzzer::Fuzz();
6187   if (index == 37) {
6188     info.GetReturnValue().Set(v8_num(625));
6189   }
6190 }
6191
6192
6193 static void IndexedPropertySetter(
6194     uint32_t index,
6195     Local<Value> value,
6196     const v8::PropertyCallbackInfo<v8::Value>& info) {
6197   ApiTestFuzzer::Fuzz();
6198   if (index == 39) {
6199     info.GetReturnValue().Set(value);
6200   }
6201 }
6202
6203
6204 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6205   v8::Isolate* isolate = CcTest::isolate();
6206   v8::HandleScope scope(isolate);
6207   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6208   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6209                                    IndexedPropertySetter);
6210   LocalContext context;
6211   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6212   Local<Script> getter_script = v8_compile(
6213       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6214   Local<Script> setter_script = v8_compile(
6215       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6216       "obj[17] = 23;"
6217       "obj.foo;");
6218   Local<Script> interceptor_setter_script = v8_compile(
6219       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6220       "obj[39] = 47;"
6221       "obj.foo;");  // This setter should not run, due to the interceptor.
6222   Local<Script> interceptor_getter_script = v8_compile(
6223       "obj[37];");
6224   Local<Value> result = getter_script->Run();
6225   CHECK_EQ(v8_num(5), result);
6226   result = setter_script->Run();
6227   CHECK_EQ(v8_num(23), result);
6228   result = interceptor_setter_script->Run();
6229   CHECK_EQ(v8_num(23), result);
6230   result = interceptor_getter_script->Run();
6231   CHECK_EQ(v8_num(625), result);
6232 }
6233
6234
6235 static void UnboxedDoubleIndexedPropertyGetter(
6236     uint32_t index,
6237     const v8::PropertyCallbackInfo<v8::Value>& info) {
6238   ApiTestFuzzer::Fuzz();
6239   if (index < 25) {
6240     info.GetReturnValue().Set(v8_num(index));
6241   }
6242 }
6243
6244
6245 static void UnboxedDoubleIndexedPropertySetter(
6246     uint32_t index,
6247     Local<Value> value,
6248     const v8::PropertyCallbackInfo<v8::Value>& info) {
6249   ApiTestFuzzer::Fuzz();
6250   if (index < 25) {
6251     info.GetReturnValue().Set(v8_num(index));
6252   }
6253 }
6254
6255
6256 void UnboxedDoubleIndexedPropertyEnumerator(
6257     const v8::PropertyCallbackInfo<v8::Array>& info) {
6258   // Force the list of returned keys to be stored in a FastDoubleArray.
6259   Local<Script> indexed_property_names_script = v8_compile(
6260       "keys = new Array(); keys[125000] = 1;"
6261       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6262       "keys.length = 25; keys;");
6263   Local<Value> result = indexed_property_names_script->Run();
6264   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6265 }
6266
6267
6268 // Make sure that the the interceptor code in the runtime properly handles
6269 // merging property name lists for double-array-backed arrays.
6270 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6271   v8::Isolate* isolate = CcTest::isolate();
6272   v8::HandleScope scope(isolate);
6273   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6274   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6275                                    UnboxedDoubleIndexedPropertySetter,
6276                                    0,
6277                                    0,
6278                                    UnboxedDoubleIndexedPropertyEnumerator);
6279   LocalContext context;
6280   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6281   // When obj is created, force it to be Stored in a FastDoubleArray.
6282   Local<Script> create_unboxed_double_script = v8_compile(
6283       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6284       "key_count = 0; "
6285       "for (x in obj) {key_count++;};"
6286       "obj;");
6287   Local<Value> result = create_unboxed_double_script->Run();
6288   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6289   Local<Script> key_count_check = v8_compile("key_count;");
6290   result = key_count_check->Run();
6291   CHECK_EQ(v8_num(40013), result);
6292 }
6293
6294
6295 void SloppyArgsIndexedPropertyEnumerator(
6296     const v8::PropertyCallbackInfo<v8::Array>& info) {
6297   // Force the list of returned keys to be stored in a Arguments object.
6298   Local<Script> indexed_property_names_script = v8_compile(
6299       "function f(w,x) {"
6300       " return arguments;"
6301       "}"
6302       "keys = f(0, 1, 2, 3);"
6303       "keys;");
6304   Local<Object> result =
6305       Local<Object>::Cast(indexed_property_names_script->Run());
6306   // Have to populate the handle manually, as it's not Cast-able.
6307   i::Handle<i::JSObject> o =
6308       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6309   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6310   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6311 }
6312
6313
6314 static void SloppyIndexedPropertyGetter(
6315     uint32_t index,
6316     const v8::PropertyCallbackInfo<v8::Value>& info) {
6317   ApiTestFuzzer::Fuzz();
6318   if (index < 4) {
6319     info.GetReturnValue().Set(v8_num(index));
6320   }
6321 }
6322
6323
6324 // Make sure that the the interceptor code in the runtime properly handles
6325 // merging property name lists for non-string arguments arrays.
6326 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6327   v8::Isolate* isolate = CcTest::isolate();
6328   v8::HandleScope scope(isolate);
6329   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6330   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6331                                    0,
6332                                    0,
6333                                    0,
6334                                    SloppyArgsIndexedPropertyEnumerator);
6335   LocalContext context;
6336   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6337   Local<Script> create_args_script = v8_compile(
6338       "var key_count = 0;"
6339       "for (x in obj) {key_count++;} key_count;");
6340   Local<Value> result = create_args_script->Run();
6341   CHECK_EQ(v8_num(4), result);
6342 }
6343
6344
6345 static void IdentityIndexedPropertyGetter(
6346     uint32_t index,
6347     const v8::PropertyCallbackInfo<v8::Value>& info) {
6348   info.GetReturnValue().Set(index);
6349 }
6350
6351
6352 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6353   v8::Isolate* isolate = CcTest::isolate();
6354   v8::HandleScope scope(isolate);
6355   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6356   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6357
6358   LocalContext context;
6359   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6360
6361   // Check fast object case.
6362   const char* fast_case_code =
6363       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6364   ExpectString(fast_case_code, "0");
6365
6366   // Check slow case.
6367   const char* slow_case_code =
6368       "obj.x = 1; delete obj.x;"
6369       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6370   ExpectString(slow_case_code, "1");
6371 }
6372
6373
6374 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6375   v8::Isolate* isolate = CcTest::isolate();
6376   v8::HandleScope scope(isolate);
6377   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6378   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6379
6380   LocalContext context;
6381   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6382
6383   const char* code =
6384       "try {"
6385       "  obj[0] = 239;"
6386       "  for (var i = 0; i < 100; i++) {"
6387       "    var v = obj[0];"
6388       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6389       "  }"
6390       "  'PASSED'"
6391       "} catch(e) {"
6392       "  e"
6393       "}";
6394   ExpectString(code, "PASSED");
6395 }
6396
6397
6398 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6399   v8::Isolate* isolate = CcTest::isolate();
6400   v8::HandleScope scope(isolate);
6401   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6402   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6403
6404   LocalContext context;
6405   Local<v8::Object> obj = templ->NewInstance();
6406   obj->TurnOnAccessCheck();
6407   context->Global()->Set(v8_str("obj"), obj);
6408
6409   const char* code =
6410       "var result = 'PASSED';"
6411       "for (var i = 0; i < 100; i++) {"
6412       "  try {"
6413       "    var v = obj[0];"
6414       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
6415       "    break;"
6416       "  } catch (e) {"
6417       "    /* pass */"
6418       "  }"
6419       "}"
6420       "result";
6421   ExpectString(code, "PASSED");
6422 }
6423
6424
6425 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6426   i::FLAG_allow_natives_syntax = true;
6427   v8::Isolate* isolate = CcTest::isolate();
6428   v8::HandleScope scope(isolate);
6429   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6430   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6431
6432   LocalContext context;
6433   Local<v8::Object> obj = templ->NewInstance();
6434   context->Global()->Set(v8_str("obj"), obj);
6435
6436   const char* code =
6437       "var result = 'PASSED';"
6438       "for (var i = 0; i < 100; i++) {"
6439       "  var expected = i;"
6440       "  if (i == 5) {"
6441       "    %EnableAccessChecks(obj);"
6442       "  }"
6443       "  try {"
6444       "    var v = obj[i];"
6445       "    if (i == 5) {"
6446       "      result = 'Should not have reached this!';"
6447       "      break;"
6448       "    } else if (v != expected) {"
6449       "      result = 'Wrong value ' + v + ' at iteration ' + i;"
6450       "      break;"
6451       "    }"
6452       "  } catch (e) {"
6453       "    if (i != 5) {"
6454       "      result = e;"
6455       "    }"
6456       "  }"
6457       "  if (i == 5) %DisableAccessChecks(obj);"
6458       "}"
6459       "result";
6460   ExpectString(code, "PASSED");
6461 }
6462
6463
6464 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6465   v8::Isolate* isolate = CcTest::isolate();
6466   v8::HandleScope scope(isolate);
6467   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6468   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6469
6470   LocalContext context;
6471   Local<v8::Object> obj = templ->NewInstance();
6472   context->Global()->Set(v8_str("obj"), obj);
6473
6474   const char* code =
6475       "try {"
6476       "  for (var i = 0; i < 100; i++) {"
6477       "    var v = obj[i];"
6478       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6479       "  }"
6480       "  'PASSED'"
6481       "} catch(e) {"
6482       "  e"
6483       "}";
6484   ExpectString(code, "PASSED");
6485 }
6486
6487
6488 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6489   v8::Isolate* isolate = CcTest::isolate();
6490   v8::HandleScope scope(isolate);
6491   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6492   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6493
6494   LocalContext context;
6495   Local<v8::Object> obj = templ->NewInstance();
6496   context->Global()->Set(v8_str("obj"), obj);
6497
6498   const char* code =
6499       "try {"
6500       "  for (var i = 0; i < 100; i++) {"
6501       "    var expected = i;"
6502       "    var key = i;"
6503       "    if (i == 25) {"
6504       "       key = -1;"
6505       "       expected = undefined;"
6506       "    }"
6507       "    if (i == 50) {"
6508       "       /* probe minimal Smi number on 32-bit platforms */"
6509       "       key = -(1 << 30);"
6510       "       expected = undefined;"
6511       "    }"
6512       "    if (i == 75) {"
6513       "       /* probe minimal Smi number on 64-bit platforms */"
6514       "       key = 1 << 31;"
6515       "       expected = undefined;"
6516       "    }"
6517       "    var v = obj[key];"
6518       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6519       "  }"
6520       "  'PASSED'"
6521       "} catch(e) {"
6522       "  e"
6523       "}";
6524   ExpectString(code, "PASSED");
6525 }
6526
6527
6528 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6529   v8::Isolate* isolate = CcTest::isolate();
6530   v8::HandleScope scope(isolate);
6531   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6532   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6533
6534   LocalContext context;
6535   Local<v8::Object> obj = templ->NewInstance();
6536   context->Global()->Set(v8_str("obj"), obj);
6537
6538   const char* code =
6539       "try {"
6540       "  for (var i = 0; i < 100; i++) {"
6541       "    var expected = i;"
6542       "    var key = i;"
6543       "    if (i == 50) {"
6544       "       key = 'foobar';"
6545       "       expected = undefined;"
6546       "    }"
6547       "    var v = obj[key];"
6548       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6549       "  }"
6550       "  'PASSED'"
6551       "} catch(e) {"
6552       "  e"
6553       "}";
6554   ExpectString(code, "PASSED");
6555 }
6556
6557
6558 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6559   v8::Isolate* isolate = CcTest::isolate();
6560   v8::HandleScope scope(isolate);
6561   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6562   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6563
6564   LocalContext context;
6565   Local<v8::Object> obj = templ->NewInstance();
6566   context->Global()->Set(v8_str("obj"), obj);
6567
6568   const char* code =
6569       "var original = obj;"
6570       "try {"
6571       "  for (var i = 0; i < 100; i++) {"
6572       "    var expected = i;"
6573       "    if (i == 50) {"
6574       "       obj = {50: 'foobar'};"
6575       "       expected = 'foobar';"
6576       "    }"
6577       "    var v = obj[i];"
6578       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6579       "    if (i == 50) obj = original;"
6580       "  }"
6581       "  'PASSED'"
6582       "} catch(e) {"
6583       "  e"
6584       "}";
6585   ExpectString(code, "PASSED");
6586 }
6587
6588
6589 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6590   v8::Isolate* isolate = CcTest::isolate();
6591   v8::HandleScope scope(isolate);
6592   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6593   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6594
6595   LocalContext context;
6596   Local<v8::Object> obj = templ->NewInstance();
6597   context->Global()->Set(v8_str("obj"), obj);
6598
6599   const char* code =
6600       "var original = obj;"
6601       "try {"
6602       "  for (var i = 0; i < 100; i++) {"
6603       "    var expected = i;"
6604       "    if (i == 5) {"
6605       "       obj = 239;"
6606       "       expected = undefined;"
6607       "    }"
6608       "    var v = obj[i];"
6609       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6610       "    if (i == 5) obj = original;"
6611       "  }"
6612       "  'PASSED'"
6613       "} catch(e) {"
6614       "  e"
6615       "}";
6616   ExpectString(code, "PASSED");
6617 }
6618
6619
6620 THREADED_TEST(IndexedInterceptorOnProto) {
6621   v8::Isolate* isolate = CcTest::isolate();
6622   v8::HandleScope scope(isolate);
6623   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6624   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6625
6626   LocalContext context;
6627   Local<v8::Object> obj = templ->NewInstance();
6628   context->Global()->Set(v8_str("obj"), obj);
6629
6630   const char* code =
6631       "var o = {__proto__: obj};"
6632       "try {"
6633       "  for (var i = 0; i < 100; i++) {"
6634       "    var v = o[i];"
6635       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6636       "  }"
6637       "  'PASSED'"
6638       "} catch(e) {"
6639       "  e"
6640       "}";
6641   ExpectString(code, "PASSED");
6642 }
6643
6644
6645 THREADED_TEST(MultiContexts) {
6646   v8::Isolate* isolate = CcTest::isolate();
6647   v8::HandleScope scope(isolate);
6648   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6649   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6650                                                         DummyCallHandler));
6651
6652   Local<String> password = v8_str("Password");
6653
6654   // Create an environment
6655   LocalContext context0(0, templ);
6656   context0->SetSecurityToken(password);
6657   v8::Handle<v8::Object> global0 = context0->Global();
6658   global0->Set(v8_str("custom"), v8_num(1234));
6659   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6660
6661   // Create an independent environment
6662   LocalContext context1(0, templ);
6663   context1->SetSecurityToken(password);
6664   v8::Handle<v8::Object> global1 = context1->Global();
6665   global1->Set(v8_str("custom"), v8_num(1234));
6666   CHECK_NE(global0, global1);
6667   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6668   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6669
6670   // Now create a new context with the old global
6671   LocalContext context2(0, templ, global1);
6672   context2->SetSecurityToken(password);
6673   v8::Handle<v8::Object> global2 = context2->Global();
6674   CHECK_EQ(global1, global2);
6675   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6676   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6677 }
6678
6679
6680 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6681   // Make sure that functions created by cloning boilerplates cannot
6682   // communicate through their __proto__ field.
6683
6684   v8::HandleScope scope(CcTest::isolate());
6685
6686   LocalContext env0;
6687   v8::Handle<v8::Object> global0 =
6688       env0->Global();
6689   v8::Handle<v8::Object> object0 =
6690       global0->Get(v8_str("Object")).As<v8::Object>();
6691   v8::Handle<v8::Object> tostring0 =
6692       object0->Get(v8_str("toString")).As<v8::Object>();
6693   v8::Handle<v8::Object> proto0 =
6694       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6695   proto0->Set(v8_str("custom"), v8_num(1234));
6696
6697   LocalContext env1;
6698   v8::Handle<v8::Object> global1 =
6699       env1->Global();
6700   v8::Handle<v8::Object> object1 =
6701       global1->Get(v8_str("Object")).As<v8::Object>();
6702   v8::Handle<v8::Object> tostring1 =
6703       object1->Get(v8_str("toString")).As<v8::Object>();
6704   v8::Handle<v8::Object> proto1 =
6705       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6706   CHECK(!proto1->Has(v8_str("custom")));
6707 }
6708
6709
6710 THREADED_TEST(Regress892105) {
6711   // Make sure that object and array literals created by cloning
6712   // boilerplates cannot communicate through their __proto__
6713   // field. This is rather difficult to check, but we try to add stuff
6714   // to Object.prototype and Array.prototype and create a new
6715   // environment. This should succeed.
6716
6717   v8::HandleScope scope(CcTest::isolate());
6718
6719   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6720                                 "Array.prototype.arr = 4567;"
6721                                 "8901");
6722
6723   LocalContext env0;
6724   Local<Script> script0 = v8_compile(source);
6725   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6726
6727   LocalContext env1;
6728   Local<Script> script1 = v8_compile(source);
6729   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6730 }
6731
6732
6733 THREADED_TEST(UndetectableObject) {
6734   LocalContext env;
6735   v8::HandleScope scope(env->GetIsolate());
6736
6737   Local<v8::FunctionTemplate> desc =
6738       v8::FunctionTemplate::New(env->GetIsolate());
6739   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6740
6741   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6742   env->Global()->Set(v8_str("undetectable"), obj);
6743
6744   ExpectString("undetectable.toString()", "[object Object]");
6745   ExpectString("typeof undetectable", "undefined");
6746   ExpectString("typeof(undetectable)", "undefined");
6747   ExpectBoolean("typeof undetectable == 'undefined'", true);
6748   ExpectBoolean("typeof undetectable == 'object'", false);
6749   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6750   ExpectBoolean("!undetectable", true);
6751
6752   ExpectObject("true&&undetectable", obj);
6753   ExpectBoolean("false&&undetectable", false);
6754   ExpectBoolean("true||undetectable", true);
6755   ExpectObject("false||undetectable", obj);
6756
6757   ExpectObject("undetectable&&true", obj);
6758   ExpectObject("undetectable&&false", obj);
6759   ExpectBoolean("undetectable||true", true);
6760   ExpectBoolean("undetectable||false", false);
6761
6762   ExpectBoolean("undetectable==null", true);
6763   ExpectBoolean("null==undetectable", true);
6764   ExpectBoolean("undetectable==undefined", true);
6765   ExpectBoolean("undefined==undetectable", true);
6766   ExpectBoolean("undetectable==undetectable", true);
6767
6768
6769   ExpectBoolean("undetectable===null", false);
6770   ExpectBoolean("null===undetectable", false);
6771   ExpectBoolean("undetectable===undefined", false);
6772   ExpectBoolean("undefined===undetectable", false);
6773   ExpectBoolean("undetectable===undetectable", true);
6774 }
6775
6776
6777 THREADED_TEST(VoidLiteral) {
6778   LocalContext env;
6779   v8::Isolate* isolate = env->GetIsolate();
6780   v8::HandleScope scope(isolate);
6781
6782   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6783   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6784
6785   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6786   env->Global()->Set(v8_str("undetectable"), obj);
6787
6788   ExpectBoolean("undefined == void 0", true);
6789   ExpectBoolean("undetectable == void 0", true);
6790   ExpectBoolean("null == void 0", true);
6791   ExpectBoolean("undefined === void 0", true);
6792   ExpectBoolean("undetectable === void 0", false);
6793   ExpectBoolean("null === void 0", false);
6794
6795   ExpectBoolean("void 0 == undefined", true);
6796   ExpectBoolean("void 0 == undetectable", true);
6797   ExpectBoolean("void 0 == null", true);
6798   ExpectBoolean("void 0 === undefined", true);
6799   ExpectBoolean("void 0 === undetectable", false);
6800   ExpectBoolean("void 0 === null", false);
6801
6802   ExpectString("(function() {"
6803                "  try {"
6804                "    return x === void 0;"
6805                "  } catch(e) {"
6806                "    return e.toString();"
6807                "  }"
6808                "})()",
6809                "ReferenceError: x is not defined");
6810   ExpectString("(function() {"
6811                "  try {"
6812                "    return void 0 === x;"
6813                "  } catch(e) {"
6814                "    return e.toString();"
6815                "  }"
6816                "})()",
6817                "ReferenceError: x is not defined");
6818 }
6819
6820
6821 THREADED_TEST(ExtensibleOnUndetectable) {
6822   LocalContext env;
6823   v8::Isolate* isolate = env->GetIsolate();
6824   v8::HandleScope scope(isolate);
6825
6826   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6827   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6828
6829   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6830   env->Global()->Set(v8_str("undetectable"), obj);
6831
6832   Local<String> source = v8_str("undetectable.x = 42;"
6833                                 "undetectable.x");
6834
6835   Local<Script> script = v8_compile(source);
6836
6837   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6838
6839   ExpectBoolean("Object.isExtensible(undetectable)", true);
6840
6841   source = v8_str("Object.preventExtensions(undetectable);");
6842   script = v8_compile(source);
6843   script->Run();
6844   ExpectBoolean("Object.isExtensible(undetectable)", false);
6845
6846   source = v8_str("undetectable.y = 2000;");
6847   script = v8_compile(source);
6848   script->Run();
6849   ExpectBoolean("undetectable.y == undefined", true);
6850 }
6851
6852
6853
6854 THREADED_TEST(UndetectableString) {
6855   LocalContext env;
6856   v8::HandleScope scope(env->GetIsolate());
6857
6858   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6859                                           String::kUndetectableString);
6860   env->Global()->Set(v8_str("undetectable"), obj);
6861
6862   ExpectString("undetectable", "foo");
6863   ExpectString("typeof undetectable", "undefined");
6864   ExpectString("typeof(undetectable)", "undefined");
6865   ExpectBoolean("typeof undetectable == 'undefined'", true);
6866   ExpectBoolean("typeof undetectable == 'string'", false);
6867   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6868   ExpectBoolean("!undetectable", true);
6869
6870   ExpectObject("true&&undetectable", obj);
6871   ExpectBoolean("false&&undetectable", false);
6872   ExpectBoolean("true||undetectable", true);
6873   ExpectObject("false||undetectable", obj);
6874
6875   ExpectObject("undetectable&&true", obj);
6876   ExpectObject("undetectable&&false", obj);
6877   ExpectBoolean("undetectable||true", true);
6878   ExpectBoolean("undetectable||false", false);
6879
6880   ExpectBoolean("undetectable==null", true);
6881   ExpectBoolean("null==undetectable", true);
6882   ExpectBoolean("undetectable==undefined", true);
6883   ExpectBoolean("undefined==undetectable", true);
6884   ExpectBoolean("undetectable==undetectable", true);
6885
6886
6887   ExpectBoolean("undetectable===null", false);
6888   ExpectBoolean("null===undetectable", false);
6889   ExpectBoolean("undetectable===undefined", false);
6890   ExpectBoolean("undefined===undetectable", false);
6891   ExpectBoolean("undetectable===undetectable", true);
6892 }
6893
6894
6895 TEST(UndetectableOptimized) {
6896   i::FLAG_allow_natives_syntax = true;
6897   LocalContext env;
6898   v8::HandleScope scope(env->GetIsolate());
6899
6900   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6901                                           String::kUndetectableString);
6902   env->Global()->Set(v8_str("undetectable"), obj);
6903   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6904
6905   ExpectString(
6906       "function testBranch() {"
6907       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6908       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6909       "}\n"
6910       "function testBool() {"
6911       "  var b1 = !%_IsUndetectableObject(undetectable);"
6912       "  var b2 = %_IsUndetectableObject(detectable);"
6913       "  if (b1) throw 3;"
6914       "  if (b2) throw 4;"
6915       "  return b1 == b2;"
6916       "}\n"
6917       "%OptimizeFunctionOnNextCall(testBranch);"
6918       "%OptimizeFunctionOnNextCall(testBool);"
6919       "for (var i = 0; i < 10; i++) {"
6920       "  testBranch();"
6921       "  testBool();"
6922       "}\n"
6923       "\"PASS\"",
6924       "PASS");
6925 }
6926
6927
6928 // The point of this test is type checking. We run it only so compilers
6929 // don't complain about an unused function.
6930 TEST(PersistentHandles) {
6931   LocalContext env;
6932   v8::Isolate* isolate = CcTest::isolate();
6933   v8::HandleScope scope(isolate);
6934   Local<String> str = v8_str("foo");
6935   v8::Persistent<String> p_str(isolate, str);
6936   p_str.Reset();
6937   Local<Script> scr = v8_compile("");
6938   v8::Persistent<Script> p_scr(isolate, scr);
6939   p_scr.Reset();
6940   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6941   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6942   p_templ.Reset();
6943 }
6944
6945
6946 static void HandleLogDelegator(
6947     const v8::FunctionCallbackInfo<v8::Value>& args) {
6948   ApiTestFuzzer::Fuzz();
6949 }
6950
6951
6952 THREADED_TEST(GlobalObjectTemplate) {
6953   v8::Isolate* isolate = CcTest::isolate();
6954   v8::HandleScope handle_scope(isolate);
6955   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6956   global_template->Set(v8_str("JSNI_Log"),
6957                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6958   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6959   Context::Scope context_scope(context);
6960   CompileRun("JSNI_Log('LOG')");
6961 }
6962
6963
6964 static const char* kSimpleExtensionSource =
6965   "function Foo() {"
6966   "  return 4;"
6967   "}";
6968
6969
6970 TEST(SimpleExtensions) {
6971   v8::HandleScope handle_scope(CcTest::isolate());
6972   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6973   const char* extension_names[] = { "simpletest" };
6974   v8::ExtensionConfiguration extensions(1, extension_names);
6975   v8::Handle<Context> context =
6976       Context::New(CcTest::isolate(), &extensions);
6977   Context::Scope lock(context);
6978   v8::Handle<Value> result = CompileRun("Foo()");
6979   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6980 }
6981
6982
6983 static const char* kStackTraceFromExtensionSource =
6984   "function foo() {"
6985   "  throw new Error();"
6986   "}"
6987   "function bar() {"
6988   "  foo();"
6989   "}";
6990
6991
6992 TEST(StackTraceInExtension) {
6993   v8::HandleScope handle_scope(CcTest::isolate());
6994   v8::RegisterExtension(new Extension("stacktracetest",
6995                         kStackTraceFromExtensionSource));
6996   const char* extension_names[] = { "stacktracetest" };
6997   v8::ExtensionConfiguration extensions(1, extension_names);
6998   v8::Handle<Context> context =
6999       Context::New(CcTest::isolate(), &extensions);
7000   Context::Scope lock(context);
7001   CompileRun("function user() { bar(); }"
7002              "var error;"
7003              "try{ user(); } catch (e) { error = e; }");
7004   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7005   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7006   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7007 }
7008
7009
7010 TEST(NullExtensions) {
7011   v8::HandleScope handle_scope(CcTest::isolate());
7012   v8::RegisterExtension(new Extension("nulltest", NULL));
7013   const char* extension_names[] = { "nulltest" };
7014   v8::ExtensionConfiguration extensions(1, extension_names);
7015   v8::Handle<Context> context =
7016       Context::New(CcTest::isolate(), &extensions);
7017   Context::Scope lock(context);
7018   v8::Handle<Value> result = CompileRun("1+3");
7019   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7020 }
7021
7022
7023 static const char* kEmbeddedExtensionSource =
7024     "function Ret54321(){return 54321;}~~@@$"
7025     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7026 static const int kEmbeddedExtensionSourceValidLen = 34;
7027
7028
7029 TEST(ExtensionMissingSourceLength) {
7030   v8::HandleScope handle_scope(CcTest::isolate());
7031   v8::RegisterExtension(new Extension("srclentest_fail",
7032                                       kEmbeddedExtensionSource));
7033   const char* extension_names[] = { "srclentest_fail" };
7034   v8::ExtensionConfiguration extensions(1, extension_names);
7035   v8::Handle<Context> context =
7036       Context::New(CcTest::isolate(), &extensions);
7037   CHECK_EQ(0, *context);
7038 }
7039
7040
7041 TEST(ExtensionWithSourceLength) {
7042   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7043        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7044     v8::HandleScope handle_scope(CcTest::isolate());
7045     i::ScopedVector<char> extension_name(32);
7046     i::SNPrintF(extension_name, "ext #%d", source_len);
7047     v8::RegisterExtension(new Extension(extension_name.start(),
7048                                         kEmbeddedExtensionSource, 0, 0,
7049                                         source_len));
7050     const char* extension_names[1] = { extension_name.start() };
7051     v8::ExtensionConfiguration extensions(1, extension_names);
7052     v8::Handle<Context> context =
7053       Context::New(CcTest::isolate(), &extensions);
7054     if (source_len == kEmbeddedExtensionSourceValidLen) {
7055       Context::Scope lock(context);
7056       v8::Handle<Value> result = CompileRun("Ret54321()");
7057       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
7058     } else {
7059       // Anything but exactly the right length should fail to compile.
7060       CHECK_EQ(0, *context);
7061     }
7062   }
7063 }
7064
7065
7066 static const char* kEvalExtensionSource1 =
7067   "function UseEval1() {"
7068   "  var x = 42;"
7069   "  return eval('x');"
7070   "}";
7071
7072
7073 static const char* kEvalExtensionSource2 =
7074   "(function() {"
7075   "  var x = 42;"
7076   "  function e() {"
7077   "    return eval('x');"
7078   "  }"
7079   "  this.UseEval2 = e;"
7080   "})()";
7081
7082
7083 TEST(UseEvalFromExtension) {
7084   v8::HandleScope handle_scope(CcTest::isolate());
7085   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7086   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7087   const char* extension_names[] = { "evaltest1", "evaltest2" };
7088   v8::ExtensionConfiguration extensions(2, extension_names);
7089   v8::Handle<Context> context =
7090       Context::New(CcTest::isolate(), &extensions);
7091   Context::Scope lock(context);
7092   v8::Handle<Value> result = CompileRun("UseEval1()");
7093   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7094   result = CompileRun("UseEval2()");
7095   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7096 }
7097
7098
7099 static const char* kWithExtensionSource1 =
7100   "function UseWith1() {"
7101   "  var x = 42;"
7102   "  with({x:87}) { return x; }"
7103   "}";
7104
7105
7106
7107 static const char* kWithExtensionSource2 =
7108   "(function() {"
7109   "  var x = 42;"
7110   "  function e() {"
7111   "    with ({x:87}) { return x; }"
7112   "  }"
7113   "  this.UseWith2 = e;"
7114   "})()";
7115
7116
7117 TEST(UseWithFromExtension) {
7118   v8::HandleScope handle_scope(CcTest::isolate());
7119   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7120   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7121   const char* extension_names[] = { "withtest1", "withtest2" };
7122   v8::ExtensionConfiguration extensions(2, extension_names);
7123   v8::Handle<Context> context =
7124       Context::New(CcTest::isolate(), &extensions);
7125   Context::Scope lock(context);
7126   v8::Handle<Value> result = CompileRun("UseWith1()");
7127   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7128   result = CompileRun("UseWith2()");
7129   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7130 }
7131
7132
7133 TEST(AutoExtensions) {
7134   v8::HandleScope handle_scope(CcTest::isolate());
7135   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7136   extension->set_auto_enable(true);
7137   v8::RegisterExtension(extension);
7138   v8::Handle<Context> context =
7139       Context::New(CcTest::isolate());
7140   Context::Scope lock(context);
7141   v8::Handle<Value> result = CompileRun("Foo()");
7142   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7143 }
7144
7145
7146 static const char* kSyntaxErrorInExtensionSource =
7147     "[";
7148
7149
7150 // Test that a syntax error in an extension does not cause a fatal
7151 // error but results in an empty context.
7152 TEST(SyntaxErrorExtensions) {
7153   v8::HandleScope handle_scope(CcTest::isolate());
7154   v8::RegisterExtension(new Extension("syntaxerror",
7155                                       kSyntaxErrorInExtensionSource));
7156   const char* extension_names[] = { "syntaxerror" };
7157   v8::ExtensionConfiguration extensions(1, extension_names);
7158   v8::Handle<Context> context =
7159       Context::New(CcTest::isolate(), &extensions);
7160   CHECK(context.IsEmpty());
7161 }
7162
7163
7164 static const char* kExceptionInExtensionSource =
7165     "throw 42";
7166
7167
7168 // Test that an exception when installing an extension does not cause
7169 // a fatal error but results in an empty context.
7170 TEST(ExceptionExtensions) {
7171   v8::HandleScope handle_scope(CcTest::isolate());
7172   v8::RegisterExtension(new Extension("exception",
7173                                       kExceptionInExtensionSource));
7174   const char* extension_names[] = { "exception" };
7175   v8::ExtensionConfiguration extensions(1, extension_names);
7176   v8::Handle<Context> context =
7177       Context::New(CcTest::isolate(), &extensions);
7178   CHECK(context.IsEmpty());
7179 }
7180
7181
7182 static const char* kNativeCallInExtensionSource =
7183     "function call_runtime_last_index_of(x) {"
7184     "  return %StringLastIndexOf(x, 'bob', 10);"
7185     "}";
7186
7187
7188 static const char* kNativeCallTest =
7189     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7190
7191 // Test that a native runtime calls are supported in extensions.
7192 TEST(NativeCallInExtensions) {
7193   v8::HandleScope handle_scope(CcTest::isolate());
7194   v8::RegisterExtension(new Extension("nativecall",
7195                                       kNativeCallInExtensionSource));
7196   const char* extension_names[] = { "nativecall" };
7197   v8::ExtensionConfiguration extensions(1, extension_names);
7198   v8::Handle<Context> context =
7199       Context::New(CcTest::isolate(), &extensions);
7200   Context::Scope lock(context);
7201   v8::Handle<Value> result = CompileRun(kNativeCallTest);
7202   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7203 }
7204
7205
7206 class NativeFunctionExtension : public Extension {
7207  public:
7208   NativeFunctionExtension(const char* name,
7209                           const char* source,
7210                           v8::FunctionCallback fun = &Echo)
7211       : Extension(name, source),
7212         function_(fun) { }
7213
7214   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7215       v8::Isolate* isolate,
7216       v8::Handle<v8::String> name) {
7217     return v8::FunctionTemplate::New(isolate, function_);
7218   }
7219
7220   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7221     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7222   }
7223  private:
7224   v8::FunctionCallback function_;
7225 };
7226
7227
7228 TEST(NativeFunctionDeclaration) {
7229   v8::HandleScope handle_scope(CcTest::isolate());
7230   const char* name = "nativedecl";
7231   v8::RegisterExtension(new NativeFunctionExtension(name,
7232                                                     "native function foo();"));
7233   const char* extension_names[] = { name };
7234   v8::ExtensionConfiguration extensions(1, extension_names);
7235   v8::Handle<Context> context =
7236       Context::New(CcTest::isolate(), &extensions);
7237   Context::Scope lock(context);
7238   v8::Handle<Value> result = CompileRun("foo(42);");
7239   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7240 }
7241
7242
7243 TEST(NativeFunctionDeclarationError) {
7244   v8::HandleScope handle_scope(CcTest::isolate());
7245   const char* name = "nativedeclerr";
7246   // Syntax error in extension code.
7247   v8::RegisterExtension(new NativeFunctionExtension(name,
7248                                                     "native\nfunction foo();"));
7249   const char* extension_names[] = { name };
7250   v8::ExtensionConfiguration extensions(1, extension_names);
7251   v8::Handle<Context> context =
7252       Context::New(CcTest::isolate(), &extensions);
7253   CHECK(context.IsEmpty());
7254 }
7255
7256
7257 TEST(NativeFunctionDeclarationErrorEscape) {
7258   v8::HandleScope handle_scope(CcTest::isolate());
7259   const char* name = "nativedeclerresc";
7260   // Syntax error in extension code - escape code in "native" means that
7261   // it's not treated as a keyword.
7262   v8::RegisterExtension(new NativeFunctionExtension(
7263       name,
7264       "nativ\\u0065 function foo();"));
7265   const char* extension_names[] = { name };
7266   v8::ExtensionConfiguration extensions(1, extension_names);
7267   v8::Handle<Context> context =
7268       Context::New(CcTest::isolate(), &extensions);
7269   CHECK(context.IsEmpty());
7270 }
7271
7272
7273 static void CheckDependencies(const char* name, const char* expected) {
7274   v8::HandleScope handle_scope(CcTest::isolate());
7275   v8::ExtensionConfiguration config(1, &name);
7276   LocalContext context(&config);
7277   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7278            context->Global()->Get(v8_str("loaded")));
7279 }
7280
7281
7282 /*
7283  * Configuration:
7284  *
7285  *     /-- B <--\
7286  * A <-          -- D <-- E
7287  *     \-- C <--/
7288  */
7289 THREADED_TEST(ExtensionDependency) {
7290   static const char* kEDeps[] = { "D" };
7291   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7292   static const char* kDDeps[] = { "B", "C" };
7293   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7294   static const char* kBCDeps[] = { "A" };
7295   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7296   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7297   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7298   CheckDependencies("A", "undefinedA");
7299   CheckDependencies("B", "undefinedAB");
7300   CheckDependencies("C", "undefinedAC");
7301   CheckDependencies("D", "undefinedABCD");
7302   CheckDependencies("E", "undefinedABCDE");
7303   v8::HandleScope handle_scope(CcTest::isolate());
7304   static const char* exts[2] = { "C", "E" };
7305   v8::ExtensionConfiguration config(2, exts);
7306   LocalContext context(&config);
7307   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7308 }
7309
7310
7311 static const char* kExtensionTestScript =
7312   "native function A();"
7313   "native function B();"
7314   "native function C();"
7315   "function Foo(i) {"
7316   "  if (i == 0) return A();"
7317   "  if (i == 1) return B();"
7318   "  if (i == 2) return C();"
7319   "}";
7320
7321
7322 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7323   ApiTestFuzzer::Fuzz();
7324   if (args.IsConstructCall()) {
7325     args.This()->Set(v8_str("data"), args.Data());
7326     args.GetReturnValue().SetNull();
7327     return;
7328   }
7329   args.GetReturnValue().Set(args.Data());
7330 }
7331
7332
7333 class FunctionExtension : public Extension {
7334  public:
7335   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7336   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7337       v8::Isolate* isolate,
7338       v8::Handle<String> name);
7339 };
7340
7341
7342 static int lookup_count = 0;
7343 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7344     v8::Isolate* isolate, v8::Handle<String> name) {
7345   lookup_count++;
7346   if (name->Equals(v8_str("A"))) {
7347     return v8::FunctionTemplate::New(
7348         isolate, CallFun, v8::Integer::New(isolate, 8));
7349   } else if (name->Equals(v8_str("B"))) {
7350     return v8::FunctionTemplate::New(
7351         isolate, CallFun, v8::Integer::New(isolate, 7));
7352   } else if (name->Equals(v8_str("C"))) {
7353     return v8::FunctionTemplate::New(
7354         isolate, CallFun, v8::Integer::New(isolate, 6));
7355   } else {
7356     return v8::Handle<v8::FunctionTemplate>();
7357   }
7358 }
7359
7360
7361 THREADED_TEST(FunctionLookup) {
7362   v8::RegisterExtension(new FunctionExtension());
7363   v8::HandleScope handle_scope(CcTest::isolate());
7364   static const char* exts[1] = { "functiontest" };
7365   v8::ExtensionConfiguration config(1, exts);
7366   LocalContext context(&config);
7367   CHECK_EQ(3, lookup_count);
7368   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7369            CompileRun("Foo(0)"));
7370   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7371            CompileRun("Foo(1)"));
7372   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7373            CompileRun("Foo(2)"));
7374 }
7375
7376
7377 THREADED_TEST(NativeFunctionConstructCall) {
7378   v8::RegisterExtension(new FunctionExtension());
7379   v8::HandleScope handle_scope(CcTest::isolate());
7380   static const char* exts[1] = { "functiontest" };
7381   v8::ExtensionConfiguration config(1, exts);
7382   LocalContext context(&config);
7383   for (int i = 0; i < 10; i++) {
7384     // Run a few times to ensure that allocation of objects doesn't
7385     // change behavior of a constructor function.
7386     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7387              CompileRun("(new A()).data"));
7388     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7389              CompileRun("(new B()).data"));
7390     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7391              CompileRun("(new C()).data"));
7392   }
7393 }
7394
7395
7396 static const char* last_location;
7397 static const char* last_message;
7398 void StoringErrorCallback(const char* location, const char* message) {
7399   if (last_location == NULL) {
7400     last_location = location;
7401     last_message = message;
7402   }
7403 }
7404
7405
7406 // ErrorReporting creates a circular extensions configuration and
7407 // tests that the fatal error handler gets called.  This renders V8
7408 // unusable and therefore this test cannot be run in parallel.
7409 TEST(ErrorReporting) {
7410   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7411   static const char* aDeps[] = { "B" };
7412   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7413   static const char* bDeps[] = { "A" };
7414   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7415   last_location = NULL;
7416   v8::ExtensionConfiguration config(1, bDeps);
7417   v8::Handle<Context> context =
7418       Context::New(CcTest::isolate(), &config);
7419   CHECK(context.IsEmpty());
7420   CHECK_NE(last_location, NULL);
7421 }
7422
7423
7424 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7425                                              v8::Handle<Value> data) {
7426   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7427   CHECK_EQ(v8::Undefined(CcTest::isolate()),
7428       message->GetScriptOrigin().ResourceName());
7429   message->GetLineNumber();
7430   message->GetSourceLine();
7431 }
7432
7433
7434 THREADED_TEST(ErrorWithMissingScriptInfo) {
7435   LocalContext context;
7436   v8::HandleScope scope(context->GetIsolate());
7437   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7438   CompileRun("throw Error()");
7439   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7440 }
7441
7442
7443 struct FlagAndPersistent {
7444   bool flag;
7445   v8::Persistent<v8::Object> handle;
7446 };
7447
7448
7449 static void DisposeAndSetFlag(
7450     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7451   data.GetParameter()->handle.Reset();
7452   data.GetParameter()->flag = true;
7453 }
7454
7455
7456 THREADED_TEST(IndependentWeakHandle) {
7457   v8::Isolate* iso = CcTest::isolate();
7458   v8::HandleScope scope(iso);
7459   v8::Handle<Context> context = Context::New(iso);
7460   Context::Scope context_scope(context);
7461
7462   FlagAndPersistent object_a, object_b;
7463
7464   {
7465     v8::HandleScope handle_scope(iso);
7466     object_a.handle.Reset(iso, v8::Object::New(iso));
7467     object_b.handle.Reset(iso, v8::Object::New(iso));
7468   }
7469
7470   object_a.flag = false;
7471   object_b.flag = false;
7472   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7473   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7474   CHECK(!object_b.handle.IsIndependent());
7475   object_a.handle.MarkIndependent();
7476   object_b.handle.MarkIndependent();
7477   CHECK(object_b.handle.IsIndependent());
7478   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7479   CHECK(object_a.flag);
7480   CHECK(object_b.flag);
7481 }
7482
7483
7484 static void InvokeScavenge() {
7485   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7486 }
7487
7488
7489 static void InvokeMarkSweep() {
7490   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7491 }
7492
7493
7494 static void ForceScavenge(
7495     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7496   data.GetParameter()->handle.Reset();
7497   data.GetParameter()->flag = true;
7498   InvokeScavenge();
7499 }
7500
7501
7502 static void ForceMarkSweep(
7503     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7504   data.GetParameter()->handle.Reset();
7505   data.GetParameter()->flag = true;
7506   InvokeMarkSweep();
7507 }
7508
7509
7510 THREADED_TEST(GCFromWeakCallbacks) {
7511   v8::Isolate* isolate = CcTest::isolate();
7512   v8::HandleScope scope(isolate);
7513   v8::Handle<Context> context = Context::New(isolate);
7514   Context::Scope context_scope(context);
7515
7516   static const int kNumberOfGCTypes = 2;
7517   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7518       Callback;
7519   Callback gc_forcing_callback[kNumberOfGCTypes] =
7520       {&ForceScavenge, &ForceMarkSweep};
7521
7522   typedef void (*GCInvoker)();
7523   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7524
7525   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7526     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7527       FlagAndPersistent object;
7528       {
7529         v8::HandleScope handle_scope(isolate);
7530         object.handle.Reset(isolate, v8::Object::New(isolate));
7531       }
7532       object.flag = false;
7533       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7534       object.handle.MarkIndependent();
7535       invoke_gc[outer_gc]();
7536       CHECK(object.flag);
7537     }
7538   }
7539 }
7540
7541
7542 static void RevivingCallback(
7543     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7544   data.GetParameter()->handle.ClearWeak();
7545   data.GetParameter()->flag = true;
7546 }
7547
7548
7549 THREADED_TEST(IndependentHandleRevival) {
7550   v8::Isolate* isolate = CcTest::isolate();
7551   v8::HandleScope scope(isolate);
7552   v8::Handle<Context> context = Context::New(isolate);
7553   Context::Scope context_scope(context);
7554
7555   FlagAndPersistent object;
7556   {
7557     v8::HandleScope handle_scope(isolate);
7558     v8::Local<v8::Object> o = v8::Object::New(isolate);
7559     object.handle.Reset(isolate, o);
7560     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7561     v8::Local<String> y_str = v8_str("y");
7562     o->Set(y_str, y_str);
7563   }
7564   object.flag = false;
7565   object.handle.SetWeak(&object, &RevivingCallback);
7566   object.handle.MarkIndependent();
7567   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7568   CHECK(object.flag);
7569   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7570   {
7571     v8::HandleScope handle_scope(isolate);
7572     v8::Local<v8::Object> o =
7573         v8::Local<v8::Object>::New(isolate, object.handle);
7574     v8::Local<String> y_str = v8_str("y");
7575     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7576     CHECK(o->Get(y_str)->Equals(y_str));
7577   }
7578 }
7579
7580
7581 v8::Handle<Function> args_fun;
7582
7583
7584 static void ArgumentsTestCallback(
7585     const v8::FunctionCallbackInfo<v8::Value>& args) {
7586   ApiTestFuzzer::Fuzz();
7587   v8::Isolate* isolate = args.GetIsolate();
7588   CHECK_EQ(args_fun, args.Callee());
7589   CHECK_EQ(3, args.Length());
7590   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7591   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7592   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7593   CHECK_EQ(v8::Undefined(isolate), args[3]);
7594   v8::HandleScope scope(args.GetIsolate());
7595   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7596 }
7597
7598
7599 THREADED_TEST(Arguments) {
7600   v8::Isolate* isolate = CcTest::isolate();
7601   v8::HandleScope scope(isolate);
7602   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7603   global->Set(v8_str("f"),
7604               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7605   LocalContext context(NULL, global);
7606   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7607   v8_compile("f(1, 2, 3)")->Run();
7608 }
7609
7610
7611 static void NoBlockGetterX(Local<String> name,
7612                            const v8::PropertyCallbackInfo<v8::Value>&) {
7613 }
7614
7615
7616 static void NoBlockGetterI(uint32_t index,
7617                            const v8::PropertyCallbackInfo<v8::Value>&) {
7618 }
7619
7620
7621 static void PDeleter(Local<String> name,
7622                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7623   if (!name->Equals(v8_str("foo"))) {
7624     return;  // not intercepted
7625   }
7626
7627   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7628 }
7629
7630
7631 static void IDeleter(uint32_t index,
7632                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7633   if (index != 2) {
7634     return;  // not intercepted
7635   }
7636
7637   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7638 }
7639
7640
7641 THREADED_TEST(Deleter) {
7642   v8::Isolate* isolate = CcTest::isolate();
7643   v8::HandleScope scope(isolate);
7644   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7645   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7646   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7647   LocalContext context;
7648   context->Global()->Set(v8_str("k"), obj->NewInstance());
7649   CompileRun(
7650     "k.foo = 'foo';"
7651     "k.bar = 'bar';"
7652     "k[2] = 2;"
7653     "k[4] = 4;");
7654   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7655   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7656
7657   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7658   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7659
7660   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7661   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7662
7663   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7664   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7665 }
7666
7667
7668 static void GetK(Local<String> name,
7669                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7670   ApiTestFuzzer::Fuzz();
7671   if (name->Equals(v8_str("foo")) ||
7672       name->Equals(v8_str("bar")) ||
7673       name->Equals(v8_str("baz"))) {
7674     info.GetReturnValue().SetUndefined();
7675   }
7676 }
7677
7678
7679 static void IndexedGetK(uint32_t index,
7680                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7681   ApiTestFuzzer::Fuzz();
7682   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7683 }
7684
7685
7686 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7687   ApiTestFuzzer::Fuzz();
7688   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7689   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7690   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7691   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7692   info.GetReturnValue().Set(result);
7693 }
7694
7695
7696 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7697   ApiTestFuzzer::Fuzz();
7698   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7699   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7700   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7701   info.GetReturnValue().Set(result);
7702 }
7703
7704
7705 THREADED_TEST(Enumerators) {
7706   v8::Isolate* isolate = CcTest::isolate();
7707   v8::HandleScope scope(isolate);
7708   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7709   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7710   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7711   LocalContext context;
7712   context->Global()->Set(v8_str("k"), obj->NewInstance());
7713   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7714     "k[10] = 0;"
7715     "k.a = 0;"
7716     "k[5] = 0;"
7717     "k.b = 0;"
7718     "k[4294967295] = 0;"
7719     "k.c = 0;"
7720     "k[4294967296] = 0;"
7721     "k.d = 0;"
7722     "k[140000] = 0;"
7723     "k.e = 0;"
7724     "k[30000000000] = 0;"
7725     "k.f = 0;"
7726     "var result = [];"
7727     "for (var prop in k) {"
7728     "  result.push(prop);"
7729     "}"
7730     "result"));
7731   // Check that we get all the property names returned including the
7732   // ones from the enumerators in the right order: indexed properties
7733   // in numerical order, indexed interceptor properties, named
7734   // properties in insertion order, named interceptor properties.
7735   // This order is not mandated by the spec, so this test is just
7736   // documenting our behavior.
7737   CHECK_EQ(17, result->Length());
7738   // Indexed properties in numerical order.
7739   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7740   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7741   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7742   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7743   // Indexed interceptor properties in the order they are returned
7744   // from the enumerator interceptor.
7745   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7746   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7747   // Named properties in insertion order.
7748   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7749   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7750   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7751   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7752   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7753   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7754   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7755   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7756   // Named interceptor properties.
7757   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7758   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7759   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7760 }
7761
7762
7763 int p_getter_count;
7764 int p_getter_count2;
7765
7766
7767 static void PGetter(Local<String> name,
7768                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7769   ApiTestFuzzer::Fuzz();
7770   p_getter_count++;
7771   v8::Handle<v8::Object> global =
7772       info.GetIsolate()->GetCurrentContext()->Global();
7773   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7774   if (name->Equals(v8_str("p1"))) {
7775     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7776   } else if (name->Equals(v8_str("p2"))) {
7777     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7778   } else if (name->Equals(v8_str("p3"))) {
7779     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7780   } else if (name->Equals(v8_str("p4"))) {
7781     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7782   }
7783 }
7784
7785
7786 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7787   ApiTestFuzzer::Fuzz();
7788   LocalContext context;
7789   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7790   CompileRun(
7791     "o1.__proto__ = { };"
7792     "var o2 = { __proto__: o1 };"
7793     "var o3 = { __proto__: o2 };"
7794     "var o4 = { __proto__: o3 };"
7795     "for (var i = 0; i < 10; i++) o4.p4;"
7796     "for (var i = 0; i < 10; i++) o3.p3;"
7797     "for (var i = 0; i < 10; i++) o2.p2;"
7798     "for (var i = 0; i < 10; i++) o1.p1;");
7799 }
7800
7801
7802 static void PGetter2(Local<String> name,
7803                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7804   ApiTestFuzzer::Fuzz();
7805   p_getter_count2++;
7806   v8::Handle<v8::Object> global =
7807       info.GetIsolate()->GetCurrentContext()->Global();
7808   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7809   if (name->Equals(v8_str("p1"))) {
7810     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7811   } else if (name->Equals(v8_str("p2"))) {
7812     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7813   } else if (name->Equals(v8_str("p3"))) {
7814     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7815   } else if (name->Equals(v8_str("p4"))) {
7816     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7817   }
7818 }
7819
7820
7821 THREADED_TEST(GetterHolders) {
7822   v8::Isolate* isolate = CcTest::isolate();
7823   v8::HandleScope scope(isolate);
7824   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7825   obj->SetAccessor(v8_str("p1"), PGetter);
7826   obj->SetAccessor(v8_str("p2"), PGetter);
7827   obj->SetAccessor(v8_str("p3"), PGetter);
7828   obj->SetAccessor(v8_str("p4"), PGetter);
7829   p_getter_count = 0;
7830   RunHolderTest(obj);
7831   CHECK_EQ(40, p_getter_count);
7832 }
7833
7834
7835 THREADED_TEST(PreInterceptorHolders) {
7836   v8::Isolate* isolate = CcTest::isolate();
7837   v8::HandleScope scope(isolate);
7838   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7839   obj->SetNamedPropertyHandler(PGetter2);
7840   p_getter_count2 = 0;
7841   RunHolderTest(obj);
7842   CHECK_EQ(40, p_getter_count2);
7843 }
7844
7845
7846 THREADED_TEST(ObjectInstantiation) {
7847   v8::Isolate* isolate = CcTest::isolate();
7848   v8::HandleScope scope(isolate);
7849   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7850   templ->SetAccessor(v8_str("t"), PGetter2);
7851   LocalContext context;
7852   context->Global()->Set(v8_str("o"), templ->NewInstance());
7853   for (int i = 0; i < 100; i++) {
7854     v8::HandleScope inner_scope(CcTest::isolate());
7855     v8::Handle<v8::Object> obj = templ->NewInstance();
7856     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7857     context->Global()->Set(v8_str("o2"), obj);
7858     v8::Handle<Value> value =
7859         CompileRun("o.__proto__ === o2.__proto__");
7860     CHECK_EQ(v8::True(isolate), value);
7861     context->Global()->Set(v8_str("o"), obj);
7862   }
7863 }
7864
7865
7866 static int StrCmp16(uint16_t* a, uint16_t* b) {
7867   while (true) {
7868     if (*a == 0 && *b == 0) return 0;
7869     if (*a != *b) return 0 + *a - *b;
7870     a++;
7871     b++;
7872   }
7873 }
7874
7875
7876 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7877   while (true) {
7878     if (n-- == 0) return 0;
7879     if (*a == 0 && *b == 0) return 0;
7880     if (*a != *b) return 0 + *a - *b;
7881     a++;
7882     b++;
7883   }
7884 }
7885
7886
7887 int GetUtf8Length(Handle<String> str) {
7888   int len = str->Utf8Length();
7889   if (len < 0) {
7890     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7891     i::String::Flatten(istr);
7892     len = str->Utf8Length();
7893   }
7894   return len;
7895 }
7896
7897
7898 THREADED_TEST(StringWrite) {
7899   LocalContext context;
7900   v8::HandleScope scope(context->GetIsolate());
7901   v8::Handle<String> str = v8_str("abcde");
7902   // abc<Icelandic eth><Unicode snowman>.
7903   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7904   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7905       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7906   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7907   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7908   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7909       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7910   // single lead surrogate
7911   uint16_t lead[1] = { 0xd800 };
7912   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7913       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7914   // single trail surrogate
7915   uint16_t trail[1] = { 0xdc00 };
7916   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7917       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7918   // surrogate pair
7919   uint16_t pair[2] = { 0xd800,  0xdc00 };
7920   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7921       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7922   const int kStride = 4;  // Must match stride in for loops in JS below.
7923   CompileRun(
7924       "var left = '';"
7925       "for (var i = 0; i < 0xd800; i += 4) {"
7926       "  left = left + String.fromCharCode(i);"
7927       "}");
7928   CompileRun(
7929       "var right = '';"
7930       "for (var i = 0; i < 0xd800; i += 4) {"
7931       "  right = String.fromCharCode(i) + right;"
7932       "}");
7933   v8::Handle<v8::Object> global = context->Global();
7934   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7935   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7936
7937   CHECK_EQ(5, str2->Length());
7938   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7939   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7940
7941   char buf[100];
7942   char utf8buf[0xd800 * 3];
7943   uint16_t wbuf[100];
7944   int len;
7945   int charlen;
7946
7947   memset(utf8buf, 0x1, 1000);
7948   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7949   CHECK_EQ(9, len);
7950   CHECK_EQ(5, charlen);
7951   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7952
7953   memset(utf8buf, 0x1, 1000);
7954   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7955   CHECK_EQ(8, len);
7956   CHECK_EQ(5, charlen);
7957   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7958
7959   memset(utf8buf, 0x1, 1000);
7960   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7961   CHECK_EQ(5, len);
7962   CHECK_EQ(4, charlen);
7963   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7964
7965   memset(utf8buf, 0x1, 1000);
7966   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7967   CHECK_EQ(5, len);
7968   CHECK_EQ(4, charlen);
7969   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7970
7971   memset(utf8buf, 0x1, 1000);
7972   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7973   CHECK_EQ(5, len);
7974   CHECK_EQ(4, charlen);
7975   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7976
7977   memset(utf8buf, 0x1, 1000);
7978   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7979   CHECK_EQ(3, len);
7980   CHECK_EQ(3, charlen);
7981   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7982
7983   memset(utf8buf, 0x1, 1000);
7984   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7985   CHECK_EQ(3, len);
7986   CHECK_EQ(3, charlen);
7987   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7988
7989   memset(utf8buf, 0x1, 1000);
7990   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7991   CHECK_EQ(2, len);
7992   CHECK_EQ(2, charlen);
7993   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7994
7995   // allow orphan surrogates by default
7996   memset(utf8buf, 0x1, 1000);
7997   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7998   CHECK_EQ(13, len);
7999   CHECK_EQ(8, charlen);
8000   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8001
8002   // replace orphan surrogates with unicode replacement character
8003   memset(utf8buf, 0x1, 1000);
8004   len = orphans_str->WriteUtf8(utf8buf,
8005                                sizeof(utf8buf),
8006                                &charlen,
8007                                String::REPLACE_INVALID_UTF8);
8008   CHECK_EQ(13, len);
8009   CHECK_EQ(8, charlen);
8010   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8011
8012   // replace single lead surrogate with unicode replacement character
8013   memset(utf8buf, 0x1, 1000);
8014   len = lead_str->WriteUtf8(utf8buf,
8015                             sizeof(utf8buf),
8016                             &charlen,
8017                             String::REPLACE_INVALID_UTF8);
8018   CHECK_EQ(4, len);
8019   CHECK_EQ(1, charlen);
8020   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8021
8022   // replace single trail surrogate with unicode replacement character
8023   memset(utf8buf, 0x1, 1000);
8024   len = trail_str->WriteUtf8(utf8buf,
8025                              sizeof(utf8buf),
8026                              &charlen,
8027                              String::REPLACE_INVALID_UTF8);
8028   CHECK_EQ(4, len);
8029   CHECK_EQ(1, charlen);
8030   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8031
8032   // do not replace / write anything if surrogate pair does not fit the buffer
8033   // space
8034   memset(utf8buf, 0x1, 1000);
8035   len = pair_str->WriteUtf8(utf8buf,
8036                              3,
8037                              &charlen,
8038                              String::REPLACE_INVALID_UTF8);
8039   CHECK_EQ(0, len);
8040   CHECK_EQ(0, charlen);
8041
8042   memset(utf8buf, 0x1, sizeof(utf8buf));
8043   len = GetUtf8Length(left_tree);
8044   int utf8_expected =
8045       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8046   CHECK_EQ(utf8_expected, len);
8047   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8048   CHECK_EQ(utf8_expected, len);
8049   CHECK_EQ(0xd800 / kStride, charlen);
8050   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8051   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8052   CHECK_EQ(0xc0 - kStride,
8053            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8054   CHECK_EQ(1, utf8buf[utf8_expected]);
8055
8056   memset(utf8buf, 0x1, sizeof(utf8buf));
8057   len = GetUtf8Length(right_tree);
8058   CHECK_EQ(utf8_expected, len);
8059   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8060   CHECK_EQ(utf8_expected, len);
8061   CHECK_EQ(0xd800 / kStride, charlen);
8062   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8063   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8064   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8065   CHECK_EQ(1, utf8buf[utf8_expected]);
8066
8067   memset(buf, 0x1, sizeof(buf));
8068   memset(wbuf, 0x1, sizeof(wbuf));
8069   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8070   CHECK_EQ(5, len);
8071   len = str->Write(wbuf);
8072   CHECK_EQ(5, len);
8073   CHECK_EQ(0, strcmp("abcde", buf));
8074   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8075   CHECK_EQ(0, StrCmp16(answer1, wbuf));
8076
8077   memset(buf, 0x1, sizeof(buf));
8078   memset(wbuf, 0x1, sizeof(wbuf));
8079   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8080   CHECK_EQ(4, len);
8081   len = str->Write(wbuf, 0, 4);
8082   CHECK_EQ(4, len);
8083   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8084   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8085   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8086
8087   memset(buf, 0x1, sizeof(buf));
8088   memset(wbuf, 0x1, sizeof(wbuf));
8089   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8090   CHECK_EQ(5, len);
8091   len = str->Write(wbuf, 0, 5);
8092   CHECK_EQ(5, len);
8093   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8094   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8095   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8096
8097   memset(buf, 0x1, sizeof(buf));
8098   memset(wbuf, 0x1, sizeof(wbuf));
8099   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8100   CHECK_EQ(5, len);
8101   len = str->Write(wbuf, 0, 6);
8102   CHECK_EQ(5, len);
8103   CHECK_EQ(0, strcmp("abcde", buf));
8104   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8105   CHECK_EQ(0, StrCmp16(answer4, wbuf));
8106
8107   memset(buf, 0x1, sizeof(buf));
8108   memset(wbuf, 0x1, sizeof(wbuf));
8109   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8110   CHECK_EQ(1, len);
8111   len = str->Write(wbuf, 4, -1);
8112   CHECK_EQ(1, len);
8113   CHECK_EQ(0, strcmp("e", buf));
8114   uint16_t answer5[] = {'e', '\0'};
8115   CHECK_EQ(0, StrCmp16(answer5, wbuf));
8116
8117   memset(buf, 0x1, sizeof(buf));
8118   memset(wbuf, 0x1, sizeof(wbuf));
8119   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8120   CHECK_EQ(1, len);
8121   len = str->Write(wbuf, 4, 6);
8122   CHECK_EQ(1, len);
8123   CHECK_EQ(0, strcmp("e", buf));
8124   CHECK_EQ(0, StrCmp16(answer5, wbuf));
8125
8126   memset(buf, 0x1, sizeof(buf));
8127   memset(wbuf, 0x1, sizeof(wbuf));
8128   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8129   CHECK_EQ(1, len);
8130   len = str->Write(wbuf, 4, 1);
8131   CHECK_EQ(1, len);
8132   CHECK_EQ(0, strncmp("e\1", buf, 2));
8133   uint16_t answer6[] = {'e', 0x101};
8134   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8135
8136   memset(buf, 0x1, sizeof(buf));
8137   memset(wbuf, 0x1, sizeof(wbuf));
8138   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8139   CHECK_EQ(1, len);
8140   len = str->Write(wbuf, 3, 1);
8141   CHECK_EQ(1, len);
8142   CHECK_EQ(0, strncmp("d\1", buf, 2));
8143   uint16_t answer7[] = {'d', 0x101};
8144   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8145
8146   memset(wbuf, 0x1, sizeof(wbuf));
8147   wbuf[5] = 'X';
8148   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8149   CHECK_EQ(5, len);
8150   CHECK_EQ('X', wbuf[5]);
8151   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8152   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8153   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8154   CHECK_NE(0, StrCmp16(answer8b, wbuf));
8155   wbuf[5] = '\0';
8156   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8157
8158   memset(buf, 0x1, sizeof(buf));
8159   buf[5] = 'X';
8160   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8161                           0,
8162                           6,
8163                           String::NO_NULL_TERMINATION);
8164   CHECK_EQ(5, len);
8165   CHECK_EQ('X', buf[5]);
8166   CHECK_EQ(0, strncmp("abcde", buf, 5));
8167   CHECK_NE(0, strcmp("abcde", buf));
8168   buf[5] = '\0';
8169   CHECK_EQ(0, strcmp("abcde", buf));
8170
8171   memset(utf8buf, 0x1, sizeof(utf8buf));
8172   utf8buf[8] = 'X';
8173   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8174                         String::NO_NULL_TERMINATION);
8175   CHECK_EQ(8, len);
8176   CHECK_EQ('X', utf8buf[8]);
8177   CHECK_EQ(5, charlen);
8178   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8179   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8180   utf8buf[8] = '\0';
8181   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8182
8183   memset(utf8buf, 0x1, sizeof(utf8buf));
8184   utf8buf[5] = 'X';
8185   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8186                         String::NO_NULL_TERMINATION);
8187   CHECK_EQ(5, len);
8188   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
8189   CHECK_EQ(5, charlen);
8190   utf8buf[5] = '\0';
8191   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8192
8193   memset(buf, 0x1, sizeof(buf));
8194   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8195   CHECK_EQ(7, len);
8196   CHECK_EQ(0, strcmp("abc", buf));
8197   CHECK_EQ(0, buf[3]);
8198   CHECK_EQ(0, strcmp("def", buf + 4));
8199
8200   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8201   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8202   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8203 }
8204
8205
8206 static void Utf16Helper(
8207     LocalContext& context,  // NOLINT
8208     const char* name,
8209     const char* lengths_name,
8210     int len) {
8211   Local<v8::Array> a =
8212       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8213   Local<v8::Array> alens =
8214       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8215   for (int i = 0; i < len; i++) {
8216     Local<v8::String> string =
8217       Local<v8::String>::Cast(a->Get(i));
8218     Local<v8::Number> expected_len =
8219       Local<v8::Number>::Cast(alens->Get(i));
8220     int length = GetUtf8Length(string);
8221     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8222   }
8223 }
8224
8225
8226 static uint16_t StringGet(Handle<String> str, int index) {
8227   i::Handle<i::String> istring =
8228       v8::Utils::OpenHandle(String::Cast(*str));
8229   return istring->Get(index);
8230 }
8231
8232
8233 static void WriteUtf8Helper(
8234     LocalContext& context,  // NOLINT
8235     const char* name,
8236     const char* lengths_name,
8237     int len) {
8238   Local<v8::Array> b =
8239       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8240   Local<v8::Array> alens =
8241       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8242   char buffer[1000];
8243   char buffer2[1000];
8244   for (int i = 0; i < len; i++) {
8245     Local<v8::String> string =
8246       Local<v8::String>::Cast(b->Get(i));
8247     Local<v8::Number> expected_len =
8248       Local<v8::Number>::Cast(alens->Get(i));
8249     int utf8_length = static_cast<int>(expected_len->Value());
8250     for (int j = utf8_length + 1; j >= 0; j--) {
8251       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8252       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8253       int nchars;
8254       int utf8_written =
8255           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8256       int utf8_written2 =
8257           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8258       CHECK_GE(utf8_length + 1, utf8_written);
8259       CHECK_GE(utf8_length, utf8_written2);
8260       for (int k = 0; k < utf8_written2; k++) {
8261         CHECK_EQ(buffer[k], buffer2[k]);
8262       }
8263       CHECK(nchars * 3 >= utf8_written - 1);
8264       CHECK(nchars <= utf8_written);
8265       if (j == utf8_length + 1) {
8266         CHECK_EQ(utf8_written2, utf8_length);
8267         CHECK_EQ(utf8_written2 + 1, utf8_written);
8268       }
8269       CHECK_EQ(buffer[utf8_written], 42);
8270       if (j > utf8_length) {
8271         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8272         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8273         Handle<String> roundtrip = v8_str(buffer);
8274         CHECK(roundtrip->Equals(string));
8275       } else {
8276         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8277       }
8278       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8279       if (nchars >= 2) {
8280         uint16_t trail = StringGet(string, nchars - 1);
8281         uint16_t lead = StringGet(string, nchars - 2);
8282         if (((lead & 0xfc00) == 0xd800) &&
8283             ((trail & 0xfc00) == 0xdc00)) {
8284           unsigned char u1 = buffer2[utf8_written2 - 4];
8285           unsigned char u2 = buffer2[utf8_written2 - 3];
8286           unsigned char u3 = buffer2[utf8_written2 - 2];
8287           unsigned char u4 = buffer2[utf8_written2 - 1];
8288           CHECK_EQ((u1 & 0xf8), 0xf0);
8289           CHECK_EQ((u2 & 0xc0), 0x80);
8290           CHECK_EQ((u3 & 0xc0), 0x80);
8291           CHECK_EQ((u4 & 0xc0), 0x80);
8292           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8293           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8294           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8295           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8296           CHECK_EQ((u1 & 0x3), c >> 18);
8297         }
8298       }
8299     }
8300   }
8301 }
8302
8303
8304 THREADED_TEST(Utf16) {
8305   LocalContext context;
8306   v8::HandleScope scope(context->GetIsolate());
8307   CompileRun(
8308       "var pad = '01234567890123456789';"
8309       "var p = [];"
8310       "var plens = [20, 3, 3];"
8311       "p.push('01234567890123456789');"
8312       "var lead = 0xd800;"
8313       "var trail = 0xdc00;"
8314       "p.push(String.fromCharCode(0xd800));"
8315       "p.push(String.fromCharCode(0xdc00));"
8316       "var a = [];"
8317       "var b = [];"
8318       "var c = [];"
8319       "var alens = [];"
8320       "for (var i = 0; i < 3; i++) {"
8321       "  p[1] = String.fromCharCode(lead++);"
8322       "  for (var j = 0; j < 3; j++) {"
8323       "    p[2] = String.fromCharCode(trail++);"
8324       "    a.push(p[i] + p[j]);"
8325       "    b.push(p[i] + p[j]);"
8326       "    c.push(p[i] + p[j]);"
8327       "    alens.push(plens[i] + plens[j]);"
8328       "  }"
8329       "}"
8330       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8331       "var a2 = [];"
8332       "var b2 = [];"
8333       "var c2 = [];"
8334       "var a2lens = [];"
8335       "for (var m = 0; m < 9; m++) {"
8336       "  for (var n = 0; n < 9; n++) {"
8337       "    a2.push(a[m] + a[n]);"
8338       "    b2.push(b[m] + b[n]);"
8339       "    var newc = 'x' + c[m] + c[n] + 'y';"
8340       "    c2.push(newc.substring(1, newc.length - 1));"
8341       "    var utf = alens[m] + alens[n];"  // And here.
8342            // The 'n's that start with 0xdc.. are 6-8
8343            // The 'm's that end with 0xd8.. are 1, 4 and 7
8344       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8345       "    a2lens.push(utf);"
8346       "  }"
8347       "}");
8348   Utf16Helper(context, "a", "alens", 9);
8349   Utf16Helper(context, "a2", "a2lens", 81);
8350   WriteUtf8Helper(context, "b", "alens", 9);
8351   WriteUtf8Helper(context, "b2", "a2lens", 81);
8352   WriteUtf8Helper(context, "c2", "a2lens", 81);
8353 }
8354
8355
8356 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8357   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8358   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8359   return *is1 == *is2;
8360 }
8361
8362 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8363                              const char* b) {
8364   Handle<String> symbol1 =
8365       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8366   Handle<String> symbol2 =
8367       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8368   CHECK(SameSymbol(symbol1, symbol2));
8369 }
8370
8371
8372 THREADED_TEST(Utf16Symbol) {
8373   LocalContext context;
8374   v8::HandleScope scope(context->GetIsolate());
8375
8376   Handle<String> symbol1 = v8::String::NewFromUtf8(
8377       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8378   Handle<String> symbol2 = v8::String::NewFromUtf8(
8379       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8380   CHECK(SameSymbol(symbol1, symbol2));
8381
8382   SameSymbolHelper(context->GetIsolate(),
8383                    "\360\220\220\205",  // 4 byte encoding.
8384                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8385   SameSymbolHelper(context->GetIsolate(),
8386                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8387                    "\360\220\220\206");  // 4 byte encoding.
8388   SameSymbolHelper(context->GetIsolate(),
8389                    "x\360\220\220\205",  // 4 byte encoding.
8390                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8391   SameSymbolHelper(context->GetIsolate(),
8392                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8393                    "x\360\220\220\206");  // 4 byte encoding.
8394   CompileRun(
8395       "var sym0 = 'benedictus';"
8396       "var sym0b = 'S\303\270ren';"
8397       "var sym1 = '\355\240\201\355\260\207';"
8398       "var sym2 = '\360\220\220\210';"
8399       "var sym3 = 'x\355\240\201\355\260\207';"
8400       "var sym4 = 'x\360\220\220\210';"
8401       "if (sym1.length != 2) throw sym1;"
8402       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8403       "if (sym2.length != 2) throw sym2;"
8404       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8405       "if (sym3.length != 3) throw sym3;"
8406       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8407       "if (sym4.length != 3) throw sym4;"
8408       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8409   Handle<String> sym0 = v8::String::NewFromUtf8(
8410       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8411   Handle<String> sym0b = v8::String::NewFromUtf8(
8412       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8413   Handle<String> sym1 =
8414       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8415                               v8::String::kInternalizedString);
8416   Handle<String> sym2 =
8417       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8418                               v8::String::kInternalizedString);
8419   Handle<String> sym3 = v8::String::NewFromUtf8(
8420       context->GetIsolate(), "x\355\240\201\355\260\207",
8421       v8::String::kInternalizedString);
8422   Handle<String> sym4 =
8423       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8424                               v8::String::kInternalizedString);
8425   v8::Local<v8::Object> global = context->Global();
8426   Local<Value> s0 = global->Get(v8_str("sym0"));
8427   Local<Value> s0b = global->Get(v8_str("sym0b"));
8428   Local<Value> s1 = global->Get(v8_str("sym1"));
8429   Local<Value> s2 = global->Get(v8_str("sym2"));
8430   Local<Value> s3 = global->Get(v8_str("sym3"));
8431   Local<Value> s4 = global->Get(v8_str("sym4"));
8432   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8433   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8434   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8435   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8436   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8437   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8438 }
8439
8440
8441 THREADED_TEST(ToArrayIndex) {
8442   LocalContext context;
8443   v8::Isolate* isolate = context->GetIsolate();
8444   v8::HandleScope scope(isolate);
8445
8446   v8::Handle<String> str = v8_str("42");
8447   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8448   CHECK(!index.IsEmpty());
8449   CHECK_EQ(42.0, index->Uint32Value());
8450   str = v8_str("42asdf");
8451   index = str->ToArrayIndex();
8452   CHECK(index.IsEmpty());
8453   str = v8_str("-42");
8454   index = str->ToArrayIndex();
8455   CHECK(index.IsEmpty());
8456   str = v8_str("4294967295");
8457   index = str->ToArrayIndex();
8458   CHECK(!index.IsEmpty());
8459   CHECK_EQ(4294967295.0, index->Uint32Value());
8460   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8461   index = num->ToArrayIndex();
8462   CHECK(!index.IsEmpty());
8463   CHECK_EQ(1.0, index->Uint32Value());
8464   num = v8::Number::New(isolate, -1);
8465   index = num->ToArrayIndex();
8466   CHECK(index.IsEmpty());
8467   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8468   index = obj->ToArrayIndex();
8469   CHECK(index.IsEmpty());
8470 }
8471
8472
8473 THREADED_TEST(ErrorConstruction) {
8474   LocalContext context;
8475   v8::HandleScope scope(context->GetIsolate());
8476
8477   v8::Handle<String> foo = v8_str("foo");
8478   v8::Handle<String> message = v8_str("message");
8479   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8480   CHECK(range_error->IsObject());
8481   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8482   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8483   CHECK(reference_error->IsObject());
8484   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8485   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8486   CHECK(syntax_error->IsObject());
8487   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8488   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8489   CHECK(type_error->IsObject());
8490   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8491   v8::Handle<Value> error = v8::Exception::Error(foo);
8492   CHECK(error->IsObject());
8493   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8494 }
8495
8496
8497 static void YGetter(Local<String> name,
8498                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8499   ApiTestFuzzer::Fuzz();
8500   info.GetReturnValue().Set(v8_num(10));
8501 }
8502
8503
8504 static void YSetter(Local<String> name,
8505                     Local<Value> value,
8506                     const v8::PropertyCallbackInfo<void>& info) {
8507   Local<Object> this_obj = Local<Object>::Cast(info.This());
8508   if (this_obj->Has(name)) this_obj->Delete(name);
8509   this_obj->Set(name, value);
8510 }
8511
8512
8513 THREADED_TEST(DeleteAccessor) {
8514   v8::Isolate* isolate = CcTest::isolate();
8515   v8::HandleScope scope(isolate);
8516   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8517   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8518   LocalContext context;
8519   v8::Handle<v8::Object> holder = obj->NewInstance();
8520   context->Global()->Set(v8_str("holder"), holder);
8521   v8::Handle<Value> result = CompileRun(
8522       "holder.y = 11; holder.y = 12; holder.y");
8523   CHECK_EQ(12, result->Uint32Value());
8524 }
8525
8526
8527 THREADED_TEST(TypeSwitch) {
8528   v8::Isolate* isolate = CcTest::isolate();
8529   v8::HandleScope scope(isolate);
8530   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8531   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8532   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8533   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8534   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8535   LocalContext context;
8536   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8537   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8538   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8539   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8540   for (int i = 0; i < 10; i++) {
8541     CHECK_EQ(0, type_switch->match(obj0));
8542     CHECK_EQ(1, type_switch->match(obj1));
8543     CHECK_EQ(2, type_switch->match(obj2));
8544     CHECK_EQ(3, type_switch->match(obj3));
8545     CHECK_EQ(3, type_switch->match(obj3));
8546     CHECK_EQ(2, type_switch->match(obj2));
8547     CHECK_EQ(1, type_switch->match(obj1));
8548     CHECK_EQ(0, type_switch->match(obj0));
8549   }
8550 }
8551
8552
8553 static int trouble_nesting = 0;
8554 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8555   ApiTestFuzzer::Fuzz();
8556   trouble_nesting++;
8557
8558   // Call a JS function that throws an uncaught exception.
8559   Local<v8::Object> arg_this =
8560       args.GetIsolate()->GetCurrentContext()->Global();
8561   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8562     arg_this->Get(v8_str("trouble_callee")) :
8563     arg_this->Get(v8_str("trouble_caller"));
8564   CHECK(trouble_callee->IsFunction());
8565   args.GetReturnValue().Set(
8566       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8567 }
8568
8569
8570 static int report_count = 0;
8571 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8572                                              v8::Handle<Value>) {
8573   report_count++;
8574 }
8575
8576
8577 // Counts uncaught exceptions, but other tests running in parallel
8578 // also have uncaught exceptions.
8579 TEST(ApiUncaughtException) {
8580   report_count = 0;
8581   LocalContext env;
8582   v8::Isolate* isolate = env->GetIsolate();
8583   v8::HandleScope scope(isolate);
8584   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8585
8586   Local<v8::FunctionTemplate> fun =
8587       v8::FunctionTemplate::New(isolate, TroubleCallback);
8588   v8::Local<v8::Object> global = env->Global();
8589   global->Set(v8_str("trouble"), fun->GetFunction());
8590
8591   CompileRun(
8592       "function trouble_callee() {"
8593       "  var x = null;"
8594       "  return x.foo;"
8595       "};"
8596       "function trouble_caller() {"
8597       "  trouble();"
8598       "};");
8599   Local<Value> trouble = global->Get(v8_str("trouble"));
8600   CHECK(trouble->IsFunction());
8601   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8602   CHECK(trouble_callee->IsFunction());
8603   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8604   CHECK(trouble_caller->IsFunction());
8605   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8606   CHECK_EQ(1, report_count);
8607   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8608 }
8609
8610 static const char* script_resource_name = "ExceptionInNativeScript.js";
8611 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8612                                                 v8::Handle<Value>) {
8613   v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8614   CHECK(!name_val.IsEmpty() && name_val->IsString());
8615   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8616   CHECK_EQ(script_resource_name, *name);
8617   CHECK_EQ(3, message->GetLineNumber());
8618   v8::String::Utf8Value source_line(message->GetSourceLine());
8619   CHECK_EQ("  new o.foo();", *source_line);
8620 }
8621
8622
8623 TEST(ExceptionInNativeScript) {
8624   LocalContext env;
8625   v8::Isolate* isolate = env->GetIsolate();
8626   v8::HandleScope scope(isolate);
8627   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8628
8629   Local<v8::FunctionTemplate> fun =
8630       v8::FunctionTemplate::New(isolate, TroubleCallback);
8631   v8::Local<v8::Object> global = env->Global();
8632   global->Set(v8_str("trouble"), fun->GetFunction());
8633
8634   CompileRunWithOrigin(
8635       "function trouble() {\n"
8636       "  var o = {};\n"
8637       "  new o.foo();\n"
8638       "};",
8639       script_resource_name);
8640   Local<Value> trouble = global->Get(v8_str("trouble"));
8641   CHECK(trouble->IsFunction());
8642   Function::Cast(*trouble)->Call(global, 0, NULL);
8643   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8644 }
8645
8646
8647 TEST(CompilationErrorUsingTryCatchHandler) {
8648   LocalContext env;
8649   v8::HandleScope scope(env->GetIsolate());
8650   v8::TryCatch try_catch;
8651   v8_compile("This doesn't &*&@#$&*^ compile.");
8652   CHECK_NE(NULL, *try_catch.Exception());
8653   CHECK(try_catch.HasCaught());
8654 }
8655
8656
8657 TEST(TryCatchFinallyUsingTryCatchHandler) {
8658   LocalContext env;
8659   v8::HandleScope scope(env->GetIsolate());
8660   v8::TryCatch try_catch;
8661   CompileRun("try { throw ''; } catch (e) {}");
8662   CHECK(!try_catch.HasCaught());
8663   CompileRun("try { throw ''; } finally {}");
8664   CHECK(try_catch.HasCaught());
8665   try_catch.Reset();
8666   CompileRun(
8667       "(function() {"
8668       "try { throw ''; } finally { return; }"
8669       "})()");
8670   CHECK(!try_catch.HasCaught());
8671   CompileRun(
8672       "(function()"
8673       "  { try { throw ''; } finally { throw 0; }"
8674       "})()");
8675   CHECK(try_catch.HasCaught());
8676 }
8677
8678
8679 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8680   v8::HandleScope scope(args.GetIsolate());
8681   CompileRun(args[0]->ToString());
8682 }
8683
8684
8685 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8686   v8::Isolate* isolate = CcTest::isolate();
8687   v8::HandleScope scope(isolate);
8688   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8689   templ->Set(v8_str("CEvaluate"),
8690              v8::FunctionTemplate::New(isolate, CEvaluate));
8691   LocalContext context(0, templ);
8692   v8::TryCatch try_catch;
8693   CompileRun("try {"
8694              "  CEvaluate('throw 1;');"
8695              "} finally {"
8696              "}");
8697   CHECK(try_catch.HasCaught());
8698   CHECK(!try_catch.Message().IsEmpty());
8699   String::Utf8Value exception_value(try_catch.Exception());
8700   CHECK_EQ(*exception_value, "1");
8701   try_catch.Reset();
8702   CompileRun("try {"
8703              "  CEvaluate('throw 1;');"
8704              "} finally {"
8705              "  throw 2;"
8706              "}");
8707   CHECK(try_catch.HasCaught());
8708   CHECK(!try_catch.Message().IsEmpty());
8709   String::Utf8Value finally_exception_value(try_catch.Exception());
8710   CHECK_EQ(*finally_exception_value, "2");
8711 }
8712
8713
8714 // For use within the TestSecurityHandler() test.
8715 static bool g_security_callback_result = false;
8716 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8717                                       Local<Value> name,
8718                                       v8::AccessType type,
8719                                       Local<Value> data) {
8720   printf("a\n");
8721   // Always allow read access.
8722   if (type == v8::ACCESS_GET)
8723     return true;
8724
8725   // Sometimes allow other access.
8726   return g_security_callback_result;
8727 }
8728
8729
8730 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8731                                         uint32_t key,
8732                                         v8::AccessType type,
8733                                         Local<Value> data) {
8734   printf("b\n");
8735   // Always allow read access.
8736   if (type == v8::ACCESS_GET)
8737     return true;
8738
8739   // Sometimes allow other access.
8740   return g_security_callback_result;
8741 }
8742
8743
8744 // SecurityHandler can't be run twice
8745 TEST(SecurityHandler) {
8746   v8::Isolate* isolate = CcTest::isolate();
8747   v8::HandleScope scope0(isolate);
8748   v8::Handle<v8::ObjectTemplate> global_template =
8749       v8::ObjectTemplate::New(isolate);
8750   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8751                                            IndexedSecurityTestCallback);
8752   // Create an environment
8753   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8754   context0->Enter();
8755
8756   v8::Handle<v8::Object> global0 = context0->Global();
8757   v8::Handle<Script> script0 = v8_compile("foo = 111");
8758   script0->Run();
8759   global0->Set(v8_str("0"), v8_num(999));
8760   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8761   CHECK_EQ(111, foo0->Int32Value());
8762   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8763   CHECK_EQ(999, z0->Int32Value());
8764
8765   // Create another environment, should fail security checks.
8766   v8::HandleScope scope1(isolate);
8767
8768   v8::Handle<Context> context1 =
8769     Context::New(isolate, NULL, global_template);
8770   context1->Enter();
8771
8772   v8::Handle<v8::Object> global1 = context1->Global();
8773   global1->Set(v8_str("othercontext"), global0);
8774   // This set will fail the security check.
8775   v8::Handle<Script> script1 =
8776     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8777   script1->Run();
8778   // This read will pass the security check.
8779   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8780   CHECK_EQ(111, foo1->Int32Value());
8781   // This read will pass the security check.
8782   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8783   CHECK_EQ(999, z1->Int32Value());
8784
8785   // Create another environment, should pass security checks.
8786   { g_security_callback_result = true;  // allow security handler to pass.
8787     v8::HandleScope scope2(isolate);
8788     LocalContext context2;
8789     v8::Handle<v8::Object> global2 = context2->Global();
8790     global2->Set(v8_str("othercontext"), global0);
8791     v8::Handle<Script> script2 =
8792         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8793     script2->Run();
8794     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8795     CHECK_EQ(333, foo2->Int32Value());
8796     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8797     CHECK_EQ(888, z2->Int32Value());
8798   }
8799
8800   context1->Exit();
8801   context0->Exit();
8802 }
8803
8804
8805 THREADED_TEST(SecurityChecks) {
8806   LocalContext env1;
8807   v8::HandleScope handle_scope(env1->GetIsolate());
8808   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8809
8810   Local<Value> foo = v8_str("foo");
8811   Local<Value> bar = v8_str("bar");
8812
8813   // Set to the same domain.
8814   env1->SetSecurityToken(foo);
8815
8816   // Create a function in env1.
8817   CompileRun("spy=function(){return spy;}");
8818   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8819   CHECK(spy->IsFunction());
8820
8821   // Create another function accessing global objects.
8822   CompileRun("spy2=function(){return new this.Array();}");
8823   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8824   CHECK(spy2->IsFunction());
8825
8826   // Switch to env2 in the same domain and invoke spy on env2.
8827   {
8828     env2->SetSecurityToken(foo);
8829     // Enter env2
8830     Context::Scope scope_env2(env2);
8831     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8832     CHECK(result->IsFunction());
8833   }
8834
8835   {
8836     env2->SetSecurityToken(bar);
8837     Context::Scope scope_env2(env2);
8838
8839     // Call cross_domain_call, it should throw an exception
8840     v8::TryCatch try_catch;
8841     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8842     CHECK(try_catch.HasCaught());
8843   }
8844 }
8845
8846
8847 // Regression test case for issue 1183439.
8848 THREADED_TEST(SecurityChecksForPrototypeChain) {
8849   LocalContext current;
8850   v8::HandleScope scope(current->GetIsolate());
8851   v8::Handle<Context> other = Context::New(current->GetIsolate());
8852
8853   // Change context to be able to get to the Object function in the
8854   // other context without hitting the security checks.
8855   v8::Local<Value> other_object;
8856   { Context::Scope scope(other);
8857     other_object = other->Global()->Get(v8_str("Object"));
8858     other->Global()->Set(v8_num(42), v8_num(87));
8859   }
8860
8861   current->Global()->Set(v8_str("other"), other->Global());
8862   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8863
8864   // Make sure the security check fails here and we get an undefined
8865   // result instead of getting the Object function. Repeat in a loop
8866   // to make sure to exercise the IC code.
8867   v8::Local<Script> access_other0 = v8_compile("other.Object");
8868   v8::Local<Script> access_other1 = v8_compile("other[42]");
8869   for (int i = 0; i < 5; i++) {
8870     CHECK(access_other0->Run().IsEmpty());
8871     CHECK(access_other1->Run().IsEmpty());
8872   }
8873
8874   // Create an object that has 'other' in its prototype chain and make
8875   // sure we cannot access the Object function indirectly through
8876   // that. Repeat in a loop to make sure to exercise the IC code.
8877   v8_compile("function F() { };"
8878              "F.prototype = other;"
8879              "var f = new F();")->Run();
8880   v8::Local<Script> access_f0 = v8_compile("f.Object");
8881   v8::Local<Script> access_f1 = v8_compile("f[42]");
8882   for (int j = 0; j < 5; j++) {
8883     CHECK(access_f0->Run().IsEmpty());
8884     CHECK(access_f1->Run().IsEmpty());
8885   }
8886
8887   // Now it gets hairy: Set the prototype for the other global object
8888   // to be the current global object. The prototype chain for 'f' now
8889   // goes through 'other' but ends up in the current global object.
8890   { Context::Scope scope(other);
8891     other->Global()->Set(v8_str("__proto__"), current->Global());
8892   }
8893   // Set a named and an index property on the current global
8894   // object. To force the lookup to go through the other global object,
8895   // the properties must not exist in the other global object.
8896   current->Global()->Set(v8_str("foo"), v8_num(100));
8897   current->Global()->Set(v8_num(99), v8_num(101));
8898   // Try to read the properties from f and make sure that the access
8899   // gets stopped by the security checks on the other global object.
8900   Local<Script> access_f2 = v8_compile("f.foo");
8901   Local<Script> access_f3 = v8_compile("f[99]");
8902   for (int k = 0; k < 5; k++) {
8903     CHECK(access_f2->Run().IsEmpty());
8904     CHECK(access_f3->Run().IsEmpty());
8905   }
8906 }
8907
8908
8909 static bool named_security_check_with_gc_called;
8910
8911 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8912                                         Local<Value> name,
8913                                         v8::AccessType type,
8914                                         Local<Value> data) {
8915   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8916   named_security_check_with_gc_called = true;
8917   return true;
8918 }
8919
8920
8921 static bool indexed_security_check_with_gc_called;
8922
8923 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8924                                               uint32_t key,
8925                                               v8::AccessType type,
8926                                               Local<Value> data) {
8927   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8928   indexed_security_check_with_gc_called = true;
8929   return true;
8930 }
8931
8932
8933 TEST(SecurityTestGCAllowed) {
8934   v8::Isolate* isolate = CcTest::isolate();
8935   v8::HandleScope handle_scope(isolate);
8936   v8::Handle<v8::ObjectTemplate> object_template =
8937       v8::ObjectTemplate::New(isolate);
8938   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8939                                            IndexedSecurityTestCallbackWithGC);
8940
8941   v8::Handle<Context> context = Context::New(isolate);
8942   v8::Context::Scope context_scope(context);
8943
8944   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8945
8946   named_security_check_with_gc_called = false;
8947   CompileRun("obj.foo = new String(1001);");
8948   CHECK(named_security_check_with_gc_called);
8949
8950   indexed_security_check_with_gc_called = false;
8951   CompileRun("obj[0] = new String(1002);");
8952   CHECK(indexed_security_check_with_gc_called);
8953
8954   named_security_check_with_gc_called = false;
8955   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8956   CHECK(named_security_check_with_gc_called);
8957
8958   indexed_security_check_with_gc_called = false;
8959   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8960   CHECK(indexed_security_check_with_gc_called);
8961 }
8962
8963
8964 THREADED_TEST(CrossDomainDelete) {
8965   LocalContext env1;
8966   v8::HandleScope handle_scope(env1->GetIsolate());
8967   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8968
8969   Local<Value> foo = v8_str("foo");
8970   Local<Value> bar = v8_str("bar");
8971
8972   // Set to the same domain.
8973   env1->SetSecurityToken(foo);
8974   env2->SetSecurityToken(foo);
8975
8976   env1->Global()->Set(v8_str("prop"), v8_num(3));
8977   env2->Global()->Set(v8_str("env1"), env1->Global());
8978
8979   // Change env2 to a different domain and delete env1.prop.
8980   env2->SetSecurityToken(bar);
8981   {
8982     Context::Scope scope_env2(env2);
8983     Local<Value> result =
8984         CompileRun("delete env1.prop");
8985     CHECK(result.IsEmpty());
8986   }
8987
8988   // Check that env1.prop still exists.
8989   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8990   CHECK(v->IsNumber());
8991   CHECK_EQ(3, v->Int32Value());
8992 }
8993
8994
8995 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8996   LocalContext env1;
8997   v8::HandleScope handle_scope(env1->GetIsolate());
8998   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8999
9000   Local<Value> foo = v8_str("foo");
9001   Local<Value> bar = v8_str("bar");
9002
9003   // Set to the same domain.
9004   env1->SetSecurityToken(foo);
9005   env2->SetSecurityToken(foo);
9006
9007   env1->Global()->Set(v8_str("prop"), v8_num(3));
9008   env2->Global()->Set(v8_str("env1"), env1->Global());
9009
9010   // env1.prop is enumerable in env2.
9011   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9012   {
9013     Context::Scope scope_env2(env2);
9014     Local<Value> result = CompileRun(test);
9015     CHECK(result->IsTrue());
9016   }
9017
9018   // Change env2 to a different domain and test again.
9019   env2->SetSecurityToken(bar);
9020   {
9021     Context::Scope scope_env2(env2);
9022     Local<Value> result = CompileRun(test);
9023     CHECK(result.IsEmpty());
9024   }
9025 }
9026
9027
9028 THREADED_TEST(CrossDomainForIn) {
9029   LocalContext env1;
9030   v8::HandleScope handle_scope(env1->GetIsolate());
9031   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9032
9033   Local<Value> foo = v8_str("foo");
9034   Local<Value> bar = v8_str("bar");
9035
9036   // Set to the same domain.
9037   env1->SetSecurityToken(foo);
9038   env2->SetSecurityToken(foo);
9039
9040   env1->Global()->Set(v8_str("prop"), v8_num(3));
9041   env2->Global()->Set(v8_str("env1"), env1->Global());
9042
9043   // Change env2 to a different domain and set env1's global object
9044   // as the __proto__ of an object in env2 and enumerate properties
9045   // in for-in. It shouldn't enumerate properties on env1's global
9046   // object.
9047   env2->SetSecurityToken(bar);
9048   {
9049     Context::Scope scope_env2(env2);
9050     Local<Value> result = CompileRun(
9051         "(function() {"
9052         "  var obj = { '__proto__': env1 };"
9053         "  try {"
9054         "    for (var p in obj) {"
9055         "      if (p == 'prop') return false;"
9056         "    }"
9057         "    return false;"
9058         "  } catch (e) {"
9059         "    return true;"
9060         "  }"
9061         "})()");
9062     CHECK(result->IsTrue());
9063   }
9064 }
9065
9066
9067 TEST(ContextDetachGlobal) {
9068   LocalContext env1;
9069   v8::HandleScope handle_scope(env1->GetIsolate());
9070   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9071
9072   Local<v8::Object> global1 = env1->Global();
9073
9074   Local<Value> foo = v8_str("foo");
9075
9076   // Set to the same domain.
9077   env1->SetSecurityToken(foo);
9078   env2->SetSecurityToken(foo);
9079
9080   // Enter env2
9081   env2->Enter();
9082
9083   // Create a function in env2 and add a reference to it in env1.
9084   Local<v8::Object> global2 = env2->Global();
9085   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9086   CompileRun("function getProp() {return prop;}");
9087
9088   env1->Global()->Set(v8_str("getProp"),
9089                       global2->Get(v8_str("getProp")));
9090
9091   // Detach env2's global, and reuse the global object of env2
9092   env2->Exit();
9093   env2->DetachGlobal();
9094
9095   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9096                                           0,
9097                                           v8::Handle<v8::ObjectTemplate>(),
9098                                           global2);
9099   env3->SetSecurityToken(v8_str("bar"));
9100   env3->Enter();
9101
9102   Local<v8::Object> global3 = env3->Global();
9103   CHECK_EQ(global2, global3);
9104   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9105   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9106   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9107   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9108   env3->Exit();
9109
9110   // Call getProp in env1, and it should return the value 1
9111   {
9112     Local<Value> get_prop = global1->Get(v8_str("getProp"));
9113     CHECK(get_prop->IsFunction());
9114     v8::TryCatch try_catch;
9115     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9116     CHECK(!try_catch.HasCaught());
9117     CHECK_EQ(1, r->Int32Value());
9118   }
9119
9120   // Check that env3 is not accessible from env1
9121   {
9122     Local<Value> r = global3->Get(v8_str("prop2"));
9123     CHECK(r.IsEmpty());
9124   }
9125 }
9126
9127
9128 TEST(DetachGlobal) {
9129   LocalContext env1;
9130   v8::HandleScope scope(env1->GetIsolate());
9131
9132   // Create second environment.
9133   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9134
9135   Local<Value> foo = v8_str("foo");
9136
9137   // Set same security token for env1 and env2.
9138   env1->SetSecurityToken(foo);
9139   env2->SetSecurityToken(foo);
9140
9141   // Create a property on the global object in env2.
9142   {
9143     v8::Context::Scope scope(env2);
9144     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9145   }
9146
9147   // Create a reference to env2 global from env1 global.
9148   env1->Global()->Set(v8_str("other"), env2->Global());
9149
9150   // Check that we have access to other.p in env2 from env1.
9151   Local<Value> result = CompileRun("other.p");
9152   CHECK(result->IsInt32());
9153   CHECK_EQ(42, result->Int32Value());
9154
9155   // Hold on to global from env2 and detach global from env2.
9156   Local<v8::Object> global2 = env2->Global();
9157   env2->DetachGlobal();
9158
9159   // Check that the global has been detached. No other.p property can
9160   // be found.
9161   result = CompileRun("other.p");
9162   CHECK(result.IsEmpty());
9163
9164   // Reuse global2 for env3.
9165   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9166                                           0,
9167                                           v8::Handle<v8::ObjectTemplate>(),
9168                                           global2);
9169   CHECK_EQ(global2, env3->Global());
9170
9171   // Start by using the same security token for env3 as for env1 and env2.
9172   env3->SetSecurityToken(foo);
9173
9174   // Create a property on the global object in env3.
9175   {
9176     v8::Context::Scope scope(env3);
9177     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9178   }
9179
9180   // Check that other.p is now the property in env3 and that we have access.
9181   result = CompileRun("other.p");
9182   CHECK(result->IsInt32());
9183   CHECK_EQ(24, result->Int32Value());
9184
9185   // Change security token for env3 to something different from env1 and env2.
9186   env3->SetSecurityToken(v8_str("bar"));
9187
9188   // Check that we do not have access to other.p in env1. |other| is now
9189   // the global object for env3 which has a different security token,
9190   // so access should be blocked.
9191   result = CompileRun("other.p");
9192   CHECK(result.IsEmpty());
9193 }
9194
9195
9196 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9197   info.GetReturnValue().Set(
9198       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9199 }
9200
9201
9202 TEST(DetachedAccesses) {
9203   LocalContext env1;
9204   v8::HandleScope scope(env1->GetIsolate());
9205
9206   // Create second environment.
9207   Local<ObjectTemplate> inner_global_template =
9208       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9209   inner_global_template ->SetAccessorProperty(
9210       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9211   v8::Local<Context> env2 =
9212       Context::New(env1->GetIsolate(), NULL, inner_global_template);
9213
9214   Local<Value> foo = v8_str("foo");
9215
9216   // Set same security token for env1 and env2.
9217   env1->SetSecurityToken(foo);
9218   env2->SetSecurityToken(foo);
9219
9220   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9221
9222   {
9223     v8::Context::Scope scope(env2);
9224     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9225     CompileRun(
9226         "function bound_x() { return x; }"
9227         "function get_x()   { return this.x; }"
9228         "function get_x_w() { return (function() {return this.x;})(); }");
9229     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9230     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9231     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9232     env1->Global()->Set(
9233         v8_str("this_x"),
9234         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9235   }
9236
9237   Local<Object> env2_global = env2->Global();
9238   env2_global->TurnOnAccessCheck();
9239   env2->DetachGlobal();
9240
9241   Local<Value> result;
9242   result = CompileRun("bound_x()");
9243   CHECK_EQ(v8_str("env2_x"), result);
9244   result = CompileRun("get_x()");
9245   CHECK(result.IsEmpty());
9246   result = CompileRun("get_x_w()");
9247   CHECK(result.IsEmpty());
9248   result = CompileRun("this_x()");
9249   CHECK_EQ(v8_str("env2_x"), result);
9250
9251   // Reattach env2's proxy
9252   env2 = Context::New(env1->GetIsolate(),
9253                       0,
9254                       v8::Handle<v8::ObjectTemplate>(),
9255                       env2_global);
9256   env2->SetSecurityToken(foo);
9257   {
9258     v8::Context::Scope scope(env2);
9259     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9260     env2->Global()->Set(v8_str("env1"), env1->Global());
9261     result = CompileRun(
9262         "results = [];"
9263         "for (var i = 0; i < 4; i++ ) {"
9264         "  results.push(env1.bound_x());"
9265         "  results.push(env1.get_x());"
9266         "  results.push(env1.get_x_w());"
9267         "  results.push(env1.this_x());"
9268         "}"
9269         "results");
9270     Local<v8::Array> results = Local<v8::Array>::Cast(result);
9271     CHECK_EQ(16, results->Length());
9272     for (int i = 0; i < 16; i += 4) {
9273       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9274       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9275       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9276       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9277     }
9278   }
9279
9280   result = CompileRun(
9281       "results = [];"
9282       "for (var i = 0; i < 4; i++ ) {"
9283       "  results.push(bound_x());"
9284       "  results.push(get_x());"
9285       "  results.push(get_x_w());"
9286       "  results.push(this_x());"
9287       "}"
9288       "results");
9289   Local<v8::Array> results = Local<v8::Array>::Cast(result);
9290   CHECK_EQ(16, results->Length());
9291   for (int i = 0; i < 16; i += 4) {
9292     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9293     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9294     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9295     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9296   }
9297
9298   result = CompileRun(
9299       "results = [];"
9300       "for (var i = 0; i < 4; i++ ) {"
9301       "  results.push(this.bound_x());"
9302       "  results.push(this.get_x());"
9303       "  results.push(this.get_x_w());"
9304       "  results.push(this.this_x());"
9305       "}"
9306       "results");
9307   results = Local<v8::Array>::Cast(result);
9308   CHECK_EQ(16, results->Length());
9309   for (int i = 0; i < 16; i += 4) {
9310     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9311     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9312     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9313     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9314   }
9315 }
9316
9317
9318 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9319 static bool NamedAccessBlocker(Local<v8::Object> global,
9320                                Local<Value> name,
9321                                v8::AccessType type,
9322                                Local<Value> data) {
9323   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9324       allowed_access_type[type];
9325 }
9326
9327
9328 static bool IndexedAccessBlocker(Local<v8::Object> global,
9329                                  uint32_t key,
9330                                  v8::AccessType type,
9331                                  Local<Value> data) {
9332   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9333       allowed_access_type[type];
9334 }
9335
9336
9337 static int g_echo_value = -1;
9338
9339
9340 static void EchoGetter(
9341     Local<String> name,
9342     const v8::PropertyCallbackInfo<v8::Value>& info) {
9343   info.GetReturnValue().Set(v8_num(g_echo_value));
9344 }
9345
9346
9347 static void EchoSetter(Local<String> name,
9348                        Local<Value> value,
9349                        const v8::PropertyCallbackInfo<void>&) {
9350   if (value->IsNumber())
9351     g_echo_value = value->Int32Value();
9352 }
9353
9354
9355 static void UnreachableGetter(
9356     Local<String> name,
9357     const v8::PropertyCallbackInfo<v8::Value>& info) {
9358   CHECK(false);  // This function should not be called..
9359 }
9360
9361
9362 static void UnreachableSetter(Local<String>,
9363                               Local<Value>,
9364                               const v8::PropertyCallbackInfo<void>&) {
9365   CHECK(false);  // This function should nto be called.
9366 }
9367
9368
9369 static void UnreachableFunction(
9370     const v8::FunctionCallbackInfo<v8::Value>& info) {
9371   CHECK(false);  // This function should not be called..
9372 }
9373
9374
9375 TEST(AccessControl) {
9376   v8::Isolate* isolate = CcTest::isolate();
9377   v8::HandleScope handle_scope(isolate);
9378   v8::Handle<v8::ObjectTemplate> global_template =
9379       v8::ObjectTemplate::New(isolate);
9380
9381   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9382                                            IndexedAccessBlocker);
9383
9384   // Add an accessor accessible by cross-domain JS code.
9385   global_template->SetAccessor(
9386       v8_str("accessible_prop"),
9387       EchoGetter, EchoSetter,
9388       v8::Handle<Value>(),
9389       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9390
9391
9392   // Add an accessor that is not accessible by cross-domain JS code.
9393   global_template->SetAccessor(v8_str("blocked_prop"),
9394                                UnreachableGetter, UnreachableSetter,
9395                                v8::Handle<Value>(),
9396                                v8::DEFAULT);
9397
9398   global_template->SetAccessorProperty(
9399       v8_str("blocked_js_prop"),
9400       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9401       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9402       v8::None,
9403       v8::DEFAULT);
9404
9405   // Create an environment
9406   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9407   context0->Enter();
9408
9409   v8::Handle<v8::Object> global0 = context0->Global();
9410
9411   // Define a property with JS getter and setter.
9412   CompileRun(
9413       "function getter() { return 'getter'; };\n"
9414       "function setter() { return 'setter'; }\n"
9415       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9416
9417   Local<Value> getter = global0->Get(v8_str("getter"));
9418   Local<Value> setter = global0->Get(v8_str("setter"));
9419
9420   // And define normal element.
9421   global0->Set(239, v8_str("239"));
9422
9423   // Define an element with JS getter and setter.
9424   CompileRun(
9425       "function el_getter() { return 'el_getter'; };\n"
9426       "function el_setter() { return 'el_setter'; };\n"
9427       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9428
9429   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9430   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9431
9432   v8::HandleScope scope1(isolate);
9433
9434   v8::Local<Context> context1 = Context::New(isolate);
9435   context1->Enter();
9436
9437   v8::Handle<v8::Object> global1 = context1->Global();
9438   global1->Set(v8_str("other"), global0);
9439
9440   // Access blocked property.
9441   CompileRun("other.blocked_prop = 1");
9442
9443   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9444   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9445             .IsEmpty());
9446   CHECK(
9447       CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9448
9449   // Access blocked element.
9450   CHECK(CompileRun("other[239] = 1").IsEmpty());
9451
9452   CHECK(CompileRun("other[239]").IsEmpty());
9453   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9454   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9455
9456   // Enable ACCESS_HAS
9457   allowed_access_type[v8::ACCESS_HAS] = true;
9458   CHECK(CompileRun("other[239]").IsEmpty());
9459   // ... and now we can get the descriptor...
9460   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9461             .IsEmpty());
9462   // ... and enumerate the property.
9463   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9464   allowed_access_type[v8::ACCESS_HAS] = false;
9465
9466   // Access a property with JS accessor.
9467   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9468
9469   CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9470   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9471             .IsEmpty());
9472
9473   // Enable both ACCESS_HAS and ACCESS_GET.
9474   allowed_access_type[v8::ACCESS_HAS] = true;
9475   allowed_access_type[v8::ACCESS_GET] = true;
9476
9477   ExpectString("other.js_accessor_p", "getter");
9478   ExpectObject(
9479       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9480   ExpectObject(
9481       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9482   ExpectUndefined(
9483       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9484
9485   allowed_access_type[v8::ACCESS_HAS] = false;
9486   allowed_access_type[v8::ACCESS_GET] = false;
9487
9488   // Access an element with JS accessor.
9489   CHECK(CompileRun("other[42] = 2").IsEmpty());
9490
9491   CHECK(CompileRun("other[42]").IsEmpty());
9492   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9493
9494   // Enable both ACCESS_HAS and ACCESS_GET.
9495   allowed_access_type[v8::ACCESS_HAS] = true;
9496   allowed_access_type[v8::ACCESS_GET] = true;
9497
9498   ExpectString("other[42]", "el_getter");
9499   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9500   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9501   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9502
9503   allowed_access_type[v8::ACCESS_HAS] = false;
9504   allowed_access_type[v8::ACCESS_GET] = false;
9505
9506   v8::Handle<Value> value;
9507
9508   // Access accessible property
9509   value = CompileRun("other.accessible_prop = 3");
9510   CHECK(value->IsNumber());
9511   CHECK_EQ(3, value->Int32Value());
9512   CHECK_EQ(3, g_echo_value);
9513
9514   value = CompileRun("other.accessible_prop");
9515   CHECK(value->IsNumber());
9516   CHECK_EQ(3, value->Int32Value());
9517
9518   value = CompileRun(
9519       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9520   CHECK(value->IsNumber());
9521   CHECK_EQ(3, value->Int32Value());
9522
9523   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9524   CHECK(value->IsTrue());
9525
9526   // Enumeration doesn't enumerate accessors from inaccessible objects in
9527   // the prototype chain even if the accessors are in themselves accessible.
9528   value = CompileRun(
9529       "(function() {"
9530       "  var obj = { '__proto__': other };"
9531       "  try {"
9532       "    for (var p in obj) {"
9533       "      if (p == 'accessible_prop' ||"
9534       "          p == 'blocked_js_prop' ||"
9535       "          p == 'blocked_js_prop') {"
9536       "        return false;"
9537       "      }"
9538       "    }"
9539       "    return false;"
9540       "  } catch (e) {"
9541       "    return true;"
9542       "  }"
9543       "})()");
9544   CHECK(value->IsTrue());
9545
9546   context1->Exit();
9547   context0->Exit();
9548 }
9549
9550
9551 TEST(AccessControlES5) {
9552   v8::Isolate* isolate = CcTest::isolate();
9553   v8::HandleScope handle_scope(isolate);
9554   v8::Handle<v8::ObjectTemplate> global_template =
9555       v8::ObjectTemplate::New(isolate);
9556
9557   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9558                                            IndexedAccessBlocker);
9559
9560   // Add accessible accessor.
9561   global_template->SetAccessor(
9562       v8_str("accessible_prop"),
9563       EchoGetter, EchoSetter,
9564       v8::Handle<Value>(),
9565       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9566
9567
9568   // Add an accessor that is not accessible by cross-domain JS code.
9569   global_template->SetAccessor(v8_str("blocked_prop"),
9570                                UnreachableGetter, UnreachableSetter,
9571                                v8::Handle<Value>(),
9572                                v8::DEFAULT);
9573
9574   // Create an environment
9575   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9576   context0->Enter();
9577
9578   v8::Handle<v8::Object> global0 = context0->Global();
9579
9580   v8::Local<Context> context1 = Context::New(isolate);
9581   context1->Enter();
9582   v8::Handle<v8::Object> global1 = context1->Global();
9583   global1->Set(v8_str("other"), global0);
9584
9585   // Regression test for issue 1154.
9586   CHECK(CompileRun("Object.keys(other)").IsEmpty());
9587   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9588
9589   // Regression test for issue 1027.
9590   CompileRun("Object.defineProperty(\n"
9591              "  other, 'blocked_prop', {configurable: false})");
9592   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9593   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9594             .IsEmpty());
9595
9596   // Regression test for issue 1171.
9597   ExpectTrue("Object.isExtensible(other)");
9598   CompileRun("Object.preventExtensions(other)");
9599   ExpectTrue("Object.isExtensible(other)");
9600
9601   // Object.seal and Object.freeze.
9602   CompileRun("Object.freeze(other)");
9603   ExpectTrue("Object.isExtensible(other)");
9604
9605   CompileRun("Object.seal(other)");
9606   ExpectTrue("Object.isExtensible(other)");
9607
9608   // Regression test for issue 1250.
9609   // Make sure that we can set the accessible accessors value using normal
9610   // assignment.
9611   CompileRun("other.accessible_prop = 42");
9612   CHECK_EQ(42, g_echo_value);
9613
9614   v8::Handle<Value> value;
9615   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9616   value = CompileRun("other.accessible_prop == 42");
9617   CHECK(value->IsTrue());
9618 }
9619
9620
9621 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9622                                  v8::AccessType type, Local<Value> data) {
9623   return false;
9624 }
9625
9626
9627 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9628                                    v8::AccessType type, Local<Value> data) {
9629   return false;
9630 }
9631
9632
9633 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9634   v8::Isolate* isolate = CcTest::isolate();
9635   v8::HandleScope handle_scope(isolate);
9636   v8::Handle<v8::ObjectTemplate> obj_template =
9637       v8::ObjectTemplate::New(isolate);
9638
9639   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9640   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9641                                         BlockEverythingIndexed);
9642
9643   // Create an environment
9644   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9645   context0->Enter();
9646
9647   v8::Handle<v8::Object> global0 = context0->Global();
9648
9649   v8::HandleScope scope1(CcTest::isolate());
9650
9651   v8::Local<Context> context1 = Context::New(isolate);
9652   context1->Enter();
9653
9654   v8::Handle<v8::Object> global1 = context1->Global();
9655   global1->Set(v8_str("other"), global0);
9656   global1->Set(v8_str("object"), obj_template->NewInstance());
9657
9658   v8::Handle<Value> value;
9659
9660   // Attempt to get the property names of the other global object and
9661   // of an object that requires access checks.  Accessing the other
9662   // global object should be blocked by access checks on the global
9663   // proxy object.  Accessing the object that requires access checks
9664   // is blocked by the access checks on the object itself.
9665   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9666   CHECK(value.IsEmpty());
9667
9668   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9669   CHECK(value.IsEmpty());
9670
9671   context1->Exit();
9672   context0->Exit();
9673 }
9674
9675
9676 TEST(SuperAccessControl) {
9677   i::FLAG_harmony_classes = true;
9678   v8::Isolate* isolate = CcTest::isolate();
9679   v8::HandleScope handle_scope(isolate);
9680   v8::Handle<v8::ObjectTemplate> obj_template =
9681       v8::ObjectTemplate::New(isolate);
9682   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9683                                         BlockEverythingIndexed);
9684   LocalContext env;
9685   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
9686
9687   {
9688     v8::TryCatch try_catch;
9689     CompileRun(
9690         "function f() { return super.hasOwnProperty; };"
9691         "var m = f.toMethod(prohibited);"
9692         "m();");
9693     CHECK(try_catch.HasCaught());
9694   }
9695
9696   {
9697     v8::TryCatch try_catch;
9698     CompileRun(
9699         "function f() { super.hasOwnProperty = function () {}; };"
9700         "var m = f.toMethod(prohibited);"
9701         "m();");
9702     CHECK(try_catch.HasCaught());
9703   }
9704
9705   {
9706     v8::TryCatch try_catch;
9707     CompileRun(
9708         "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
9709         "function f() { "
9710         "     'use strict';"
9711         "     super.x = function () {}; "
9712         "};"
9713         "var m = f.toMethod(prohibited);"
9714         "m();");
9715     CHECK(try_catch.HasCaught());
9716   }
9717 }
9718
9719
9720 static void IndexedPropertyEnumerator(
9721     const v8::PropertyCallbackInfo<v8::Array>& info) {
9722   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9723   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9724   result->Set(1, v8::Object::New(info.GetIsolate()));
9725   info.GetReturnValue().Set(result);
9726 }
9727
9728
9729 static void NamedPropertyEnumerator(
9730     const v8::PropertyCallbackInfo<v8::Array>& info) {
9731   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9732   result->Set(0, v8_str("x"));
9733   result->Set(1, v8::Object::New(info.GetIsolate()));
9734   info.GetReturnValue().Set(result);
9735 }
9736
9737
9738 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9739   v8::Isolate* isolate = CcTest::isolate();
9740   v8::HandleScope handle_scope(isolate);
9741   v8::Handle<v8::ObjectTemplate> obj_template =
9742       v8::ObjectTemplate::New(isolate);
9743
9744   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9745   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9746   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9747                                           IndexedPropertyEnumerator);
9748   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9749                                         NamedPropertyEnumerator);
9750
9751   LocalContext context;
9752   v8::Handle<v8::Object> global = context->Global();
9753   global->Set(v8_str("object"), obj_template->NewInstance());
9754
9755   v8::Handle<v8::Value> result =
9756       CompileRun("Object.getOwnPropertyNames(object)");
9757   CHECK(result->IsArray());
9758   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9759   CHECK_EQ(3, result_array->Length());
9760   CHECK(result_array->Get(0)->IsString());
9761   CHECK(result_array->Get(1)->IsString());
9762   CHECK(result_array->Get(2)->IsString());
9763   CHECK_EQ(v8_str("7"), result_array->Get(0));
9764   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9765   CHECK_EQ(v8_str("x"), result_array->Get(2));
9766 }
9767
9768
9769 static void ConstTenGetter(Local<String> name,
9770                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9771   info.GetReturnValue().Set(v8_num(10));
9772 }
9773
9774
9775 THREADED_TEST(CrossDomainAccessors) {
9776   v8::Isolate* isolate = CcTest::isolate();
9777   v8::HandleScope handle_scope(isolate);
9778
9779   v8::Handle<v8::FunctionTemplate> func_template =
9780       v8::FunctionTemplate::New(isolate);
9781
9782   v8::Handle<v8::ObjectTemplate> global_template =
9783       func_template->InstanceTemplate();
9784
9785   v8::Handle<v8::ObjectTemplate> proto_template =
9786       func_template->PrototypeTemplate();
9787
9788   // Add an accessor to proto that's accessible by cross-domain JS code.
9789   proto_template->SetAccessor(v8_str("accessible"),
9790                               ConstTenGetter, 0,
9791                               v8::Handle<Value>(),
9792                               v8::ALL_CAN_READ);
9793
9794   // Add an accessor that is not accessible by cross-domain JS code.
9795   global_template->SetAccessor(v8_str("unreachable"),
9796                                UnreachableGetter, 0,
9797                                v8::Handle<Value>(),
9798                                v8::DEFAULT);
9799
9800   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9801   context0->Enter();
9802
9803   Local<v8::Object> global = context0->Global();
9804   // Add a normal property that shadows 'accessible'
9805   global->Set(v8_str("accessible"), v8_num(11));
9806
9807   // Enter a new context.
9808   v8::HandleScope scope1(CcTest::isolate());
9809   v8::Local<Context> context1 = Context::New(isolate);
9810   context1->Enter();
9811
9812   v8::Handle<v8::Object> global1 = context1->Global();
9813   global1->Set(v8_str("other"), global);
9814
9815   // Should return 10, instead of 11
9816   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9817   CHECK(value->IsNumber());
9818   CHECK_EQ(10, value->Int32Value());
9819
9820   value = v8_compile("other.unreachable")->Run();
9821   CHECK(value.IsEmpty());
9822
9823   context1->Exit();
9824   context0->Exit();
9825 }
9826
9827
9828 static int named_access_count = 0;
9829 static int indexed_access_count = 0;
9830
9831 static bool NamedAccessCounter(Local<v8::Object> global,
9832                                Local<Value> name,
9833                                v8::AccessType type,
9834                                Local<Value> data) {
9835   named_access_count++;
9836   return true;
9837 }
9838
9839
9840 static bool IndexedAccessCounter(Local<v8::Object> global,
9841                                  uint32_t key,
9842                                  v8::AccessType type,
9843                                  Local<Value> data) {
9844   indexed_access_count++;
9845   return true;
9846 }
9847
9848
9849 // This one is too easily disturbed by other tests.
9850 TEST(AccessControlIC) {
9851   named_access_count = 0;
9852   indexed_access_count = 0;
9853
9854   v8::Isolate* isolate = CcTest::isolate();
9855   v8::HandleScope handle_scope(isolate);
9856
9857   // Create an environment.
9858   v8::Local<Context> context0 = Context::New(isolate);
9859   context0->Enter();
9860
9861   // Create an object that requires access-check functions to be
9862   // called for cross-domain access.
9863   v8::Handle<v8::ObjectTemplate> object_template =
9864       v8::ObjectTemplate::New(isolate);
9865   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9866                                            IndexedAccessCounter);
9867   Local<v8::Object> object = object_template->NewInstance();
9868
9869   v8::HandleScope scope1(isolate);
9870
9871   // Create another environment.
9872   v8::Local<Context> context1 = Context::New(isolate);
9873   context1->Enter();
9874
9875   // Make easy access to the object from the other environment.
9876   v8::Handle<v8::Object> global1 = context1->Global();
9877   global1->Set(v8_str("obj"), object);
9878
9879   v8::Handle<Value> value;
9880
9881   // Check that the named access-control function is called every time.
9882   CompileRun("function testProp(obj) {"
9883              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9884              "  for (var j = 0; j < 10; j++) obj.prop;"
9885              "  return obj.prop"
9886              "}");
9887   value = CompileRun("testProp(obj)");
9888   CHECK(value->IsNumber());
9889   CHECK_EQ(1, value->Int32Value());
9890   CHECK_EQ(21, named_access_count);
9891
9892   // Check that the named access-control function is called every time.
9893   CompileRun("var p = 'prop';"
9894              "function testKeyed(obj) {"
9895              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9896              "  for (var j = 0; j < 10; j++) obj[p];"
9897              "  return obj[p];"
9898              "}");
9899   // Use obj which requires access checks.  No inline caching is used
9900   // in that case.
9901   value = CompileRun("testKeyed(obj)");
9902   CHECK(value->IsNumber());
9903   CHECK_EQ(1, value->Int32Value());
9904   CHECK_EQ(42, named_access_count);
9905   // Force the inline caches into generic state and try again.
9906   CompileRun("testKeyed({ a: 0 })");
9907   CompileRun("testKeyed({ b: 0 })");
9908   value = CompileRun("testKeyed(obj)");
9909   CHECK(value->IsNumber());
9910   CHECK_EQ(1, value->Int32Value());
9911   CHECK_EQ(63, named_access_count);
9912
9913   // Check that the indexed access-control function is called every time.
9914   CompileRun("function testIndexed(obj) {"
9915              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9916              "  for (var j = 0; j < 10; j++) obj[0];"
9917              "  return obj[0]"
9918              "}");
9919   value = CompileRun("testIndexed(obj)");
9920   CHECK(value->IsNumber());
9921   CHECK_EQ(1, value->Int32Value());
9922   CHECK_EQ(21, indexed_access_count);
9923   // Force the inline caches into generic state.
9924   CompileRun("testIndexed(new Array(1))");
9925   // Test that the indexed access check is called.
9926   value = CompileRun("testIndexed(obj)");
9927   CHECK(value->IsNumber());
9928   CHECK_EQ(1, value->Int32Value());
9929   CHECK_EQ(42, indexed_access_count);
9930
9931   // Check that the named access check is called when invoking
9932   // functions on an object that requires access checks.
9933   CompileRun("obj.f = function() {}");
9934   CompileRun("function testCallNormal(obj) {"
9935              "  for (var i = 0; i < 10; i++) obj.f();"
9936              "}");
9937   CompileRun("testCallNormal(obj)");
9938   CHECK_EQ(74, named_access_count);
9939
9940   // Force obj into slow case.
9941   value = CompileRun("delete obj.prop");
9942   CHECK(value->BooleanValue());
9943   // Force inline caches into dictionary probing mode.
9944   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9945   // Test that the named access check is called.
9946   value = CompileRun("testProp(obj);");
9947   CHECK(value->IsNumber());
9948   CHECK_EQ(1, value->Int32Value());
9949   CHECK_EQ(96, named_access_count);
9950
9951   // Force the call inline cache into dictionary probing mode.
9952   CompileRun("o.f = function() {}; testCallNormal(o)");
9953   // Test that the named access check is still called for each
9954   // invocation of the function.
9955   value = CompileRun("testCallNormal(obj)");
9956   CHECK_EQ(106, named_access_count);
9957
9958   context1->Exit();
9959   context0->Exit();
9960 }
9961
9962
9963 static bool NamedAccessFlatten(Local<v8::Object> global,
9964                                Local<Value> name,
9965                                v8::AccessType type,
9966                                Local<Value> data) {
9967   char buf[100];
9968   int len;
9969
9970   CHECK(name->IsString());
9971
9972   memset(buf, 0x1, sizeof(buf));
9973   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9974   CHECK_EQ(4, len);
9975
9976   uint16_t buf2[100];
9977
9978   memset(buf, 0x1, sizeof(buf));
9979   len = name.As<String>()->Write(buf2);
9980   CHECK_EQ(4, len);
9981
9982   return true;
9983 }
9984
9985
9986 static bool IndexedAccessFlatten(Local<v8::Object> global,
9987                                  uint32_t key,
9988                                  v8::AccessType type,
9989                                  Local<Value> data) {
9990   return true;
9991 }
9992
9993
9994 // Regression test.  In access checks, operations that may cause
9995 // garbage collection are not allowed.  It used to be the case that
9996 // using the Write operation on a string could cause a garbage
9997 // collection due to flattening of the string.  This is no longer the
9998 // case.
9999 THREADED_TEST(AccessControlFlatten) {
10000   named_access_count = 0;
10001   indexed_access_count = 0;
10002
10003   v8::Isolate* isolate = CcTest::isolate();
10004   v8::HandleScope handle_scope(isolate);
10005
10006   // Create an environment.
10007   v8::Local<Context> context0 = Context::New(isolate);
10008   context0->Enter();
10009
10010   // Create an object that requires access-check functions to be
10011   // called for cross-domain access.
10012   v8::Handle<v8::ObjectTemplate> object_template =
10013       v8::ObjectTemplate::New(isolate);
10014   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10015                                            IndexedAccessFlatten);
10016   Local<v8::Object> object = object_template->NewInstance();
10017
10018   v8::HandleScope scope1(isolate);
10019
10020   // Create another environment.
10021   v8::Local<Context> context1 = Context::New(isolate);
10022   context1->Enter();
10023
10024   // Make easy access to the object from the other environment.
10025   v8::Handle<v8::Object> global1 = context1->Global();
10026   global1->Set(v8_str("obj"), object);
10027
10028   v8::Handle<Value> value;
10029
10030   value = v8_compile("var p = 'as' + 'df';")->Run();
10031   value = v8_compile("obj[p];")->Run();
10032
10033   context1->Exit();
10034   context0->Exit();
10035 }
10036
10037
10038 static void AccessControlNamedGetter(
10039     Local<String>,
10040     const v8::PropertyCallbackInfo<v8::Value>& info) {
10041   info.GetReturnValue().Set(42);
10042 }
10043
10044
10045 static void AccessControlNamedSetter(
10046     Local<String>,
10047     Local<Value> value,
10048     const v8::PropertyCallbackInfo<v8::Value>& info) {
10049   info.GetReturnValue().Set(value);
10050 }
10051
10052
10053 static void AccessControlIndexedGetter(
10054       uint32_t index,
10055       const v8::PropertyCallbackInfo<v8::Value>& info) {
10056   info.GetReturnValue().Set(v8_num(42));
10057 }
10058
10059
10060 static void AccessControlIndexedSetter(
10061     uint32_t,
10062     Local<Value> value,
10063     const v8::PropertyCallbackInfo<v8::Value>& info) {
10064   info.GetReturnValue().Set(value);
10065 }
10066
10067
10068 THREADED_TEST(AccessControlInterceptorIC) {
10069   named_access_count = 0;
10070   indexed_access_count = 0;
10071
10072   v8::Isolate* isolate = CcTest::isolate();
10073   v8::HandleScope handle_scope(isolate);
10074
10075   // Create an environment.
10076   v8::Local<Context> context0 = Context::New(isolate);
10077   context0->Enter();
10078
10079   // Create an object that requires access-check functions to be
10080   // called for cross-domain access.  The object also has interceptors
10081   // interceptor.
10082   v8::Handle<v8::ObjectTemplate> object_template =
10083       v8::ObjectTemplate::New(isolate);
10084   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10085                                            IndexedAccessCounter);
10086   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
10087                                            AccessControlNamedSetter);
10088   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
10089                                              AccessControlIndexedSetter);
10090   Local<v8::Object> object = object_template->NewInstance();
10091
10092   v8::HandleScope scope1(isolate);
10093
10094   // Create another environment.
10095   v8::Local<Context> context1 = Context::New(isolate);
10096   context1->Enter();
10097
10098   // Make easy access to the object from the other environment.
10099   v8::Handle<v8::Object> global1 = context1->Global();
10100   global1->Set(v8_str("obj"), object);
10101
10102   v8::Handle<Value> value;
10103
10104   // Check that the named access-control function is called every time
10105   // eventhough there is an interceptor on the object.
10106   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10107   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10108                      "obj.x")->Run();
10109   CHECK(value->IsNumber());
10110   CHECK_EQ(42, value->Int32Value());
10111   CHECK_EQ(21, named_access_count);
10112
10113   value = v8_compile("var p = 'x';")->Run();
10114   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10115   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10116                      "obj[p]")->Run();
10117   CHECK(value->IsNumber());
10118   CHECK_EQ(42, value->Int32Value());
10119   CHECK_EQ(42, named_access_count);
10120
10121   // Check that the indexed access-control function is called every
10122   // time eventhough there is an interceptor on the object.
10123   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10124   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10125                      "obj[0]")->Run();
10126   CHECK(value->IsNumber());
10127   CHECK_EQ(42, value->Int32Value());
10128   CHECK_EQ(21, indexed_access_count);
10129
10130   context1->Exit();
10131   context0->Exit();
10132 }
10133
10134
10135 THREADED_TEST(Version) {
10136   v8::V8::GetVersion();
10137 }
10138
10139
10140 static void InstanceFunctionCallback(
10141     const v8::FunctionCallbackInfo<v8::Value>& args) {
10142   ApiTestFuzzer::Fuzz();
10143   args.GetReturnValue().Set(v8_num(12));
10144 }
10145
10146
10147 THREADED_TEST(InstanceProperties) {
10148   LocalContext context;
10149   v8::Isolate* isolate = context->GetIsolate();
10150   v8::HandleScope handle_scope(isolate);
10151
10152   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10153   Local<ObjectTemplate> instance = t->InstanceTemplate();
10154
10155   instance->Set(v8_str("x"), v8_num(42));
10156   instance->Set(v8_str("f"),
10157                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10158
10159   Local<Value> o = t->GetFunction()->NewInstance();
10160
10161   context->Global()->Set(v8_str("i"), o);
10162   Local<Value> value = CompileRun("i.x");
10163   CHECK_EQ(42, value->Int32Value());
10164
10165   value = CompileRun("i.f()");
10166   CHECK_EQ(12, value->Int32Value());
10167 }
10168
10169
10170 static void GlobalObjectInstancePropertiesGet(
10171     Local<String> key,
10172     const v8::PropertyCallbackInfo<v8::Value>&) {
10173   ApiTestFuzzer::Fuzz();
10174 }
10175
10176
10177 THREADED_TEST(GlobalObjectInstanceProperties) {
10178   v8::Isolate* isolate = CcTest::isolate();
10179   v8::HandleScope handle_scope(isolate);
10180
10181   Local<Value> global_object;
10182
10183   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10184   t->InstanceTemplate()->SetNamedPropertyHandler(
10185       GlobalObjectInstancePropertiesGet);
10186   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10187   instance_template->Set(v8_str("x"), v8_num(42));
10188   instance_template->Set(v8_str("f"),
10189                          v8::FunctionTemplate::New(isolate,
10190                                                    InstanceFunctionCallback));
10191
10192   // The script to check how Crankshaft compiles missing global function
10193   // invocations.  function g is not defined and should throw on call.
10194   const char* script =
10195       "function wrapper(call) {"
10196       "  var x = 0, y = 1;"
10197       "  for (var i = 0; i < 1000; i++) {"
10198       "    x += i * 100;"
10199       "    y += i * 100;"
10200       "  }"
10201       "  if (call) g();"
10202       "}"
10203       "for (var i = 0; i < 17; i++) wrapper(false);"
10204       "var thrown = 0;"
10205       "try { wrapper(true); } catch (e) { thrown = 1; };"
10206       "thrown";
10207
10208   {
10209     LocalContext env(NULL, instance_template);
10210     // Hold on to the global object so it can be used again in another
10211     // environment initialization.
10212     global_object = env->Global();
10213
10214     Local<Value> value = CompileRun("x");
10215     CHECK_EQ(42, value->Int32Value());
10216     value = CompileRun("f()");
10217     CHECK_EQ(12, value->Int32Value());
10218     value = CompileRun(script);
10219     CHECK_EQ(1, value->Int32Value());
10220   }
10221
10222   {
10223     // Create new environment reusing the global object.
10224     LocalContext env(NULL, instance_template, global_object);
10225     Local<Value> value = CompileRun("x");
10226     CHECK_EQ(42, value->Int32Value());
10227     value = CompileRun("f()");
10228     CHECK_EQ(12, value->Int32Value());
10229     value = CompileRun(script);
10230     CHECK_EQ(1, value->Int32Value());
10231   }
10232 }
10233
10234
10235 THREADED_TEST(CallKnownGlobalReceiver) {
10236   v8::Isolate* isolate = CcTest::isolate();
10237   v8::HandleScope handle_scope(isolate);
10238
10239   Local<Value> global_object;
10240
10241   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10242   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10243
10244   // The script to check that we leave global object not
10245   // global object proxy on stack when we deoptimize from inside
10246   // arguments evaluation.
10247   // To provoke error we need to both force deoptimization
10248   // from arguments evaluation and to force CallIC to take
10249   // CallIC_Miss code path that can't cope with global proxy.
10250   const char* script =
10251       "function bar(x, y) { try { } finally { } }"
10252       "function baz(x) { try { } finally { } }"
10253       "function bom(x) { try { } finally { } }"
10254       "function foo(x) { bar([x], bom(2)); }"
10255       "for (var i = 0; i < 10000; i++) foo(1);"
10256       "foo";
10257
10258   Local<Value> foo;
10259   {
10260     LocalContext env(NULL, instance_template);
10261     // Hold on to the global object so it can be used again in another
10262     // environment initialization.
10263     global_object = env->Global();
10264     foo = CompileRun(script);
10265   }
10266
10267   {
10268     // Create new environment reusing the global object.
10269     LocalContext env(NULL, instance_template, global_object);
10270     env->Global()->Set(v8_str("foo"), foo);
10271     CompileRun("foo()");
10272   }
10273 }
10274
10275
10276 static void ShadowFunctionCallback(
10277     const v8::FunctionCallbackInfo<v8::Value>& args) {
10278   ApiTestFuzzer::Fuzz();
10279   args.GetReturnValue().Set(v8_num(42));
10280 }
10281
10282
10283 static int shadow_y;
10284 static int shadow_y_setter_call_count;
10285 static int shadow_y_getter_call_count;
10286
10287
10288 static void ShadowYSetter(Local<String>,
10289                           Local<Value>,
10290                           const v8::PropertyCallbackInfo<void>&) {
10291   shadow_y_setter_call_count++;
10292   shadow_y = 42;
10293 }
10294
10295
10296 static void ShadowYGetter(Local<String> name,
10297                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10298   ApiTestFuzzer::Fuzz();
10299   shadow_y_getter_call_count++;
10300   info.GetReturnValue().Set(v8_num(shadow_y));
10301 }
10302
10303
10304 static void ShadowIndexedGet(uint32_t index,
10305                              const v8::PropertyCallbackInfo<v8::Value>&) {
10306 }
10307
10308
10309 static void ShadowNamedGet(Local<String> key,
10310                            const v8::PropertyCallbackInfo<v8::Value>&) {
10311 }
10312
10313
10314 THREADED_TEST(ShadowObject) {
10315   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10316   v8::Isolate* isolate = CcTest::isolate();
10317   v8::HandleScope handle_scope(isolate);
10318
10319   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10320   LocalContext context(NULL, global_template);
10321
10322   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10323   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10324   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10325   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10326   Local<ObjectTemplate> instance = t->InstanceTemplate();
10327
10328   proto->Set(v8_str("f"),
10329              v8::FunctionTemplate::New(isolate,
10330                                        ShadowFunctionCallback,
10331                                        Local<Value>()));
10332   proto->Set(v8_str("x"), v8_num(12));
10333
10334   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10335
10336   Local<Value> o = t->GetFunction()->NewInstance();
10337   context->Global()->Set(v8_str("__proto__"), o);
10338
10339   Local<Value> value =
10340       CompileRun("this.propertyIsEnumerable(0)");
10341   CHECK(value->IsBoolean());
10342   CHECK(!value->BooleanValue());
10343
10344   value = CompileRun("x");
10345   CHECK_EQ(12, value->Int32Value());
10346
10347   value = CompileRun("f()");
10348   CHECK_EQ(42, value->Int32Value());
10349
10350   CompileRun("y = 43");
10351   CHECK_EQ(1, shadow_y_setter_call_count);
10352   value = CompileRun("y");
10353   CHECK_EQ(1, shadow_y_getter_call_count);
10354   CHECK_EQ(42, value->Int32Value());
10355 }
10356
10357
10358 THREADED_TEST(HiddenPrototype) {
10359   LocalContext context;
10360   v8::Isolate* isolate = context->GetIsolate();
10361   v8::HandleScope handle_scope(isolate);
10362
10363   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10364   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10365   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10366   t1->SetHiddenPrototype(true);
10367   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10368   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10369   t2->SetHiddenPrototype(true);
10370   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10371   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10372   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10373
10374   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10375   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10376   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10377   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10378
10379   // Setting the prototype on an object skips hidden prototypes.
10380   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10381   o0->Set(v8_str("__proto__"), o1);
10382   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10383   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10384   o0->Set(v8_str("__proto__"), o2);
10385   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10386   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10387   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10388   o0->Set(v8_str("__proto__"), o3);
10389   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10390   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10391   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10392   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10393
10394   // Getting the prototype of o0 should get the first visible one
10395   // which is o3.  Therefore, z should not be defined on the prototype
10396   // object.
10397   Local<Value> proto = o0->Get(v8_str("__proto__"));
10398   CHECK(proto->IsObject());
10399   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10400 }
10401
10402
10403 THREADED_TEST(HiddenPrototypeSet) {
10404   LocalContext context;
10405   v8::Isolate* isolate = context->GetIsolate();
10406   v8::HandleScope handle_scope(isolate);
10407
10408   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10409   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10410   ht->SetHiddenPrototype(true);
10411   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10412   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10413
10414   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10415   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10416   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10417   o->Set(v8_str("__proto__"), h);
10418   h->Set(v8_str("__proto__"), p);
10419
10420   // Setting a property that exists on the hidden prototype goes there.
10421   o->Set(v8_str("x"), v8_num(7));
10422   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10423   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10424   CHECK(p->Get(v8_str("x"))->IsUndefined());
10425
10426   // Setting a new property should not be forwarded to the hidden prototype.
10427   o->Set(v8_str("y"), v8_num(6));
10428   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10429   CHECK(h->Get(v8_str("y"))->IsUndefined());
10430   CHECK(p->Get(v8_str("y"))->IsUndefined());
10431
10432   // Setting a property that only exists on a prototype of the hidden prototype
10433   // is treated normally again.
10434   p->Set(v8_str("z"), v8_num(8));
10435   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10436   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10437   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10438   o->Set(v8_str("z"), v8_num(9));
10439   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10440   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10441   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10442 }
10443
10444
10445 // Regression test for issue 2457.
10446 THREADED_TEST(HiddenPrototypeIdentityHash) {
10447   LocalContext context;
10448   v8::HandleScope handle_scope(context->GetIsolate());
10449
10450   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10451   t->SetHiddenPrototype(true);
10452   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10453   Handle<Object> p = t->GetFunction()->NewInstance();
10454   Handle<Object> o = Object::New(context->GetIsolate());
10455   o->SetPrototype(p);
10456
10457   int hash = o->GetIdentityHash();
10458   USE(hash);
10459   o->Set(v8_str("foo"), v8_num(42));
10460   DCHECK_EQ(hash, o->GetIdentityHash());
10461 }
10462
10463
10464 THREADED_TEST(SetPrototype) {
10465   LocalContext context;
10466   v8::Isolate* isolate = context->GetIsolate();
10467   v8::HandleScope handle_scope(isolate);
10468
10469   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10470   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10471   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10472   t1->SetHiddenPrototype(true);
10473   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10474   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10475   t2->SetHiddenPrototype(true);
10476   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10477   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10478   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10479
10480   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10481   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10482   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10483   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10484
10485   // Setting the prototype on an object does not skip hidden prototypes.
10486   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10487   CHECK(o0->SetPrototype(o1));
10488   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10489   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10490   CHECK(o1->SetPrototype(o2));
10491   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10492   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10493   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10494   CHECK(o2->SetPrototype(o3));
10495   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10496   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10497   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10498   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10499
10500   // Getting the prototype of o0 should get the first visible one
10501   // which is o3.  Therefore, z should not be defined on the prototype
10502   // object.
10503   Local<Value> proto = o0->Get(v8_str("__proto__"));
10504   CHECK(proto->IsObject());
10505   CHECK_EQ(proto.As<v8::Object>(), o3);
10506
10507   // However, Object::GetPrototype ignores hidden prototype.
10508   Local<Value> proto0 = o0->GetPrototype();
10509   CHECK(proto0->IsObject());
10510   CHECK_EQ(proto0.As<v8::Object>(), o1);
10511
10512   Local<Value> proto1 = o1->GetPrototype();
10513   CHECK(proto1->IsObject());
10514   CHECK_EQ(proto1.As<v8::Object>(), o2);
10515
10516   Local<Value> proto2 = o2->GetPrototype();
10517   CHECK(proto2->IsObject());
10518   CHECK_EQ(proto2.As<v8::Object>(), o3);
10519 }
10520
10521
10522 // Getting property names of an object with a prototype chain that
10523 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10524 // crash the runtime.
10525 THREADED_TEST(Regress91517) {
10526   i::FLAG_allow_natives_syntax = true;
10527   LocalContext context;
10528   v8::Isolate* isolate = context->GetIsolate();
10529   v8::HandleScope handle_scope(isolate);
10530
10531   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10532   t1->SetHiddenPrototype(true);
10533   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10534   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10535   t2->SetHiddenPrototype(true);
10536   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10537   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10538   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10539   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10540   t3->SetHiddenPrototype(true);
10541   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10542   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10543   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10544
10545   // Force dictionary-based properties.
10546   i::ScopedVector<char> name_buf(1024);
10547   for (int i = 1; i <= 1000; i++) {
10548     i::SNPrintF(name_buf, "sdf%d", i);
10549     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10550   }
10551
10552   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10553   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10554   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10555   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10556
10557   // Create prototype chain of hidden prototypes.
10558   CHECK(o4->SetPrototype(o3));
10559   CHECK(o3->SetPrototype(o2));
10560   CHECK(o2->SetPrototype(o1));
10561
10562   // Call the runtime version of GetOwnPropertyNames() on the natively
10563   // created object through JavaScript.
10564   context->Global()->Set(v8_str("obj"), o4);
10565   // PROPERTY_ATTRIBUTES_NONE = 0
10566   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10567
10568   ExpectInt32("names.length", 1006);
10569   ExpectTrue("names.indexOf(\"baz\") >= 0");
10570   ExpectTrue("names.indexOf(\"boo\") >= 0");
10571   ExpectTrue("names.indexOf(\"foo\") >= 0");
10572   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10573   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10574   ExpectFalse("names[1005] == undefined");
10575 }
10576
10577
10578 // Getting property names of an object with a hidden and inherited
10579 // prototype should not duplicate the accessor properties inherited.
10580 THREADED_TEST(Regress269562) {
10581   i::FLAG_allow_natives_syntax = true;
10582   LocalContext context;
10583   v8::HandleScope handle_scope(context->GetIsolate());
10584
10585   Local<v8::FunctionTemplate> t1 =
10586       v8::FunctionTemplate::New(context->GetIsolate());
10587   t1->SetHiddenPrototype(true);
10588
10589   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10590   i1->SetAccessor(v8_str("foo"),
10591                   SimpleAccessorGetter, SimpleAccessorSetter);
10592   i1->SetAccessor(v8_str("bar"),
10593                   SimpleAccessorGetter, SimpleAccessorSetter);
10594   i1->SetAccessor(v8_str("baz"),
10595                   SimpleAccessorGetter, SimpleAccessorSetter);
10596   i1->Set(v8_str("n1"), v8_num(1));
10597   i1->Set(v8_str("n2"), v8_num(2));
10598
10599   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10600   Local<v8::FunctionTemplate> t2 =
10601       v8::FunctionTemplate::New(context->GetIsolate());
10602   t2->SetHiddenPrototype(true);
10603
10604   // Inherit from t1 and mark prototype as hidden.
10605   t2->Inherit(t1);
10606   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10607
10608   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10609   CHECK(o2->SetPrototype(o1));
10610
10611   v8::Local<v8::Symbol> sym =
10612       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10613   o1->Set(sym, v8_num(3));
10614   o1->SetHiddenValue(
10615       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10616
10617   // Call the runtime version of GetOwnPropertyNames() on
10618   // the natively created object through JavaScript.
10619   context->Global()->Set(v8_str("obj"), o2);
10620   context->Global()->Set(v8_str("sym"), sym);
10621   // PROPERTY_ATTRIBUTES_NONE = 0
10622   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10623
10624   ExpectInt32("names.length", 7);
10625   ExpectTrue("names.indexOf(\"foo\") >= 0");
10626   ExpectTrue("names.indexOf(\"bar\") >= 0");
10627   ExpectTrue("names.indexOf(\"baz\") >= 0");
10628   ExpectTrue("names.indexOf(\"n1\") >= 0");
10629   ExpectTrue("names.indexOf(\"n2\") >= 0");
10630   ExpectTrue("names.indexOf(sym) >= 0");
10631   ExpectTrue("names.indexOf(\"mine\") >= 0");
10632 }
10633
10634
10635 THREADED_TEST(FunctionReadOnlyPrototype) {
10636   LocalContext context;
10637   v8::Isolate* isolate = context->GetIsolate();
10638   v8::HandleScope handle_scope(isolate);
10639
10640   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10641   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10642   t1->ReadOnlyPrototype();
10643   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10644   // Configured value of ReadOnly flag.
10645   CHECK(CompileRun(
10646       "(function() {"
10647       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10648       "  return (descriptor['writable'] == false);"
10649       "})()")->BooleanValue());
10650   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10651   CHECK_EQ(42,
10652            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10653
10654   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10655   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10656   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10657   // Default value of ReadOnly flag.
10658   CHECK(CompileRun(
10659       "(function() {"
10660       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10661       "  return (descriptor['writable'] == true);"
10662       "})()")->BooleanValue());
10663   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10664 }
10665
10666
10667 THREADED_TEST(SetPrototypeThrows) {
10668   LocalContext context;
10669   v8::Isolate* isolate = context->GetIsolate();
10670   v8::HandleScope handle_scope(isolate);
10671
10672   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10673
10674   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10675   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10676
10677   CHECK(o0->SetPrototype(o1));
10678   // If setting the prototype leads to the cycle, SetPrototype should
10679   // return false and keep VM in sane state.
10680   v8::TryCatch try_catch;
10681   CHECK(!o1->SetPrototype(o0));
10682   CHECK(!try_catch.HasCaught());
10683   DCHECK(!CcTest::i_isolate()->has_pending_exception());
10684
10685   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10686 }
10687
10688
10689 THREADED_TEST(FunctionRemovePrototype) {
10690   LocalContext context;
10691   v8::Isolate* isolate = context->GetIsolate();
10692   v8::HandleScope handle_scope(isolate);
10693
10694   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10695   t1->RemovePrototype();
10696   Local<v8::Function> fun = t1->GetFunction();
10697   context->Global()->Set(v8_str("fun"), fun);
10698   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10699
10700   v8::TryCatch try_catch;
10701   CompileRun("new fun()");
10702   CHECK(try_catch.HasCaught());
10703
10704   try_catch.Reset();
10705   fun->NewInstance();
10706   CHECK(try_catch.HasCaught());
10707 }
10708
10709
10710 THREADED_TEST(GetterSetterExceptions) {
10711   LocalContext context;
10712   v8::Isolate* isolate = context->GetIsolate();
10713   v8::HandleScope handle_scope(isolate);
10714   CompileRun(
10715     "function Foo() { };"
10716     "function Throw() { throw 5; };"
10717     "var x = { };"
10718     "x.__defineSetter__('set', Throw);"
10719     "x.__defineGetter__('get', Throw);");
10720   Local<v8::Object> x =
10721       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10722   v8::TryCatch try_catch;
10723   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10724   x->Get(v8_str("get"));
10725   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10726   x->Get(v8_str("get"));
10727   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10728   x->Get(v8_str("get"));
10729   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10730   x->Get(v8_str("get"));
10731 }
10732
10733
10734 THREADED_TEST(Constructor) {
10735   LocalContext context;
10736   v8::Isolate* isolate = context->GetIsolate();
10737   v8::HandleScope handle_scope(isolate);
10738   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10739   templ->SetClassName(v8_str("Fun"));
10740   Local<Function> cons = templ->GetFunction();
10741   context->Global()->Set(v8_str("Fun"), cons);
10742   Local<v8::Object> inst = cons->NewInstance();
10743   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10744   CHECK(obj->IsJSObject());
10745   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10746   CHECK(value->BooleanValue());
10747 }
10748
10749
10750 static void ConstructorCallback(
10751     const v8::FunctionCallbackInfo<v8::Value>& args) {
10752   ApiTestFuzzer::Fuzz();
10753   Local<Object> This;
10754
10755   if (args.IsConstructCall()) {
10756     Local<Object> Holder = args.Holder();
10757     This = Object::New(args.GetIsolate());
10758     Local<Value> proto = Holder->GetPrototype();
10759     if (proto->IsObject()) {
10760       This->SetPrototype(proto);
10761     }
10762   } else {
10763     This = args.This();
10764   }
10765
10766   This->Set(v8_str("a"), args[0]);
10767   args.GetReturnValue().Set(This);
10768 }
10769
10770
10771 static void FakeConstructorCallback(
10772     const v8::FunctionCallbackInfo<v8::Value>& args) {
10773   ApiTestFuzzer::Fuzz();
10774   args.GetReturnValue().Set(args[0]);
10775 }
10776
10777
10778 THREADED_TEST(ConstructorForObject) {
10779   LocalContext context;
10780   v8::Isolate* isolate = context->GetIsolate();
10781   v8::HandleScope handle_scope(isolate);
10782
10783   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10784     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10785     Local<Object> instance = instance_template->NewInstance();
10786     context->Global()->Set(v8_str("obj"), instance);
10787     v8::TryCatch try_catch;
10788     Local<Value> value;
10789     CHECK(!try_catch.HasCaught());
10790
10791     // Call the Object's constructor with a 32-bit signed integer.
10792     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10793     CHECK(!try_catch.HasCaught());
10794     CHECK(value->IsInt32());
10795     CHECK_EQ(28, value->Int32Value());
10796
10797     Local<Value> args1[] = { v8_num(28) };
10798     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10799     CHECK(value_obj1->IsObject());
10800     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10801     value = object1->Get(v8_str("a"));
10802     CHECK(value->IsInt32());
10803     CHECK(!try_catch.HasCaught());
10804     CHECK_EQ(28, value->Int32Value());
10805
10806     // Call the Object's constructor with a String.
10807     value = CompileRun(
10808         "(function() { var o = new obj('tipli'); return o.a; })()");
10809     CHECK(!try_catch.HasCaught());
10810     CHECK(value->IsString());
10811     String::Utf8Value string_value1(value->ToString());
10812     CHECK_EQ("tipli", *string_value1);
10813
10814     Local<Value> args2[] = { v8_str("tipli") };
10815     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10816     CHECK(value_obj2->IsObject());
10817     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10818     value = object2->Get(v8_str("a"));
10819     CHECK(!try_catch.HasCaught());
10820     CHECK(value->IsString());
10821     String::Utf8Value string_value2(value->ToString());
10822     CHECK_EQ("tipli", *string_value2);
10823
10824     // Call the Object's constructor with a Boolean.
10825     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10826     CHECK(!try_catch.HasCaught());
10827     CHECK(value->IsBoolean());
10828     CHECK_EQ(true, value->BooleanValue());
10829
10830     Handle<Value> args3[] = { v8::True(isolate) };
10831     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10832     CHECK(value_obj3->IsObject());
10833     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10834     value = object3->Get(v8_str("a"));
10835     CHECK(!try_catch.HasCaught());
10836     CHECK(value->IsBoolean());
10837     CHECK_EQ(true, value->BooleanValue());
10838
10839     // Call the Object's constructor with undefined.
10840     Handle<Value> args4[] = { v8::Undefined(isolate) };
10841     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10842     CHECK(value_obj4->IsObject());
10843     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10844     value = object4->Get(v8_str("a"));
10845     CHECK(!try_catch.HasCaught());
10846     CHECK(value->IsUndefined());
10847
10848     // Call the Object's constructor with null.
10849     Handle<Value> args5[] = { v8::Null(isolate) };
10850     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10851     CHECK(value_obj5->IsObject());
10852     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10853     value = object5->Get(v8_str("a"));
10854     CHECK(!try_catch.HasCaught());
10855     CHECK(value->IsNull());
10856   }
10857
10858   // Check exception handling when there is no constructor set for the Object.
10859   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10860     Local<Object> instance = instance_template->NewInstance();
10861     context->Global()->Set(v8_str("obj2"), instance);
10862     v8::TryCatch try_catch;
10863     Local<Value> value;
10864     CHECK(!try_catch.HasCaught());
10865
10866     value = CompileRun("new obj2(28)");
10867     CHECK(try_catch.HasCaught());
10868     String::Utf8Value exception_value1(try_catch.Exception());
10869     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10870     try_catch.Reset();
10871
10872     Local<Value> args[] = { v8_num(29) };
10873     value = instance->CallAsConstructor(1, args);
10874     CHECK(try_catch.HasCaught());
10875     String::Utf8Value exception_value2(try_catch.Exception());
10876     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10877     try_catch.Reset();
10878   }
10879
10880   // Check the case when constructor throws exception.
10881   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10882     instance_template->SetCallAsFunctionHandler(ThrowValue);
10883     Local<Object> instance = instance_template->NewInstance();
10884     context->Global()->Set(v8_str("obj3"), instance);
10885     v8::TryCatch try_catch;
10886     Local<Value> value;
10887     CHECK(!try_catch.HasCaught());
10888
10889     value = CompileRun("new obj3(22)");
10890     CHECK(try_catch.HasCaught());
10891     String::Utf8Value exception_value1(try_catch.Exception());
10892     CHECK_EQ("22", *exception_value1);
10893     try_catch.Reset();
10894
10895     Local<Value> args[] = { v8_num(23) };
10896     value = instance->CallAsConstructor(1, args);
10897     CHECK(try_catch.HasCaught());
10898     String::Utf8Value exception_value2(try_catch.Exception());
10899     CHECK_EQ("23", *exception_value2);
10900     try_catch.Reset();
10901   }
10902
10903   // Check whether constructor returns with an object or non-object.
10904   { Local<FunctionTemplate> function_template =
10905         FunctionTemplate::New(isolate, FakeConstructorCallback);
10906     Local<Function> function = function_template->GetFunction();
10907     Local<Object> instance1 = function;
10908     context->Global()->Set(v8_str("obj4"), instance1);
10909     v8::TryCatch try_catch;
10910     Local<Value> value;
10911     CHECK(!try_catch.HasCaught());
10912
10913     CHECK(instance1->IsObject());
10914     CHECK(instance1->IsFunction());
10915
10916     value = CompileRun("new obj4(28)");
10917     CHECK(!try_catch.HasCaught());
10918     CHECK(value->IsObject());
10919
10920     Local<Value> args1[] = { v8_num(28) };
10921     value = instance1->CallAsConstructor(1, args1);
10922     CHECK(!try_catch.HasCaught());
10923     CHECK(value->IsObject());
10924
10925     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10926     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10927     Local<Object> instance2 = instance_template->NewInstance();
10928     context->Global()->Set(v8_str("obj5"), instance2);
10929     CHECK(!try_catch.HasCaught());
10930
10931     CHECK(instance2->IsObject());
10932     CHECK(!instance2->IsFunction());
10933
10934     value = CompileRun("new obj5(28)");
10935     CHECK(!try_catch.HasCaught());
10936     CHECK(!value->IsObject());
10937
10938     Local<Value> args2[] = { v8_num(28) };
10939     value = instance2->CallAsConstructor(1, args2);
10940     CHECK(!try_catch.HasCaught());
10941     CHECK(!value->IsObject());
10942   }
10943 }
10944
10945
10946 THREADED_TEST(FunctionDescriptorException) {
10947   LocalContext context;
10948   v8::Isolate* isolate = context->GetIsolate();
10949   v8::HandleScope handle_scope(isolate);
10950   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10951   templ->SetClassName(v8_str("Fun"));
10952   Local<Function> cons = templ->GetFunction();
10953   context->Global()->Set(v8_str("Fun"), cons);
10954   Local<Value> value = CompileRun(
10955     "function test() {"
10956     "  try {"
10957     "    (new Fun()).blah()"
10958     "  } catch (e) {"
10959     "    var str = String(e);"
10960     // "    if (str.indexOf('TypeError') == -1) return 1;"
10961     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10962     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10963     "    return 0;"
10964     "  }"
10965     "  return 4;"
10966     "}"
10967     "test();");
10968   CHECK_EQ(0, value->Int32Value());
10969 }
10970
10971
10972 THREADED_TEST(EvalAliasedDynamic) {
10973   LocalContext current;
10974   v8::HandleScope scope(current->GetIsolate());
10975
10976   // Tests where aliased eval can only be resolved dynamically.
10977   Local<Script> script = v8_compile(
10978       "function f(x) { "
10979       "  var foo = 2;"
10980       "  with (x) { return eval('foo'); }"
10981       "}"
10982       "foo = 0;"
10983       "result1 = f(new Object());"
10984       "result2 = f(this);"
10985       "var x = new Object();"
10986       "x.eval = function(x) { return 1; };"
10987       "result3 = f(x);");
10988   script->Run();
10989   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10990   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10991   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10992
10993   v8::TryCatch try_catch;
10994   script = v8_compile(
10995       "function f(x) { "
10996       "  var bar = 2;"
10997       "  with (x) { return eval('bar'); }"
10998       "}"
10999       "result4 = f(this)");
11000   script->Run();
11001   CHECK(!try_catch.HasCaught());
11002   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11003
11004   try_catch.Reset();
11005 }
11006
11007
11008 THREADED_TEST(CrossEval) {
11009   v8::HandleScope scope(CcTest::isolate());
11010   LocalContext other;
11011   LocalContext current;
11012
11013   Local<String> token = v8_str("<security token>");
11014   other->SetSecurityToken(token);
11015   current->SetSecurityToken(token);
11016
11017   // Set up reference from current to other.
11018   current->Global()->Set(v8_str("other"), other->Global());
11019
11020   // Check that new variables are introduced in other context.
11021   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11022   script->Run();
11023   Local<Value> foo = other->Global()->Get(v8_str("foo"));
11024   CHECK_EQ(1234, foo->Int32Value());
11025   CHECK(!current->Global()->Has(v8_str("foo")));
11026
11027   // Check that writing to non-existing properties introduces them in
11028   // the other context.
11029   script = v8_compile("other.eval('na = 1234')");
11030   script->Run();
11031   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11032   CHECK(!current->Global()->Has(v8_str("na")));
11033
11034   // Check that global variables in current context are not visible in other
11035   // context.
11036   v8::TryCatch try_catch;
11037   script = v8_compile("var bar = 42; other.eval('bar');");
11038   Local<Value> result = script->Run();
11039   CHECK(try_catch.HasCaught());
11040   try_catch.Reset();
11041
11042   // Check that local variables in current context are not visible in other
11043   // context.
11044   script = v8_compile(
11045       "(function() { "
11046       "  var baz = 87;"
11047       "  return other.eval('baz');"
11048       "})();");
11049   result = script->Run();
11050   CHECK(try_catch.HasCaught());
11051   try_catch.Reset();
11052
11053   // Check that global variables in the other environment are visible
11054   // when evaluting code.
11055   other->Global()->Set(v8_str("bis"), v8_num(1234));
11056   script = v8_compile("other.eval('bis')");
11057   CHECK_EQ(1234, script->Run()->Int32Value());
11058   CHECK(!try_catch.HasCaught());
11059
11060   // Check that the 'this' pointer points to the global object evaluating
11061   // code.
11062   other->Global()->Set(v8_str("t"), other->Global());
11063   script = v8_compile("other.eval('this == t')");
11064   result = script->Run();
11065   CHECK(result->IsTrue());
11066   CHECK(!try_catch.HasCaught());
11067
11068   // Check that variables introduced in with-statement are not visible in
11069   // other context.
11070   script = v8_compile("with({x:2}){other.eval('x')}");
11071   result = script->Run();
11072   CHECK(try_catch.HasCaught());
11073   try_catch.Reset();
11074
11075   // Check that you cannot use 'eval.call' with another object than the
11076   // current global object.
11077   script = v8_compile("other.y = 1; eval.call(other, 'y')");
11078   result = script->Run();
11079   CHECK(try_catch.HasCaught());
11080 }
11081
11082
11083 // Test that calling eval in a context which has been detached from
11084 // its global throws an exception.  This behavior is consistent with
11085 // other JavaScript implementations.
11086 THREADED_TEST(EvalInDetachedGlobal) {
11087   v8::Isolate* isolate = CcTest::isolate();
11088   v8::HandleScope scope(isolate);
11089
11090   v8::Local<Context> context0 = Context::New(isolate);
11091   v8::Local<Context> context1 = Context::New(isolate);
11092
11093   // Set up function in context0 that uses eval from context0.
11094   context0->Enter();
11095   v8::Handle<v8::Value> fun =
11096       CompileRun("var x = 42;"
11097                  "(function() {"
11098                  "  var e = eval;"
11099                  "  return function(s) { return e(s); }"
11100                  "})()");
11101   context0->Exit();
11102
11103   // Put the function into context1 and call it before and after
11104   // detaching the global.  Before detaching, the call succeeds and
11105   // after detaching and exception is thrown.
11106   context1->Enter();
11107   context1->Global()->Set(v8_str("fun"), fun);
11108   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11109   CHECK_EQ(42, x_value->Int32Value());
11110   context0->DetachGlobal();
11111   v8::TryCatch catcher;
11112   x_value = CompileRun("fun('x')");
11113   CHECK(x_value.IsEmpty());
11114   CHECK(catcher.HasCaught());
11115   context1->Exit();
11116 }
11117
11118
11119 THREADED_TEST(CrossLazyLoad) {
11120   v8::HandleScope scope(CcTest::isolate());
11121   LocalContext other;
11122   LocalContext current;
11123
11124   Local<String> token = v8_str("<security token>");
11125   other->SetSecurityToken(token);
11126   current->SetSecurityToken(token);
11127
11128   // Set up reference from current to other.
11129   current->Global()->Set(v8_str("other"), other->Global());
11130
11131   // Trigger lazy loading in other context.
11132   Local<Script> script = v8_compile("other.eval('new Date(42)')");
11133   Local<Value> value = script->Run();
11134   CHECK_EQ(42.0, value->NumberValue());
11135 }
11136
11137
11138 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11139   ApiTestFuzzer::Fuzz();
11140   if (args.IsConstructCall()) {
11141     if (args[0]->IsInt32()) {
11142       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11143       return;
11144     }
11145   }
11146
11147   args.GetReturnValue().Set(args[0]);
11148 }
11149
11150
11151 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11152   args.GetReturnValue().Set(args.This());
11153 }
11154
11155
11156 // Test that a call handler can be set for objects which will allow
11157 // non-function objects created through the API to be called as
11158 // functions.
11159 THREADED_TEST(CallAsFunction) {
11160   LocalContext context;
11161   v8::Isolate* isolate = context->GetIsolate();
11162   v8::HandleScope scope(isolate);
11163
11164   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11165     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11166     instance_template->SetCallAsFunctionHandler(call_as_function);
11167     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11168     context->Global()->Set(v8_str("obj"), instance);
11169     v8::TryCatch try_catch;
11170     Local<Value> value;
11171     CHECK(!try_catch.HasCaught());
11172
11173     value = CompileRun("obj(42)");
11174     CHECK(!try_catch.HasCaught());
11175     CHECK_EQ(42, value->Int32Value());
11176
11177     value = CompileRun("(function(o){return o(49)})(obj)");
11178     CHECK(!try_catch.HasCaught());
11179     CHECK_EQ(49, value->Int32Value());
11180
11181     // test special case of call as function
11182     value = CompileRun("[obj]['0'](45)");
11183     CHECK(!try_catch.HasCaught());
11184     CHECK_EQ(45, value->Int32Value());
11185
11186     value = CompileRun("obj.call = Function.prototype.call;"
11187                        "obj.call(null, 87)");
11188     CHECK(!try_catch.HasCaught());
11189     CHECK_EQ(87, value->Int32Value());
11190
11191     // Regression tests for bug #1116356: Calling call through call/apply
11192     // must work for non-function receivers.
11193     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11194     value = CompileRun(apply_99);
11195     CHECK(!try_catch.HasCaught());
11196     CHECK_EQ(99, value->Int32Value());
11197
11198     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11199     value = CompileRun(call_17);
11200     CHECK(!try_catch.HasCaught());
11201     CHECK_EQ(17, value->Int32Value());
11202
11203     // Check that the call-as-function handler can be called through
11204     // new.
11205     value = CompileRun("new obj(43)");
11206     CHECK(!try_catch.HasCaught());
11207     CHECK_EQ(-43, value->Int32Value());
11208
11209     // Check that the call-as-function handler can be called through
11210     // the API.
11211     v8::Handle<Value> args[] = { v8_num(28) };
11212     value = instance->CallAsFunction(instance, 1, args);
11213     CHECK(!try_catch.HasCaught());
11214     CHECK_EQ(28, value->Int32Value());
11215   }
11216
11217   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11218     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11219     USE(instance_template);
11220     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11221     context->Global()->Set(v8_str("obj2"), instance);
11222     v8::TryCatch try_catch;
11223     Local<Value> value;
11224     CHECK(!try_catch.HasCaught());
11225
11226     // Call an object without call-as-function handler through the JS
11227     value = CompileRun("obj2(28)");
11228     CHECK(value.IsEmpty());
11229     CHECK(try_catch.HasCaught());
11230     String::Utf8Value exception_value1(try_catch.Exception());
11231     // TODO(verwaest): Better message
11232     CHECK_EQ("TypeError: object is not a function",
11233              *exception_value1);
11234     try_catch.Reset();
11235
11236     // Call an object without call-as-function handler through the API
11237     value = CompileRun("obj2(28)");
11238     v8::Handle<Value> args[] = { v8_num(28) };
11239     value = instance->CallAsFunction(instance, 1, args);
11240     CHECK(value.IsEmpty());
11241     CHECK(try_catch.HasCaught());
11242     String::Utf8Value exception_value2(try_catch.Exception());
11243     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11244     try_catch.Reset();
11245   }
11246
11247   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11248     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11249     instance_template->SetCallAsFunctionHandler(ThrowValue);
11250     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11251     context->Global()->Set(v8_str("obj3"), instance);
11252     v8::TryCatch try_catch;
11253     Local<Value> value;
11254     CHECK(!try_catch.HasCaught());
11255
11256     // Catch the exception which is thrown by call-as-function handler
11257     value = CompileRun("obj3(22)");
11258     CHECK(try_catch.HasCaught());
11259     String::Utf8Value exception_value1(try_catch.Exception());
11260     CHECK_EQ("22", *exception_value1);
11261     try_catch.Reset();
11262
11263     v8::Handle<Value> args[] = { v8_num(23) };
11264     value = instance->CallAsFunction(instance, 1, args);
11265     CHECK(try_catch.HasCaught());
11266     String::Utf8Value exception_value2(try_catch.Exception());
11267     CHECK_EQ("23", *exception_value2);
11268     try_catch.Reset();
11269   }
11270
11271   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11272     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11273     instance_template->SetCallAsFunctionHandler(ReturnThis);
11274     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11275
11276     Local<v8::Value> a1 =
11277         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11278     CHECK(a1->StrictEquals(instance));
11279     Local<v8::Value> a2 =
11280         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11281     CHECK(a2->StrictEquals(instance));
11282     Local<v8::Value> a3 =
11283         instance->CallAsFunction(v8_num(42), 0, NULL);
11284     CHECK(a3->StrictEquals(instance));
11285     Local<v8::Value> a4 =
11286         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11287     CHECK(a4->StrictEquals(instance));
11288     Local<v8::Value> a5 =
11289         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11290     CHECK(a5->StrictEquals(instance));
11291   }
11292
11293   { CompileRun(
11294       "function ReturnThisSloppy() {"
11295       "  return this;"
11296       "}"
11297       "function ReturnThisStrict() {"
11298       "  'use strict';"
11299       "  return this;"
11300       "}");
11301     Local<Function> ReturnThisSloppy =
11302         Local<Function>::Cast(
11303             context->Global()->Get(v8_str("ReturnThisSloppy")));
11304     Local<Function> ReturnThisStrict =
11305         Local<Function>::Cast(
11306             context->Global()->Get(v8_str("ReturnThisStrict")));
11307
11308     Local<v8::Value> a1 =
11309         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11310     CHECK(a1->StrictEquals(context->Global()));
11311     Local<v8::Value> a2 =
11312         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11313     CHECK(a2->StrictEquals(context->Global()));
11314     Local<v8::Value> a3 =
11315         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11316     CHECK(a3->IsNumberObject());
11317     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11318     Local<v8::Value> a4 =
11319         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11320     CHECK(a4->IsStringObject());
11321     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11322     Local<v8::Value> a5 =
11323         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11324     CHECK(a5->IsBooleanObject());
11325     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11326
11327     Local<v8::Value> a6 =
11328         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11329     CHECK(a6->IsUndefined());
11330     Local<v8::Value> a7 =
11331         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11332     CHECK(a7->IsNull());
11333     Local<v8::Value> a8 =
11334         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11335     CHECK(a8->StrictEquals(v8_num(42)));
11336     Local<v8::Value> a9 =
11337         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11338     CHECK(a9->StrictEquals(v8_str("hello")));
11339     Local<v8::Value> a10 =
11340         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11341     CHECK(a10->StrictEquals(v8::True(isolate)));
11342   }
11343 }
11344
11345
11346 // Check whether a non-function object is callable.
11347 THREADED_TEST(CallableObject) {
11348   LocalContext context;
11349   v8::Isolate* isolate = context->GetIsolate();
11350   v8::HandleScope scope(isolate);
11351
11352   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11353     instance_template->SetCallAsFunctionHandler(call_as_function);
11354     Local<Object> instance = instance_template->NewInstance();
11355     v8::TryCatch try_catch;
11356
11357     CHECK(instance->IsCallable());
11358     CHECK(!try_catch.HasCaught());
11359   }
11360
11361   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11362     Local<Object> instance = instance_template->NewInstance();
11363     v8::TryCatch try_catch;
11364
11365     CHECK(!instance->IsCallable());
11366     CHECK(!try_catch.HasCaught());
11367   }
11368
11369   { Local<FunctionTemplate> function_template =
11370         FunctionTemplate::New(isolate, call_as_function);
11371     Local<Function> function = function_template->GetFunction();
11372     Local<Object> instance = function;
11373     v8::TryCatch try_catch;
11374
11375     CHECK(instance->IsCallable());
11376     CHECK(!try_catch.HasCaught());
11377   }
11378
11379   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11380     Local<Function> function = function_template->GetFunction();
11381     Local<Object> instance = function;
11382     v8::TryCatch try_catch;
11383
11384     CHECK(instance->IsCallable());
11385     CHECK(!try_catch.HasCaught());
11386   }
11387 }
11388
11389
11390 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11391   v8::HandleScope scope(isolate);
11392   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11393   for (int i = 0; i < iterations; i++) {
11394     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11395   }
11396   return Recurse(isolate, depth - 1, iterations);
11397 }
11398
11399
11400 THREADED_TEST(HandleIteration) {
11401   static const int kIterations = 500;
11402   static const int kNesting = 200;
11403   LocalContext context;
11404   v8::Isolate* isolate = context->GetIsolate();
11405   v8::HandleScope scope0(isolate);
11406   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11407   {
11408     v8::HandleScope scope1(isolate);
11409     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11410     for (int i = 0; i < kIterations; i++) {
11411       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11412       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11413     }
11414
11415     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11416     {
11417       v8::HandleScope scope2(CcTest::isolate());
11418       for (int j = 0; j < kIterations; j++) {
11419         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11420         CHECK_EQ(j + 1 + kIterations,
11421                  v8::HandleScope::NumberOfHandles(isolate));
11422       }
11423     }
11424     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11425   }
11426   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11427   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11428 }
11429
11430
11431 static void InterceptorHasOwnPropertyGetter(
11432     Local<String> name,
11433     const v8::PropertyCallbackInfo<v8::Value>& info) {
11434   ApiTestFuzzer::Fuzz();
11435 }
11436
11437
11438 THREADED_TEST(InterceptorHasOwnProperty) {
11439   LocalContext context;
11440   v8::Isolate* isolate = context->GetIsolate();
11441   v8::HandleScope scope(isolate);
11442   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11443   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11444   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11445   Local<Function> function = fun_templ->GetFunction();
11446   context->Global()->Set(v8_str("constructor"), function);
11447   v8::Handle<Value> value = CompileRun(
11448       "var o = new constructor();"
11449       "o.hasOwnProperty('ostehaps');");
11450   CHECK_EQ(false, value->BooleanValue());
11451   value = CompileRun(
11452       "o.ostehaps = 42;"
11453       "o.hasOwnProperty('ostehaps');");
11454   CHECK_EQ(true, value->BooleanValue());
11455   value = CompileRun(
11456       "var p = new constructor();"
11457       "p.hasOwnProperty('ostehaps');");
11458   CHECK_EQ(false, value->BooleanValue());
11459 }
11460
11461
11462 static void InterceptorHasOwnPropertyGetterGC(
11463     Local<String> name,
11464     const v8::PropertyCallbackInfo<v8::Value>& info) {
11465   ApiTestFuzzer::Fuzz();
11466   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11467 }
11468
11469
11470 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11471   LocalContext context;
11472   v8::Isolate* isolate = context->GetIsolate();
11473   v8::HandleScope scope(isolate);
11474   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11475   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11476   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11477   Local<Function> function = fun_templ->GetFunction();
11478   context->Global()->Set(v8_str("constructor"), function);
11479   // Let's first make some stuff so we can be sure to get a good GC.
11480   CompileRun(
11481       "function makestr(size) {"
11482       "  switch (size) {"
11483       "    case 1: return 'f';"
11484       "    case 2: return 'fo';"
11485       "    case 3: return 'foo';"
11486       "  }"
11487       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11488       "}"
11489       "var x = makestr(12345);"
11490       "x = makestr(31415);"
11491       "x = makestr(23456);");
11492   v8::Handle<Value> value = CompileRun(
11493       "var o = new constructor();"
11494       "o.__proto__ = new String(x);"
11495       "o.hasOwnProperty('ostehaps');");
11496   CHECK_EQ(false, value->BooleanValue());
11497 }
11498
11499
11500 typedef void (*NamedPropertyGetter)(
11501     Local<String> property,
11502     const v8::PropertyCallbackInfo<v8::Value>& info);
11503
11504
11505 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11506                                    const char* source,
11507                                    int expected) {
11508   v8::Isolate* isolate = CcTest::isolate();
11509   v8::HandleScope scope(isolate);
11510   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11511   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11512   LocalContext context;
11513   context->Global()->Set(v8_str("o"), templ->NewInstance());
11514   v8::Handle<Value> value = CompileRun(source);
11515   CHECK_EQ(expected, value->Int32Value());
11516 }
11517
11518
11519 static void InterceptorLoadICGetter(
11520     Local<String> name,
11521     const v8::PropertyCallbackInfo<v8::Value>& info) {
11522   ApiTestFuzzer::Fuzz();
11523   v8::Isolate* isolate = CcTest::isolate();
11524   CHECK_EQ(isolate, info.GetIsolate());
11525   CHECK_EQ(v8_str("data"), info.Data());
11526   CHECK_EQ(v8_str("x"), name);
11527   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11528 }
11529
11530
11531 // This test should hit the load IC for the interceptor case.
11532 THREADED_TEST(InterceptorLoadIC) {
11533   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11534     "var result = 0;"
11535     "for (var i = 0; i < 1000; i++) {"
11536     "  result = o.x;"
11537     "}",
11538     42);
11539 }
11540
11541
11542 // Below go several tests which verify that JITing for various
11543 // configurations of interceptor and explicit fields works fine
11544 // (those cases are special cased to get better performance).
11545
11546 static void InterceptorLoadXICGetter(
11547     Local<String> name,
11548     const v8::PropertyCallbackInfo<v8::Value>& info) {
11549   ApiTestFuzzer::Fuzz();
11550   info.GetReturnValue().Set(
11551       v8_str("x")->Equals(name) ?
11552           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11553           v8::Handle<v8::Value>());
11554 }
11555
11556
11557 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11558   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11559     "var result = 0;"
11560     "o.y = 239;"
11561     "for (var i = 0; i < 1000; i++) {"
11562     "  result = o.y;"
11563     "}",
11564     239);
11565 }
11566
11567
11568 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11569   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11570     "var result = 0;"
11571     "o.__proto__ = { 'y': 239 };"
11572     "for (var i = 0; i < 1000; i++) {"
11573     "  result = o.y + o.x;"
11574     "}",
11575     239 + 42);
11576 }
11577
11578
11579 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11580   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11581     "var result = 0;"
11582     "o.__proto__.y = 239;"
11583     "for (var i = 0; i < 1000; i++) {"
11584     "  result = o.y + o.x;"
11585     "}",
11586     239 + 42);
11587 }
11588
11589
11590 THREADED_TEST(InterceptorLoadICUndefined) {
11591   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11592     "var result = 0;"
11593     "for (var i = 0; i < 1000; i++) {"
11594     "  result = (o.y == undefined) ? 239 : 42;"
11595     "}",
11596     239);
11597 }
11598
11599
11600 THREADED_TEST(InterceptorLoadICWithOverride) {
11601   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11602     "fst = new Object();  fst.__proto__ = o;"
11603     "snd = new Object();  snd.__proto__ = fst;"
11604     "var result1 = 0;"
11605     "for (var i = 0; i < 1000;  i++) {"
11606     "  result1 = snd.x;"
11607     "}"
11608     "fst.x = 239;"
11609     "var result = 0;"
11610     "for (var i = 0; i < 1000; i++) {"
11611     "  result = snd.x;"
11612     "}"
11613     "result + result1",
11614     239 + 42);
11615 }
11616
11617
11618 // Test the case when we stored field into
11619 // a stub, but interceptor produced value on its own.
11620 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11621   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11622     "proto = new Object();"
11623     "o.__proto__ = proto;"
11624     "proto.x = 239;"
11625     "for (var i = 0; i < 1000; i++) {"
11626     "  o.x;"
11627     // Now it should be ICed and keep a reference to x defined on proto
11628     "}"
11629     "var result = 0;"
11630     "for (var i = 0; i < 1000; i++) {"
11631     "  result += o.x;"
11632     "}"
11633     "result;",
11634     42 * 1000);
11635 }
11636
11637
11638 // Test the case when we stored field into
11639 // a stub, but it got invalidated later on.
11640 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11641   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11642     "proto1 = new Object();"
11643     "proto2 = new Object();"
11644     "o.__proto__ = proto1;"
11645     "proto1.__proto__ = proto2;"
11646     "proto2.y = 239;"
11647     "for (var i = 0; i < 1000; i++) {"
11648     "  o.y;"
11649     // Now it should be ICed and keep a reference to y defined on proto2
11650     "}"
11651     "proto1.y = 42;"
11652     "var result = 0;"
11653     "for (var i = 0; i < 1000; i++) {"
11654     "  result += o.y;"
11655     "}"
11656     "result;",
11657     42 * 1000);
11658 }
11659
11660
11661 static int interceptor_load_not_handled_calls = 0;
11662 static void InterceptorLoadNotHandled(
11663     Local<String> name,
11664     const v8::PropertyCallbackInfo<v8::Value>& info) {
11665   ++interceptor_load_not_handled_calls;
11666 }
11667
11668
11669 // Test how post-interceptor lookups are done in the non-cacheable
11670 // case: the interceptor should not be invoked during this lookup.
11671 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11672   interceptor_load_not_handled_calls = 0;
11673   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11674     "receiver = new Object();"
11675     "receiver.__proto__ = o;"
11676     "proto = new Object();"
11677     "/* Make proto a slow-case object. */"
11678     "for (var i = 0; i < 1000; i++) {"
11679     "  proto[\"xxxxxxxx\" + i] = [];"
11680     "}"
11681     "proto.x = 17;"
11682     "o.__proto__ = proto;"
11683     "var result = 0;"
11684     "for (var i = 0; i < 1000; i++) {"
11685     "  result += receiver.x;"
11686     "}"
11687     "result;",
11688     17 * 1000);
11689   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11690 }
11691
11692
11693 // Test the case when we stored field into
11694 // a stub, but it got invalidated later on due to override on
11695 // global object which is between interceptor and fields' holders.
11696 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11697   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11698     "o.__proto__ = this;"  // set a global to be a proto of o.
11699     "this.__proto__.y = 239;"
11700     "for (var i = 0; i < 10; i++) {"
11701     "  if (o.y != 239) throw 'oops: ' + o.y;"
11702     // Now it should be ICed and keep a reference to y defined on field_holder.
11703     "}"
11704     "this.y = 42;"  // Assign on a global.
11705     "var result = 0;"
11706     "for (var i = 0; i < 10; i++) {"
11707     "  result += o.y;"
11708     "}"
11709     "result;",
11710     42 * 10);
11711 }
11712
11713
11714 static void SetOnThis(Local<String> name,
11715                       Local<Value> value,
11716                       const v8::PropertyCallbackInfo<void>& info) {
11717   Local<Object>::Cast(info.This())->ForceSet(name, value);
11718 }
11719
11720
11721 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11722   v8::Isolate* isolate = CcTest::isolate();
11723   v8::HandleScope scope(isolate);
11724   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11725   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11726   templ->SetAccessor(v8_str("y"), Return239Callback);
11727   LocalContext context;
11728   context->Global()->Set(v8_str("o"), templ->NewInstance());
11729
11730   // Check the case when receiver and interceptor's holder
11731   // are the same objects.
11732   v8::Handle<Value> value = CompileRun(
11733       "var result = 0;"
11734       "for (var i = 0; i < 7; i++) {"
11735       "  result = o.y;"
11736       "}");
11737   CHECK_EQ(239, value->Int32Value());
11738
11739   // Check the case when interceptor's holder is in proto chain
11740   // of receiver.
11741   value = CompileRun(
11742       "r = { __proto__: o };"
11743       "var result = 0;"
11744       "for (var i = 0; i < 7; i++) {"
11745       "  result = r.y;"
11746       "}");
11747   CHECK_EQ(239, value->Int32Value());
11748 }
11749
11750
11751 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11752   v8::Isolate* isolate = CcTest::isolate();
11753   v8::HandleScope scope(isolate);
11754   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11755   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11756   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11757   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11758
11759   LocalContext context;
11760   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11761   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11762
11763   // Check the case when receiver and interceptor's holder
11764   // are the same objects.
11765   v8::Handle<Value> value = CompileRun(
11766       "o.__proto__ = p;"
11767       "var result = 0;"
11768       "for (var i = 0; i < 7; i++) {"
11769       "  result = o.x + o.y;"
11770       "}");
11771   CHECK_EQ(239 + 42, value->Int32Value());
11772
11773   // Check the case when interceptor's holder is in proto chain
11774   // of receiver.
11775   value = CompileRun(
11776       "r = { __proto__: o };"
11777       "var result = 0;"
11778       "for (var i = 0; i < 7; i++) {"
11779       "  result = r.x + r.y;"
11780       "}");
11781   CHECK_EQ(239 + 42, value->Int32Value());
11782 }
11783
11784
11785 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11786   v8::Isolate* isolate = CcTest::isolate();
11787   v8::HandleScope scope(isolate);
11788   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11789   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11790   templ->SetAccessor(v8_str("y"), Return239Callback);
11791
11792   LocalContext context;
11793   context->Global()->Set(v8_str("o"), templ->NewInstance());
11794
11795   v8::Handle<Value> value = CompileRun(
11796     "fst = new Object();  fst.__proto__ = o;"
11797     "snd = new Object();  snd.__proto__ = fst;"
11798     "var result1 = 0;"
11799     "for (var i = 0; i < 7;  i++) {"
11800     "  result1 = snd.x;"
11801     "}"
11802     "fst.x = 239;"
11803     "var result = 0;"
11804     "for (var i = 0; i < 7; i++) {"
11805     "  result = snd.x;"
11806     "}"
11807     "result + result1");
11808   CHECK_EQ(239 + 42, value->Int32Value());
11809 }
11810
11811
11812 // Test the case when we stored callback into
11813 // a stub, but interceptor produced value on its own.
11814 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11815   v8::Isolate* isolate = CcTest::isolate();
11816   v8::HandleScope scope(isolate);
11817   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11818   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11819   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11820   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11821
11822   LocalContext context;
11823   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11824   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11825
11826   v8::Handle<Value> value = CompileRun(
11827     "o.__proto__ = p;"
11828     "for (var i = 0; i < 7; i++) {"
11829     "  o.x;"
11830     // Now it should be ICed and keep a reference to x defined on p
11831     "}"
11832     "var result = 0;"
11833     "for (var i = 0; i < 7; i++) {"
11834     "  result += o.x;"
11835     "}"
11836     "result");
11837   CHECK_EQ(42 * 7, value->Int32Value());
11838 }
11839
11840
11841 // Test the case when we stored callback into
11842 // a stub, but it got invalidated later on.
11843 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11844   v8::Isolate* isolate = CcTest::isolate();
11845   v8::HandleScope scope(isolate);
11846   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11847   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11848   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11849   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11850
11851   LocalContext context;
11852   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11853   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11854
11855   v8::Handle<Value> value = CompileRun(
11856     "inbetween = new Object();"
11857     "o.__proto__ = inbetween;"
11858     "inbetween.__proto__ = p;"
11859     "for (var i = 0; i < 10; i++) {"
11860     "  o.y;"
11861     // Now it should be ICed and keep a reference to y defined on p
11862     "}"
11863     "inbetween.y = 42;"
11864     "var result = 0;"
11865     "for (var i = 0; i < 10; i++) {"
11866     "  result += o.y;"
11867     "}"
11868     "result");
11869   CHECK_EQ(42 * 10, value->Int32Value());
11870 }
11871
11872
11873 // Test the case when we stored callback into
11874 // a stub, but it got invalidated later on due to override on
11875 // global object which is between interceptor and callbacks' holders.
11876 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11877   v8::Isolate* isolate = CcTest::isolate();
11878   v8::HandleScope scope(isolate);
11879   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11880   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11881   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11882   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11883
11884   LocalContext context;
11885   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11886   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11887
11888   v8::Handle<Value> value = CompileRun(
11889     "o.__proto__ = this;"
11890     "this.__proto__ = p;"
11891     "for (var i = 0; i < 10; i++) {"
11892     "  if (o.y != 239) throw 'oops: ' + o.y;"
11893     // Now it should be ICed and keep a reference to y defined on p
11894     "}"
11895     "this.y = 42;"
11896     "var result = 0;"
11897     "for (var i = 0; i < 10; i++) {"
11898     "  result += o.y;"
11899     "}"
11900     "result");
11901   CHECK_EQ(42 * 10, value->Int32Value());
11902 }
11903
11904
11905 static void InterceptorLoadICGetter0(
11906     Local<String> name,
11907     const v8::PropertyCallbackInfo<v8::Value>& info) {
11908   ApiTestFuzzer::Fuzz();
11909   CHECK(v8_str("x")->Equals(name));
11910   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11911 }
11912
11913
11914 THREADED_TEST(InterceptorReturningZero) {
11915   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11916      "o.x == undefined ? 1 : 0",
11917      0);
11918 }
11919
11920
11921 static void InterceptorStoreICSetter(
11922     Local<String> key,
11923     Local<Value> value,
11924     const v8::PropertyCallbackInfo<v8::Value>& info) {
11925   CHECK(v8_str("x")->Equals(key));
11926   CHECK_EQ(42, value->Int32Value());
11927   info.GetReturnValue().Set(value);
11928 }
11929
11930
11931 // This test should hit the store IC for the interceptor case.
11932 THREADED_TEST(InterceptorStoreIC) {
11933   v8::Isolate* isolate = CcTest::isolate();
11934   v8::HandleScope scope(isolate);
11935   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11936   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11937                                  InterceptorStoreICSetter,
11938                                  0, 0, 0, v8_str("data"));
11939   LocalContext context;
11940   context->Global()->Set(v8_str("o"), templ->NewInstance());
11941   CompileRun(
11942       "for (var i = 0; i < 1000; i++) {"
11943       "  o.x = 42;"
11944       "}");
11945 }
11946
11947
11948 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11949   v8::Isolate* isolate = CcTest::isolate();
11950   v8::HandleScope scope(isolate);
11951   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11952   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11953   LocalContext context;
11954   context->Global()->Set(v8_str("o"), templ->NewInstance());
11955   v8::Handle<Value> value = CompileRun(
11956     "for (var i = 0; i < 1000; i++) {"
11957     "  o.y = 239;"
11958     "}"
11959     "42 + o.y");
11960   CHECK_EQ(239 + 42, value->Int32Value());
11961 }
11962
11963
11964
11965
11966 v8::Handle<Value> call_ic_function;
11967 v8::Handle<Value> call_ic_function2;
11968 v8::Handle<Value> call_ic_function3;
11969
11970 static void InterceptorCallICGetter(
11971     Local<String> name,
11972     const v8::PropertyCallbackInfo<v8::Value>& info) {
11973   ApiTestFuzzer::Fuzz();
11974   CHECK(v8_str("x")->Equals(name));
11975   info.GetReturnValue().Set(call_ic_function);
11976 }
11977
11978
11979 // This test should hit the call IC for the interceptor case.
11980 THREADED_TEST(InterceptorCallIC) {
11981   v8::Isolate* isolate = CcTest::isolate();
11982   v8::HandleScope scope(isolate);
11983   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11984   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11985   LocalContext context;
11986   context->Global()->Set(v8_str("o"), templ->NewInstance());
11987   call_ic_function =
11988       v8_compile("function f(x) { return x + 1; }; f")->Run();
11989   v8::Handle<Value> value = CompileRun(
11990     "var result = 0;"
11991     "for (var i = 0; i < 1000; i++) {"
11992     "  result = o.x(41);"
11993     "}");
11994   CHECK_EQ(42, value->Int32Value());
11995 }
11996
11997
11998 // This test checks that if interceptor doesn't provide
11999 // a value, we can fetch regular value.
12000 THREADED_TEST(InterceptorCallICSeesOthers) {
12001   v8::Isolate* isolate = CcTest::isolate();
12002   v8::HandleScope scope(isolate);
12003   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12004   templ->SetNamedPropertyHandler(NoBlockGetterX);
12005   LocalContext context;
12006   context->Global()->Set(v8_str("o"), templ->NewInstance());
12007   v8::Handle<Value> value = CompileRun(
12008     "o.x = function f(x) { return x + 1; };"
12009     "var result = 0;"
12010     "for (var i = 0; i < 7; i++) {"
12011     "  result = o.x(41);"
12012     "}");
12013   CHECK_EQ(42, value->Int32Value());
12014 }
12015
12016
12017 static v8::Handle<Value> call_ic_function4;
12018 static void InterceptorCallICGetter4(
12019     Local<String> name,
12020     const v8::PropertyCallbackInfo<v8::Value>& info) {
12021   ApiTestFuzzer::Fuzz();
12022   CHECK(v8_str("x")->Equals(name));
12023   info.GetReturnValue().Set(call_ic_function4);
12024 }
12025
12026
12027 // This test checks that if interceptor provides a function,
12028 // even if we cached shadowed variant, interceptor's function
12029 // is invoked
12030 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
12031   v8::Isolate* isolate = CcTest::isolate();
12032   v8::HandleScope scope(isolate);
12033   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12034   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
12035   LocalContext context;
12036   context->Global()->Set(v8_str("o"), templ->NewInstance());
12037   call_ic_function4 =
12038       v8_compile("function f(x) { return x - 1; }; f")->Run();
12039   v8::Handle<Value> value = CompileRun(
12040     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
12041     "var result = 0;"
12042     "for (var i = 0; i < 1000; i++) {"
12043     "  result = o.x(42);"
12044     "}");
12045   CHECK_EQ(41, value->Int32Value());
12046 }
12047
12048
12049 // Test the case when we stored cacheable lookup into
12050 // a stub, but it got invalidated later on
12051 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
12052   v8::Isolate* isolate = CcTest::isolate();
12053   v8::HandleScope scope(isolate);
12054   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12055   templ->SetNamedPropertyHandler(NoBlockGetterX);
12056   LocalContext context;
12057   context->Global()->Set(v8_str("o"), templ->NewInstance());
12058   v8::Handle<Value> value = CompileRun(
12059     "proto1 = new Object();"
12060     "proto2 = new Object();"
12061     "o.__proto__ = proto1;"
12062     "proto1.__proto__ = proto2;"
12063     "proto2.y = function(x) { return x + 1; };"
12064     // Invoke it many times to compile a stub
12065     "for (var i = 0; i < 7; i++) {"
12066     "  o.y(42);"
12067     "}"
12068     "proto1.y = function(x) { return x - 1; };"
12069     "var result = 0;"
12070     "for (var i = 0; i < 7; i++) {"
12071     "  result += o.y(42);"
12072     "}");
12073   CHECK_EQ(41 * 7, value->Int32Value());
12074 }
12075
12076
12077 // This test checks that if interceptor doesn't provide a function,
12078 // cached constant function is used
12079 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
12080   v8::Isolate* isolate = CcTest::isolate();
12081   v8::HandleScope scope(isolate);
12082   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12083   templ->SetNamedPropertyHandler(NoBlockGetterX);
12084   LocalContext context;
12085   context->Global()->Set(v8_str("o"), templ->NewInstance());
12086   v8::Handle<Value> value = CompileRun(
12087     "function inc(x) { return x + 1; };"
12088     "inc(1);"
12089     "o.x = inc;"
12090     "var result = 0;"
12091     "for (var i = 0; i < 1000; i++) {"
12092     "  result = o.x(42);"
12093     "}");
12094   CHECK_EQ(43, value->Int32Value());
12095 }
12096
12097
12098 static v8::Handle<Value> call_ic_function5;
12099 static void InterceptorCallICGetter5(
12100     Local<String> name,
12101     const v8::PropertyCallbackInfo<v8::Value>& info) {
12102   ApiTestFuzzer::Fuzz();
12103   if (v8_str("x")->Equals(name))
12104     info.GetReturnValue().Set(call_ic_function5);
12105 }
12106
12107
12108 // This test checks that if interceptor provides a function,
12109 // even if we cached constant function, interceptor's function
12110 // is invoked
12111 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12112   v8::Isolate* isolate = CcTest::isolate();
12113   v8::HandleScope scope(isolate);
12114   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12115   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
12116   LocalContext context;
12117   context->Global()->Set(v8_str("o"), templ->NewInstance());
12118   call_ic_function5 =
12119       v8_compile("function f(x) { return x - 1; }; f")->Run();
12120   v8::Handle<Value> value = CompileRun(
12121     "function inc(x) { return x + 1; };"
12122     "inc(1);"
12123     "o.x = inc;"
12124     "var result = 0;"
12125     "for (var i = 0; i < 1000; i++) {"
12126     "  result = o.x(42);"
12127     "}");
12128   CHECK_EQ(41, value->Int32Value());
12129 }
12130
12131
12132 static v8::Handle<Value> call_ic_function6;
12133 static void InterceptorCallICGetter6(
12134     Local<String> name,
12135     const v8::PropertyCallbackInfo<v8::Value>& info) {
12136   ApiTestFuzzer::Fuzz();
12137   if (v8_str("x")->Equals(name))
12138     info.GetReturnValue().Set(call_ic_function6);
12139 }
12140
12141
12142 // Same test as above, except the code is wrapped in a function
12143 // to test the optimized compiler.
12144 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12145   i::FLAG_allow_natives_syntax = true;
12146   v8::Isolate* isolate = CcTest::isolate();
12147   v8::HandleScope scope(isolate);
12148   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12149   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
12150   LocalContext context;
12151   context->Global()->Set(v8_str("o"), templ->NewInstance());
12152   call_ic_function6 =
12153       v8_compile("function f(x) { return x - 1; }; f")->Run();
12154   v8::Handle<Value> value = CompileRun(
12155     "function inc(x) { return x + 1; };"
12156     "inc(1);"
12157     "o.x = inc;"
12158     "function test() {"
12159     "  var result = 0;"
12160     "  for (var i = 0; i < 1000; i++) {"
12161     "    result = o.x(42);"
12162     "  }"
12163     "  return result;"
12164     "};"
12165     "test();"
12166     "test();"
12167     "test();"
12168     "%OptimizeFunctionOnNextCall(test);"
12169     "test()");
12170   CHECK_EQ(41, value->Int32Value());
12171 }
12172
12173
12174 // Test the case when we stored constant function into
12175 // a stub, but it got invalidated later on
12176 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12177   v8::Isolate* isolate = CcTest::isolate();
12178   v8::HandleScope scope(isolate);
12179   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12180   templ->SetNamedPropertyHandler(NoBlockGetterX);
12181   LocalContext context;
12182   context->Global()->Set(v8_str("o"), templ->NewInstance());
12183   v8::Handle<Value> value = CompileRun(
12184     "function inc(x) { return x + 1; };"
12185     "inc(1);"
12186     "proto1 = new Object();"
12187     "proto2 = new Object();"
12188     "o.__proto__ = proto1;"
12189     "proto1.__proto__ = proto2;"
12190     "proto2.y = inc;"
12191     // Invoke it many times to compile a stub
12192     "for (var i = 0; i < 7; i++) {"
12193     "  o.y(42);"
12194     "}"
12195     "proto1.y = function(x) { return x - 1; };"
12196     "var result = 0;"
12197     "for (var i = 0; i < 7; i++) {"
12198     "  result += o.y(42);"
12199     "}");
12200   CHECK_EQ(41 * 7, value->Int32Value());
12201 }
12202
12203
12204 // Test the case when we stored constant function into
12205 // a stub, but it got invalidated later on due to override on
12206 // global object which is between interceptor and constant function' holders.
12207 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12208   v8::Isolate* isolate = CcTest::isolate();
12209   v8::HandleScope scope(isolate);
12210   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12211   templ->SetNamedPropertyHandler(NoBlockGetterX);
12212   LocalContext context;
12213   context->Global()->Set(v8_str("o"), templ->NewInstance());
12214   v8::Handle<Value> value = CompileRun(
12215     "function inc(x) { return x + 1; };"
12216     "inc(1);"
12217     "o.__proto__ = this;"
12218     "this.__proto__.y = inc;"
12219     // Invoke it many times to compile a stub
12220     "for (var i = 0; i < 7; i++) {"
12221     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12222     "}"
12223     "this.y = function(x) { return x - 1; };"
12224     "var result = 0;"
12225     "for (var i = 0; i < 7; i++) {"
12226     "  result += o.y(42);"
12227     "}");
12228   CHECK_EQ(41 * 7, value->Int32Value());
12229 }
12230
12231
12232 // Test the case when actual function to call sits on global object.
12233 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12234   v8::Isolate* isolate = CcTest::isolate();
12235   v8::HandleScope scope(isolate);
12236   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12237   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12238
12239   LocalContext context;
12240   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12241
12242   v8::Handle<Value> value = CompileRun(
12243     "try {"
12244     "  o.__proto__ = this;"
12245     "  for (var i = 0; i < 10; i++) {"
12246     "    var v = o.parseFloat('239');"
12247     "    if (v != 239) throw v;"
12248       // Now it should be ICed and keep a reference to parseFloat.
12249     "  }"
12250     "  var result = 0;"
12251     "  for (var i = 0; i < 10; i++) {"
12252     "    result += o.parseFloat('239');"
12253     "  }"
12254     "  result"
12255     "} catch(e) {"
12256     "  e"
12257     "};");
12258   CHECK_EQ(239 * 10, value->Int32Value());
12259 }
12260
12261 static void InterceptorCallICFastApi(
12262     Local<String> name,
12263     const v8::PropertyCallbackInfo<v8::Value>& info) {
12264   ApiTestFuzzer::Fuzz();
12265   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12266   int* call_count =
12267       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12268   ++(*call_count);
12269   if ((*call_count) % 20 == 0) {
12270     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12271   }
12272 }
12273
12274 static void FastApiCallback_TrivialSignature(
12275     const v8::FunctionCallbackInfo<v8::Value>& args) {
12276   ApiTestFuzzer::Fuzz();
12277   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12278   v8::Isolate* isolate = CcTest::isolate();
12279   CHECK_EQ(isolate, args.GetIsolate());
12280   CHECK_EQ(args.This(), args.Holder());
12281   CHECK(args.Data()->Equals(v8_str("method_data")));
12282   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12283 }
12284
12285 static void FastApiCallback_SimpleSignature(
12286     const v8::FunctionCallbackInfo<v8::Value>& args) {
12287   ApiTestFuzzer::Fuzz();
12288   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12289   v8::Isolate* isolate = CcTest::isolate();
12290   CHECK_EQ(isolate, args.GetIsolate());
12291   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12292   CHECK(args.Data()->Equals(v8_str("method_data")));
12293   // Note, we're using HasRealNamedProperty instead of Has to avoid
12294   // invoking the interceptor again.
12295   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12296   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12297 }
12298
12299
12300 // Helper to maximize the odds of object moving.
12301 static void GenerateSomeGarbage() {
12302   CompileRun(
12303       "var garbage;"
12304       "for (var i = 0; i < 1000; i++) {"
12305       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12306       "}"
12307       "garbage = undefined;");
12308 }
12309
12310
12311 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12312   static int count = 0;
12313   if (count++ % 3 == 0) {
12314     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12315         // This should move the stub
12316     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12317   }
12318 }
12319
12320
12321 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12322   LocalContext context;
12323   v8::Isolate* isolate = context->GetIsolate();
12324   v8::HandleScope scope(isolate);
12325   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12326       v8::ObjectTemplate::New(isolate);
12327   nativeobject_templ->Set(isolate, "callback",
12328                           v8::FunctionTemplate::New(isolate,
12329                                                     DirectApiCallback));
12330   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12331   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12332   // call the api function multiple times to ensure direct call stub creation.
12333   CompileRun(
12334         "function f() {"
12335         "  for (var i = 1; i <= 30; i++) {"
12336         "    nativeobject.callback();"
12337         "  }"
12338         "}"
12339         "f();");
12340 }
12341
12342
12343 void ThrowingDirectApiCallback(
12344     const v8::FunctionCallbackInfo<v8::Value>& args) {
12345   args.GetIsolate()->ThrowException(v8_str("g"));
12346 }
12347
12348
12349 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12350   LocalContext context;
12351   v8::Isolate* isolate = context->GetIsolate();
12352   v8::HandleScope scope(isolate);
12353   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12354       v8::ObjectTemplate::New(isolate);
12355   nativeobject_templ->Set(isolate, "callback",
12356                           v8::FunctionTemplate::New(isolate,
12357                                                     ThrowingDirectApiCallback));
12358   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12359   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12360   // call the api function multiple times to ensure direct call stub creation.
12361   v8::Handle<Value> result = CompileRun(
12362       "var result = '';"
12363       "function f() {"
12364       "  for (var i = 1; i <= 5; i++) {"
12365       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12366       "  }"
12367       "}"
12368       "f(); result;");
12369   CHECK_EQ(v8_str("ggggg"), result);
12370 }
12371
12372
12373 static Handle<Value> DoDirectGetter() {
12374   if (++p_getter_count % 3 == 0) {
12375     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12376     GenerateSomeGarbage();
12377   }
12378   return v8_str("Direct Getter Result");
12379 }
12380
12381 static void DirectGetterCallback(
12382     Local<String> name,
12383     const v8::PropertyCallbackInfo<v8::Value>& info) {
12384   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12385   info.GetReturnValue().Set(DoDirectGetter());
12386 }
12387
12388
12389 template<typename Accessor>
12390 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12391   LocalContext context;
12392   v8::Isolate* isolate = context->GetIsolate();
12393   v8::HandleScope scope(isolate);
12394   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12395   obj->SetAccessor(v8_str("p1"), accessor);
12396   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12397   p_getter_count = 0;
12398   v8::Handle<v8::Value> result = CompileRun(
12399       "function f() {"
12400       "  for (var i = 0; i < 30; i++) o1.p1;"
12401       "  return o1.p1"
12402       "}"
12403       "f();");
12404   CHECK_EQ(v8_str("Direct Getter Result"), result);
12405   CHECK_EQ(31, p_getter_count);
12406 }
12407
12408
12409 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12410   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12411 }
12412
12413
12414 void ThrowingDirectGetterCallback(
12415     Local<String> name,
12416     const v8::PropertyCallbackInfo<v8::Value>& info) {
12417   info.GetIsolate()->ThrowException(v8_str("g"));
12418 }
12419
12420
12421 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12422   LocalContext context;
12423   v8::Isolate* isolate = context->GetIsolate();
12424   v8::HandleScope scope(isolate);
12425   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12426   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12427   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12428   v8::Handle<Value> result = CompileRun(
12429       "var result = '';"
12430       "for (var i = 0; i < 5; i++) {"
12431       "    try { o1.p1; } catch (e) { result += e; }"
12432       "}"
12433       "result;");
12434   CHECK_EQ(v8_str("ggggg"), result);
12435 }
12436
12437
12438 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12439   int interceptor_call_count = 0;
12440   v8::Isolate* isolate = CcTest::isolate();
12441   v8::HandleScope scope(isolate);
12442   v8::Handle<v8::FunctionTemplate> fun_templ =
12443       v8::FunctionTemplate::New(isolate);
12444   v8::Handle<v8::FunctionTemplate> method_templ =
12445       v8::FunctionTemplate::New(isolate,
12446                                 FastApiCallback_TrivialSignature,
12447                                 v8_str("method_data"),
12448                                 v8::Handle<v8::Signature>());
12449   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12450   proto_templ->Set(v8_str("method"), method_templ);
12451   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12452   templ->SetNamedPropertyHandler(
12453       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12454       v8::External::New(isolate, &interceptor_call_count));
12455   LocalContext context;
12456   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12457   GenerateSomeGarbage();
12458   context->Global()->Set(v8_str("o"), fun->NewInstance());
12459   CompileRun(
12460       "var result = 0;"
12461       "for (var i = 0; i < 100; i++) {"
12462       "  result = o.method(41);"
12463       "}");
12464   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12465   CHECK_EQ(100, interceptor_call_count);
12466 }
12467
12468
12469 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12470   int interceptor_call_count = 0;
12471   v8::Isolate* isolate = CcTest::isolate();
12472   v8::HandleScope scope(isolate);
12473   v8::Handle<v8::FunctionTemplate> fun_templ =
12474       v8::FunctionTemplate::New(isolate);
12475   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12476       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12477       v8::Signature::New(isolate, fun_templ));
12478   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12479   proto_templ->Set(v8_str("method"), method_templ);
12480   fun_templ->SetHiddenPrototype(true);
12481   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12482   templ->SetNamedPropertyHandler(
12483       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12484       v8::External::New(isolate, &interceptor_call_count));
12485   LocalContext context;
12486   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12487   GenerateSomeGarbage();
12488   context->Global()->Set(v8_str("o"), fun->NewInstance());
12489   CompileRun(
12490       "o.foo = 17;"
12491       "var receiver = {};"
12492       "receiver.__proto__ = o;"
12493       "var result = 0;"
12494       "for (var i = 0; i < 100; i++) {"
12495       "  result = receiver.method(41);"
12496       "}");
12497   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12498   CHECK_EQ(100, interceptor_call_count);
12499 }
12500
12501
12502 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12503   int interceptor_call_count = 0;
12504   v8::Isolate* isolate = CcTest::isolate();
12505   v8::HandleScope scope(isolate);
12506   v8::Handle<v8::FunctionTemplate> fun_templ =
12507       v8::FunctionTemplate::New(isolate);
12508   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12509       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12510       v8::Signature::New(isolate, fun_templ));
12511   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12512   proto_templ->Set(v8_str("method"), method_templ);
12513   fun_templ->SetHiddenPrototype(true);
12514   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12515   templ->SetNamedPropertyHandler(
12516       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12517       v8::External::New(isolate, &interceptor_call_count));
12518   LocalContext context;
12519   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12520   GenerateSomeGarbage();
12521   context->Global()->Set(v8_str("o"), fun->NewInstance());
12522   CompileRun(
12523       "o.foo = 17;"
12524       "var receiver = {};"
12525       "receiver.__proto__ = o;"
12526       "var result = 0;"
12527       "var saved_result = 0;"
12528       "for (var i = 0; i < 100; i++) {"
12529       "  result = receiver.method(41);"
12530       "  if (i == 50) {"
12531       "    saved_result = result;"
12532       "    receiver = {method: function(x) { return x - 1 }};"
12533       "  }"
12534       "}");
12535   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12536   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12537   CHECK_GE(interceptor_call_count, 50);
12538 }
12539
12540
12541 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12542   int interceptor_call_count = 0;
12543   v8::Isolate* isolate = CcTest::isolate();
12544   v8::HandleScope scope(isolate);
12545   v8::Handle<v8::FunctionTemplate> fun_templ =
12546       v8::FunctionTemplate::New(isolate);
12547   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12548       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12549       v8::Signature::New(isolate, fun_templ));
12550   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12551   proto_templ->Set(v8_str("method"), method_templ);
12552   fun_templ->SetHiddenPrototype(true);
12553   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12554   templ->SetNamedPropertyHandler(
12555       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12556       v8::External::New(isolate, &interceptor_call_count));
12557   LocalContext context;
12558   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12559   GenerateSomeGarbage();
12560   context->Global()->Set(v8_str("o"), fun->NewInstance());
12561   CompileRun(
12562       "o.foo = 17;"
12563       "var receiver = {};"
12564       "receiver.__proto__ = o;"
12565       "var result = 0;"
12566       "var saved_result = 0;"
12567       "for (var i = 0; i < 100; i++) {"
12568       "  result = receiver.method(41);"
12569       "  if (i == 50) {"
12570       "    saved_result = result;"
12571       "    o.method = function(x) { return x - 1 };"
12572       "  }"
12573       "}");
12574   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12575   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12576   CHECK_GE(interceptor_call_count, 50);
12577 }
12578
12579
12580 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12581   int interceptor_call_count = 0;
12582   v8::Isolate* isolate = CcTest::isolate();
12583   v8::HandleScope scope(isolate);
12584   v8::Handle<v8::FunctionTemplate> fun_templ =
12585       v8::FunctionTemplate::New(isolate);
12586   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12587       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12588       v8::Signature::New(isolate, fun_templ));
12589   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12590   proto_templ->Set(v8_str("method"), method_templ);
12591   fun_templ->SetHiddenPrototype(true);
12592   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12593   templ->SetNamedPropertyHandler(
12594       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12595       v8::External::New(isolate, &interceptor_call_count));
12596   LocalContext context;
12597   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12598   GenerateSomeGarbage();
12599   context->Global()->Set(v8_str("o"), fun->NewInstance());
12600   v8::TryCatch try_catch;
12601   CompileRun(
12602       "o.foo = 17;"
12603       "var receiver = {};"
12604       "receiver.__proto__ = o;"
12605       "var result = 0;"
12606       "var saved_result = 0;"
12607       "for (var i = 0; i < 100; i++) {"
12608       "  result = receiver.method(41);"
12609       "  if (i == 50) {"
12610       "    saved_result = result;"
12611       "    receiver = 333;"
12612       "  }"
12613       "}");
12614   CHECK(try_catch.HasCaught());
12615   // TODO(verwaest): Adjust message.
12616   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12617            try_catch.Exception()->ToString());
12618   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12619   CHECK_GE(interceptor_call_count, 50);
12620 }
12621
12622
12623 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12624   int interceptor_call_count = 0;
12625   v8::Isolate* isolate = CcTest::isolate();
12626   v8::HandleScope scope(isolate);
12627   v8::Handle<v8::FunctionTemplate> fun_templ =
12628       v8::FunctionTemplate::New(isolate);
12629   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12630       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12631       v8::Signature::New(isolate, fun_templ));
12632   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12633   proto_templ->Set(v8_str("method"), method_templ);
12634   fun_templ->SetHiddenPrototype(true);
12635   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12636   templ->SetNamedPropertyHandler(
12637       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12638       v8::External::New(isolate, &interceptor_call_count));
12639   LocalContext context;
12640   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12641   GenerateSomeGarbage();
12642   context->Global()->Set(v8_str("o"), fun->NewInstance());
12643   v8::TryCatch try_catch;
12644   CompileRun(
12645       "o.foo = 17;"
12646       "var receiver = {};"
12647       "receiver.__proto__ = o;"
12648       "var result = 0;"
12649       "var saved_result = 0;"
12650       "for (var i = 0; i < 100; i++) {"
12651       "  result = receiver.method(41);"
12652       "  if (i == 50) {"
12653       "    saved_result = result;"
12654       "    receiver = {method: receiver.method};"
12655       "  }"
12656       "}");
12657   CHECK(try_catch.HasCaught());
12658   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12659            try_catch.Exception()->ToString());
12660   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12661   CHECK_GE(interceptor_call_count, 50);
12662 }
12663
12664
12665 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12666   v8::Isolate* isolate = CcTest::isolate();
12667   v8::HandleScope scope(isolate);
12668   v8::Handle<v8::FunctionTemplate> fun_templ =
12669       v8::FunctionTemplate::New(isolate);
12670   v8::Handle<v8::FunctionTemplate> method_templ =
12671       v8::FunctionTemplate::New(isolate,
12672                                 FastApiCallback_TrivialSignature,
12673                                 v8_str("method_data"),
12674                                 v8::Handle<v8::Signature>());
12675   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12676   proto_templ->Set(v8_str("method"), method_templ);
12677   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12678   USE(templ);
12679   LocalContext context;
12680   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12681   GenerateSomeGarbage();
12682   context->Global()->Set(v8_str("o"), fun->NewInstance());
12683   CompileRun(
12684       "var result = 0;"
12685       "for (var i = 0; i < 100; i++) {"
12686       "  result = o.method(41);"
12687       "}");
12688
12689   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12690 }
12691
12692
12693 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12694   v8::Isolate* isolate = CcTest::isolate();
12695   v8::HandleScope scope(isolate);
12696   v8::Handle<v8::FunctionTemplate> fun_templ =
12697       v8::FunctionTemplate::New(isolate);
12698   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12699       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12700       v8::Signature::New(isolate, fun_templ));
12701   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12702   proto_templ->Set(v8_str("method"), method_templ);
12703   fun_templ->SetHiddenPrototype(true);
12704   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12705   CHECK(!templ.IsEmpty());
12706   LocalContext context;
12707   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12708   GenerateSomeGarbage();
12709   context->Global()->Set(v8_str("o"), fun->NewInstance());
12710   CompileRun(
12711       "o.foo = 17;"
12712       "var receiver = {};"
12713       "receiver.__proto__ = o;"
12714       "var result = 0;"
12715       "for (var i = 0; i < 100; i++) {"
12716       "  result = receiver.method(41);"
12717       "}");
12718
12719   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12720 }
12721
12722
12723 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12724   v8::Isolate* isolate = CcTest::isolate();
12725   v8::HandleScope scope(isolate);
12726   v8::Handle<v8::FunctionTemplate> fun_templ =
12727       v8::FunctionTemplate::New(isolate);
12728   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12729       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12730       v8::Signature::New(isolate, fun_templ));
12731   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12732   proto_templ->Set(v8_str("method"), method_templ);
12733   fun_templ->SetHiddenPrototype(true);
12734   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12735   CHECK(!templ.IsEmpty());
12736   LocalContext context;
12737   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12738   GenerateSomeGarbage();
12739   context->Global()->Set(v8_str("o"), fun->NewInstance());
12740   CompileRun(
12741       "o.foo = 17;"
12742       "var receiver = {};"
12743       "receiver.__proto__ = o;"
12744       "var result = 0;"
12745       "var saved_result = 0;"
12746       "for (var i = 0; i < 100; i++) {"
12747       "  result = receiver.method(41);"
12748       "  if (i == 50) {"
12749       "    saved_result = result;"
12750       "    receiver = {method: function(x) { return x - 1 }};"
12751       "  }"
12752       "}");
12753   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12754   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12755 }
12756
12757
12758 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12759   v8::Isolate* isolate = CcTest::isolate();
12760   v8::HandleScope scope(isolate);
12761   v8::Handle<v8::FunctionTemplate> fun_templ =
12762       v8::FunctionTemplate::New(isolate);
12763   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12764       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12765       v8::Signature::New(isolate, fun_templ));
12766   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12767   proto_templ->Set(v8_str("method"), method_templ);
12768   fun_templ->SetHiddenPrototype(true);
12769   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12770   CHECK(!templ.IsEmpty());
12771   LocalContext context;
12772   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12773   GenerateSomeGarbage();
12774   context->Global()->Set(v8_str("o"), fun->NewInstance());
12775   v8::TryCatch try_catch;
12776   CompileRun(
12777       "o.foo = 17;"
12778       "var receiver = {};"
12779       "receiver.__proto__ = o;"
12780       "var result = 0;"
12781       "var saved_result = 0;"
12782       "for (var i = 0; i < 100; i++) {"
12783       "  result = receiver.method(41);"
12784       "  if (i == 50) {"
12785       "    saved_result = result;"
12786       "    receiver = 333;"
12787       "  }"
12788       "}");
12789   CHECK(try_catch.HasCaught());
12790   // TODO(verwaest): Adjust message.
12791   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12792            try_catch.Exception()->ToString());
12793   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12794 }
12795
12796
12797 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12798   v8::Isolate* isolate = CcTest::isolate();
12799   v8::HandleScope scope(isolate);
12800   v8::Handle<v8::FunctionTemplate> fun_templ =
12801       v8::FunctionTemplate::New(isolate);
12802   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12803       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12804       v8::Signature::New(isolate, fun_templ));
12805   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12806   proto_templ->Set(v8_str("method"), method_templ);
12807   fun_templ->SetHiddenPrototype(true);
12808   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12809   CHECK(!templ.IsEmpty());
12810   LocalContext context;
12811   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12812   GenerateSomeGarbage();
12813   context->Global()->Set(v8_str("o"), fun->NewInstance());
12814   v8::TryCatch try_catch;
12815   CompileRun(
12816       "o.foo = 17;"
12817       "var receiver = {};"
12818       "receiver.__proto__ = o;"
12819       "var result = 0;"
12820       "var saved_result = 0;"
12821       "for (var i = 0; i < 100; i++) {"
12822       "  result = receiver.method(41);"
12823       "  if (i == 50) {"
12824       "    saved_result = result;"
12825       "    receiver = Object.create(receiver);"
12826       "  }"
12827       "}");
12828   CHECK(try_catch.HasCaught());
12829   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12830            try_catch.Exception()->ToString());
12831   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12832 }
12833
12834
12835 v8::Handle<Value> keyed_call_ic_function;
12836
12837 static void InterceptorKeyedCallICGetter(
12838     Local<String> name,
12839     const v8::PropertyCallbackInfo<v8::Value>& info) {
12840   ApiTestFuzzer::Fuzz();
12841   if (v8_str("x")->Equals(name)) {
12842     info.GetReturnValue().Set(keyed_call_ic_function);
12843   }
12844 }
12845
12846
12847 // Test the case when we stored cacheable lookup into
12848 // a stub, but the function name changed (to another cacheable function).
12849 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12850   v8::Isolate* isolate = CcTest::isolate();
12851   v8::HandleScope scope(isolate);
12852   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12853   templ->SetNamedPropertyHandler(NoBlockGetterX);
12854   LocalContext context;
12855   context->Global()->Set(v8_str("o"), templ->NewInstance());
12856   CompileRun(
12857     "proto = new Object();"
12858     "proto.y = function(x) { return x + 1; };"
12859     "proto.z = function(x) { return x - 1; };"
12860     "o.__proto__ = proto;"
12861     "var result = 0;"
12862     "var method = 'y';"
12863     "for (var i = 0; i < 10; i++) {"
12864     "  if (i == 5) { method = 'z'; };"
12865     "  result += o[method](41);"
12866     "}");
12867   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12868 }
12869
12870
12871 // Test the case when we stored cacheable lookup into
12872 // a stub, but the function name changed (and the new function is present
12873 // both before and after the interceptor in the prototype chain).
12874 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12875   v8::Isolate* isolate = CcTest::isolate();
12876   v8::HandleScope scope(isolate);
12877   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12878   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12879   LocalContext context;
12880   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12881   keyed_call_ic_function =
12882       v8_compile("function f(x) { return x - 1; }; f")->Run();
12883   CompileRun(
12884     "o = new Object();"
12885     "proto2 = new Object();"
12886     "o.y = function(x) { return x + 1; };"
12887     "proto2.y = function(x) { return x + 2; };"
12888     "o.__proto__ = proto1;"
12889     "proto1.__proto__ = proto2;"
12890     "var result = 0;"
12891     "var method = 'x';"
12892     "for (var i = 0; i < 10; i++) {"
12893     "  if (i == 5) { method = 'y'; };"
12894     "  result += o[method](41);"
12895     "}");
12896   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12897 }
12898
12899
12900 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12901 // on the global object.
12902 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12903   v8::Isolate* isolate = CcTest::isolate();
12904   v8::HandleScope scope(isolate);
12905   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12906   templ->SetNamedPropertyHandler(NoBlockGetterX);
12907   LocalContext context;
12908   context->Global()->Set(v8_str("o"), templ->NewInstance());
12909   CompileRun(
12910     "function inc(x) { return x + 1; };"
12911     "inc(1);"
12912     "function dec(x) { return x - 1; };"
12913     "dec(1);"
12914     "o.__proto__ = this;"
12915     "this.__proto__.x = inc;"
12916     "this.__proto__.y = dec;"
12917     "var result = 0;"
12918     "var method = 'x';"
12919     "for (var i = 0; i < 10; i++) {"
12920     "  if (i == 5) { method = 'y'; };"
12921     "  result += o[method](41);"
12922     "}");
12923   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12924 }
12925
12926
12927 // Test the case when actual function to call sits on global object.
12928 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12929   v8::Isolate* isolate = CcTest::isolate();
12930   v8::HandleScope scope(isolate);
12931   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12932   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12933   LocalContext context;
12934   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12935
12936   CompileRun(
12937     "function len(x) { return x.length; };"
12938     "o.__proto__ = this;"
12939     "var m = 'parseFloat';"
12940     "var result = 0;"
12941     "for (var i = 0; i < 10; i++) {"
12942     "  if (i == 5) {"
12943     "    m = 'len';"
12944     "    saved_result = result;"
12945     "  };"
12946     "  result = o[m]('239');"
12947     "}");
12948   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12949   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12950 }
12951
12952
12953 // Test the map transition before the interceptor.
12954 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12955   v8::Isolate* isolate = CcTest::isolate();
12956   v8::HandleScope scope(isolate);
12957   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12958   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12959   LocalContext context;
12960   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12961
12962   CompileRun(
12963     "var o = new Object();"
12964     "o.__proto__ = proto;"
12965     "o.method = function(x) { return x + 1; };"
12966     "var m = 'method';"
12967     "var result = 0;"
12968     "for (var i = 0; i < 10; i++) {"
12969     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12970     "  result += o[m](41);"
12971     "}");
12972   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12973 }
12974
12975
12976 // Test the map transition after the interceptor.
12977 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12978   v8::Isolate* isolate = CcTest::isolate();
12979   v8::HandleScope scope(isolate);
12980   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12981   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12982   LocalContext context;
12983   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12984
12985   CompileRun(
12986     "var proto = new Object();"
12987     "o.__proto__ = proto;"
12988     "proto.method = function(x) { return x + 1; };"
12989     "var m = 'method';"
12990     "var result = 0;"
12991     "for (var i = 0; i < 10; i++) {"
12992     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12993     "  result += o[m](41);"
12994     "}");
12995   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12996 }
12997
12998
12999 static int interceptor_call_count = 0;
13000
13001 static void InterceptorICRefErrorGetter(
13002     Local<String> name,
13003     const v8::PropertyCallbackInfo<v8::Value>& info) {
13004   ApiTestFuzzer::Fuzz();
13005   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
13006     info.GetReturnValue().Set(call_ic_function2);
13007   }
13008 }
13009
13010
13011 // This test should hit load and call ICs for the interceptor case.
13012 // Once in a while, the interceptor will reply that a property was not
13013 // found in which case we should get a reference error.
13014 THREADED_TEST(InterceptorICReferenceErrors) {
13015   v8::Isolate* isolate = CcTest::isolate();
13016   v8::HandleScope scope(isolate);
13017   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13018   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
13019   LocalContext context(0, templ, v8::Handle<Value>());
13020   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13021   v8::Handle<Value> value = CompileRun(
13022     "function f() {"
13023     "  for (var i = 0; i < 1000; i++) {"
13024     "    try { x; } catch(e) { return true; }"
13025     "  }"
13026     "  return false;"
13027     "};"
13028     "f();");
13029   CHECK_EQ(true, value->BooleanValue());
13030   interceptor_call_count = 0;
13031   value = CompileRun(
13032     "function g() {"
13033     "  for (var i = 0; i < 1000; i++) {"
13034     "    try { x(42); } catch(e) { return true; }"
13035     "  }"
13036     "  return false;"
13037     "};"
13038     "g();");
13039   CHECK_EQ(true, value->BooleanValue());
13040 }
13041
13042
13043 static int interceptor_ic_exception_get_count = 0;
13044
13045 static void InterceptorICExceptionGetter(
13046     Local<String> name,
13047     const v8::PropertyCallbackInfo<v8::Value>& info) {
13048   ApiTestFuzzer::Fuzz();
13049   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
13050     info.GetReturnValue().Set(call_ic_function3);
13051   }
13052   if (interceptor_ic_exception_get_count == 20) {
13053     info.GetIsolate()->ThrowException(v8_num(42));
13054     return;
13055   }
13056 }
13057
13058
13059 // Test interceptor load/call IC where the interceptor throws an
13060 // exception once in a while.
13061 THREADED_TEST(InterceptorICGetterExceptions) {
13062   interceptor_ic_exception_get_count = 0;
13063   v8::Isolate* isolate = CcTest::isolate();
13064   v8::HandleScope scope(isolate);
13065   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13066   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
13067   LocalContext context(0, templ, v8::Handle<Value>());
13068   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13069   v8::Handle<Value> value = CompileRun(
13070     "function f() {"
13071     "  for (var i = 0; i < 100; i++) {"
13072     "    try { x; } catch(e) { return true; }"
13073     "  }"
13074     "  return false;"
13075     "};"
13076     "f();");
13077   CHECK_EQ(true, value->BooleanValue());
13078   interceptor_ic_exception_get_count = 0;
13079   value = CompileRun(
13080     "function f() {"
13081     "  for (var i = 0; i < 100; i++) {"
13082     "    try { x(42); } catch(e) { return true; }"
13083     "  }"
13084     "  return false;"
13085     "};"
13086     "f();");
13087   CHECK_EQ(true, value->BooleanValue());
13088 }
13089
13090
13091 static int interceptor_ic_exception_set_count = 0;
13092
13093 static void InterceptorICExceptionSetter(
13094       Local<String> key,
13095       Local<Value> value,
13096       const v8::PropertyCallbackInfo<v8::Value>& info) {
13097   ApiTestFuzzer::Fuzz();
13098   if (++interceptor_ic_exception_set_count > 20) {
13099     info.GetIsolate()->ThrowException(v8_num(42));
13100   }
13101 }
13102
13103
13104 // Test interceptor store IC where the interceptor throws an exception
13105 // once in a while.
13106 THREADED_TEST(InterceptorICSetterExceptions) {
13107   interceptor_ic_exception_set_count = 0;
13108   v8::Isolate* isolate = CcTest::isolate();
13109   v8::HandleScope scope(isolate);
13110   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13111   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
13112   LocalContext context(0, templ, v8::Handle<Value>());
13113   v8::Handle<Value> value = CompileRun(
13114     "function f() {"
13115     "  for (var i = 0; i < 100; i++) {"
13116     "    try { x = 42; } catch(e) { return true; }"
13117     "  }"
13118     "  return false;"
13119     "};"
13120     "f();");
13121   CHECK_EQ(true, value->BooleanValue());
13122 }
13123
13124
13125 // Test that we ignore null interceptors.
13126 THREADED_TEST(NullNamedInterceptor) {
13127   v8::Isolate* isolate = CcTest::isolate();
13128   v8::HandleScope scope(isolate);
13129   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13130   templ->SetNamedPropertyHandler(
13131       static_cast<v8::NamedPropertyGetterCallback>(0));
13132   LocalContext context;
13133   templ->Set(CcTest::isolate(), "x", v8_num(42));
13134   v8::Handle<v8::Object> obj = templ->NewInstance();
13135   context->Global()->Set(v8_str("obj"), obj);
13136   v8::Handle<Value> value = CompileRun("obj.x");
13137   CHECK(value->IsInt32());
13138   CHECK_EQ(42, value->Int32Value());
13139 }
13140
13141
13142 // Test that we ignore null interceptors.
13143 THREADED_TEST(NullIndexedInterceptor) {
13144   v8::Isolate* isolate = CcTest::isolate();
13145   v8::HandleScope scope(isolate);
13146   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13147   templ->SetIndexedPropertyHandler(
13148       static_cast<v8::IndexedPropertyGetterCallback>(0));
13149   LocalContext context;
13150   templ->Set(CcTest::isolate(), "42", v8_num(42));
13151   v8::Handle<v8::Object> obj = templ->NewInstance();
13152   context->Global()->Set(v8_str("obj"), obj);
13153   v8::Handle<Value> value = CompileRun("obj[42]");
13154   CHECK(value->IsInt32());
13155   CHECK_EQ(42, value->Int32Value());
13156 }
13157
13158
13159 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13160   v8::Isolate* isolate = CcTest::isolate();
13161   v8::HandleScope scope(isolate);
13162   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13163   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
13164   LocalContext env;
13165   env->Global()->Set(v8_str("obj"),
13166                      templ->GetFunction()->NewInstance());
13167   ExpectTrue("obj.x === 42");
13168   ExpectTrue("!obj.propertyIsEnumerable('x')");
13169 }
13170
13171
13172 static void ThrowingGetter(Local<String> name,
13173                            const v8::PropertyCallbackInfo<v8::Value>& info) {
13174   ApiTestFuzzer::Fuzz();
13175   info.GetIsolate()->ThrowException(Handle<Value>());
13176   info.GetReturnValue().SetUndefined();
13177 }
13178
13179
13180 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13181   LocalContext context;
13182   HandleScope scope(context->GetIsolate());
13183
13184   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13185   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13186   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13187
13188   Local<Object> instance = templ->GetFunction()->NewInstance();
13189
13190   Local<Object> another = Object::New(context->GetIsolate());
13191   another->SetPrototype(instance);
13192
13193   Local<Object> with_js_getter = CompileRun(
13194       "o = {};\n"
13195       "o.__defineGetter__('f', function() { throw undefined; });\n"
13196       "o\n").As<Object>();
13197   CHECK(!with_js_getter.IsEmpty());
13198
13199   TryCatch try_catch;
13200
13201   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13202   CHECK(try_catch.HasCaught());
13203   try_catch.Reset();
13204   CHECK(result.IsEmpty());
13205
13206   result = another->GetRealNamedProperty(v8_str("f"));
13207   CHECK(try_catch.HasCaught());
13208   try_catch.Reset();
13209   CHECK(result.IsEmpty());
13210
13211   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13212   CHECK(try_catch.HasCaught());
13213   try_catch.Reset();
13214   CHECK(result.IsEmpty());
13215
13216   result = another->Get(v8_str("f"));
13217   CHECK(try_catch.HasCaught());
13218   try_catch.Reset();
13219   CHECK(result.IsEmpty());
13220
13221   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13222   CHECK(try_catch.HasCaught());
13223   try_catch.Reset();
13224   CHECK(result.IsEmpty());
13225
13226   result = with_js_getter->Get(v8_str("f"));
13227   CHECK(try_catch.HasCaught());
13228   try_catch.Reset();
13229   CHECK(result.IsEmpty());
13230 }
13231
13232
13233 static void ThrowingCallbackWithTryCatch(
13234     const v8::FunctionCallbackInfo<v8::Value>& args) {
13235   TryCatch try_catch;
13236   // Verboseness is important: it triggers message delivery which can call into
13237   // external code.
13238   try_catch.SetVerbose(true);
13239   CompileRun("throw 'from JS';");
13240   CHECK(try_catch.HasCaught());
13241   CHECK(!CcTest::i_isolate()->has_pending_exception());
13242   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13243 }
13244
13245
13246 static int call_depth;
13247
13248
13249 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13250   TryCatch try_catch;
13251 }
13252
13253
13254 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13255   if (--call_depth) CompileRun("throw 'ThrowInJS';");
13256 }
13257
13258
13259 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13260   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13261 }
13262
13263
13264 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13265   Handle<String> errorMessageString = message->Get();
13266   CHECK(!errorMessageString.IsEmpty());
13267   message->GetStackTrace();
13268   message->GetScriptOrigin().ResourceName();
13269 }
13270
13271
13272 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13273   LocalContext context;
13274   v8::Isolate* isolate = context->GetIsolate();
13275   HandleScope scope(isolate);
13276
13277   Local<Function> func =
13278       FunctionTemplate::New(isolate,
13279                             ThrowingCallbackWithTryCatch)->GetFunction();
13280   context->Global()->Set(v8_str("func"), func);
13281
13282   MessageCallback callbacks[] =
13283       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13284   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13285     MessageCallback callback = callbacks[i];
13286     if (callback != NULL) {
13287       V8::AddMessageListener(callback);
13288     }
13289     // Some small number to control number of times message handler should
13290     // throw an exception.
13291     call_depth = 5;
13292     ExpectFalse(
13293         "var thrown = false;\n"
13294         "try { func(); } catch(e) { thrown = true; }\n"
13295         "thrown\n");
13296     if (callback != NULL) {
13297       V8::RemoveMessageListeners(callback);
13298     }
13299   }
13300 }
13301
13302
13303 static void ParentGetter(Local<String> name,
13304                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13305   ApiTestFuzzer::Fuzz();
13306   info.GetReturnValue().Set(v8_num(1));
13307 }
13308
13309
13310 static void ChildGetter(Local<String> name,
13311                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13312   ApiTestFuzzer::Fuzz();
13313   info.GetReturnValue().Set(v8_num(42));
13314 }
13315
13316
13317 THREADED_TEST(Overriding) {
13318   LocalContext context;
13319   v8::Isolate* isolate = context->GetIsolate();
13320   v8::HandleScope scope(isolate);
13321
13322   // Parent template.
13323   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13324   Local<ObjectTemplate> parent_instance_templ =
13325       parent_templ->InstanceTemplate();
13326   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13327
13328   // Template that inherits from the parent template.
13329   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13330   Local<ObjectTemplate> child_instance_templ =
13331       child_templ->InstanceTemplate();
13332   child_templ->Inherit(parent_templ);
13333   // Override 'f'.  The child version of 'f' should get called for child
13334   // instances.
13335   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13336   // Add 'g' twice.  The 'g' added last should get called for instances.
13337   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13338   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13339
13340   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13341   // so 'h' can be shadowed on the instance object.
13342   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13343   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13344       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13345
13346   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13347   // but the attribute does not have effect because it is duplicated with
13348   // NULL setter.
13349   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13350       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13351
13352
13353
13354   // Instantiate the child template.
13355   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13356
13357   // Check that the child function overrides the parent one.
13358   context->Global()->Set(v8_str("o"), instance);
13359   Local<Value> value = v8_compile("o.f")->Run();
13360   // Check that the 'g' that was added last is hit.
13361   CHECK_EQ(42, value->Int32Value());
13362   value = v8_compile("o.g")->Run();
13363   CHECK_EQ(42, value->Int32Value());
13364
13365   // Check that 'h' cannot be shadowed.
13366   value = v8_compile("o.h = 3; o.h")->Run();
13367   CHECK_EQ(1, value->Int32Value());
13368
13369   // Check that 'i' cannot be shadowed or changed.
13370   value = v8_compile("o.i = 3; o.i")->Run();
13371   CHECK_EQ(42, value->Int32Value());
13372 }
13373
13374
13375 static void IsConstructHandler(
13376     const v8::FunctionCallbackInfo<v8::Value>& args) {
13377   ApiTestFuzzer::Fuzz();
13378   args.GetReturnValue().Set(args.IsConstructCall());
13379 }
13380
13381
13382 THREADED_TEST(IsConstructCall) {
13383   v8::Isolate* isolate = CcTest::isolate();
13384   v8::HandleScope scope(isolate);
13385
13386   // Function template with call handler.
13387   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13388   templ->SetCallHandler(IsConstructHandler);
13389
13390   LocalContext context;
13391
13392   context->Global()->Set(v8_str("f"), templ->GetFunction());
13393   Local<Value> value = v8_compile("f()")->Run();
13394   CHECK(!value->BooleanValue());
13395   value = v8_compile("new f()")->Run();
13396   CHECK(value->BooleanValue());
13397 }
13398
13399
13400 THREADED_TEST(ObjectProtoToString) {
13401   v8::Isolate* isolate = CcTest::isolate();
13402   v8::HandleScope scope(isolate);
13403   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13404   templ->SetClassName(v8_str("MyClass"));
13405
13406   LocalContext context;
13407
13408   Local<String> customized_tostring = v8_str("customized toString");
13409
13410   // Replace Object.prototype.toString
13411   v8_compile("Object.prototype.toString = function() {"
13412                   "  return 'customized toString';"
13413                   "}")->Run();
13414
13415   // Normal ToString call should call replaced Object.prototype.toString
13416   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13417   Local<String> value = instance->ToString();
13418   CHECK(value->IsString() && value->Equals(customized_tostring));
13419
13420   // ObjectProtoToString should not call replace toString function.
13421   value = instance->ObjectProtoToString();
13422   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13423
13424   // Check global
13425   value = context->Global()->ObjectProtoToString();
13426   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13427
13428   // Check ordinary object
13429   Local<Value> object = v8_compile("new Object()")->Run();
13430   value = object.As<v8::Object>()->ObjectProtoToString();
13431   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13432 }
13433
13434
13435 THREADED_TEST(ObjectGetConstructorName) {
13436   LocalContext context;
13437   v8::HandleScope scope(context->GetIsolate());
13438   v8_compile("function Parent() {};"
13439              "function Child() {};"
13440              "Child.prototype = new Parent();"
13441              "var outer = { inner: function() { } };"
13442              "var p = new Parent();"
13443              "var c = new Child();"
13444              "var x = new outer.inner();")->Run();
13445
13446   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13447   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13448       v8_str("Parent")));
13449
13450   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13451   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13452       v8_str("Child")));
13453
13454   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13455   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13456       v8_str("outer.inner")));
13457 }
13458
13459
13460 bool ApiTestFuzzer::fuzzing_ = false;
13461 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13462 int ApiTestFuzzer::active_tests_;
13463 int ApiTestFuzzer::tests_being_run_;
13464 int ApiTestFuzzer::current_;
13465
13466
13467 // We are in a callback and want to switch to another thread (if we
13468 // are currently running the thread fuzzing test).
13469 void ApiTestFuzzer::Fuzz() {
13470   if (!fuzzing_) return;
13471   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13472   test->ContextSwitch();
13473 }
13474
13475
13476 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13477 // not start immediately.
13478 bool ApiTestFuzzer::NextThread() {
13479   int test_position = GetNextTestNumber();
13480   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13481   if (test_position == current_) {
13482     if (kLogThreading)
13483       printf("Stay with %s\n", test_name);
13484     return false;
13485   }
13486   if (kLogThreading) {
13487     printf("Switch from %s to %s\n",
13488            test_name,
13489            RegisterThreadedTest::nth(test_position)->name());
13490   }
13491   current_ = test_position;
13492   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13493   return true;
13494 }
13495
13496
13497 void ApiTestFuzzer::Run() {
13498   // When it is our turn...
13499   gate_.Wait();
13500   {
13501     // ... get the V8 lock and start running the test.
13502     v8::Locker locker(CcTest::isolate());
13503     CallTest();
13504   }
13505   // This test finished.
13506   active_ = false;
13507   active_tests_--;
13508   // If it was the last then signal that fact.
13509   if (active_tests_ == 0) {
13510     all_tests_done_.Signal();
13511   } else {
13512     // Otherwise select a new test and start that.
13513     NextThread();
13514   }
13515 }
13516
13517
13518 static unsigned linear_congruential_generator;
13519
13520
13521 void ApiTestFuzzer::SetUp(PartOfTest part) {
13522   linear_congruential_generator = i::FLAG_testing_prng_seed;
13523   fuzzing_ = true;
13524   int count = RegisterThreadedTest::count();
13525   int start =  count * part / (LAST_PART + 1);
13526   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13527   active_tests_ = tests_being_run_ = end - start + 1;
13528   for (int i = 0; i < tests_being_run_; i++) {
13529     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13530   }
13531   for (int i = 0; i < active_tests_; i++) {
13532     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13533   }
13534 }
13535
13536
13537 static void CallTestNumber(int test_number) {
13538   (RegisterThreadedTest::nth(test_number)->callback())();
13539 }
13540
13541
13542 void ApiTestFuzzer::RunAllTests() {
13543   // Set off the first test.
13544   current_ = -1;
13545   NextThread();
13546   // Wait till they are all done.
13547   all_tests_done_.Wait();
13548 }
13549
13550
13551 int ApiTestFuzzer::GetNextTestNumber() {
13552   int next_test;
13553   do {
13554     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13555     linear_congruential_generator *= 1664525u;
13556     linear_congruential_generator += 1013904223u;
13557   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13558   return next_test;
13559 }
13560
13561
13562 void ApiTestFuzzer::ContextSwitch() {
13563   // If the new thread is the same as the current thread there is nothing to do.
13564   if (NextThread()) {
13565     // Now it can start.
13566     v8::Unlocker unlocker(CcTest::isolate());
13567     // Wait till someone starts us again.
13568     gate_.Wait();
13569     // And we're off.
13570   }
13571 }
13572
13573
13574 void ApiTestFuzzer::TearDown() {
13575   fuzzing_ = false;
13576   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13577     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13578     if (fuzzer != NULL) fuzzer->Join();
13579   }
13580 }
13581
13582
13583 // Lets not be needlessly self-referential.
13584 TEST(Threading1) {
13585   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13586   ApiTestFuzzer::RunAllTests();
13587   ApiTestFuzzer::TearDown();
13588 }
13589
13590
13591 TEST(Threading2) {
13592   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13593   ApiTestFuzzer::RunAllTests();
13594   ApiTestFuzzer::TearDown();
13595 }
13596
13597
13598 TEST(Threading3) {
13599   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13600   ApiTestFuzzer::RunAllTests();
13601   ApiTestFuzzer::TearDown();
13602 }
13603
13604
13605 TEST(Threading4) {
13606   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13607   ApiTestFuzzer::RunAllTests();
13608   ApiTestFuzzer::TearDown();
13609 }
13610
13611
13612 void ApiTestFuzzer::CallTest() {
13613   v8::Isolate::Scope scope(CcTest::isolate());
13614   if (kLogThreading)
13615     printf("Start test %d\n", test_number_);
13616   CallTestNumber(test_number_);
13617   if (kLogThreading)
13618     printf("End test %d\n", test_number_);
13619 }
13620
13621
13622 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13623   v8::Isolate* isolate = args.GetIsolate();
13624   CHECK(v8::Locker::IsLocked(isolate));
13625   ApiTestFuzzer::Fuzz();
13626   v8::Unlocker unlocker(isolate);
13627   const char* code = "throw 7;";
13628   {
13629     v8::Locker nested_locker(isolate);
13630     v8::HandleScope scope(isolate);
13631     v8::Handle<Value> exception;
13632     { v8::TryCatch try_catch;
13633       v8::Handle<Value> value = CompileRun(code);
13634       CHECK(value.IsEmpty());
13635       CHECK(try_catch.HasCaught());
13636       // Make sure to wrap the exception in a new handle because
13637       // the handle returned from the TryCatch is destroyed
13638       // when the TryCatch is destroyed.
13639       exception = Local<Value>::New(isolate, try_catch.Exception());
13640     }
13641     args.GetIsolate()->ThrowException(exception);
13642   }
13643 }
13644
13645
13646 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13647   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13648   ApiTestFuzzer::Fuzz();
13649   v8::Unlocker unlocker(CcTest::isolate());
13650   const char* code = "throw 7;";
13651   {
13652     v8::Locker nested_locker(CcTest::isolate());
13653     v8::HandleScope scope(args.GetIsolate());
13654     v8::Handle<Value> value = CompileRun(code);
13655     CHECK(value.IsEmpty());
13656     args.GetReturnValue().Set(v8_str("foo"));
13657   }
13658 }
13659
13660
13661 // These are locking tests that don't need to be run again
13662 // as part of the locking aggregation tests.
13663 TEST(NestedLockers) {
13664   v8::Isolate* isolate = CcTest::isolate();
13665   v8::Locker locker(isolate);
13666   CHECK(v8::Locker::IsLocked(isolate));
13667   LocalContext env;
13668   v8::HandleScope scope(env->GetIsolate());
13669   Local<v8::FunctionTemplate> fun_templ =
13670       v8::FunctionTemplate::New(isolate, ThrowInJS);
13671   Local<Function> fun = fun_templ->GetFunction();
13672   env->Global()->Set(v8_str("throw_in_js"), fun);
13673   Local<Script> script = v8_compile("(function () {"
13674                                     "  try {"
13675                                     "    throw_in_js();"
13676                                     "    return 42;"
13677                                     "  } catch (e) {"
13678                                     "    return e * 13;"
13679                                     "  }"
13680                                     "})();");
13681   CHECK_EQ(91, script->Run()->Int32Value());
13682 }
13683
13684
13685 // These are locking tests that don't need to be run again
13686 // as part of the locking aggregation tests.
13687 TEST(NestedLockersNoTryCatch) {
13688   v8::Locker locker(CcTest::isolate());
13689   LocalContext env;
13690   v8::HandleScope scope(env->GetIsolate());
13691   Local<v8::FunctionTemplate> fun_templ =
13692       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13693   Local<Function> fun = fun_templ->GetFunction();
13694   env->Global()->Set(v8_str("throw_in_js"), fun);
13695   Local<Script> script = v8_compile("(function () {"
13696                                     "  try {"
13697                                     "    throw_in_js();"
13698                                     "    return 42;"
13699                                     "  } catch (e) {"
13700                                     "    return e * 13;"
13701                                     "  }"
13702                                     "})();");
13703   CHECK_EQ(91, script->Run()->Int32Value());
13704 }
13705
13706
13707 THREADED_TEST(RecursiveLocking) {
13708   v8::Locker locker(CcTest::isolate());
13709   {
13710     v8::Locker locker2(CcTest::isolate());
13711     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13712   }
13713 }
13714
13715
13716 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13717   ApiTestFuzzer::Fuzz();
13718   v8::Unlocker unlocker(CcTest::isolate());
13719 }
13720
13721
13722 THREADED_TEST(LockUnlockLock) {
13723   {
13724     v8::Locker locker(CcTest::isolate());
13725     v8::HandleScope scope(CcTest::isolate());
13726     LocalContext env;
13727     Local<v8::FunctionTemplate> fun_templ =
13728         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13729     Local<Function> fun = fun_templ->GetFunction();
13730     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13731     Local<Script> script = v8_compile("(function () {"
13732                                       "  unlock_for_a_moment();"
13733                                       "  return 42;"
13734                                       "})();");
13735     CHECK_EQ(42, script->Run()->Int32Value());
13736   }
13737   {
13738     v8::Locker locker(CcTest::isolate());
13739     v8::HandleScope scope(CcTest::isolate());
13740     LocalContext env;
13741     Local<v8::FunctionTemplate> fun_templ =
13742         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13743     Local<Function> fun = fun_templ->GetFunction();
13744     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13745     Local<Script> script = v8_compile("(function () {"
13746                                       "  unlock_for_a_moment();"
13747                                       "  return 42;"
13748                                       "})();");
13749     CHECK_EQ(42, script->Run()->Int32Value());
13750   }
13751 }
13752
13753
13754 static int GetGlobalObjectsCount() {
13755   int count = 0;
13756   i::HeapIterator it(CcTest::heap());
13757   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13758     if (object->IsJSGlobalObject()) count++;
13759   return count;
13760 }
13761
13762
13763 static void CheckSurvivingGlobalObjectsCount(int expected) {
13764   // We need to collect all garbage twice to be sure that everything
13765   // has been collected.  This is because inline caches are cleared in
13766   // the first garbage collection but some of the maps have already
13767   // been marked at that point.  Therefore some of the maps are not
13768   // collected until the second garbage collection.
13769   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13770   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13771   int count = GetGlobalObjectsCount();
13772 #ifdef DEBUG
13773   if (count != expected) CcTest::heap()->TracePathToGlobal();
13774 #endif
13775   CHECK_EQ(expected, count);
13776 }
13777
13778
13779 TEST(DontLeakGlobalObjects) {
13780   // Regression test for issues 1139850 and 1174891.
13781
13782   i::FLAG_expose_gc = true;
13783   v8::V8::Initialize();
13784
13785   for (int i = 0; i < 5; i++) {
13786     { v8::HandleScope scope(CcTest::isolate());
13787       LocalContext context;
13788     }
13789     CcTest::isolate()->ContextDisposedNotification();
13790     CheckSurvivingGlobalObjectsCount(0);
13791
13792     { v8::HandleScope scope(CcTest::isolate());
13793       LocalContext context;
13794       v8_compile("Date")->Run();
13795     }
13796     CcTest::isolate()->ContextDisposedNotification();
13797     CheckSurvivingGlobalObjectsCount(0);
13798
13799     { v8::HandleScope scope(CcTest::isolate());
13800       LocalContext context;
13801       v8_compile("/aaa/")->Run();
13802     }
13803     CcTest::isolate()->ContextDisposedNotification();
13804     CheckSurvivingGlobalObjectsCount(0);
13805
13806     { v8::HandleScope scope(CcTest::isolate());
13807       const char* extension_list[] = { "v8/gc" };
13808       v8::ExtensionConfiguration extensions(1, extension_list);
13809       LocalContext context(&extensions);
13810       v8_compile("gc();")->Run();
13811     }
13812     CcTest::isolate()->ContextDisposedNotification();
13813     CheckSurvivingGlobalObjectsCount(0);
13814   }
13815 }
13816
13817
13818 TEST(CopyablePersistent) {
13819   LocalContext context;
13820   v8::Isolate* isolate = context->GetIsolate();
13821   i::GlobalHandles* globals =
13822       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13823   int initial_handles = globals->global_handles_count();
13824   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13825       CopyableObject;
13826   {
13827     CopyableObject handle1;
13828     {
13829       v8::HandleScope scope(isolate);
13830       handle1.Reset(isolate, v8::Object::New(isolate));
13831     }
13832     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13833     CopyableObject  handle2;
13834     handle2 = handle1;
13835     CHECK(handle1 == handle2);
13836     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13837     CopyableObject handle3(handle2);
13838     CHECK(handle1 == handle3);
13839     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13840   }
13841   // Verify autodispose
13842   CHECK_EQ(initial_handles, globals->global_handles_count());
13843 }
13844
13845
13846 static void WeakApiCallback(
13847     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13848   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13849   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13850   data.GetParameter()->Reset();
13851   delete data.GetParameter();
13852 }
13853
13854
13855 TEST(WeakCallbackApi) {
13856   LocalContext context;
13857   v8::Isolate* isolate = context->GetIsolate();
13858   i::GlobalHandles* globals =
13859       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13860   int initial_handles = globals->global_handles_count();
13861   {
13862     v8::HandleScope scope(isolate);
13863     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13864     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13865     v8::Persistent<v8::Object>* handle =
13866         new v8::Persistent<v8::Object>(isolate, obj);
13867     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13868                                                              WeakApiCallback);
13869   }
13870   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13871       CollectAllGarbage(i::Heap::kNoGCFlags);
13872   // Verify disposed.
13873   CHECK_EQ(initial_handles, globals->global_handles_count());
13874 }
13875
13876
13877 v8::Persistent<v8::Object> some_object;
13878 v8::Persistent<v8::Object> bad_handle;
13879
13880 void NewPersistentHandleCallback(
13881     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13882   v8::HandleScope scope(data.GetIsolate());
13883   bad_handle.Reset(data.GetIsolate(), some_object);
13884   data.GetParameter()->Reset();
13885 }
13886
13887
13888 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13889   LocalContext context;
13890   v8::Isolate* isolate = context->GetIsolate();
13891
13892   v8::Persistent<v8::Object> handle1, handle2;
13893   {
13894     v8::HandleScope scope(isolate);
13895     some_object.Reset(isolate, v8::Object::New(isolate));
13896     handle1.Reset(isolate, v8::Object::New(isolate));
13897     handle2.Reset(isolate, v8::Object::New(isolate));
13898   }
13899   // Note: order is implementation dependent alas: currently
13900   // global handle nodes are processed by PostGarbageCollectionProcessing
13901   // in reverse allocation order, so if second allocated handle is deleted,
13902   // weak callback of the first handle would be able to 'reallocate' it.
13903   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13904   handle2.Reset();
13905   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13906 }
13907
13908
13909 v8::Persistent<v8::Object> to_be_disposed;
13910
13911 void DisposeAndForceGcCallback(
13912     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13913   to_be_disposed.Reset();
13914   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13915   data.GetParameter()->Reset();
13916 }
13917
13918
13919 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13920   LocalContext context;
13921   v8::Isolate* isolate = context->GetIsolate();
13922
13923   v8::Persistent<v8::Object> handle1, handle2;
13924   {
13925     v8::HandleScope scope(isolate);
13926     handle1.Reset(isolate, v8::Object::New(isolate));
13927     handle2.Reset(isolate, v8::Object::New(isolate));
13928   }
13929   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13930   to_be_disposed.Reset(isolate, handle2);
13931   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13932 }
13933
13934 void DisposingCallback(
13935     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13936   data.GetParameter()->Reset();
13937 }
13938
13939 void HandleCreatingCallback(
13940     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13941   v8::HandleScope scope(data.GetIsolate());
13942   v8::Persistent<v8::Object>(data.GetIsolate(),
13943                              v8::Object::New(data.GetIsolate()));
13944   data.GetParameter()->Reset();
13945 }
13946
13947
13948 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13949   LocalContext context;
13950   v8::Isolate* isolate = context->GetIsolate();
13951
13952   v8::Persistent<v8::Object> handle1, handle2, handle3;
13953   {
13954     v8::HandleScope scope(isolate);
13955     handle3.Reset(isolate, v8::Object::New(isolate));
13956     handle2.Reset(isolate, v8::Object::New(isolate));
13957     handle1.Reset(isolate, v8::Object::New(isolate));
13958   }
13959   handle2.SetWeak(&handle2, DisposingCallback);
13960   handle3.SetWeak(&handle3, HandleCreatingCallback);
13961   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13962 }
13963
13964
13965 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13966   v8::V8::Initialize();
13967
13968   const int nof = 2;
13969   const char* sources[nof] = {
13970     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13971     "Object()"
13972   };
13973
13974   for (int i = 0; i < nof; i++) {
13975     const char* source = sources[i];
13976     { v8::HandleScope scope(CcTest::isolate());
13977       LocalContext context;
13978       CompileRun(source);
13979     }
13980     { v8::HandleScope scope(CcTest::isolate());
13981       LocalContext context;
13982       CompileRun(source);
13983     }
13984   }
13985 }
13986
13987
13988 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13989   v8::EscapableHandleScope inner(env->GetIsolate());
13990   env->Enter();
13991   v8::Local<Value> three = v8_num(3);
13992   v8::Local<Value> value = inner.Escape(three);
13993   env->Exit();
13994   return value;
13995 }
13996
13997
13998 THREADED_TEST(NestedHandleScopeAndContexts) {
13999   v8::Isolate* isolate = CcTest::isolate();
14000   v8::HandleScope outer(isolate);
14001   v8::Local<Context> env = Context::New(isolate);
14002   env->Enter();
14003   v8::Handle<Value> value = NestedScope(env);
14004   v8::Handle<String> str(value->ToString());
14005   CHECK(!str.IsEmpty());
14006   env->Exit();
14007 }
14008
14009
14010 static bool MatchPointers(void* key1, void* key2) {
14011   return key1 == key2;
14012 }
14013
14014
14015 struct SymbolInfo {
14016   size_t id;
14017   size_t size;
14018   std::string name;
14019 };
14020
14021
14022 class SetFunctionEntryHookTest {
14023  public:
14024   SetFunctionEntryHookTest() {
14025     CHECK(instance_ == NULL);
14026     instance_ = this;
14027   }
14028   ~SetFunctionEntryHookTest() {
14029     CHECK(instance_ == this);
14030     instance_ = NULL;
14031   }
14032   void Reset() {
14033     symbols_.clear();
14034     symbol_locations_.clear();
14035     invocations_.clear();
14036   }
14037   void RunTest();
14038   void OnJitEvent(const v8::JitCodeEvent* event);
14039   static void JitEvent(const v8::JitCodeEvent* event) {
14040     CHECK(instance_ != NULL);
14041     instance_->OnJitEvent(event);
14042   }
14043
14044   void OnEntryHook(uintptr_t function,
14045                    uintptr_t return_addr_location);
14046   static void EntryHook(uintptr_t function,
14047                         uintptr_t return_addr_location) {
14048     CHECK(instance_ != NULL);
14049     instance_->OnEntryHook(function, return_addr_location);
14050   }
14051
14052   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14053     CHECK(instance_ != NULL);
14054     args.GetReturnValue().Set(v8_num(42));
14055   }
14056   void RunLoopInNewEnv(v8::Isolate* isolate);
14057
14058   // Records addr as location of symbol.
14059   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14060
14061   // Finds the symbol containing addr
14062   SymbolInfo* FindSymbolForAddr(i::Address addr);
14063   // Returns the number of invocations where the caller name contains
14064   // \p caller_name and the function name contains \p function_name.
14065   int CountInvocations(const char* caller_name,
14066                        const char* function_name);
14067
14068   i::Handle<i::JSFunction> foo_func_;
14069   i::Handle<i::JSFunction> bar_func_;
14070
14071   typedef std::map<size_t, SymbolInfo> SymbolMap;
14072   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14073   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14074   SymbolMap symbols_;
14075   SymbolLocationMap symbol_locations_;
14076   InvocationMap invocations_;
14077
14078   static SetFunctionEntryHookTest* instance_;
14079 };
14080 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14081
14082
14083 // Returns true if addr is in the range [start, start+len).
14084 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14085   if (start <= addr && start + len > addr)
14086     return true;
14087
14088   return false;
14089 }
14090
14091 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14092                                               SymbolInfo* symbol) {
14093   // Insert the symbol at the new location.
14094   SymbolLocationMap::iterator it =
14095       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14096   // Now erase symbols to the left and right that overlap this one.
14097   while (it != symbol_locations_.begin()) {
14098     SymbolLocationMap::iterator left = it;
14099     --left;
14100     if (!Overlaps(left->first, left->second->size, addr))
14101       break;
14102     symbol_locations_.erase(left);
14103   }
14104
14105   // Now erase symbols to the left and right that overlap this one.
14106   while (true) {
14107     SymbolLocationMap::iterator right = it;
14108     ++right;
14109     if (right == symbol_locations_.end())
14110         break;
14111     if (!Overlaps(addr, symbol->size, right->first))
14112       break;
14113     symbol_locations_.erase(right);
14114   }
14115 }
14116
14117
14118 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14119   switch (event->type) {
14120     case v8::JitCodeEvent::CODE_ADDED: {
14121         CHECK(event->code_start != NULL);
14122         CHECK_NE(0, static_cast<int>(event->code_len));
14123         CHECK(event->name.str != NULL);
14124         size_t symbol_id = symbols_.size();
14125
14126         // Record the new symbol.
14127         SymbolInfo& info = symbols_[symbol_id];
14128         info.id = symbol_id;
14129         info.size = event->code_len;
14130         info.name.assign(event->name.str, event->name.str + event->name.len);
14131
14132         // And record it's location.
14133         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14134       }
14135       break;
14136
14137     case v8::JitCodeEvent::CODE_MOVED: {
14138         // We would like to never see code move that we haven't seen before,
14139         // but the code creation event does not happen until the line endings
14140         // have been calculated (this is so that we can report the line in the
14141         // script at which the function source is found, see
14142         // Compiler::RecordFunctionCompilation) and the line endings
14143         // calculations can cause a GC, which can move the newly created code
14144         // before its existence can be logged.
14145         SymbolLocationMap::iterator it(
14146             symbol_locations_.find(
14147                 reinterpret_cast<i::Address>(event->code_start)));
14148         if (it != symbol_locations_.end()) {
14149           // Found a symbol at this location, move it.
14150           SymbolInfo* info = it->second;
14151           symbol_locations_.erase(it);
14152           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14153                          info);
14154         }
14155       }
14156     default:
14157       break;
14158   }
14159 }
14160
14161 void SetFunctionEntryHookTest::OnEntryHook(
14162     uintptr_t function, uintptr_t return_addr_location) {
14163   // Get the function's code object.
14164   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14165       reinterpret_cast<i::Address>(function));
14166   CHECK(function_code != NULL);
14167
14168   // Then try and look up the caller's code object.
14169   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14170
14171   // Count the invocation.
14172   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14173   SymbolInfo* function_symbol =
14174       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14175   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14176
14177   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14178     // Check that we have a symbol for the "bar" function at the right location.
14179     SymbolLocationMap::iterator it(
14180         symbol_locations_.find(function_code->instruction_start()));
14181     CHECK(it != symbol_locations_.end());
14182   }
14183
14184   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14185     // Check that we have a symbol for "foo" at the right location.
14186     SymbolLocationMap::iterator it(
14187         symbol_locations_.find(function_code->instruction_start()));
14188     CHECK(it != symbol_locations_.end());
14189   }
14190 }
14191
14192
14193 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14194   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14195   // Do we have a direct hit on a symbol?
14196   if (it != symbol_locations_.end()) {
14197     if (it->first == addr)
14198       return it->second;
14199   }
14200
14201   // If not a direct hit, it'll have to be the previous symbol.
14202   if (it == symbol_locations_.begin())
14203     return NULL;
14204
14205   --it;
14206   size_t offs = addr - it->first;
14207   if (offs < it->second->size)
14208     return it->second;
14209
14210   return NULL;
14211 }
14212
14213
14214 int SetFunctionEntryHookTest::CountInvocations(
14215     const char* caller_name, const char* function_name) {
14216   InvocationMap::iterator it(invocations_.begin());
14217   int invocations = 0;
14218   for (; it != invocations_.end(); ++it) {
14219     SymbolInfo* caller = it->first.first;
14220     SymbolInfo* function = it->first.second;
14221
14222     // Filter out non-matching functions.
14223     if (function_name != NULL) {
14224       if (function->name.find(function_name) == std::string::npos)
14225         continue;
14226     }
14227
14228     // Filter out non-matching callers.
14229     if (caller_name != NULL) {
14230       if (caller == NULL)
14231         continue;
14232       if (caller->name.find(caller_name) == std::string::npos)
14233         continue;
14234     }
14235
14236     // It matches add the invocation count to the tally.
14237     invocations += it->second;
14238   }
14239
14240   return invocations;
14241 }
14242
14243
14244 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14245   v8::HandleScope outer(isolate);
14246   v8::Local<Context> env = Context::New(isolate);
14247   env->Enter();
14248
14249   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14250   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14251   env->Global()->Set(v8_str("obj"), t->NewInstance());
14252
14253   const char* script =
14254       "function bar() {\n"
14255       "  var sum = 0;\n"
14256       "  for (i = 0; i < 100; ++i)\n"
14257       "    sum = foo(i);\n"
14258       "  return sum;\n"
14259       "}\n"
14260       "function foo(i) { return i * i; }\n"
14261       "// Invoke on the runtime function.\n"
14262       "obj.asdf()";
14263   CompileRun(script);
14264   bar_func_ = i::Handle<i::JSFunction>::cast(
14265           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14266   DCHECK(!bar_func_.is_null());
14267
14268   foo_func_ =
14269       i::Handle<i::JSFunction>::cast(
14270            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14271   DCHECK(!foo_func_.is_null());
14272
14273   v8::Handle<v8::Value> value = CompileRun("bar();");
14274   CHECK(value->IsNumber());
14275   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14276
14277   // Test the optimized codegen path.
14278   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14279                      "bar();");
14280   CHECK(value->IsNumber());
14281   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14282
14283   env->Exit();
14284 }
14285
14286
14287 void SetFunctionEntryHookTest::RunTest() {
14288   // Work in a new isolate throughout.
14289   v8::Isolate::CreateParams create_params;
14290   create_params.entry_hook = EntryHook;
14291   create_params.code_event_handler = JitEvent;
14292   v8::Isolate* isolate = v8::Isolate::New(create_params);
14293
14294   {
14295     v8::Isolate::Scope scope(isolate);
14296
14297     RunLoopInNewEnv(isolate);
14298
14299     // Check the exepected invocation counts.
14300     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14301     CHECK_EQ(200, CountInvocations("bar", "foo"));
14302     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14303
14304     // Verify that we have an entry hook on some specific stubs.
14305     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14306     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14307     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14308   }
14309   isolate->Dispose();
14310
14311   Reset();
14312
14313   // Make sure a second isolate is unaffected by the previous entry hook.
14314   isolate = v8::Isolate::New();
14315   {
14316     v8::Isolate::Scope scope(isolate);
14317
14318     // Reset the entry count to zero and set the entry hook.
14319     RunLoopInNewEnv(isolate);
14320
14321     // We should record no invocations in this isolate.
14322     CHECK_EQ(0, static_cast<int>(invocations_.size()));
14323   }
14324
14325   isolate->Dispose();
14326 }
14327
14328
14329 TEST(SetFunctionEntryHook) {
14330   // FunctionEntryHook does not work well with experimental natives.
14331   // Experimental natives are compiled during snapshot deserialization.
14332   // This test breaks because InstallGetter (function from snapshot that
14333   // only gets called from experimental natives) is compiled with entry hooks.
14334   i::FLAG_allow_natives_syntax = true;
14335   i::FLAG_use_inlining = false;
14336
14337   SetFunctionEntryHookTest test;
14338   test.RunTest();
14339 }
14340
14341
14342 static i::HashMap* code_map = NULL;
14343 static i::HashMap* jitcode_line_info = NULL;
14344 static int saw_bar = 0;
14345 static int move_events = 0;
14346
14347
14348 static bool FunctionNameIs(const char* expected,
14349                            const v8::JitCodeEvent* event) {
14350   // Log lines for functions are of the general form:
14351   // "LazyCompile:<type><function_name>", where the type is one of
14352   // "*", "~" or "".
14353   static const char kPreamble[] = "LazyCompile:";
14354   static size_t kPreambleLen = sizeof(kPreamble) - 1;
14355
14356   if (event->name.len < sizeof(kPreamble) - 1 ||
14357       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14358     return false;
14359   }
14360
14361   const char* tail = event->name.str + kPreambleLen;
14362   size_t tail_len = event->name.len - kPreambleLen;
14363   size_t expected_len = strlen(expected);
14364   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14365     --tail_len;
14366     ++tail;
14367   }
14368
14369   // Check for tails like 'bar :1'.
14370   if (tail_len > expected_len + 2 &&
14371       tail[expected_len] == ' ' &&
14372       tail[expected_len + 1] == ':' &&
14373       tail[expected_len + 2] &&
14374       !strncmp(tail, expected, expected_len)) {
14375     return true;
14376   }
14377
14378   if (tail_len != expected_len)
14379     return false;
14380
14381   return strncmp(tail, expected, expected_len) == 0;
14382 }
14383
14384
14385 static void event_handler(const v8::JitCodeEvent* event) {
14386   CHECK(event != NULL);
14387   CHECK(code_map != NULL);
14388   CHECK(jitcode_line_info != NULL);
14389
14390   class DummyJitCodeLineInfo {
14391   };
14392
14393   switch (event->type) {
14394     case v8::JitCodeEvent::CODE_ADDED: {
14395         CHECK(event->code_start != NULL);
14396         CHECK_NE(0, static_cast<int>(event->code_len));
14397         CHECK(event->name.str != NULL);
14398         i::HashMap::Entry* entry =
14399             code_map->Lookup(event->code_start,
14400                              i::ComputePointerHash(event->code_start),
14401                              true);
14402         entry->value = reinterpret_cast<void*>(event->code_len);
14403
14404         if (FunctionNameIs("bar", event)) {
14405           ++saw_bar;
14406         }
14407       }
14408       break;
14409
14410     case v8::JitCodeEvent::CODE_MOVED: {
14411         uint32_t hash = i::ComputePointerHash(event->code_start);
14412         // We would like to never see code move that we haven't seen before,
14413         // but the code creation event does not happen until the line endings
14414         // have been calculated (this is so that we can report the line in the
14415         // script at which the function source is found, see
14416         // Compiler::RecordFunctionCompilation) and the line endings
14417         // calculations can cause a GC, which can move the newly created code
14418         // before its existence can be logged.
14419         i::HashMap::Entry* entry =
14420             code_map->Lookup(event->code_start, hash, false);
14421         if (entry != NULL) {
14422           ++move_events;
14423
14424           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14425           code_map->Remove(event->code_start, hash);
14426
14427           entry = code_map->Lookup(event->new_code_start,
14428                                    i::ComputePointerHash(event->new_code_start),
14429                                    true);
14430           CHECK(entry != NULL);
14431           entry->value = reinterpret_cast<void*>(event->code_len);
14432         }
14433       }
14434       break;
14435
14436     case v8::JitCodeEvent::CODE_REMOVED:
14437       // Object/code removal events are currently not dispatched from the GC.
14438       CHECK(false);
14439       break;
14440
14441     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14442     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14443     // record it in jitcode_line_info.
14444     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14445         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14446         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14447         temp_event->user_data = line_info;
14448         i::HashMap::Entry* entry =
14449             jitcode_line_info->Lookup(line_info,
14450                                       i::ComputePointerHash(line_info),
14451                                       true);
14452         entry->value = reinterpret_cast<void*>(line_info);
14453       }
14454       break;
14455     // For these two events, we will check whether the event->user_data
14456     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14457     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14458     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14459         CHECK(event->user_data != NULL);
14460         uint32_t hash = i::ComputePointerHash(event->user_data);
14461         i::HashMap::Entry* entry =
14462             jitcode_line_info->Lookup(event->user_data, hash, false);
14463         CHECK(entry != NULL);
14464         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14465       }
14466       break;
14467
14468     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14469         CHECK(event->user_data != NULL);
14470         uint32_t hash = i::ComputePointerHash(event->user_data);
14471         i::HashMap::Entry* entry =
14472             jitcode_line_info->Lookup(event->user_data, hash, false);
14473         CHECK(entry != NULL);
14474       }
14475       break;
14476
14477     default:
14478       // Impossible event.
14479       CHECK(false);
14480       break;
14481   }
14482 }
14483
14484
14485 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14486   i::FLAG_stress_compaction = true;
14487   i::FLAG_incremental_marking = false;
14488   if (i::FLAG_never_compact) return;
14489   const char* script =
14490     "function bar() {"
14491     "  var sum = 0;"
14492     "  for (i = 0; i < 100; ++i)"
14493     "    sum = foo(i);"
14494     "  return sum;"
14495     "}"
14496     "function foo(i) { return i * i; };"
14497     "bar();";
14498
14499   // Run this test in a new isolate to make sure we don't
14500   // have remnants of state from other code.
14501   v8::Isolate* isolate = v8::Isolate::New();
14502   isolate->Enter();
14503   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14504   i::Heap* heap = i_isolate->heap();
14505
14506   {
14507     v8::HandleScope scope(isolate);
14508     i::HashMap code(MatchPointers);
14509     code_map = &code;
14510
14511     i::HashMap lineinfo(MatchPointers);
14512     jitcode_line_info = &lineinfo;
14513
14514     saw_bar = 0;
14515     move_events = 0;
14516
14517     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14518
14519     // Generate new code objects sparsely distributed across several
14520     // different fragmented code-space pages.
14521     const int kIterations = 10;
14522     for (int i = 0; i < kIterations; ++i) {
14523       LocalContext env(isolate);
14524       i::AlwaysAllocateScope always_allocate(i_isolate);
14525       SimulateFullSpace(heap->code_space());
14526       CompileRun(script);
14527
14528       // Keep a strong reference to the code object in the handle scope.
14529       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14530           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14531       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14532           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14533
14534       // Clear the compilation cache to get more wastage.
14535       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14536     }
14537
14538     // Force code movement.
14539     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14540
14541     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14542
14543     CHECK_LE(kIterations, saw_bar);
14544     CHECK_LT(0, move_events);
14545
14546     code_map = NULL;
14547     jitcode_line_info = NULL;
14548   }
14549
14550   isolate->Exit();
14551   isolate->Dispose();
14552
14553   // Do this in a new isolate.
14554   isolate = v8::Isolate::New();
14555   isolate->Enter();
14556
14557   // Verify that we get callbacks for existing code objects when we
14558   // request enumeration of existing code.
14559   {
14560     v8::HandleScope scope(isolate);
14561     LocalContext env(isolate);
14562     CompileRun(script);
14563
14564     // Now get code through initial iteration.
14565     i::HashMap code(MatchPointers);
14566     code_map = &code;
14567
14568     i::HashMap lineinfo(MatchPointers);
14569     jitcode_line_info = &lineinfo;
14570
14571     isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14572                                     event_handler);
14573     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14574
14575     jitcode_line_info = NULL;
14576     // We expect that we got some events. Note that if we could get code removal
14577     // notifications, we could compare two collections, one created by listening
14578     // from the time of creation of an isolate, and the other by subscribing
14579     // with EnumExisting.
14580     CHECK_LT(0, code.occupancy());
14581
14582     code_map = NULL;
14583   }
14584
14585   isolate->Exit();
14586   isolate->Dispose();
14587 }
14588
14589
14590 THREADED_TEST(ExternalAllocatedMemory) {
14591   v8::Isolate* isolate = CcTest::isolate();
14592   v8::HandleScope outer(isolate);
14593   v8::Local<Context> env(Context::New(isolate));
14594   CHECK(!env.IsEmpty());
14595   const int64_t kSize = 1024*1024;
14596   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14597   CHECK_EQ(baseline + kSize,
14598            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14599   CHECK_EQ(baseline,
14600            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14601 }
14602
14603
14604 // Regression test for issue 54, object templates with internal fields
14605 // but no accessors or interceptors did not get their internal field
14606 // count set on instances.
14607 THREADED_TEST(Regress54) {
14608   LocalContext context;
14609   v8::Isolate* isolate = context->GetIsolate();
14610   v8::HandleScope outer(isolate);
14611   static v8::Persistent<v8::ObjectTemplate> templ;
14612   if (templ.IsEmpty()) {
14613     v8::EscapableHandleScope inner(isolate);
14614     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14615     local->SetInternalFieldCount(1);
14616     templ.Reset(isolate, inner.Escape(local));
14617   }
14618   v8::Handle<v8::Object> result =
14619       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14620   CHECK_EQ(1, result->InternalFieldCount());
14621 }
14622
14623
14624 // If part of the threaded tests, this test makes ThreadingTest fail
14625 // on mac.
14626 TEST(CatchStackOverflow) {
14627   LocalContext context;
14628   v8::HandleScope scope(context->GetIsolate());
14629   v8::TryCatch try_catch;
14630   v8::Handle<v8::Value> result = CompileRun(
14631     "function f() {"
14632     "  return f();"
14633     "}"
14634     ""
14635     "f();");
14636   CHECK(result.IsEmpty());
14637 }
14638
14639
14640 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14641                                     const char* resource_name,
14642                                     int line_offset) {
14643   v8::HandleScope scope(CcTest::isolate());
14644   v8::TryCatch try_catch;
14645   v8::Handle<v8::Value> result = script->Run();
14646   CHECK(result.IsEmpty());
14647   CHECK(try_catch.HasCaught());
14648   v8::Handle<v8::Message> message = try_catch.Message();
14649   CHECK(!message.IsEmpty());
14650   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14651   CHECK_EQ(91, message->GetStartPosition());
14652   CHECK_EQ(92, message->GetEndPosition());
14653   CHECK_EQ(2, message->GetStartColumn());
14654   CHECK_EQ(3, message->GetEndColumn());
14655   v8::String::Utf8Value line(message->GetSourceLine());
14656   CHECK_EQ("  throw 'nirk';", *line);
14657   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14658   CHECK_EQ(resource_name, *name);
14659 }
14660
14661
14662 THREADED_TEST(TryCatchSourceInfo) {
14663   LocalContext context;
14664   v8::HandleScope scope(context->GetIsolate());
14665   v8::Local<v8::String> source = v8_str(
14666       "function Foo() {\n"
14667       "  return Bar();\n"
14668       "}\n"
14669       "\n"
14670       "function Bar() {\n"
14671       "  return Baz();\n"
14672       "}\n"
14673       "\n"
14674       "function Baz() {\n"
14675       "  throw 'nirk';\n"
14676       "}\n"
14677       "\n"
14678       "Foo();\n");
14679
14680   const char* resource_name;
14681   v8::Handle<v8::Script> script;
14682   resource_name = "test.js";
14683   script = CompileWithOrigin(source, resource_name);
14684   CheckTryCatchSourceInfo(script, resource_name, 0);
14685
14686   resource_name = "test1.js";
14687   v8::ScriptOrigin origin1(
14688       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14689   script = v8::Script::Compile(source, &origin1);
14690   CheckTryCatchSourceInfo(script, resource_name, 0);
14691
14692   resource_name = "test2.js";
14693   v8::ScriptOrigin origin2(
14694       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14695       v8::Integer::New(context->GetIsolate(), 7));
14696   script = v8::Script::Compile(source, &origin2);
14697   CheckTryCatchSourceInfo(script, resource_name, 7);
14698 }
14699
14700
14701 THREADED_TEST(CompilationCache) {
14702   LocalContext context;
14703   v8::HandleScope scope(context->GetIsolate());
14704   v8::Handle<v8::String> source0 =
14705       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14706   v8::Handle<v8::String> source1 =
14707       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14708   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14709   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14710   v8::Handle<v8::Script> script2 =
14711       v8::Script::Compile(source0);  // different origin
14712   CHECK_EQ(1234, script0->Run()->Int32Value());
14713   CHECK_EQ(1234, script1->Run()->Int32Value());
14714   CHECK_EQ(1234, script2->Run()->Int32Value());
14715 }
14716
14717
14718 static void FunctionNameCallback(
14719     const v8::FunctionCallbackInfo<v8::Value>& args) {
14720   ApiTestFuzzer::Fuzz();
14721   args.GetReturnValue().Set(v8_num(42));
14722 }
14723
14724
14725 THREADED_TEST(CallbackFunctionName) {
14726   LocalContext context;
14727   v8::Isolate* isolate = context->GetIsolate();
14728   v8::HandleScope scope(isolate);
14729   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14730   t->Set(v8_str("asdf"),
14731          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14732   context->Global()->Set(v8_str("obj"), t->NewInstance());
14733   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14734   CHECK(value->IsString());
14735   v8::String::Utf8Value name(value);
14736   CHECK_EQ("asdf", *name);
14737 }
14738
14739
14740 THREADED_TEST(DateAccess) {
14741   LocalContext context;
14742   v8::HandleScope scope(context->GetIsolate());
14743   v8::Handle<v8::Value> date =
14744       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14745   CHECK(date->IsDate());
14746   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14747 }
14748
14749
14750 void CheckProperties(v8::Isolate* isolate,
14751                      v8::Handle<v8::Value> val,
14752                      int elmc,
14753                      const char* elmv[]) {
14754   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14755   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14756   CHECK_EQ(elmc, props->Length());
14757   for (int i = 0; i < elmc; i++) {
14758     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14759     CHECK_EQ(elmv[i], *elm);
14760   }
14761 }
14762
14763
14764 void CheckOwnProperties(v8::Isolate* isolate,
14765                         v8::Handle<v8::Value> val,
14766                         int elmc,
14767                         const char* elmv[]) {
14768   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14769   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14770   CHECK_EQ(elmc, props->Length());
14771   for (int i = 0; i < elmc; i++) {
14772     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14773     CHECK_EQ(elmv[i], *elm);
14774   }
14775 }
14776
14777
14778 THREADED_TEST(PropertyEnumeration) {
14779   LocalContext context;
14780   v8::Isolate* isolate = context->GetIsolate();
14781   v8::HandleScope scope(isolate);
14782   v8::Handle<v8::Value> obj = CompileRun(
14783       "var result = [];"
14784       "result[0] = {};"
14785       "result[1] = {a: 1, b: 2};"
14786       "result[2] = [1, 2, 3];"
14787       "var proto = {x: 1, y: 2, z: 3};"
14788       "var x = { __proto__: proto, w: 0, z: 1 };"
14789       "result[3] = x;"
14790       "result;");
14791   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14792   CHECK_EQ(4, elms->Length());
14793   int elmc0 = 0;
14794   const char** elmv0 = NULL;
14795   CheckProperties(
14796       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14797   CheckOwnProperties(
14798       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14799   int elmc1 = 2;
14800   const char* elmv1[] = {"a", "b"};
14801   CheckProperties(
14802       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14803   CheckOwnProperties(
14804       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14805   int elmc2 = 3;
14806   const char* elmv2[] = {"0", "1", "2"};
14807   CheckProperties(
14808       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14809   CheckOwnProperties(
14810       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14811   int elmc3 = 4;
14812   const char* elmv3[] = {"w", "z", "x", "y"};
14813   CheckProperties(
14814       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14815   int elmc4 = 2;
14816   const char* elmv4[] = {"w", "z"};
14817   CheckOwnProperties(
14818       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14819 }
14820
14821
14822 THREADED_TEST(PropertyEnumeration2) {
14823   LocalContext context;
14824   v8::Isolate* isolate = context->GetIsolate();
14825   v8::HandleScope scope(isolate);
14826   v8::Handle<v8::Value> obj = CompileRun(
14827       "var result = [];"
14828       "result[0] = {};"
14829       "result[1] = {a: 1, b: 2};"
14830       "result[2] = [1, 2, 3];"
14831       "var proto = {x: 1, y: 2, z: 3};"
14832       "var x = { __proto__: proto, w: 0, z: 1 };"
14833       "result[3] = x;"
14834       "result;");
14835   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14836   CHECK_EQ(4, elms->Length());
14837   int elmc0 = 0;
14838   const char** elmv0 = NULL;
14839   CheckProperties(isolate,
14840                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14841
14842   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14843   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14844   CHECK_EQ(0, props->Length());
14845   for (uint32_t i = 0; i < props->Length(); i++) {
14846     printf("p[%d]\n", i);
14847   }
14848 }
14849
14850 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14851                                   Local<Value> name,
14852                                   v8::AccessType type,
14853                                   Local<Value> data) {
14854   return type != v8::ACCESS_SET;
14855 }
14856
14857
14858 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14859                                     uint32_t key,
14860                                     v8::AccessType type,
14861                                     Local<Value> data) {
14862   return type != v8::ACCESS_SET;
14863 }
14864
14865
14866 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14867   LocalContext context;
14868   v8::Isolate* isolate = context->GetIsolate();
14869   v8::HandleScope scope(isolate);
14870   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14871   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14872                                  IndexedSetAccessBlocker);
14873   templ->Set(v8_str("x"), v8::True(isolate));
14874   Local<v8::Object> instance = templ->NewInstance();
14875   context->Global()->Set(v8_str("obj"), instance);
14876   Local<Value> value = CompileRun("obj.x");
14877   CHECK(value->BooleanValue());
14878 }
14879
14880
14881 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14882                                   Local<Value> name,
14883                                   v8::AccessType type,
14884                                   Local<Value> data) {
14885   return false;
14886 }
14887
14888
14889 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14890                                     uint32_t key,
14891                                     v8::AccessType type,
14892                                     Local<Value> data) {
14893   return false;
14894 }
14895
14896
14897
14898 THREADED_TEST(AccessChecksReenabledCorrectly) {
14899   LocalContext context;
14900   v8::Isolate* isolate = context->GetIsolate();
14901   v8::HandleScope scope(isolate);
14902   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14903   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14904                                  IndexedGetAccessBlocker);
14905   templ->Set(v8_str("a"), v8_str("a"));
14906   // Add more than 8 (see kMaxFastProperties) properties
14907   // so that the constructor will force copying map.
14908   // Cannot sprintf, gcc complains unsafety.
14909   char buf[4];
14910   for (char i = '0'; i <= '9' ; i++) {
14911     buf[0] = i;
14912     for (char j = '0'; j <= '9'; j++) {
14913       buf[1] = j;
14914       for (char k = '0'; k <= '9'; k++) {
14915         buf[2] = k;
14916         buf[3] = 0;
14917         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14918       }
14919     }
14920   }
14921
14922   Local<v8::Object> instance_1 = templ->NewInstance();
14923   context->Global()->Set(v8_str("obj_1"), instance_1);
14924
14925   Local<Value> value_1 = CompileRun("obj_1.a");
14926   CHECK(value_1.IsEmpty());
14927
14928   Local<v8::Object> instance_2 = templ->NewInstance();
14929   context->Global()->Set(v8_str("obj_2"), instance_2);
14930
14931   Local<Value> value_2 = CompileRun("obj_2.a");
14932   CHECK(value_2.IsEmpty());
14933 }
14934
14935
14936 // This tests that access check information remains on the global
14937 // object template when creating contexts.
14938 THREADED_TEST(AccessControlRepeatedContextCreation) {
14939   v8::Isolate* isolate = CcTest::isolate();
14940   v8::HandleScope handle_scope(isolate);
14941   v8::Handle<v8::ObjectTemplate> global_template =
14942       v8::ObjectTemplate::New(isolate);
14943   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14944                                            IndexedSetAccessBlocker);
14945   i::Handle<i::ObjectTemplateInfo> internal_template =
14946       v8::Utils::OpenHandle(*global_template);
14947   CHECK(!internal_template->constructor()->IsUndefined());
14948   i::Handle<i::FunctionTemplateInfo> constructor(
14949       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14950   CHECK(!constructor->access_check_info()->IsUndefined());
14951   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14952   CHECK(!context0.IsEmpty());
14953   CHECK(!constructor->access_check_info()->IsUndefined());
14954 }
14955
14956
14957 THREADED_TEST(TurnOnAccessCheck) {
14958   v8::Isolate* isolate = CcTest::isolate();
14959   v8::HandleScope handle_scope(isolate);
14960
14961   // Create an environment with access check to the global object disabled by
14962   // default.
14963   v8::Handle<v8::ObjectTemplate> global_template =
14964       v8::ObjectTemplate::New(isolate);
14965   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14966                                            IndexedGetAccessBlocker,
14967                                            v8::Handle<v8::Value>(),
14968                                            false);
14969   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14970   Context::Scope context_scope(context);
14971
14972   // Set up a property and a number of functions.
14973   context->Global()->Set(v8_str("a"), v8_num(1));
14974   CompileRun("function f1() {return a;}"
14975              "function f2() {return a;}"
14976              "function g1() {return h();}"
14977              "function g2() {return h();}"
14978              "function h() {return 1;}");
14979   Local<Function> f1 =
14980       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14981   Local<Function> f2 =
14982       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14983   Local<Function> g1 =
14984       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14985   Local<Function> g2 =
14986       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14987   Local<Function> h =
14988       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14989
14990   // Get the global object.
14991   v8::Handle<v8::Object> global = context->Global();
14992
14993   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14994   // uses the runtime system to retreive property a whereas f2 uses global load
14995   // inline cache.
14996   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14997   for (int i = 0; i < 4; i++) {
14998     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14999   }
15000
15001   // Same for g1 and g2.
15002   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15003   for (int i = 0; i < 4; i++) {
15004     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15005   }
15006
15007   // Detach the global and turn on access check.
15008   Local<Object> hidden_global = Local<Object>::Cast(
15009       context->Global()->GetPrototype());
15010   context->DetachGlobal();
15011   hidden_global->TurnOnAccessCheck();
15012
15013   // Failing access check results in exception.
15014   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15015   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15016   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15017   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15018
15019   // No failing access check when just returning a constant.
15020   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15021 }
15022
15023
15024 static const char* kPropertyA = "a";
15025 static const char* kPropertyH = "h";
15026
15027 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15028                                        Local<Value> name,
15029                                        v8::AccessType type,
15030                                        Local<Value> data) {
15031   if (!name->IsString()) return false;
15032   i::Handle<i::String> name_handle =
15033       v8::Utils::OpenHandle(String::Cast(*name));
15034   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15035       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
15036 }
15037
15038
15039 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
15040   v8::Isolate* isolate = CcTest::isolate();
15041   v8::HandleScope handle_scope(isolate);
15042
15043   // Create an environment with access check to the global object disabled by
15044   // default. When the registered access checker will block access to properties
15045   // a and h.
15046   v8::Handle<v8::ObjectTemplate> global_template =
15047      v8::ObjectTemplate::New(isolate);
15048   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15049                                            IndexedGetAccessBlocker,
15050                                            v8::Handle<v8::Value>(),
15051                                            false);
15052   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15053   Context::Scope context_scope(context);
15054
15055   // Set up a property and a number of functions.
15056   context->Global()->Set(v8_str("a"), v8_num(1));
15057   static const char* source = "function f1() {return a;}"
15058                               "function f2() {return a;}"
15059                               "function g1() {return h();}"
15060                               "function g2() {return h();}"
15061                               "function h() {return 1;}";
15062
15063   CompileRun(source);
15064   Local<Function> f1;
15065   Local<Function> f2;
15066   Local<Function> g1;
15067   Local<Function> g2;
15068   Local<Function> h;
15069   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15070   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15071   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15072   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15073   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15074
15075   // Get the global object.
15076   v8::Handle<v8::Object> global = context->Global();
15077
15078   // Call f1 one time and f2 a number of times. This will ensure that f1 still
15079   // uses the runtime system to retreive property a whereas f2 uses global load
15080   // inline cache.
15081   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15082   for (int i = 0; i < 4; i++) {
15083     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15084   }
15085
15086   // Same for g1 and g2.
15087   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15088   for (int i = 0; i < 4; i++) {
15089     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15090   }
15091
15092   // Detach the global and turn on access check now blocking access to property
15093   // a and function h.
15094   Local<Object> hidden_global = Local<Object>::Cast(
15095       context->Global()->GetPrototype());
15096   context->DetachGlobal();
15097   hidden_global->TurnOnAccessCheck();
15098
15099   // Failing access check results in exception.
15100   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15101   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15102   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15103   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15104
15105   // No failing access check when just returning a constant.
15106   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15107
15108   // Now compile the source again. And get the newly compiled functions, except
15109   // for h for which access is blocked.
15110   CompileRun(source);
15111   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15112   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15113   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15114   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15115   CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15116
15117   // Failing access check results in exception.
15118   v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15119   CHECK(result.IsEmpty());
15120   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15121   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15122   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15123   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15124 }
15125
15126
15127 // Tests that ScriptData can be serialized and deserialized.
15128 TEST(PreCompileSerialization) {
15129   v8::V8::Initialize();
15130   LocalContext env;
15131   v8::Isolate* isolate = env->GetIsolate();
15132   HandleScope handle_scope(isolate);
15133
15134   i::FLAG_min_preparse_length = 0;
15135   const char* script = "function foo(a) { return a+1; }";
15136   v8::ScriptCompiler::Source source(v8_str(script));
15137   v8::ScriptCompiler::Compile(isolate, &source,
15138                               v8::ScriptCompiler::kProduceParserCache);
15139   // Serialize.
15140   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15141   i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15142   i::MemCopy(serialized_data, cd->data, cd->length);
15143
15144   // Deserialize.
15145   i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15146
15147   // Verify that the original is the same as the deserialized.
15148   CHECK_EQ(cd->length, deserialized->length());
15149   CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15150
15151   delete deserialized;
15152   i::DeleteArray(serialized_data);
15153 }
15154
15155
15156 // This tests that we do not allow dictionary load/call inline caches
15157 // to use functions that have not yet been compiled.  The potential
15158 // problem of loading a function that has not yet been compiled can
15159 // arise because we share code between contexts via the compilation
15160 // cache.
15161 THREADED_TEST(DictionaryICLoadedFunction) {
15162   v8::HandleScope scope(CcTest::isolate());
15163   // Test LoadIC.
15164   for (int i = 0; i < 2; i++) {
15165     LocalContext context;
15166     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15167     context->Global()->Delete(v8_str("tmp"));
15168     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15169   }
15170   // Test CallIC.
15171   for (int i = 0; i < 2; i++) {
15172     LocalContext context;
15173     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15174     context->Global()->Delete(v8_str("tmp"));
15175     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15176   }
15177 }
15178
15179
15180 // Test that cross-context new calls use the context of the callee to
15181 // create the new JavaScript object.
15182 THREADED_TEST(CrossContextNew) {
15183   v8::Isolate* isolate = CcTest::isolate();
15184   v8::HandleScope scope(isolate);
15185   v8::Local<Context> context0 = Context::New(isolate);
15186   v8::Local<Context> context1 = Context::New(isolate);
15187
15188   // Allow cross-domain access.
15189   Local<String> token = v8_str("<security token>");
15190   context0->SetSecurityToken(token);
15191   context1->SetSecurityToken(token);
15192
15193   // Set an 'x' property on the Object prototype and define a
15194   // constructor function in context0.
15195   context0->Enter();
15196   CompileRun("Object.prototype.x = 42; function C() {};");
15197   context0->Exit();
15198
15199   // Call the constructor function from context0 and check that the
15200   // result has the 'x' property.
15201   context1->Enter();
15202   context1->Global()->Set(v8_str("other"), context0->Global());
15203   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15204   CHECK(value->IsInt32());
15205   CHECK_EQ(42, value->Int32Value());
15206   context1->Exit();
15207 }
15208
15209
15210 // Verify that we can clone an object
15211 TEST(ObjectClone) {
15212   LocalContext env;
15213   v8::Isolate* isolate = env->GetIsolate();
15214   v8::HandleScope scope(isolate);
15215
15216   const char* sample =
15217     "var rv = {};"      \
15218     "rv.alpha = 'hello';" \
15219     "rv.beta = 123;"     \
15220     "rv;";
15221
15222   // Create an object, verify basics.
15223   Local<Value> val = CompileRun(sample);
15224   CHECK(val->IsObject());
15225   Local<v8::Object> obj = val.As<v8::Object>();
15226   obj->Set(v8_str("gamma"), v8_str("cloneme"));
15227
15228   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15229   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15230   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15231
15232   // Clone it.
15233   Local<v8::Object> clone = obj->Clone();
15234   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15235   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15236   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15237
15238   // Set a property on the clone, verify each object.
15239   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15240   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15241   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15242 }
15243
15244
15245 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15246  public:
15247   explicit OneByteVectorResource(i::Vector<const char> vector)
15248       : data_(vector) {}
15249   virtual ~OneByteVectorResource() {}
15250   virtual size_t length() const { return data_.length(); }
15251   virtual const char* data() const { return data_.start(); }
15252  private:
15253   i::Vector<const char> data_;
15254 };
15255
15256
15257 class UC16VectorResource : public v8::String::ExternalStringResource {
15258  public:
15259   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15260       : data_(vector) {}
15261   virtual ~UC16VectorResource() {}
15262   virtual size_t length() const { return data_.length(); }
15263   virtual const i::uc16* data() const { return data_.start(); }
15264  private:
15265   i::Vector<const i::uc16> data_;
15266 };
15267
15268
15269 static void MorphAString(i::String* string,
15270                          OneByteVectorResource* one_byte_resource,
15271                          UC16VectorResource* uc16_resource) {
15272   CHECK(i::StringShape(string).IsExternal());
15273   if (string->IsOneByteRepresentation()) {
15274     // Check old map is not internalized or long.
15275     CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15276     // Morph external string to be TwoByte string.
15277     string->set_map(CcTest::heap()->external_string_map());
15278     i::ExternalTwoByteString* morphed =
15279          i::ExternalTwoByteString::cast(string);
15280     morphed->set_resource(uc16_resource);
15281   } else {
15282     // Check old map is not internalized or long.
15283     CHECK(string->map() == CcTest::heap()->external_string_map());
15284     // Morph external string to be one-byte string.
15285     string->set_map(CcTest::heap()->external_one_byte_string_map());
15286     i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15287     morphed->set_resource(one_byte_resource);
15288   }
15289 }
15290
15291
15292 // Test that we can still flatten a string if the components it is built up
15293 // from have been turned into 16 bit strings in the mean time.
15294 THREADED_TEST(MorphCompositeStringTest) {
15295   char utf_buffer[129];
15296   const char* c_string = "Now is the time for all good men"
15297                          " to come to the aid of the party";
15298   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15299   {
15300     LocalContext env;
15301     i::Factory* factory = CcTest::i_isolate()->factory();
15302     v8::HandleScope scope(env->GetIsolate());
15303     OneByteVectorResource one_byte_resource(
15304         i::Vector<const char>(c_string, i::StrLength(c_string)));
15305     UC16VectorResource uc16_resource(
15306         i::Vector<const uint16_t>(two_byte_string,
15307                                   i::StrLength(c_string)));
15308
15309     Local<String> lhs(
15310         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15311                                         &one_byte_resource).ToHandleChecked()));
15312     Local<String> rhs(
15313         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15314                                         &one_byte_resource).ToHandleChecked()));
15315
15316     env->Global()->Set(v8_str("lhs"), lhs);
15317     env->Global()->Set(v8_str("rhs"), rhs);
15318
15319     CompileRun(
15320         "var cons = lhs + rhs;"
15321         "var slice = lhs.substring(1, lhs.length - 1);"
15322         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15323
15324     CHECK(lhs->IsOneByte());
15325     CHECK(rhs->IsOneByte());
15326
15327     MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15328                  &uc16_resource);
15329     MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15330                  &uc16_resource);
15331
15332     // This should UTF-8 without flattening, since everything is ASCII.
15333     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15334     CHECK_EQ(128, cons->Utf8Length());
15335     int nchars = -1;
15336     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15337     CHECK_EQ(128, nchars);
15338     CHECK_EQ(0, strcmp(
15339         utf_buffer,
15340         "Now is the time for all good men to come to the aid of the party"
15341         "Now is the time for all good men to come to the aid of the party"));
15342
15343     // Now do some stuff to make sure the strings are flattened, etc.
15344     CompileRun(
15345         "/[^a-z]/.test(cons);"
15346         "/[^a-z]/.test(slice);"
15347         "/[^a-z]/.test(slice_on_cons);");
15348     const char* expected_cons =
15349         "Now is the time for all good men to come to the aid of the party"
15350         "Now is the time for all good men to come to the aid of the party";
15351     const char* expected_slice =
15352         "ow is the time for all good men to come to the aid of the part";
15353     const char* expected_slice_on_cons =
15354         "ow is the time for all good men to come to the aid of the party"
15355         "Now is the time for all good men to come to the aid of the part";
15356     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15357              env->Global()->Get(v8_str("cons")));
15358     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15359              env->Global()->Get(v8_str("slice")));
15360     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15361              env->Global()->Get(v8_str("slice_on_cons")));
15362   }
15363   i::DeleteArray(two_byte_string);
15364 }
15365
15366
15367 TEST(CompileExternalTwoByteSource) {
15368   LocalContext context;
15369   v8::HandleScope scope(context->GetIsolate());
15370
15371   // This is a very short list of sources, which currently is to check for a
15372   // regression caused by r2703.
15373   const char* one_byte_sources[] = {
15374       "0.5",
15375       "-0.5",   // This mainly testes PushBack in the Scanner.
15376       "--0.5",  // This mainly testes PushBack in the Scanner.
15377       NULL};
15378
15379   // Compile the sources as external two byte strings.
15380   for (int i = 0; one_byte_sources[i] != NULL; i++) {
15381     uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15382     TestResource* uc16_resource = new TestResource(two_byte_string);
15383     v8::Local<v8::String> source =
15384         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15385     v8::Script::Compile(source);
15386   }
15387 }
15388
15389
15390 #ifndef V8_INTERPRETED_REGEXP
15391
15392 struct RegExpInterruptionData {
15393   int loop_count;
15394   UC16VectorResource* string_resource;
15395   v8::Persistent<v8::String> string;
15396 } regexp_interruption_data;
15397
15398
15399 class RegExpInterruptionThread : public v8::base::Thread {
15400  public:
15401   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15402       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15403
15404   virtual void Run() {
15405     for (regexp_interruption_data.loop_count = 0;
15406          regexp_interruption_data.loop_count < 7;
15407          regexp_interruption_data.loop_count++) {
15408       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
15409       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15410     }
15411     v8::base::OS::Sleep(50);  // Wait a bit before terminating.
15412     v8::V8::TerminateExecution(isolate_);
15413   }
15414
15415  private:
15416   v8::Isolate* isolate_;
15417 };
15418
15419
15420 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15421   if (regexp_interruption_data.loop_count != 2) return;
15422   v8::HandleScope scope(CcTest::isolate());
15423   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15424       CcTest::isolate(), regexp_interruption_data.string);
15425   string->MakeExternal(regexp_interruption_data.string_resource);
15426 }
15427
15428
15429 // Test that RegExp execution can be interrupted.  Specifically, we test
15430 // * interrupting with GC
15431 // * turn the subject string from one-byte internal to two-byte external string
15432 // * force termination
15433 TEST(RegExpInterruption) {
15434   v8::HandleScope scope(CcTest::isolate());
15435   LocalContext env;
15436
15437   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15438
15439   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15440   static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15441   i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15442   v8::Local<v8::String> string = v8_str(one_byte_content);
15443
15444   CcTest::global()->Set(v8_str("a"), string);
15445   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15446   regexp_interruption_data.string_resource = new UC16VectorResource(
15447       i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15448
15449   v8::TryCatch try_catch;
15450   timeout_thread.Start();
15451
15452   CompileRun("/((a*)*)*b/.exec(a)");
15453   CHECK(try_catch.HasTerminated());
15454
15455   timeout_thread.Join();
15456
15457   regexp_interruption_data.string.Reset();
15458   i::DeleteArray(uc16_content);
15459 }
15460
15461 #endif  // V8_INTERPRETED_REGEXP
15462
15463
15464 // Test that we cannot set a property on the global object if there
15465 // is a read-only property in the prototype chain.
15466 TEST(ReadOnlyPropertyInGlobalProto) {
15467   v8::Isolate* isolate = CcTest::isolate();
15468   v8::HandleScope scope(isolate);
15469   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15470   LocalContext context(0, templ);
15471   v8::Handle<v8::Object> global = context->Global();
15472   v8::Handle<v8::Object> global_proto =
15473       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15474   global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15475                          v8::ReadOnly);
15476   global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15477                          v8::ReadOnly);
15478   // Check without 'eval' or 'with'.
15479   v8::Handle<v8::Value> res =
15480       CompileRun("function f() { x = 42; return x; }; f()");
15481   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15482   // Check with 'eval'.
15483   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15484   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15485   // Check with 'with'.
15486   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15487   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15488 }
15489
15490 static int force_set_set_count = 0;
15491 static int force_set_get_count = 0;
15492 bool pass_on_get = false;
15493
15494 static void ForceSetGetter(v8::Local<v8::String> name,
15495                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15496   force_set_get_count++;
15497   if (pass_on_get) {
15498     return;
15499   }
15500   info.GetReturnValue().Set(3);
15501 }
15502
15503 static void ForceSetSetter(v8::Local<v8::String> name,
15504                            v8::Local<v8::Value> value,
15505                            const v8::PropertyCallbackInfo<void>& info) {
15506   force_set_set_count++;
15507 }
15508
15509 static void ForceSetInterceptSetter(
15510     v8::Local<v8::String> name,
15511     v8::Local<v8::Value> value,
15512     const v8::PropertyCallbackInfo<v8::Value>& info) {
15513   force_set_set_count++;
15514   info.GetReturnValue().SetUndefined();
15515 }
15516
15517
15518 TEST(ForceSet) {
15519   force_set_get_count = 0;
15520   force_set_set_count = 0;
15521   pass_on_get = false;
15522
15523   v8::Isolate* isolate = CcTest::isolate();
15524   v8::HandleScope scope(isolate);
15525   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15526   v8::Handle<v8::String> access_property =
15527       v8::String::NewFromUtf8(isolate, "a");
15528   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15529   LocalContext context(NULL, templ);
15530   v8::Handle<v8::Object> global = context->Global();
15531
15532   // Ordinary properties
15533   v8::Handle<v8::String> simple_property =
15534       v8::String::NewFromUtf8(isolate, "p");
15535   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15536   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15537   // This should fail because the property is read-only
15538   global->Set(simple_property, v8::Int32::New(isolate, 5));
15539   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15540   // This should succeed even though the property is read-only
15541   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15542   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15543
15544   // Accessors
15545   CHECK_EQ(0, force_set_set_count);
15546   CHECK_EQ(0, force_set_get_count);
15547   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15548   // CHECK_EQ the property shouldn't override it, just call the setter
15549   // which in this case does nothing.
15550   global->Set(access_property, v8::Int32::New(isolate, 7));
15551   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15552   CHECK_EQ(1, force_set_set_count);
15553   CHECK_EQ(2, force_set_get_count);
15554   // Forcing the property to be set should override the accessor without
15555   // calling it
15556   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15557   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15558   CHECK_EQ(1, force_set_set_count);
15559   CHECK_EQ(2, force_set_get_count);
15560 }
15561
15562
15563 TEST(ForceSetWithInterceptor) {
15564   force_set_get_count = 0;
15565   force_set_set_count = 0;
15566   pass_on_get = false;
15567
15568   v8::Isolate* isolate = CcTest::isolate();
15569   v8::HandleScope scope(isolate);
15570   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15571   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15572   LocalContext context(NULL, templ);
15573   v8::Handle<v8::Object> global = context->Global();
15574
15575   v8::Handle<v8::String> some_property =
15576       v8::String::NewFromUtf8(isolate, "a");
15577   CHECK_EQ(0, force_set_set_count);
15578   CHECK_EQ(0, force_set_get_count);
15579   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15580   // Setting the property shouldn't override it, just call the setter
15581   // which in this case does nothing.
15582   global->Set(some_property, v8::Int32::New(isolate, 7));
15583   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15584   CHECK_EQ(1, force_set_set_count);
15585   CHECK_EQ(2, force_set_get_count);
15586   // Getting the property when the interceptor returns an empty handle
15587   // should yield undefined, since the property isn't present on the
15588   // object itself yet.
15589   pass_on_get = true;
15590   CHECK(global->Get(some_property)->IsUndefined());
15591   CHECK_EQ(1, force_set_set_count);
15592   CHECK_EQ(3, force_set_get_count);
15593   // Forcing the property to be set should cause the value to be
15594   // set locally without calling the interceptor.
15595   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15596   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15597   CHECK_EQ(1, force_set_set_count);
15598   CHECK_EQ(4, force_set_get_count);
15599   // Reenabling the interceptor should cause it to take precedence over
15600   // the property
15601   pass_on_get = false;
15602   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15603   CHECK_EQ(1, force_set_set_count);
15604   CHECK_EQ(5, force_set_get_count);
15605   // The interceptor should also work for other properties
15606   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15607                   ->Int32Value());
15608   CHECK_EQ(1, force_set_set_count);
15609   CHECK_EQ(6, force_set_get_count);
15610 }
15611
15612
15613 THREADED_TEST(ForceDelete) {
15614   v8::Isolate* isolate = CcTest::isolate();
15615   v8::HandleScope scope(isolate);
15616   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15617   LocalContext context(NULL, templ);
15618   v8::Handle<v8::Object> global = context->Global();
15619
15620   // Ordinary properties
15621   v8::Handle<v8::String> simple_property =
15622       v8::String::NewFromUtf8(isolate, "p");
15623   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15624   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15625   // This should fail because the property is dont-delete.
15626   CHECK(!global->Delete(simple_property));
15627   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15628   // This should succeed even though the property is dont-delete.
15629   CHECK(global->ForceDelete(simple_property));
15630   CHECK(global->Get(simple_property)->IsUndefined());
15631 }
15632
15633
15634 static int force_delete_interceptor_count = 0;
15635 static bool pass_on_delete = false;
15636
15637
15638 static void ForceDeleteDeleter(
15639     v8::Local<v8::String> name,
15640     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15641   force_delete_interceptor_count++;
15642   if (pass_on_delete) return;
15643   info.GetReturnValue().Set(true);
15644 }
15645
15646
15647 THREADED_TEST(ForceDeleteWithInterceptor) {
15648   force_delete_interceptor_count = 0;
15649   pass_on_delete = false;
15650
15651   v8::Isolate* isolate = CcTest::isolate();
15652   v8::HandleScope scope(isolate);
15653   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15654   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15655   LocalContext context(NULL, templ);
15656   v8::Handle<v8::Object> global = context->Global();
15657
15658   v8::Handle<v8::String> some_property =
15659       v8::String::NewFromUtf8(isolate, "a");
15660   global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15661                    v8::DontDelete);
15662
15663   // Deleting a property should get intercepted and nothing should
15664   // happen.
15665   CHECK_EQ(0, force_delete_interceptor_count);
15666   CHECK(global->Delete(some_property));
15667   CHECK_EQ(1, force_delete_interceptor_count);
15668   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15669   // Deleting the property when the interceptor returns an empty
15670   // handle should not delete the property since it is DontDelete.
15671   pass_on_delete = true;
15672   CHECK(!global->Delete(some_property));
15673   CHECK_EQ(2, force_delete_interceptor_count);
15674   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15675   // Forcing the property to be deleted should delete the value
15676   // without calling the interceptor.
15677   CHECK(global->ForceDelete(some_property));
15678   CHECK(global->Get(some_property)->IsUndefined());
15679   CHECK_EQ(2, force_delete_interceptor_count);
15680 }
15681
15682
15683 // Make sure that forcing a delete invalidates any IC stubs, so we
15684 // don't read the hole value.
15685 THREADED_TEST(ForceDeleteIC) {
15686   LocalContext context;
15687   v8::HandleScope scope(context->GetIsolate());
15688   // Create a DontDelete variable on the global object.
15689   CompileRun("this.__proto__ = { foo: 'horse' };"
15690              "var foo = 'fish';"
15691              "function f() { return foo.length; }");
15692   // Initialize the IC for foo in f.
15693   CompileRun("for (var i = 0; i < 4; i++) f();");
15694   // Make sure the value of foo is correct before the deletion.
15695   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15696   // Force the deletion of foo.
15697   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15698   // Make sure the value for foo is read from the prototype, and that
15699   // we don't get in trouble with reading the deleted cell value
15700   // sentinel.
15701   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15702 }
15703
15704
15705 TEST(InlinedFunctionAcrossContexts) {
15706   i::FLAG_allow_natives_syntax = true;
15707   v8::Isolate* isolate = CcTest::isolate();
15708   v8::HandleScope outer_scope(isolate);
15709   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15710   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15711   ctx1->Enter();
15712
15713   {
15714     v8::HandleScope inner_scope(CcTest::isolate());
15715     CompileRun("var G = 42; function foo() { return G; }");
15716     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15717     ctx2->Enter();
15718     ctx2->Global()->Set(v8_str("o"), foo);
15719     v8::Local<v8::Value> res = CompileRun(
15720         "function f() { return o(); }"
15721         "for (var i = 0; i < 10; ++i) f();"
15722         "%OptimizeFunctionOnNextCall(f);"
15723         "f();");
15724     CHECK_EQ(42, res->Int32Value());
15725     ctx2->Exit();
15726     v8::Handle<v8::String> G_property =
15727         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15728     CHECK(ctx1->Global()->ForceDelete(G_property));
15729     ctx2->Enter();
15730     ExpectString(
15731         "(function() {"
15732         "  try {"
15733         "    return f();"
15734         "  } catch(e) {"
15735         "    return e.toString();"
15736         "  }"
15737         " })()",
15738         "ReferenceError: G is not defined");
15739     ctx2->Exit();
15740     ctx1->Exit();
15741   }
15742 }
15743
15744
15745 static v8::Local<Context> calling_context0;
15746 static v8::Local<Context> calling_context1;
15747 static v8::Local<Context> calling_context2;
15748
15749
15750 // Check that the call to the callback is initiated in
15751 // calling_context2, the directly calling context is calling_context1
15752 // and the callback itself is in calling_context0.
15753 static void GetCallingContextCallback(
15754     const v8::FunctionCallbackInfo<v8::Value>& args) {
15755   ApiTestFuzzer::Fuzz();
15756   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15757   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15758   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15759   args.GetReturnValue().Set(42);
15760 }
15761
15762
15763 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15764   i::Isolate* isolate = CcTest::i_isolate();
15765   CHECK(isolate != NULL);
15766   CHECK(isolate->context() == NULL);
15767   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15768   v8::HandleScope scope(v8_isolate);
15769   // The following should not crash, but return an empty handle.
15770   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15771   CHECK(current.IsEmpty());
15772 }
15773
15774
15775 THREADED_TEST(GetCallingContext) {
15776   v8::Isolate* isolate = CcTest::isolate();
15777   v8::HandleScope scope(isolate);
15778
15779   Local<Context> calling_context0(Context::New(isolate));
15780   Local<Context> calling_context1(Context::New(isolate));
15781   Local<Context> calling_context2(Context::New(isolate));
15782   ::calling_context0 = calling_context0;
15783   ::calling_context1 = calling_context1;
15784   ::calling_context2 = calling_context2;
15785
15786   // Allow cross-domain access.
15787   Local<String> token = v8_str("<security token>");
15788   calling_context0->SetSecurityToken(token);
15789   calling_context1->SetSecurityToken(token);
15790   calling_context2->SetSecurityToken(token);
15791
15792   // Create an object with a C++ callback in context0.
15793   calling_context0->Enter();
15794   Local<v8::FunctionTemplate> callback_templ =
15795       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15796   calling_context0->Global()->Set(v8_str("callback"),
15797                                   callback_templ->GetFunction());
15798   calling_context0->Exit();
15799
15800   // Expose context0 in context1 and set up a function that calls the
15801   // callback function.
15802   calling_context1->Enter();
15803   calling_context1->Global()->Set(v8_str("context0"),
15804                                   calling_context0->Global());
15805   CompileRun("function f() { context0.callback() }");
15806   calling_context1->Exit();
15807
15808   // Expose context1 in context2 and call the callback function in
15809   // context0 indirectly through f in context1.
15810   calling_context2->Enter();
15811   calling_context2->Global()->Set(v8_str("context1"),
15812                                   calling_context1->Global());
15813   CompileRun("context1.f()");
15814   calling_context2->Exit();
15815   ::calling_context0.Clear();
15816   ::calling_context1.Clear();
15817   ::calling_context2.Clear();
15818 }
15819
15820
15821 // Check that a variable declaration with no explicit initialization
15822 // value does shadow an existing property in the prototype chain.
15823 THREADED_TEST(InitGlobalVarInProtoChain) {
15824   LocalContext context;
15825   v8::HandleScope scope(context->GetIsolate());
15826   // Introduce a variable in the prototype chain.
15827   CompileRun("__proto__.x = 42");
15828   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15829   CHECK(!result->IsUndefined());
15830   CHECK_EQ(43, result->Int32Value());
15831 }
15832
15833
15834 // Regression test for issue 398.
15835 // If a function is added to an object, creating a constant function
15836 // field, and the result is cloned, replacing the constant function on the
15837 // original should not affect the clone.
15838 // See http://code.google.com/p/v8/issues/detail?id=398
15839 THREADED_TEST(ReplaceConstantFunction) {
15840   LocalContext context;
15841   v8::Isolate* isolate = context->GetIsolate();
15842   v8::HandleScope scope(isolate);
15843   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15844   v8::Handle<v8::FunctionTemplate> func_templ =
15845       v8::FunctionTemplate::New(isolate);
15846   v8::Handle<v8::String> foo_string =
15847       v8::String::NewFromUtf8(isolate, "foo");
15848   obj->Set(foo_string, func_templ->GetFunction());
15849   v8::Handle<v8::Object> obj_clone = obj->Clone();
15850   obj_clone->Set(foo_string,
15851                  v8::String::NewFromUtf8(isolate, "Hello"));
15852   CHECK(!obj->Get(foo_string)->IsUndefined());
15853 }
15854
15855
15856 static void CheckElementValue(i::Isolate* isolate,
15857                               int expected,
15858                               i::Handle<i::Object> obj,
15859                               int offset) {
15860   i::Object* element =
15861       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15862   CHECK_EQ(expected, i::Smi::cast(element)->value());
15863 }
15864
15865
15866 THREADED_TEST(PixelArray) {
15867   LocalContext context;
15868   i::Isolate* isolate = CcTest::i_isolate();
15869   i::Factory* factory = isolate->factory();
15870   v8::HandleScope scope(context->GetIsolate());
15871   const int kElementCount = 260;
15872   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15873   i::Handle<i::ExternalUint8ClampedArray> pixels =
15874       i::Handle<i::ExternalUint8ClampedArray>::cast(
15875           factory->NewExternalArray(kElementCount,
15876                                     v8::kExternalUint8ClampedArray,
15877                                     pixel_data));
15878   // Force GC to trigger verification.
15879   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15880   for (int i = 0; i < kElementCount; i++) {
15881     pixels->set(i, i % 256);
15882   }
15883   // Force GC to trigger verification.
15884   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15885   for (int i = 0; i < kElementCount; i++) {
15886     CHECK_EQ(i % 256, pixels->get_scalar(i));
15887     CHECK_EQ(i % 256, pixel_data[i]);
15888   }
15889
15890   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15891   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15892   // Set the elements to be the pixels.
15893   // jsobj->set_elements(*pixels);
15894   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15895   CheckElementValue(isolate, 1, jsobj, 1);
15896   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15897   context->Global()->Set(v8_str("pixels"), obj);
15898   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15899   CHECK_EQ(1503, result->Int32Value());
15900   result = CompileRun("pixels[1]");
15901   CHECK_EQ(1, result->Int32Value());
15902
15903   result = CompileRun("var sum = 0;"
15904                       "for (var i = 0; i < 8; i++) {"
15905                       "  sum += pixels[i] = pixels[i] = -i;"
15906                       "}"
15907                       "sum;");
15908   CHECK_EQ(-28, result->Int32Value());
15909
15910   result = CompileRun("var sum = 0;"
15911                       "for (var i = 0; i < 8; i++) {"
15912                       "  sum += pixels[i] = pixels[i] = 0;"
15913                       "}"
15914                       "sum;");
15915   CHECK_EQ(0, result->Int32Value());
15916
15917   result = CompileRun("var sum = 0;"
15918                       "for (var i = 0; i < 8; i++) {"
15919                       "  sum += pixels[i] = pixels[i] = 255;"
15920                       "}"
15921                       "sum;");
15922   CHECK_EQ(8 * 255, result->Int32Value());
15923
15924   result = CompileRun("var sum = 0;"
15925                       "for (var i = 0; i < 8; i++) {"
15926                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15927                       "}"
15928                       "sum;");
15929   CHECK_EQ(2076, result->Int32Value());
15930
15931   result = CompileRun("var sum = 0;"
15932                       "for (var i = 0; i < 8; i++) {"
15933                       "  sum += pixels[i] = pixels[i] = i;"
15934                       "}"
15935                       "sum;");
15936   CHECK_EQ(28, result->Int32Value());
15937
15938   result = CompileRun("var sum = 0;"
15939                       "for (var i = 0; i < 8; i++) {"
15940                       "  sum += pixels[i];"
15941                       "}"
15942                       "sum;");
15943   CHECK_EQ(28, result->Int32Value());
15944
15945   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15946                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15947   i::Handle<i::Object> no_failure;
15948   no_failure = i::JSObject::SetElement(
15949       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15950   DCHECK(!no_failure.is_null());
15951   USE(no_failure);
15952   CheckElementValue(isolate, 2, jsobj, 1);
15953   *value.location() = i::Smi::FromInt(256);
15954   no_failure = i::JSObject::SetElement(
15955       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15956   DCHECK(!no_failure.is_null());
15957   USE(no_failure);
15958   CheckElementValue(isolate, 255, jsobj, 1);
15959   *value.location() = i::Smi::FromInt(-1);
15960   no_failure = i::JSObject::SetElement(
15961       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15962   DCHECK(!no_failure.is_null());
15963   USE(no_failure);
15964   CheckElementValue(isolate, 0, jsobj, 1);
15965
15966   result = CompileRun("for (var i = 0; i < 8; i++) {"
15967                       "  pixels[i] = (i * 65) - 109;"
15968                       "}"
15969                       "pixels[1] + pixels[6];");
15970   CHECK_EQ(255, result->Int32Value());
15971   CheckElementValue(isolate, 0, jsobj, 0);
15972   CheckElementValue(isolate, 0, jsobj, 1);
15973   CheckElementValue(isolate, 21, jsobj, 2);
15974   CheckElementValue(isolate, 86, jsobj, 3);
15975   CheckElementValue(isolate, 151, jsobj, 4);
15976   CheckElementValue(isolate, 216, jsobj, 5);
15977   CheckElementValue(isolate, 255, jsobj, 6);
15978   CheckElementValue(isolate, 255, jsobj, 7);
15979   result = CompileRun("var sum = 0;"
15980                       "for (var i = 0; i < 8; i++) {"
15981                       "  sum += pixels[i];"
15982                       "}"
15983                       "sum;");
15984   CHECK_EQ(984, result->Int32Value());
15985
15986   result = CompileRun("for (var i = 0; i < 8; i++) {"
15987                       "  pixels[i] = (i * 1.1);"
15988                       "}"
15989                       "pixels[1] + pixels[6];");
15990   CHECK_EQ(8, result->Int32Value());
15991   CheckElementValue(isolate, 0, jsobj, 0);
15992   CheckElementValue(isolate, 1, jsobj, 1);
15993   CheckElementValue(isolate, 2, jsobj, 2);
15994   CheckElementValue(isolate, 3, jsobj, 3);
15995   CheckElementValue(isolate, 4, jsobj, 4);
15996   CheckElementValue(isolate, 6, jsobj, 5);
15997   CheckElementValue(isolate, 7, jsobj, 6);
15998   CheckElementValue(isolate, 8, jsobj, 7);
15999
16000   result = CompileRun("for (var i = 0; i < 8; i++) {"
16001                       "  pixels[7] = undefined;"
16002                       "}"
16003                       "pixels[7];");
16004   CHECK_EQ(0, result->Int32Value());
16005   CheckElementValue(isolate, 0, jsobj, 7);
16006
16007   result = CompileRun("for (var i = 0; i < 8; i++) {"
16008                       "  pixels[6] = '2.3';"
16009                       "}"
16010                       "pixels[6];");
16011   CHECK_EQ(2, result->Int32Value());
16012   CheckElementValue(isolate, 2, jsobj, 6);
16013
16014   result = CompileRun("for (var i = 0; i < 8; i++) {"
16015                       "  pixels[5] = NaN;"
16016                       "}"
16017                       "pixels[5];");
16018   CHECK_EQ(0, result->Int32Value());
16019   CheckElementValue(isolate, 0, jsobj, 5);
16020
16021   result = CompileRun("for (var i = 0; i < 8; i++) {"
16022                       "  pixels[8] = Infinity;"
16023                       "}"
16024                       "pixels[8];");
16025   CHECK_EQ(255, result->Int32Value());
16026   CheckElementValue(isolate, 255, jsobj, 8);
16027
16028   result = CompileRun("for (var i = 0; i < 8; i++) {"
16029                       "  pixels[9] = -Infinity;"
16030                       "}"
16031                       "pixels[9];");
16032   CHECK_EQ(0, result->Int32Value());
16033   CheckElementValue(isolate, 0, jsobj, 9);
16034
16035   result = CompileRun("pixels[3] = 33;"
16036                       "delete pixels[3];"
16037                       "pixels[3];");
16038   CHECK_EQ(33, result->Int32Value());
16039
16040   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16041                       "pixels[2] = 12; pixels[3] = 13;"
16042                       "pixels.__defineGetter__('2',"
16043                       "function() { return 120; });"
16044                       "pixels[2];");
16045   CHECK_EQ(12, result->Int32Value());
16046
16047   result = CompileRun("var js_array = new Array(40);"
16048                       "js_array[0] = 77;"
16049                       "js_array;");
16050   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16051
16052   result = CompileRun("pixels[1] = 23;"
16053                       "pixels.__proto__ = [];"
16054                       "js_array.__proto__ = pixels;"
16055                       "js_array.concat(pixels);");
16056   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16057   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16058
16059   result = CompileRun("pixels[1] = 23;");
16060   CHECK_EQ(23, result->Int32Value());
16061
16062   // Test for index greater than 255.  Regression test for:
16063   // http://code.google.com/p/chromium/issues/detail?id=26337.
16064   result = CompileRun("pixels[256] = 255;");
16065   CHECK_EQ(255, result->Int32Value());
16066   result = CompileRun("var i = 0;"
16067                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16068                       "i");
16069   CHECK_EQ(255, result->Int32Value());
16070
16071   // Make sure that pixel array ICs recognize when a non-pixel array
16072   // is passed to it.
16073   result = CompileRun("function pa_load(p) {"
16074                       "  var sum = 0;"
16075                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16076                       "  return sum;"
16077                       "}"
16078                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16079                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16080                       "just_ints = new Object();"
16081                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16082                       "for (var i = 0; i < 10; ++i) {"
16083                       "  result = pa_load(just_ints);"
16084                       "}"
16085                       "result");
16086   CHECK_EQ(32640, result->Int32Value());
16087
16088   // Make sure that pixel array ICs recognize out-of-bound accesses.
16089   result = CompileRun("function pa_load(p, start) {"
16090                       "  var sum = 0;"
16091                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16092                       "  return sum;"
16093                       "}"
16094                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16095                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16096                       "for (var i = 0; i < 10; ++i) {"
16097                       "  result = pa_load(pixels,-10);"
16098                       "}"
16099                       "result");
16100   CHECK_EQ(0, result->Int32Value());
16101
16102   // Make sure that generic ICs properly handles a pixel array.
16103   result = CompileRun("function pa_load(p) {"
16104                       "  var sum = 0;"
16105                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16106                       "  return sum;"
16107                       "}"
16108                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16109                       "just_ints = new Object();"
16110                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16111                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16112                       "for (var i = 0; i < 10; ++i) {"
16113                       "  result = pa_load(pixels);"
16114                       "}"
16115                       "result");
16116   CHECK_EQ(32640, result->Int32Value());
16117
16118   // Make sure that generic load ICs recognize out-of-bound accesses in
16119   // pixel arrays.
16120   result = CompileRun("function pa_load(p, start) {"
16121                       "  var sum = 0;"
16122                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16123                       "  return sum;"
16124                       "}"
16125                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16126                       "just_ints = new Object();"
16127                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16128                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16129                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16130                       "for (var i = 0; i < 10; ++i) {"
16131                       "  result = pa_load(pixels,-10);"
16132                       "}"
16133                       "result");
16134   CHECK_EQ(0, result->Int32Value());
16135
16136   // Make sure that generic ICs properly handles other types than pixel
16137   // arrays (that the inlined fast pixel array test leaves the right information
16138   // in the right registers).
16139   result = CompileRun("function pa_load(p) {"
16140                       "  var sum = 0;"
16141                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16142                       "  return sum;"
16143                       "}"
16144                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16145                       "just_ints = new Object();"
16146                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16147                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16148                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16149                       "sparse_array = new Object();"
16150                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16151                       "sparse_array[1000000] = 3;"
16152                       "for (var i = 0; i < 10; ++i) {"
16153                       "  result = pa_load(sparse_array);"
16154                       "}"
16155                       "result");
16156   CHECK_EQ(32640, result->Int32Value());
16157
16158   // Make sure that pixel array store ICs clamp values correctly.
16159   result = CompileRun("function pa_store(p) {"
16160                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16161                       "}"
16162                       "pa_store(pixels);"
16163                       "var sum = 0;"
16164                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16165                       "sum");
16166   CHECK_EQ(48896, result->Int32Value());
16167
16168   // Make sure that pixel array stores correctly handle accesses outside
16169   // of the pixel array..
16170   result = CompileRun("function pa_store(p,start) {"
16171                       "  for (var j = 0; j < 256; j++) {"
16172                       "    p[j+start] = j * 2;"
16173                       "  }"
16174                       "}"
16175                       "pa_store(pixels,0);"
16176                       "pa_store(pixels,-128);"
16177                       "var sum = 0;"
16178                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16179                       "sum");
16180   CHECK_EQ(65280, result->Int32Value());
16181
16182   // Make sure that the generic store stub correctly handle accesses outside
16183   // of the pixel array..
16184   result = CompileRun("function pa_store(p,start) {"
16185                       "  for (var j = 0; j < 256; j++) {"
16186                       "    p[j+start] = j * 2;"
16187                       "  }"
16188                       "}"
16189                       "pa_store(pixels,0);"
16190                       "just_ints = new Object();"
16191                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16192                       "pa_store(just_ints, 0);"
16193                       "pa_store(pixels,-128);"
16194                       "var sum = 0;"
16195                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16196                       "sum");
16197   CHECK_EQ(65280, result->Int32Value());
16198
16199   // Make sure that the generic keyed store stub clamps pixel array values
16200   // correctly.
16201   result = CompileRun("function pa_store(p) {"
16202                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16203                       "}"
16204                       "pa_store(pixels);"
16205                       "just_ints = new Object();"
16206                       "pa_store(just_ints);"
16207                       "pa_store(pixels);"
16208                       "var sum = 0;"
16209                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16210                       "sum");
16211   CHECK_EQ(48896, result->Int32Value());
16212
16213   // Make sure that pixel array loads are optimized by crankshaft.
16214   result = CompileRun("function pa_load(p) {"
16215                       "  var sum = 0;"
16216                       "  for (var i=0; i<256; ++i) {"
16217                       "    sum += p[i];"
16218                       "  }"
16219                       "  return sum; "
16220                       "}"
16221                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16222                       "for (var i = 0; i < 5000; ++i) {"
16223                       "  result = pa_load(pixels);"
16224                       "}"
16225                       "result");
16226   CHECK_EQ(32640, result->Int32Value());
16227
16228   // Make sure that pixel array stores are optimized by crankshaft.
16229   result = CompileRun("function pa_init(p) {"
16230                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16231                       "}"
16232                       "function pa_load(p) {"
16233                       "  var sum = 0;"
16234                       "  for (var i=0; i<256; ++i) {"
16235                       "    sum += p[i];"
16236                       "  }"
16237                       "  return sum; "
16238                       "}"
16239                       "for (var i = 0; i < 5000; ++i) {"
16240                       "  pa_init(pixels);"
16241                       "}"
16242                       "result = pa_load(pixels);"
16243                       "result");
16244   CHECK_EQ(32640, result->Int32Value());
16245
16246   free(pixel_data);
16247 }
16248
16249
16250 THREADED_TEST(PixelArrayInfo) {
16251   LocalContext context;
16252   v8::HandleScope scope(context->GetIsolate());
16253   for (int size = 0; size < 100; size += 10) {
16254     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16255     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16256     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16257     CHECK(obj->HasIndexedPropertiesInPixelData());
16258     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16259     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16260     free(pixel_data);
16261   }
16262 }
16263
16264
16265 static void NotHandledIndexedPropertyGetter(
16266     uint32_t index,
16267     const v8::PropertyCallbackInfo<v8::Value>& info) {
16268   ApiTestFuzzer::Fuzz();
16269 }
16270
16271
16272 static void NotHandledIndexedPropertySetter(
16273     uint32_t index,
16274     Local<Value> value,
16275     const v8::PropertyCallbackInfo<v8::Value>& info) {
16276   ApiTestFuzzer::Fuzz();
16277 }
16278
16279
16280 THREADED_TEST(PixelArrayWithInterceptor) {
16281   LocalContext context;
16282   i::Factory* factory = CcTest::i_isolate()->factory();
16283   v8::Isolate* isolate = context->GetIsolate();
16284   v8::HandleScope scope(isolate);
16285   const int kElementCount = 260;
16286   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16287   i::Handle<i::ExternalUint8ClampedArray> pixels =
16288       i::Handle<i::ExternalUint8ClampedArray>::cast(
16289           factory->NewExternalArray(kElementCount,
16290                                     v8::kExternalUint8ClampedArray,
16291                                     pixel_data));
16292   for (int i = 0; i < kElementCount; i++) {
16293     pixels->set(i, i % 256);
16294   }
16295   v8::Handle<v8::ObjectTemplate> templ =
16296       v8::ObjectTemplate::New(context->GetIsolate());
16297   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16298                                    NotHandledIndexedPropertySetter);
16299   v8::Handle<v8::Object> obj = templ->NewInstance();
16300   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16301   context->Global()->Set(v8_str("pixels"), obj);
16302   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16303   CHECK_EQ(1, result->Int32Value());
16304   result = CompileRun("var sum = 0;"
16305                       "for (var i = 0; i < 8; i++) {"
16306                       "  sum += pixels[i] = pixels[i] = -i;"
16307                       "}"
16308                       "sum;");
16309   CHECK_EQ(-28, result->Int32Value());
16310   result = CompileRun("pixels.hasOwnProperty('1')");
16311   CHECK(result->BooleanValue());
16312   free(pixel_data);
16313 }
16314
16315
16316 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16317   switch (array_type) {
16318     case v8::kExternalInt8Array:
16319     case v8::kExternalUint8Array:
16320     case v8::kExternalUint8ClampedArray:
16321       return 1;
16322       break;
16323     case v8::kExternalInt16Array:
16324     case v8::kExternalUint16Array:
16325       return 2;
16326       break;
16327     case v8::kExternalInt32Array:
16328     case v8::kExternalUint32Array:
16329     case v8::kExternalFloat32Array:
16330       return 4;
16331       break;
16332     case v8::kExternalFloat64Array:
16333       return 8;
16334       break;
16335     default:
16336       UNREACHABLE();
16337       return -1;
16338   }
16339   UNREACHABLE();
16340   return -1;
16341 }
16342
16343
16344 template <class ExternalArrayClass, class ElementType>
16345 static void ObjectWithExternalArrayTestHelper(
16346     Handle<Context> context,
16347     v8::Handle<Object> obj,
16348     int element_count,
16349     v8::ExternalArrayType array_type,
16350     int64_t low, int64_t high) {
16351   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16352   i::Isolate* isolate = jsobj->GetIsolate();
16353   obj->Set(v8_str("field"),
16354            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16355   context->Global()->Set(v8_str("ext_array"), obj);
16356   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16357   CHECK_EQ(1503, result->Int32Value());
16358   result = CompileRun("ext_array[1]");
16359   CHECK_EQ(1, result->Int32Value());
16360
16361   // Check assigned smis
16362   result = CompileRun("for (var i = 0; i < 8; i++) {"
16363                       "  ext_array[i] = i;"
16364                       "}"
16365                       "var sum = 0;"
16366                       "for (var i = 0; i < 8; i++) {"
16367                       "  sum += ext_array[i];"
16368                       "}"
16369                       "sum;");
16370
16371   CHECK_EQ(28, result->Int32Value());
16372   // Check pass through of assigned smis
16373   result = CompileRun("var sum = 0;"
16374                       "for (var i = 0; i < 8; i++) {"
16375                       "  sum += ext_array[i] = ext_array[i] = -i;"
16376                       "}"
16377                       "sum;");
16378   CHECK_EQ(-28, result->Int32Value());
16379
16380
16381   // Check assigned smis in reverse order
16382   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16383                       "  ext_array[i] = i;"
16384                       "}"
16385                       "var sum = 0;"
16386                       "for (var i = 0; i < 8; i++) {"
16387                       "  sum += ext_array[i];"
16388                       "}"
16389                       "sum;");
16390   CHECK_EQ(28, result->Int32Value());
16391
16392   // Check pass through of assigned HeapNumbers
16393   result = CompileRun("var sum = 0;"
16394                       "for (var i = 0; i < 16; i+=2) {"
16395                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16396                       "}"
16397                       "sum;");
16398   CHECK_EQ(-28, result->Int32Value());
16399
16400   // Check assigned HeapNumbers
16401   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16402                       "  ext_array[i] = (i * 0.5);"
16403                       "}"
16404                       "var sum = 0;"
16405                       "for (var i = 0; i < 16; i+=2) {"
16406                       "  sum += ext_array[i];"
16407                       "}"
16408                       "sum;");
16409   CHECK_EQ(28, result->Int32Value());
16410
16411   // Check assigned HeapNumbers in reverse order
16412   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16413                       "  ext_array[i] = (i * 0.5);"
16414                       "}"
16415                       "var sum = 0;"
16416                       "for (var i = 0; i < 16; i+=2) {"
16417                       "  sum += ext_array[i];"
16418                       "}"
16419                       "sum;");
16420   CHECK_EQ(28, result->Int32Value());
16421
16422   i::ScopedVector<char> test_buf(1024);
16423
16424   // Check legal boundary conditions.
16425   // The repeated loads and stores ensure the ICs are exercised.
16426   const char* boundary_program =
16427       "var res = 0;"
16428       "for (var i = 0; i < 16; i++) {"
16429       "  ext_array[i] = %lld;"
16430       "  if (i > 8) {"
16431       "    res = ext_array[i];"
16432       "  }"
16433       "}"
16434       "res;";
16435   i::SNPrintF(test_buf,
16436               boundary_program,
16437               low);
16438   result = CompileRun(test_buf.start());
16439   CHECK_EQ(low, result->IntegerValue());
16440
16441   i::SNPrintF(test_buf,
16442               boundary_program,
16443               high);
16444   result = CompileRun(test_buf.start());
16445   CHECK_EQ(high, result->IntegerValue());
16446
16447   // Check misprediction of type in IC.
16448   result = CompileRun("var tmp_array = ext_array;"
16449                       "var sum = 0;"
16450                       "for (var i = 0; i < 8; i++) {"
16451                       "  tmp_array[i] = i;"
16452                       "  sum += tmp_array[i];"
16453                       "  if (i == 4) {"
16454                       "    tmp_array = {};"
16455                       "  }"
16456                       "}"
16457                       "sum;");
16458   // Force GC to trigger verification.
16459   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16460   CHECK_EQ(28, result->Int32Value());
16461
16462   // Make sure out-of-range loads do not throw.
16463   i::SNPrintF(test_buf,
16464               "var caught_exception = false;"
16465               "try {"
16466               "  ext_array[%d];"
16467               "} catch (e) {"
16468               "  caught_exception = true;"
16469               "}"
16470               "caught_exception;",
16471               element_count);
16472   result = CompileRun(test_buf.start());
16473   CHECK_EQ(false, result->BooleanValue());
16474
16475   // Make sure out-of-range stores do not throw.
16476   i::SNPrintF(test_buf,
16477               "var caught_exception = false;"
16478               "try {"
16479               "  ext_array[%d] = 1;"
16480               "} catch (e) {"
16481               "  caught_exception = true;"
16482               "}"
16483               "caught_exception;",
16484               element_count);
16485   result = CompileRun(test_buf.start());
16486   CHECK_EQ(false, result->BooleanValue());
16487
16488   // Check other boundary conditions, values and operations.
16489   result = CompileRun("for (var i = 0; i < 8; i++) {"
16490                       "  ext_array[7] = undefined;"
16491                       "}"
16492                       "ext_array[7];");
16493   CHECK_EQ(0, result->Int32Value());
16494   if (array_type == v8::kExternalFloat64Array ||
16495       array_type == v8::kExternalFloat32Array) {
16496     CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16497              static_cast<int>(
16498                  i::Object::GetElement(
16499                      isolate, jsobj, 7).ToHandleChecked()->Number()));
16500   } else {
16501     CheckElementValue(isolate, 0, jsobj, 7);
16502   }
16503
16504   result = CompileRun("for (var i = 0; i < 8; i++) {"
16505                       "  ext_array[6] = '2.3';"
16506                       "}"
16507                       "ext_array[6];");
16508   CHECK_EQ(2, result->Int32Value());
16509   CHECK_EQ(2,
16510            static_cast<int>(
16511                i::Object::GetElement(
16512                    isolate, jsobj, 6).ToHandleChecked()->Number()));
16513
16514   if (array_type != v8::kExternalFloat32Array &&
16515       array_type != v8::kExternalFloat64Array) {
16516     // Though the specification doesn't state it, be explicit about
16517     // converting NaNs and +/-Infinity to zero.
16518     result = CompileRun("for (var i = 0; i < 8; i++) {"
16519                         "  ext_array[i] = 5;"
16520                         "}"
16521                         "for (var i = 0; i < 8; i++) {"
16522                         "  ext_array[i] = NaN;"
16523                         "}"
16524                         "ext_array[5];");
16525     CHECK_EQ(0, result->Int32Value());
16526     CheckElementValue(isolate, 0, jsobj, 5);
16527
16528     result = CompileRun("for (var i = 0; i < 8; i++) {"
16529                         "  ext_array[i] = 5;"
16530                         "}"
16531                         "for (var i = 0; i < 8; i++) {"
16532                         "  ext_array[i] = Infinity;"
16533                         "}"
16534                         "ext_array[5];");
16535     int expected_value =
16536         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16537     CHECK_EQ(expected_value, result->Int32Value());
16538     CheckElementValue(isolate, expected_value, jsobj, 5);
16539
16540     result = CompileRun("for (var i = 0; i < 8; i++) {"
16541                         "  ext_array[i] = 5;"
16542                         "}"
16543                         "for (var i = 0; i < 8; i++) {"
16544                         "  ext_array[i] = -Infinity;"
16545                         "}"
16546                         "ext_array[5];");
16547     CHECK_EQ(0, result->Int32Value());
16548     CheckElementValue(isolate, 0, jsobj, 5);
16549
16550     // Check truncation behavior of integral arrays.
16551     const char* unsigned_data =
16552         "var source_data = [0.6, 10.6];"
16553         "var expected_results = [0, 10];";
16554     const char* signed_data =
16555         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16556         "var expected_results = [0, 10, 0, -10];";
16557     const char* pixel_data =
16558         "var source_data = [0.6, 10.6];"
16559         "var expected_results = [1, 11];";
16560     bool is_unsigned =
16561         (array_type == v8::kExternalUint8Array ||
16562          array_type == v8::kExternalUint16Array ||
16563          array_type == v8::kExternalUint32Array);
16564     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16565
16566     i::SNPrintF(test_buf,
16567                 "%s"
16568                 "var all_passed = true;"
16569                 "for (var i = 0; i < source_data.length; i++) {"
16570                 "  for (var j = 0; j < 8; j++) {"
16571                 "    ext_array[j] = source_data[i];"
16572                 "  }"
16573                 "  all_passed = all_passed &&"
16574                 "               (ext_array[5] == expected_results[i]);"
16575                 "}"
16576                 "all_passed;",
16577                 (is_unsigned ?
16578                      unsigned_data :
16579                      (is_pixel_data ? pixel_data : signed_data)));
16580     result = CompileRun(test_buf.start());
16581     CHECK_EQ(true, result->BooleanValue());
16582   }
16583
16584   i::Handle<ExternalArrayClass> array(
16585       ExternalArrayClass::cast(jsobj->elements()));
16586   for (int i = 0; i < element_count; i++) {
16587     array->set(i, static_cast<ElementType>(i));
16588   }
16589
16590   // Test complex assignments
16591   result = CompileRun("function ee_op_test_complex_func(sum) {"
16592                       " for (var i = 0; i < 40; ++i) {"
16593                       "   sum += (ext_array[i] += 1);"
16594                       "   sum += (ext_array[i] -= 1);"
16595                       " } "
16596                       " return sum;"
16597                       "}"
16598                       "sum=0;"
16599                       "for (var i=0;i<10000;++i) {"
16600                       "  sum=ee_op_test_complex_func(sum);"
16601                       "}"
16602                       "sum;");
16603   CHECK_EQ(16000000, result->Int32Value());
16604
16605   // Test count operations
16606   result = CompileRun("function ee_op_test_count_func(sum) {"
16607                       " for (var i = 0; i < 40; ++i) {"
16608                       "   sum += (++ext_array[i]);"
16609                       "   sum += (--ext_array[i]);"
16610                       " } "
16611                       " return sum;"
16612                       "}"
16613                       "sum=0;"
16614                       "for (var i=0;i<10000;++i) {"
16615                       "  sum=ee_op_test_count_func(sum);"
16616                       "}"
16617                       "sum;");
16618   CHECK_EQ(16000000, result->Int32Value());
16619
16620   result = CompileRun("ext_array[3] = 33;"
16621                       "delete ext_array[3];"
16622                       "ext_array[3];");
16623   CHECK_EQ(33, result->Int32Value());
16624
16625   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16626                       "ext_array[2] = 12; ext_array[3] = 13;"
16627                       "ext_array.__defineGetter__('2',"
16628                       "function() { return 120; });"
16629                       "ext_array[2];");
16630   CHECK_EQ(12, result->Int32Value());
16631
16632   result = CompileRun("var js_array = new Array(40);"
16633                       "js_array[0] = 77;"
16634                       "js_array;");
16635   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16636
16637   result = CompileRun("ext_array[1] = 23;"
16638                       "ext_array.__proto__ = [];"
16639                       "js_array.__proto__ = ext_array;"
16640                       "js_array.concat(ext_array);");
16641   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16642   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16643
16644   result = CompileRun("ext_array[1] = 23;");
16645   CHECK_EQ(23, result->Int32Value());
16646 }
16647
16648
16649 template <class FixedTypedArrayClass,
16650           i::ElementsKind elements_kind,
16651           class ElementType>
16652 static void FixedTypedArrayTestHelper(
16653     v8::ExternalArrayType array_type,
16654     ElementType low,
16655     ElementType high) {
16656   i::FLAG_allow_natives_syntax = true;
16657   LocalContext context;
16658   i::Isolate* isolate = CcTest::i_isolate();
16659   i::Factory* factory = isolate->factory();
16660   v8::HandleScope scope(context->GetIsolate());
16661   const int kElementCount = 260;
16662   i::Handle<FixedTypedArrayClass> fixed_array =
16663     i::Handle<FixedTypedArrayClass>::cast(
16664         factory->NewFixedTypedArray(kElementCount, array_type));
16665   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16666            fixed_array->map()->instance_type());
16667   CHECK_EQ(kElementCount, fixed_array->length());
16668   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16669   for (int i = 0; i < kElementCount; i++) {
16670     fixed_array->set(i, static_cast<ElementType>(i));
16671   }
16672   // Force GC to trigger verification.
16673   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16674   for (int i = 0; i < kElementCount; i++) {
16675     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16676              static_cast<int64_t>(fixed_array->get_scalar(i)));
16677   }
16678   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16679   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16680   i::Handle<i::Map> fixed_array_map =
16681       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16682   jsobj->set_map(*fixed_array_map);
16683   jsobj->set_elements(*fixed_array);
16684
16685   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16686       context.local(), obj, kElementCount, array_type,
16687       static_cast<int64_t>(low),
16688       static_cast<int64_t>(high));
16689 }
16690
16691
16692 THREADED_TEST(FixedUint8Array) {
16693   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16694     v8::kExternalUint8Array,
16695     0x0, 0xFF);
16696 }
16697
16698
16699 THREADED_TEST(FixedUint8ClampedArray) {
16700   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16701                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16702     v8::kExternalUint8ClampedArray,
16703     0x0, 0xFF);
16704 }
16705
16706
16707 THREADED_TEST(FixedInt8Array) {
16708   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16709     v8::kExternalInt8Array,
16710     -0x80, 0x7F);
16711 }
16712
16713
16714 THREADED_TEST(FixedUint16Array) {
16715   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16716     v8::kExternalUint16Array,
16717     0x0, 0xFFFF);
16718 }
16719
16720
16721 THREADED_TEST(FixedInt16Array) {
16722   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16723     v8::kExternalInt16Array,
16724     -0x8000, 0x7FFF);
16725 }
16726
16727
16728 THREADED_TEST(FixedUint32Array) {
16729   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16730     v8::kExternalUint32Array,
16731     0x0, UINT_MAX);
16732 }
16733
16734
16735 THREADED_TEST(FixedInt32Array) {
16736   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16737     v8::kExternalInt32Array,
16738     INT_MIN, INT_MAX);
16739 }
16740
16741
16742 THREADED_TEST(FixedFloat32Array) {
16743   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16744     v8::kExternalFloat32Array,
16745     -500, 500);
16746 }
16747
16748
16749 THREADED_TEST(FixedFloat64Array) {
16750   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16751     v8::kExternalFloat64Array,
16752     -500, 500);
16753 }
16754
16755
16756 template <class ExternalArrayClass, class ElementType>
16757 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16758                                     int64_t low,
16759                                     int64_t high) {
16760   LocalContext context;
16761   i::Isolate* isolate = CcTest::i_isolate();
16762   i::Factory* factory = isolate->factory();
16763   v8::HandleScope scope(context->GetIsolate());
16764   const int kElementCount = 40;
16765   int element_size = ExternalArrayElementSize(array_type);
16766   ElementType* array_data =
16767       static_cast<ElementType*>(malloc(kElementCount * element_size));
16768   i::Handle<ExternalArrayClass> array =
16769       i::Handle<ExternalArrayClass>::cast(
16770           factory->NewExternalArray(kElementCount, array_type, array_data));
16771   // Force GC to trigger verification.
16772   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16773   for (int i = 0; i < kElementCount; i++) {
16774     array->set(i, static_cast<ElementType>(i));
16775   }
16776   // Force GC to trigger verification.
16777   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16778   for (int i = 0; i < kElementCount; i++) {
16779     CHECK_EQ(static_cast<int64_t>(i),
16780              static_cast<int64_t>(array->get_scalar(i)));
16781     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16782   }
16783
16784   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16785   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16786   // Set the elements to be the external array.
16787   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16788                                                array_type,
16789                                                kElementCount);
16790   CHECK_EQ(1,
16791            static_cast<int>(
16792                i::Object::GetElement(
16793                    isolate, jsobj, 1).ToHandleChecked()->Number()));
16794
16795   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16796       context.local(), obj, kElementCount, array_type, low, high);
16797
16798   v8::Handle<v8::Value> result;
16799
16800   // Test more complex manipulations which cause eax to contain values
16801   // that won't be completely overwritten by loads from the arrays.
16802   // This catches bugs in the instructions used for the KeyedLoadIC
16803   // for byte and word types.
16804   {
16805     const int kXSize = 300;
16806     const int kYSize = 300;
16807     const int kLargeElementCount = kXSize * kYSize * 4;
16808     ElementType* large_array_data =
16809         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16810     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16811     // Set the elements to be the external array.
16812     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16813                                                        array_type,
16814                                                        kLargeElementCount);
16815     context->Global()->Set(v8_str("large_array"), large_obj);
16816     // Initialize contents of a few rows.
16817     for (int x = 0; x < 300; x++) {
16818       int row = 0;
16819       int offset = row * 300 * 4;
16820       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16821       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16822       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16823       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16824       row = 150;
16825       offset = row * 300 * 4;
16826       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16827       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16828       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16829       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16830       row = 298;
16831       offset = row * 300 * 4;
16832       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16833       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16834       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16835       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16836     }
16837     // The goal of the code below is to make "offset" large enough
16838     // that the computation of the index (which goes into eax) has
16839     // high bits set which will not be overwritten by a byte or short
16840     // load.
16841     result = CompileRun("var failed = false;"
16842                         "var offset = 0;"
16843                         "for (var i = 0; i < 300; i++) {"
16844                         "  if (large_array[4 * i] != 127 ||"
16845                         "      large_array[4 * i + 1] != 0 ||"
16846                         "      large_array[4 * i + 2] != 0 ||"
16847                         "      large_array[4 * i + 3] != 127) {"
16848                         "    failed = true;"
16849                         "  }"
16850                         "}"
16851                         "offset = 150 * 300 * 4;"
16852                         "for (var i = 0; i < 300; i++) {"
16853                         "  if (large_array[offset + 4 * i] != 127 ||"
16854                         "      large_array[offset + 4 * i + 1] != 0 ||"
16855                         "      large_array[offset + 4 * i + 2] != 0 ||"
16856                         "      large_array[offset + 4 * i + 3] != 127) {"
16857                         "    failed = true;"
16858                         "  }"
16859                         "}"
16860                         "offset = 298 * 300 * 4;"
16861                         "for (var i = 0; i < 300; i++) {"
16862                         "  if (large_array[offset + 4 * i] != 127 ||"
16863                         "      large_array[offset + 4 * i + 1] != 0 ||"
16864                         "      large_array[offset + 4 * i + 2] != 0 ||"
16865                         "      large_array[offset + 4 * i + 3] != 127) {"
16866                         "    failed = true;"
16867                         "  }"
16868                         "}"
16869                         "!failed;");
16870     CHECK_EQ(true, result->BooleanValue());
16871     free(large_array_data);
16872   }
16873
16874   // The "" property descriptor is overloaded to store information about
16875   // the external array. Ensure that setting and accessing the "" property
16876   // works (it should overwrite the information cached about the external
16877   // array in the DescriptorArray) in various situations.
16878   result = CompileRun("ext_array[''] = 23; ext_array['']");
16879   CHECK_EQ(23, result->Int32Value());
16880
16881   // Property "" set after the external array is associated with the object.
16882   {
16883     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16884     obj2->Set(v8_str("ee_test_field"),
16885               v8::Int32::New(context->GetIsolate(), 256));
16886     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16887     // Set the elements to be the external array.
16888     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16889                                                   array_type,
16890                                                   kElementCount);
16891     context->Global()->Set(v8_str("ext_array"), obj2);
16892     result = CompileRun("ext_array['']");
16893     CHECK_EQ(1503, result->Int32Value());
16894   }
16895
16896   // Property "" set after the external array is associated with the object.
16897   {
16898     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16899     obj2->Set(v8_str("ee_test_field_2"),
16900               v8::Int32::New(context->GetIsolate(), 256));
16901     // Set the elements to be the external array.
16902     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16903                                                   array_type,
16904                                                   kElementCount);
16905     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16906     context->Global()->Set(v8_str("ext_array"), obj2);
16907     result = CompileRun("ext_array['']");
16908     CHECK_EQ(1503, result->Int32Value());
16909   }
16910
16911   // Should reuse the map from previous test.
16912   {
16913     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16914     obj2->Set(v8_str("ee_test_field_2"),
16915               v8::Int32::New(context->GetIsolate(), 256));
16916     // Set the elements to be the external array. Should re-use the map
16917     // from previous test.
16918     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16919                                                   array_type,
16920                                                   kElementCount);
16921     context->Global()->Set(v8_str("ext_array"), obj2);
16922     result = CompileRun("ext_array['']");
16923   }
16924
16925   // Property "" is a constant function that shouldn't not be interfered with
16926   // when an external array is set.
16927   {
16928     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16929     // Start
16930     obj2->Set(v8_str("ee_test_field3"),
16931               v8::Int32::New(context->GetIsolate(), 256));
16932
16933     // Add a constant function to an object.
16934     context->Global()->Set(v8_str("ext_array"), obj2);
16935     result = CompileRun("ext_array[''] = function() {return 1503;};"
16936                         "ext_array['']();");
16937
16938     // Add an external array transition to the same map that
16939     // has the constant transition.
16940     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16941     obj3->Set(v8_str("ee_test_field3"),
16942               v8::Int32::New(context->GetIsolate(), 256));
16943     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16944                                                   array_type,
16945                                                   kElementCount);
16946     context->Global()->Set(v8_str("ext_array"), obj3);
16947   }
16948
16949   // If a external array transition is in the map, it should get clobbered
16950   // by a constant function.
16951   {
16952     // Add an external array transition.
16953     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16954     obj3->Set(v8_str("ee_test_field4"),
16955               v8::Int32::New(context->GetIsolate(), 256));
16956     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16957                                                   array_type,
16958                                                   kElementCount);
16959
16960     // Add a constant function to the same map that just got an external array
16961     // transition.
16962     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16963     obj2->Set(v8_str("ee_test_field4"),
16964               v8::Int32::New(context->GetIsolate(), 256));
16965     context->Global()->Set(v8_str("ext_array"), obj2);
16966     result = CompileRun("ext_array[''] = function() {return 1503;};"
16967                         "ext_array['']();");
16968   }
16969
16970   free(array_data);
16971 }
16972
16973
16974 THREADED_TEST(ExternalInt8Array) {
16975   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16976       v8::kExternalInt8Array,
16977       -128,
16978       127);
16979 }
16980
16981
16982 THREADED_TEST(ExternalUint8Array) {
16983   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16984       v8::kExternalUint8Array,
16985       0,
16986       255);
16987 }
16988
16989
16990 THREADED_TEST(ExternalUint8ClampedArray) {
16991   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16992       v8::kExternalUint8ClampedArray,
16993       0,
16994       255);
16995 }
16996
16997
16998 THREADED_TEST(ExternalInt16Array) {
16999   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17000       v8::kExternalInt16Array,
17001       -32768,
17002       32767);
17003 }
17004
17005
17006 THREADED_TEST(ExternalUint16Array) {
17007   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17008       v8::kExternalUint16Array,
17009       0,
17010       65535);
17011 }
17012
17013
17014 THREADED_TEST(ExternalInt32Array) {
17015   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17016       v8::kExternalInt32Array,
17017       INT_MIN,   // -2147483648
17018       INT_MAX);  //  2147483647
17019 }
17020
17021
17022 THREADED_TEST(ExternalUint32Array) {
17023   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17024       v8::kExternalUint32Array,
17025       0,
17026       UINT_MAX);  // 4294967295
17027 }
17028
17029
17030 THREADED_TEST(ExternalFloat32Array) {
17031   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17032       v8::kExternalFloat32Array,
17033       -500,
17034       500);
17035 }
17036
17037
17038 THREADED_TEST(ExternalFloat64Array) {
17039   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17040       v8::kExternalFloat64Array,
17041       -500,
17042       500);
17043 }
17044
17045
17046 THREADED_TEST(ExternalArrays) {
17047   TestExternalInt8Array();
17048   TestExternalUint8Array();
17049   TestExternalInt16Array();
17050   TestExternalUint16Array();
17051   TestExternalInt32Array();
17052   TestExternalUint32Array();
17053   TestExternalFloat32Array();
17054 }
17055
17056
17057 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
17058   LocalContext context;
17059   v8::HandleScope scope(context->GetIsolate());
17060   for (int size = 0; size < 100; size += 10) {
17061     int element_size = ExternalArrayElementSize(array_type);
17062     void* external_data = malloc(size * element_size);
17063     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17064     obj->SetIndexedPropertiesToExternalArrayData(
17065         external_data, array_type, size);
17066     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17067     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17068     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17069     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17070     free(external_data);
17071   }
17072 }
17073
17074
17075 THREADED_TEST(ExternalArrayInfo) {
17076   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17077   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17078   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17079   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17080   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17081   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17082   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17083   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17084   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
17085 }
17086
17087
17088 void ExtArrayLimitsHelper(v8::Isolate* isolate,
17089                           v8::ExternalArrayType array_type,
17090                           int size) {
17091   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17092   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17093   last_location = last_message = NULL;
17094   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17095   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17096   CHECK_NE(NULL, last_location);
17097   CHECK_NE(NULL, last_message);
17098 }
17099
17100
17101 TEST(ExternalArrayLimits) {
17102   LocalContext context;
17103   v8::Isolate* isolate = context->GetIsolate();
17104   v8::HandleScope scope(isolate);
17105   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17106   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17107   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17108   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17109   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17110   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17111   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17112   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17113   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17114   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17115   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17116   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17117   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17118   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17119   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17120   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17121   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17122   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17123 }
17124
17125
17126 template <typename ElementType, typename TypedArray,
17127           class ExternalArrayClass>
17128 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17129                           int64_t low, int64_t high) {
17130   const int kElementCount = 50;
17131
17132   i::ScopedVector<ElementType> backing_store(kElementCount+2);
17133
17134   LocalContext env;
17135   v8::Isolate* isolate = env->GetIsolate();
17136   v8::HandleScope handle_scope(isolate);
17137
17138   Local<v8::ArrayBuffer> ab =
17139       v8::ArrayBuffer::New(isolate, backing_store.start(),
17140                            (kElementCount + 2) * sizeof(ElementType));
17141   Local<TypedArray> ta =
17142       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17143   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17144   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17145   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17146   CHECK_EQ(kElementCount*sizeof(ElementType),
17147            static_cast<int>(ta->ByteLength()));
17148   CHECK_EQ(ab, ta->Buffer());
17149
17150   ElementType* data = backing_store.start() + 2;
17151   for (int i = 0; i < kElementCount; i++) {
17152     data[i] = static_cast<ElementType>(i);
17153   }
17154
17155   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17156       env.local(), ta, kElementCount, array_type, low, high);
17157 }
17158
17159
17160 THREADED_TEST(Uint8Array) {
17161   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17162       v8::kExternalUint8Array, 0, 0xFF);
17163 }
17164
17165
17166 THREADED_TEST(Int8Array) {
17167   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17168       v8::kExternalInt8Array, -0x80, 0x7F);
17169 }
17170
17171
17172 THREADED_TEST(Uint16Array) {
17173   TypedArrayTestHelper<uint16_t,
17174                        v8::Uint16Array,
17175                        i::ExternalUint16Array>(
17176       v8::kExternalUint16Array, 0, 0xFFFF);
17177 }
17178
17179
17180 THREADED_TEST(Int16Array) {
17181   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17182       v8::kExternalInt16Array, -0x8000, 0x7FFF);
17183 }
17184
17185
17186 THREADED_TEST(Uint32Array) {
17187   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17188       v8::kExternalUint32Array, 0, UINT_MAX);
17189 }
17190
17191
17192 THREADED_TEST(Int32Array) {
17193   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17194       v8::kExternalInt32Array, INT_MIN, INT_MAX);
17195 }
17196
17197
17198 THREADED_TEST(Float32Array) {
17199   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17200       v8::kExternalFloat32Array, -500, 500);
17201 }
17202
17203
17204 THREADED_TEST(Float64Array) {
17205   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17206       v8::kExternalFloat64Array, -500, 500);
17207 }
17208
17209
17210 THREADED_TEST(Uint8ClampedArray) {
17211   TypedArrayTestHelper<uint8_t,
17212                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17213       v8::kExternalUint8ClampedArray, 0, 0xFF);
17214 }
17215
17216
17217 THREADED_TEST(DataView) {
17218   const int kSize = 50;
17219
17220   i::ScopedVector<uint8_t> backing_store(kSize+2);
17221
17222   LocalContext env;
17223   v8::Isolate* isolate = env->GetIsolate();
17224   v8::HandleScope handle_scope(isolate);
17225
17226   Local<v8::ArrayBuffer> ab =
17227       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17228   Local<v8::DataView> dv =
17229       v8::DataView::New(ab, 2, kSize);
17230   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17231   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17232   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17233   CHECK_EQ(ab, dv->Buffer());
17234 }
17235
17236
17237 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17238   THREADED_TEST(Is##View) {                                                   \
17239     LocalContext env;                                                         \
17240     v8::Isolate* isolate = env->GetIsolate();                                 \
17241     v8::HandleScope handle_scope(isolate);                                    \
17242                                                                               \
17243     Handle<Value> result = CompileRun(                                        \
17244         "var ab = new ArrayBuffer(128);"                                      \
17245         "new " #View "(ab)");                                                 \
17246     CHECK(result->IsArrayBufferView());                                       \
17247     CHECK(result->Is##View());                                                \
17248     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17249   }
17250
17251 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17252 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17253 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17254 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17255 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17256 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17257 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17258 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17259 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17260 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17261
17262 #undef IS_ARRAY_BUFFER_VIEW_TEST
17263
17264
17265
17266 THREADED_TEST(ScriptContextDependence) {
17267   LocalContext c1;
17268   v8::HandleScope scope(c1->GetIsolate());
17269   const char *source = "foo";
17270   v8::Handle<v8::Script> dep = v8_compile(source);
17271   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17272       c1->GetIsolate(), source));
17273   v8::Handle<v8::UnboundScript> indep =
17274       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17275   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17276                     v8::Integer::New(c1->GetIsolate(), 100));
17277   CHECK_EQ(dep->Run()->Int32Value(), 100);
17278   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17279   LocalContext c2;
17280   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17281                     v8::Integer::New(c2->GetIsolate(), 101));
17282   CHECK_EQ(dep->Run()->Int32Value(), 100);
17283   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17284 }
17285
17286
17287 THREADED_TEST(StackTrace) {
17288   LocalContext context;
17289   v8::HandleScope scope(context->GetIsolate());
17290   v8::TryCatch try_catch;
17291   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17292   v8::Handle<v8::String> src =
17293       v8::String::NewFromUtf8(context->GetIsolate(), source);
17294   v8::Handle<v8::String> origin =
17295       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17296   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17297   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17298       ->BindToCurrentContext()
17299       ->Run();
17300   CHECK(try_catch.HasCaught());
17301   v8::String::Utf8Value stack(try_catch.StackTrace());
17302   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17303 }
17304
17305
17306 // Checks that a StackFrame has certain expected values.
17307 void checkStackFrame(const char* expected_script_name,
17308     const char* expected_func_name, int expected_line_number,
17309     int expected_column, bool is_eval, bool is_constructor,
17310     v8::Handle<v8::StackFrame> frame) {
17311   v8::HandleScope scope(CcTest::isolate());
17312   v8::String::Utf8Value func_name(frame->GetFunctionName());
17313   v8::String::Utf8Value script_name(frame->GetScriptName());
17314   if (*script_name == NULL) {
17315     // The situation where there is no associated script, like for evals.
17316     CHECK(expected_script_name == NULL);
17317   } else {
17318     CHECK(strstr(*script_name, expected_script_name) != NULL);
17319   }
17320   CHECK(strstr(*func_name, expected_func_name) != NULL);
17321   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17322   CHECK_EQ(expected_column, frame->GetColumn());
17323   CHECK_EQ(is_eval, frame->IsEval());
17324   CHECK_EQ(is_constructor, frame->IsConstructor());
17325 }
17326
17327
17328 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17329   v8::HandleScope scope(args.GetIsolate());
17330   const char* origin = "capture-stack-trace-test";
17331   const int kOverviewTest = 1;
17332   const int kDetailedTest = 2;
17333
17334   DCHECK(args.Length() == 1);
17335
17336   int testGroup = args[0]->Int32Value();
17337   if (testGroup == kOverviewTest) {
17338     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17339         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17340     CHECK_EQ(4, stackTrace->GetFrameCount());
17341     checkStackFrame(origin, "bar", 2, 10, false, false,
17342                     stackTrace->GetFrame(0));
17343     checkStackFrame(origin, "foo", 6, 3, false, false,
17344                     stackTrace->GetFrame(1));
17345     // This is the source string inside the eval which has the call to foo.
17346     checkStackFrame(NULL, "", 1, 5, false, false,
17347                     stackTrace->GetFrame(2));
17348     // The last frame is an anonymous function which has the initial eval call.
17349     checkStackFrame(origin, "", 8, 7, false, false,
17350                     stackTrace->GetFrame(3));
17351
17352     CHECK(stackTrace->AsArray()->IsArray());
17353   } else if (testGroup == kDetailedTest) {
17354     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17355         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17356     CHECK_EQ(4, stackTrace->GetFrameCount());
17357     checkStackFrame(origin, "bat", 4, 22, false, false,
17358                     stackTrace->GetFrame(0));
17359     checkStackFrame(origin, "baz", 8, 3, false, true,
17360                     stackTrace->GetFrame(1));
17361     bool is_eval = true;
17362     // This is the source string inside the eval which has the call to baz.
17363     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17364                     stackTrace->GetFrame(2));
17365     // The last frame is an anonymous function which has the initial eval call.
17366     checkStackFrame(origin, "", 10, 1, false, false,
17367                     stackTrace->GetFrame(3));
17368
17369     CHECK(stackTrace->AsArray()->IsArray());
17370   }
17371 }
17372
17373
17374 // Tests the C++ StackTrace API.
17375 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17376 // THREADED_TEST(CaptureStackTrace) {
17377 TEST(CaptureStackTrace) {
17378   v8::Isolate* isolate = CcTest::isolate();
17379   v8::HandleScope scope(isolate);
17380   v8::Handle<v8::String> origin =
17381       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17382   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17383   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17384              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17385   LocalContext context(0, templ);
17386
17387   // Test getting OVERVIEW information. Should ignore information that is not
17388   // script name, function name, line number, and column offset.
17389   const char *overview_source =
17390     "function bar() {\n"
17391     "  var y; AnalyzeStackInNativeCode(1);\n"
17392     "}\n"
17393     "function foo() {\n"
17394     "\n"
17395     "  bar();\n"
17396     "}\n"
17397     "var x;eval('new foo();');";
17398   v8::Handle<v8::String> overview_src =
17399       v8::String::NewFromUtf8(isolate, overview_source);
17400   v8::ScriptCompiler::Source script_source(overview_src,
17401                                            v8::ScriptOrigin(origin));
17402   v8::Handle<Value> overview_result(
17403       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17404           ->BindToCurrentContext()
17405           ->Run());
17406   CHECK(!overview_result.IsEmpty());
17407   CHECK(overview_result->IsObject());
17408
17409   // Test getting DETAILED information.
17410   const char *detailed_source =
17411     "function bat() {AnalyzeStackInNativeCode(2);\n"
17412     "}\n"
17413     "\n"
17414     "function baz() {\n"
17415     "  bat();\n"
17416     "}\n"
17417     "eval('new baz();');";
17418   v8::Handle<v8::String> detailed_src =
17419       v8::String::NewFromUtf8(isolate, detailed_source);
17420   // Make the script using a non-zero line and column offset.
17421   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17422   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17423   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17424   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17425   v8::Handle<v8::UnboundScript> detailed_script(
17426       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17427   v8::Handle<Value> detailed_result(
17428       detailed_script->BindToCurrentContext()->Run());
17429   CHECK(!detailed_result.IsEmpty());
17430   CHECK(detailed_result->IsObject());
17431 }
17432
17433
17434 static void StackTraceForUncaughtExceptionListener(
17435     v8::Handle<v8::Message> message,
17436     v8::Handle<Value>) {
17437   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17438   CHECK_EQ(2, stack_trace->GetFrameCount());
17439   checkStackFrame("origin", "foo", 2, 3, false, false,
17440                   stack_trace->GetFrame(0));
17441   checkStackFrame("origin", "bar", 5, 3, false, false,
17442                   stack_trace->GetFrame(1));
17443 }
17444
17445
17446 TEST(CaptureStackTraceForUncaughtException) {
17447   report_count = 0;
17448   LocalContext env;
17449   v8::HandleScope scope(env->GetIsolate());
17450   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17451   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17452
17453   CompileRunWithOrigin(
17454       "function foo() {\n"
17455       "  throw 1;\n"
17456       "};\n"
17457       "function bar() {\n"
17458       "  foo();\n"
17459       "};",
17460       "origin");
17461   v8::Local<v8::Object> global = env->Global();
17462   Local<Value> trouble = global->Get(v8_str("bar"));
17463   CHECK(trouble->IsFunction());
17464   Function::Cast(*trouble)->Call(global, 0, NULL);
17465   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17466   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17467 }
17468
17469
17470 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17471   LocalContext env;
17472   v8::HandleScope scope(env->GetIsolate());
17473   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17474                                                     1024,
17475                                                     v8::StackTrace::kDetailed);
17476
17477   CompileRun(
17478       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17479       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17480       "    'isConstructor'];\n"
17481       "for (var i = 0; i < setters.length; i++) {\n"
17482       "  var prop = setters[i];\n"
17483       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17484       "}\n");
17485   CompileRun("throw 'exception';");
17486   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17487 }
17488
17489
17490 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17491                                      v8::Handle<v8::Value> data) {
17492   // Use the frame where JavaScript is called from.
17493   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17494   CHECK(!stack_trace.IsEmpty());
17495   int frame_count = stack_trace->GetFrameCount();
17496   CHECK_EQ(3, frame_count);
17497   int line_number[] = {1, 2, 5};
17498   for (int i = 0; i < frame_count; i++) {
17499     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17500   }
17501 }
17502
17503
17504 // Test that we only return the stack trace at the site where the exception
17505 // is first thrown (not where it is rethrown).
17506 TEST(RethrowStackTrace) {
17507   LocalContext env;
17508   v8::HandleScope scope(env->GetIsolate());
17509   // We make sure that
17510   // - the stack trace of the ReferenceError in g() is reported.
17511   // - the stack trace is not overwritten when e1 is rethrown by t().
17512   // - the stack trace of e2 does not overwrite that of e1.
17513   const char* source =
17514       "function g() { error; }          \n"
17515       "function f() { g(); }            \n"
17516       "function t(e) { throw e; }       \n"
17517       "try {                            \n"
17518       "  f();                           \n"
17519       "} catch (e1) {                   \n"
17520       "  try {                          \n"
17521       "    error;                       \n"
17522       "  } catch (e2) {                 \n"
17523       "    t(e1);                       \n"
17524       "  }                              \n"
17525       "}                                \n";
17526   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17527   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17528   CompileRun(source);
17529   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17530   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17531 }
17532
17533
17534 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17535                                               v8::Handle<v8::Value> data) {
17536   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17537   CHECK(!stack_trace.IsEmpty());
17538   int frame_count = stack_trace->GetFrameCount();
17539   CHECK_EQ(2, frame_count);
17540   int line_number[] = {3, 7};
17541   for (int i = 0; i < frame_count; i++) {
17542     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17543   }
17544 }
17545
17546
17547 // Test that we do not recognize identity for primitive exceptions.
17548 TEST(RethrowPrimitiveStackTrace) {
17549   LocalContext env;
17550   v8::HandleScope scope(env->GetIsolate());
17551   // We do not capture stack trace for non Error objects on creation time.
17552   // Instead, we capture the stack trace on last throw.
17553   const char* source =
17554       "function g() { throw 404; }      \n"
17555       "function f() { g(); }            \n"
17556       "function t(e) { throw e; }       \n"
17557       "try {                            \n"
17558       "  f();                           \n"
17559       "} catch (e1) {                   \n"
17560       "  t(e1)                          \n"
17561       "}                                \n";
17562   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17563   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17564   CompileRun(source);
17565   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17566   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17567 }
17568
17569
17570 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17571                                               v8::Handle<v8::Value> data) {
17572   // Use the frame where JavaScript is called from.
17573   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17574   CHECK(!stack_trace.IsEmpty());
17575   CHECK_EQ(1, stack_trace->GetFrameCount());
17576   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17577 }
17578
17579
17580 // Test that the stack trace is captured when the error object is created and
17581 // not where it is thrown.
17582 TEST(RethrowExistingStackTrace) {
17583   LocalContext env;
17584   v8::HandleScope scope(env->GetIsolate());
17585   const char* source =
17586       "var e = new Error();           \n"
17587       "throw e;                       \n";
17588   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17589   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17590   CompileRun(source);
17591   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17592   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17593 }
17594
17595
17596 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17597                                                v8::Handle<v8::Value> data) {
17598   // Use the frame where JavaScript is called from.
17599   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17600   CHECK(!stack_trace.IsEmpty());
17601   CHECK_EQ(1, stack_trace->GetFrameCount());
17602   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17603 }
17604
17605
17606 // Test that the stack trace is captured where the bogus Error object is thrown.
17607 TEST(RethrowBogusErrorStackTrace) {
17608   LocalContext env;
17609   v8::HandleScope scope(env->GetIsolate());
17610   const char* source =
17611       "var e = {__proto__: new Error()} \n"
17612       "throw e;                         \n";
17613   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17614   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17615   CompileRun(source);
17616   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17617   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17618 }
17619
17620
17621 void AnalyzeStackOfEvalWithSourceURL(
17622     const v8::FunctionCallbackInfo<v8::Value>& args) {
17623   v8::HandleScope scope(args.GetIsolate());
17624   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17625       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17626   CHECK_EQ(5, stackTrace->GetFrameCount());
17627   v8::Handle<v8::String> url = v8_str("eval_url");
17628   for (int i = 0; i < 3; i++) {
17629     v8::Handle<v8::String> name =
17630         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17631     CHECK(!name.IsEmpty());
17632     CHECK_EQ(url, name);
17633   }
17634 }
17635
17636
17637 TEST(SourceURLInStackTrace) {
17638   v8::Isolate* isolate = CcTest::isolate();
17639   v8::HandleScope scope(isolate);
17640   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17641   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17642              v8::FunctionTemplate::New(isolate,
17643                                        AnalyzeStackOfEvalWithSourceURL));
17644   LocalContext context(0, templ);
17645
17646   const char *source =
17647     "function outer() {\n"
17648     "function bar() {\n"
17649     "  AnalyzeStackOfEvalWithSourceURL();\n"
17650     "}\n"
17651     "function foo() {\n"
17652     "\n"
17653     "  bar();\n"
17654     "}\n"
17655     "foo();\n"
17656     "}\n"
17657     "eval('(' + outer +')()%s');";
17658
17659   i::ScopedVector<char> code(1024);
17660   i::SNPrintF(code, source, "//# sourceURL=eval_url");
17661   CHECK(CompileRun(code.start())->IsUndefined());
17662   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17663   CHECK(CompileRun(code.start())->IsUndefined());
17664 }
17665
17666
17667 static int scriptIdInStack[2];
17668
17669 void AnalyzeScriptIdInStack(
17670     const v8::FunctionCallbackInfo<v8::Value>& args) {
17671   v8::HandleScope scope(args.GetIsolate());
17672   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17673       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17674   CHECK_EQ(2, stackTrace->GetFrameCount());
17675   for (int i = 0; i < 2; i++) {
17676     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17677   }
17678 }
17679
17680
17681 TEST(ScriptIdInStackTrace) {
17682   v8::Isolate* isolate = CcTest::isolate();
17683   v8::HandleScope scope(isolate);
17684   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17685   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17686              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17687   LocalContext context(0, templ);
17688
17689   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17690     isolate,
17691     "function foo() {\n"
17692     "  AnalyzeScriptIdInStack();"
17693     "}\n"
17694     "foo();\n");
17695   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17696   script->Run();
17697   for (int i = 0; i < 2; i++) {
17698     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17699     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17700   }
17701 }
17702
17703
17704 void AnalyzeStackOfInlineScriptWithSourceURL(
17705     const v8::FunctionCallbackInfo<v8::Value>& args) {
17706   v8::HandleScope scope(args.GetIsolate());
17707   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17708       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17709   CHECK_EQ(4, stackTrace->GetFrameCount());
17710   v8::Handle<v8::String> url = v8_str("url");
17711   for (int i = 0; i < 3; i++) {
17712     v8::Handle<v8::String> name =
17713         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17714     CHECK(!name.IsEmpty());
17715     CHECK_EQ(url, name);
17716   }
17717 }
17718
17719
17720 TEST(InlineScriptWithSourceURLInStackTrace) {
17721   v8::Isolate* isolate = CcTest::isolate();
17722   v8::HandleScope scope(isolate);
17723   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17724   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17725              v8::FunctionTemplate::New(
17726                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17727   LocalContext context(0, templ);
17728
17729   const char *source =
17730     "function outer() {\n"
17731     "function bar() {\n"
17732     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17733     "}\n"
17734     "function foo() {\n"
17735     "\n"
17736     "  bar();\n"
17737     "}\n"
17738     "foo();\n"
17739     "}\n"
17740     "outer()\n%s";
17741
17742   i::ScopedVector<char> code(1024);
17743   i::SNPrintF(code, source, "//# sourceURL=source_url");
17744   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17745   i::SNPrintF(code, source, "//@ sourceURL=source_url");
17746   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17747 }
17748
17749
17750 void AnalyzeStackOfDynamicScriptWithSourceURL(
17751     const v8::FunctionCallbackInfo<v8::Value>& args) {
17752   v8::HandleScope scope(args.GetIsolate());
17753   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17754       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17755   CHECK_EQ(4, stackTrace->GetFrameCount());
17756   v8::Handle<v8::String> url = v8_str("source_url");
17757   for (int i = 0; i < 3; i++) {
17758     v8::Handle<v8::String> name =
17759         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17760     CHECK(!name.IsEmpty());
17761     CHECK_EQ(url, name);
17762   }
17763 }
17764
17765
17766 TEST(DynamicWithSourceURLInStackTrace) {
17767   v8::Isolate* isolate = CcTest::isolate();
17768   v8::HandleScope scope(isolate);
17769   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17770   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17771              v8::FunctionTemplate::New(
17772                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17773   LocalContext context(0, templ);
17774
17775   const char *source =
17776     "function outer() {\n"
17777     "function bar() {\n"
17778     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17779     "}\n"
17780     "function foo() {\n"
17781     "\n"
17782     "  bar();\n"
17783     "}\n"
17784     "foo();\n"
17785     "}\n"
17786     "outer()\n%s";
17787
17788   i::ScopedVector<char> code(1024);
17789   i::SNPrintF(code, source, "//# sourceURL=source_url");
17790   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17791   i::SNPrintF(code, source, "//@ sourceURL=source_url");
17792   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17793 }
17794
17795
17796 TEST(DynamicWithSourceURLInStackTraceString) {
17797   LocalContext context;
17798   v8::HandleScope scope(context->GetIsolate());
17799
17800   const char *source =
17801     "function outer() {\n"
17802     "  function foo() {\n"
17803     "    FAIL.FAIL;\n"
17804     "  }\n"
17805     "  foo();\n"
17806     "}\n"
17807     "outer()\n%s";
17808
17809   i::ScopedVector<char> code(1024);
17810   i::SNPrintF(code, source, "//# sourceURL=source_url");
17811   v8::TryCatch try_catch;
17812   CompileRunWithOrigin(code.start(), "", 0, 0);
17813   CHECK(try_catch.HasCaught());
17814   v8::String::Utf8Value stack(try_catch.StackTrace());
17815   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17816 }
17817
17818
17819 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17820   LocalContext context;
17821   v8::HandleScope scope(context->GetIsolate());
17822
17823   const char *source =
17824     "function outer() {\n"
17825     "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17826     "  //# sourceURL=source_url\";\n"
17827     "  eval(scriptContents);\n"
17828     "  foo(); }\n"
17829     "outer();\n"
17830     "//# sourceURL=outer_url";
17831
17832   v8::TryCatch try_catch;
17833   CompileRun(source);
17834   CHECK(try_catch.HasCaught());
17835
17836   Local<v8::Message> message = try_catch.Message();
17837   Handle<Value> sourceURL =
17838     message->GetScriptOrigin().ResourceName();
17839   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17840 }
17841
17842
17843 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17844   LocalContext context;
17845   v8::HandleScope scope(context->GetIsolate());
17846
17847   const char *source =
17848     "function outer() {\n"
17849     "  var scriptContents = \"function boo(){ boo(); }\\\n"
17850     "  //# sourceURL=source_url\";\n"
17851     "  eval(scriptContents);\n"
17852     "  boo(); }\n"
17853     "outer();\n"
17854     "//# sourceURL=outer_url";
17855
17856   v8::TryCatch try_catch;
17857   CompileRun(source);
17858   CHECK(try_catch.HasCaught());
17859
17860   Local<v8::Message> message = try_catch.Message();
17861   Handle<Value> sourceURL =
17862     message->GetScriptOrigin().ResourceName();
17863   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17864 }
17865
17866
17867 static void CreateGarbageInOldSpace() {
17868   i::Factory* factory = CcTest::i_isolate()->factory();
17869   v8::HandleScope scope(CcTest::isolate());
17870   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17871   for (int i = 0; i < 1000; i++) {
17872     factory->NewFixedArray(1000, i::TENURED);
17873   }
17874 }
17875
17876
17877 // Test that idle notification can be handled and eventually returns true.
17878 TEST(IdleNotification) {
17879   const intptr_t MB = 1024 * 1024;
17880   const int IdlePauseInMs = 1000;
17881   LocalContext env;
17882   v8::HandleScope scope(env->GetIsolate());
17883   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17884   CreateGarbageInOldSpace();
17885   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17886   CHECK_GT(size_with_garbage, initial_size + MB);
17887   bool finished = false;
17888   for (int i = 0; i < 200 && !finished; i++) {
17889     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17890   }
17891   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17892   CHECK(finished);
17893   CHECK_LT(final_size, initial_size + 1);
17894 }
17895
17896
17897 // Test that idle notification can be handled and eventually collects garbage.
17898 TEST(IdleNotificationWithSmallHint) {
17899   const intptr_t MB = 1024 * 1024;
17900   const int IdlePauseInMs = 900;
17901   LocalContext env;
17902   v8::HandleScope scope(env->GetIsolate());
17903   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17904   CreateGarbageInOldSpace();
17905   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17906   CHECK_GT(size_with_garbage, initial_size + MB);
17907   bool finished = false;
17908   for (int i = 0; i < 200 && !finished; i++) {
17909     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17910   }
17911   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17912   CHECK(finished);
17913   CHECK_LT(final_size, initial_size + 1);
17914 }
17915
17916
17917 // Test that idle notification can be handled and eventually collects garbage.
17918 TEST(IdleNotificationWithLargeHint) {
17919   const intptr_t MB = 1024 * 1024;
17920   const int IdlePauseInMs = 900;
17921   LocalContext env;
17922   v8::HandleScope scope(env->GetIsolate());
17923   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17924   CreateGarbageInOldSpace();
17925   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17926   CHECK_GT(size_with_garbage, initial_size + MB);
17927   bool finished = false;
17928   for (int i = 0; i < 200 && !finished; i++) {
17929     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17930   }
17931   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17932   CHECK(finished);
17933   CHECK_LT(final_size, initial_size + 1);
17934 }
17935
17936
17937 TEST(Regress2107) {
17938   const intptr_t MB = 1024 * 1024;
17939   const int kIdlePauseInMs = 1000;
17940   LocalContext env;
17941   v8::Isolate* isolate = env->GetIsolate();
17942   v8::HandleScope scope(env->GetIsolate());
17943   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17944   // Send idle notification to start a round of incremental GCs.
17945   env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17946   // Emulate 7 page reloads.
17947   for (int i = 0; i < 7; i++) {
17948     {
17949       v8::HandleScope inner_scope(env->GetIsolate());
17950       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17951       ctx->Enter();
17952       CreateGarbageInOldSpace();
17953       ctx->Exit();
17954     }
17955     env->GetIsolate()->ContextDisposedNotification();
17956     env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17957   }
17958   // Create garbage and check that idle notification still collects it.
17959   CreateGarbageInOldSpace();
17960   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17961   CHECK_GT(size_with_garbage, initial_size + MB);
17962   bool finished = false;
17963   for (int i = 0; i < 200 && !finished; i++) {
17964     finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
17965   }
17966   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17967   CHECK_LT(final_size, initial_size + 1);
17968 }
17969
17970
17971 TEST(Regress2333) {
17972   LocalContext env;
17973   for (int i = 0; i < 3; i++) {
17974     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17975   }
17976 }
17977
17978 static uint32_t* stack_limit;
17979
17980 static void GetStackLimitCallback(
17981     const v8::FunctionCallbackInfo<v8::Value>& args) {
17982   stack_limit = reinterpret_cast<uint32_t*>(
17983       CcTest::i_isolate()->stack_guard()->real_climit());
17984 }
17985
17986
17987 // Uses the address of a local variable to determine the stack top now.
17988 // Given a size, returns an address that is that far from the current
17989 // top of stack.
17990 static uint32_t* ComputeStackLimit(uint32_t size) {
17991   uint32_t* answer = &size - (size / sizeof(size));
17992   // If the size is very large and the stack is very near the bottom of
17993   // memory then the calculation above may wrap around and give an address
17994   // that is above the (downwards-growing) stack.  In that case we return
17995   // a very low address.
17996   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17997   return answer;
17998 }
17999
18000
18001 // We need at least 165kB for an x64 debug build with clang and ASAN.
18002 static const int stack_breathing_room = 256 * i::KB;
18003
18004
18005 TEST(SetStackLimit) {
18006   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18007
18008   // Set stack limit.
18009   CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18010
18011   // Execute a script.
18012   LocalContext env;
18013   v8::HandleScope scope(env->GetIsolate());
18014   Local<v8::FunctionTemplate> fun_templ =
18015       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18016   Local<Function> fun = fun_templ->GetFunction();
18017   env->Global()->Set(v8_str("get_stack_limit"), fun);
18018   CompileRun("get_stack_limit();");
18019
18020   CHECK(stack_limit == set_limit);
18021 }
18022
18023
18024 TEST(SetStackLimitInThread) {
18025   uint32_t* set_limit;
18026   {
18027     v8::Locker locker(CcTest::isolate());
18028     set_limit = ComputeStackLimit(stack_breathing_room);
18029
18030     // Set stack limit.
18031     CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18032
18033     // Execute a script.
18034     v8::HandleScope scope(CcTest::isolate());
18035     LocalContext env;
18036     Local<v8::FunctionTemplate> fun_templ =
18037         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18038     Local<Function> fun = fun_templ->GetFunction();
18039     env->Global()->Set(v8_str("get_stack_limit"), fun);
18040     CompileRun("get_stack_limit();");
18041
18042     CHECK(stack_limit == set_limit);
18043   }
18044   {
18045     v8::Locker locker(CcTest::isolate());
18046     CHECK(stack_limit == set_limit);
18047   }
18048 }
18049
18050
18051 THREADED_TEST(GetHeapStatistics) {
18052   LocalContext c1;
18053   v8::HandleScope scope(c1->GetIsolate());
18054   v8::HeapStatistics heap_statistics;
18055   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
18056   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
18057   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18058   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18059   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18060 }
18061
18062
18063 class VisitorImpl : public v8::ExternalResourceVisitor {
18064  public:
18065   explicit VisitorImpl(TestResource** resource) {
18066     for (int i = 0; i < 4; i++) {
18067       resource_[i] = resource[i];
18068       found_resource_[i] = false;
18069     }
18070   }
18071   virtual ~VisitorImpl() {}
18072   virtual void VisitExternalString(v8::Handle<v8::String> string) {
18073     if (!string->IsExternal()) {
18074       CHECK(string->IsExternalOneByte());
18075       return;
18076     }
18077     v8::String::ExternalStringResource* resource =
18078         string->GetExternalStringResource();
18079     CHECK(resource);
18080     for (int i = 0; i < 4; i++) {
18081       if (resource_[i] == resource) {
18082         CHECK(!found_resource_[i]);
18083         found_resource_[i] = true;
18084       }
18085     }
18086   }
18087   void CheckVisitedResources() {
18088     for (int i = 0; i < 4; i++) {
18089       CHECK(found_resource_[i]);
18090     }
18091   }
18092
18093  private:
18094   v8::String::ExternalStringResource* resource_[4];
18095   bool found_resource_[4];
18096 };
18097
18098
18099 TEST(ExternalizeOldSpaceTwoByteCons) {
18100   LocalContext env;
18101   v8::HandleScope scope(env->GetIsolate());
18102   v8::Local<v8::String> cons =
18103       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18104   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18105   CcTest::heap()->CollectAllAvailableGarbage();
18106   CHECK(CcTest::heap()->old_pointer_space()->Contains(
18107             *v8::Utils::OpenHandle(*cons)));
18108
18109   TestResource* resource = new TestResource(
18110       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18111   cons->MakeExternal(resource);
18112
18113   CHECK(cons->IsExternal());
18114   CHECK_EQ(resource, cons->GetExternalStringResource());
18115   String::Encoding encoding;
18116   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18117   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18118 }
18119
18120
18121 TEST(ExternalizeOldSpaceOneByteCons) {
18122   LocalContext env;
18123   v8::HandleScope scope(env->GetIsolate());
18124   v8::Local<v8::String> cons =
18125       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18126   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18127   CcTest::heap()->CollectAllAvailableGarbage();
18128   CHECK(CcTest::heap()->old_pointer_space()->Contains(
18129             *v8::Utils::OpenHandle(*cons)));
18130
18131   TestOneByteResource* resource =
18132       new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18133   cons->MakeExternal(resource);
18134
18135   CHECK(cons->IsExternalOneByte());
18136   CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18137   String::Encoding encoding;
18138   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18139   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18140 }
18141
18142
18143 TEST(VisitExternalStrings) {
18144   LocalContext env;
18145   v8::HandleScope scope(env->GetIsolate());
18146   const char* string = "Some string";
18147   uint16_t* two_byte_string = AsciiToTwoByteString(string);
18148   TestResource* resource[4];
18149   resource[0] = new TestResource(two_byte_string);
18150   v8::Local<v8::String> string0 =
18151       v8::String::NewExternal(env->GetIsolate(), resource[0]);
18152   resource[1] = new TestResource(two_byte_string, NULL, false);
18153   v8::Local<v8::String> string1 =
18154       v8::String::NewExternal(env->GetIsolate(), resource[1]);
18155
18156   // Externalized symbol.
18157   resource[2] = new TestResource(two_byte_string, NULL, false);
18158   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
18159       env->GetIsolate(), string, v8::String::kInternalizedString);
18160   CHECK(string2->MakeExternal(resource[2]));
18161
18162   // Symbolized External.
18163   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18164   v8::Local<v8::String> string3 =
18165       v8::String::NewExternal(env->GetIsolate(), resource[3]);
18166   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
18167   // Turn into a symbol.
18168   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18169   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18170       string3_i).is_null());
18171   CHECK(string3_i->IsInternalizedString());
18172
18173   // We need to add usages for string* to avoid warnings in GCC 4.7
18174   CHECK(string0->IsExternal());
18175   CHECK(string1->IsExternal());
18176   CHECK(string2->IsExternal());
18177   CHECK(string3->IsExternal());
18178
18179   VisitorImpl visitor(resource);
18180   v8::V8::VisitExternalResources(&visitor);
18181   visitor.CheckVisitedResources();
18182 }
18183
18184
18185 TEST(ExternalStringCollectedAtTearDown) {
18186   int destroyed = 0;
18187   v8::Isolate* isolate = v8::Isolate::New();
18188   { v8::Isolate::Scope isolate_scope(isolate);
18189     v8::HandleScope handle_scope(isolate);
18190     const char* s = "One string to test them all, one string to find them.";
18191     TestOneByteResource* inscription =
18192         new TestOneByteResource(i::StrDup(s), &destroyed);
18193     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18194     // Ring is still alive.  Orcs are roaming freely across our lands.
18195     CHECK_EQ(0, destroyed);
18196     USE(ring);
18197   }
18198
18199   isolate->Dispose();
18200   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18201   CHECK_EQ(1, destroyed);
18202 }
18203
18204
18205 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18206   int destroyed = 0;
18207   v8::Isolate* isolate = v8::Isolate::New();
18208   { v8::Isolate::Scope isolate_scope(isolate);
18209     LocalContext env(isolate);
18210     v8::HandleScope handle_scope(isolate);
18211     CompileRun("var ring = 'One string to test them all';");
18212     const char* s = "One string to test them all";
18213     TestOneByteResource* inscription =
18214         new TestOneByteResource(i::StrDup(s), &destroyed);
18215     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18216     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18217     ring->MakeExternal(inscription);
18218     // Ring is still alive.  Orcs are roaming freely across our lands.
18219     CHECK_EQ(0, destroyed);
18220     USE(ring);
18221   }
18222
18223   isolate->Dispose();
18224   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18225   CHECK_EQ(1, destroyed);
18226 }
18227
18228
18229 TEST(ExternalInternalizedStringCollectedAtGC) {
18230   int destroyed = 0;
18231   { LocalContext env;
18232     v8::HandleScope handle_scope(env->GetIsolate());
18233     CompileRun("var ring = 'One string to test them all';");
18234     const char* s = "One string to test them all";
18235     TestOneByteResource* inscription =
18236         new TestOneByteResource(i::StrDup(s), &destroyed);
18237     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18238     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18239     ring->MakeExternal(inscription);
18240     // Ring is still alive.  Orcs are roaming freely across our lands.
18241     CHECK_EQ(0, destroyed);
18242     USE(ring);
18243   }
18244
18245   // Garbage collector deals swift blows to evil.
18246   CcTest::i_isolate()->compilation_cache()->Clear();
18247   CcTest::heap()->CollectAllAvailableGarbage();
18248
18249   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18250   CHECK_EQ(1, destroyed);
18251 }
18252
18253
18254 static double DoubleFromBits(uint64_t value) {
18255   double target;
18256   i::MemCopy(&target, &value, sizeof(target));
18257   return target;
18258 }
18259
18260
18261 static uint64_t DoubleToBits(double value) {
18262   uint64_t target;
18263   i::MemCopy(&target, &value, sizeof(target));
18264   return target;
18265 }
18266
18267
18268 static double DoubleToDateTime(double input) {
18269   double date_limit = 864e13;
18270   if (std::isnan(input) || input < -date_limit || input > date_limit) {
18271     return v8::base::OS::nan_value();
18272   }
18273   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18274 }
18275
18276
18277 // We don't have a consistent way to write 64-bit constants syntactically, so we
18278 // split them into two 32-bit constants and combine them programmatically.
18279 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18280   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18281 }
18282
18283
18284 THREADED_TEST(QuietSignalingNaNs) {
18285   LocalContext context;
18286   v8::Isolate* isolate = context->GetIsolate();
18287   v8::HandleScope scope(isolate);
18288   v8::TryCatch try_catch;
18289
18290   // Special double values.
18291   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18292   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18293   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18294   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18295   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18296   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18297   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18298
18299   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18300   // on either side of the epoch.
18301   double date_limit = 864e13;
18302
18303   double test_values[] = {
18304       snan,
18305       qnan,
18306       infinity,
18307       max_normal,
18308       date_limit + 1,
18309       date_limit,
18310       min_normal,
18311       max_denormal,
18312       min_denormal,
18313       0,
18314       -0,
18315       -min_denormal,
18316       -max_denormal,
18317       -min_normal,
18318       -date_limit,
18319       -date_limit - 1,
18320       -max_normal,
18321       -infinity,
18322       -qnan,
18323       -snan
18324   };
18325   int num_test_values = 20;
18326
18327   for (int i = 0; i < num_test_values; i++) {
18328     double test_value = test_values[i];
18329
18330     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18331     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18332     double stored_number = number->NumberValue();
18333     if (!std::isnan(test_value)) {
18334       CHECK_EQ(test_value, stored_number);
18335     } else {
18336       uint64_t stored_bits = DoubleToBits(stored_number);
18337       // Check if quiet nan (bits 51..62 all set).
18338 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18339     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18340       // Most significant fraction bit for quiet nan is set to 0
18341       // on MIPS architecture. Allowed by IEEE-754.
18342       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18343 #else
18344       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18345 #endif
18346     }
18347
18348     // Check that Date::New preserves non-NaNs in the date range and
18349     // quiets SNaNs.
18350     v8::Handle<v8::Value> date =
18351         v8::Date::New(isolate, test_value);
18352     double expected_stored_date = DoubleToDateTime(test_value);
18353     double stored_date = date->NumberValue();
18354     if (!std::isnan(expected_stored_date)) {
18355       CHECK_EQ(expected_stored_date, stored_date);
18356     } else {
18357       uint64_t stored_bits = DoubleToBits(stored_date);
18358       // Check if quiet nan (bits 51..62 all set).
18359 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18360     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18361       // Most significant fraction bit for quiet nan is set to 0
18362       // on MIPS architecture. Allowed by IEEE-754.
18363       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18364 #else
18365       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18366 #endif
18367     }
18368   }
18369 }
18370
18371
18372 static void SpaghettiIncident(
18373     const v8::FunctionCallbackInfo<v8::Value>& args) {
18374   v8::HandleScope scope(args.GetIsolate());
18375   v8::TryCatch tc;
18376   v8::Handle<v8::String> str(args[0]->ToString());
18377   USE(str);
18378   if (tc.HasCaught())
18379     tc.ReThrow();
18380 }
18381
18382
18383 // Test that an exception can be propagated down through a spaghetti
18384 // stack using ReThrow.
18385 THREADED_TEST(SpaghettiStackReThrow) {
18386   v8::Isolate* isolate = CcTest::isolate();
18387   v8::HandleScope scope(isolate);
18388   LocalContext context;
18389   context->Global()->Set(
18390       v8::String::NewFromUtf8(isolate, "s"),
18391       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18392   v8::TryCatch try_catch;
18393   CompileRun(
18394       "var i = 0;"
18395       "var o = {"
18396       "  toString: function () {"
18397       "    if (i == 10) {"
18398       "      throw 'Hey!';"
18399       "    } else {"
18400       "      i++;"
18401       "      return s(o);"
18402       "    }"
18403       "  }"
18404       "};"
18405       "s(o);");
18406   CHECK(try_catch.HasCaught());
18407   v8::String::Utf8Value value(try_catch.Exception());
18408   CHECK_EQ(0, strcmp(*value, "Hey!"));
18409 }
18410
18411
18412 TEST(Regress528) {
18413   v8::V8::Initialize();
18414   v8::Isolate* isolate = CcTest::isolate();
18415   v8::HandleScope scope(isolate);
18416   v8::Local<Context> other_context;
18417   int gc_count;
18418
18419   // Create a context used to keep the code from aging in the compilation
18420   // cache.
18421   other_context = Context::New(isolate);
18422
18423   // Context-dependent context data creates reference from the compilation
18424   // cache to the global object.
18425   const char* source_simple = "1";
18426   {
18427     v8::HandleScope scope(isolate);
18428     v8::Local<Context> context = Context::New(isolate);
18429
18430     context->Enter();
18431     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18432     context->SetEmbedderData(0, obj);
18433     CompileRun(source_simple);
18434     context->Exit();
18435   }
18436   isolate->ContextDisposedNotification();
18437   for (gc_count = 1; gc_count < 10; gc_count++) {
18438     other_context->Enter();
18439     CompileRun(source_simple);
18440     other_context->Exit();
18441     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18442     if (GetGlobalObjectsCount() == 1) break;
18443   }
18444   CHECK_GE(2, gc_count);
18445   CHECK_EQ(1, GetGlobalObjectsCount());
18446
18447   // Eval in a function creates reference from the compilation cache to the
18448   // global object.
18449   const char* source_eval = "function f(){eval('1')}; f()";
18450   {
18451     v8::HandleScope scope(isolate);
18452     v8::Local<Context> context = Context::New(isolate);
18453
18454     context->Enter();
18455     CompileRun(source_eval);
18456     context->Exit();
18457   }
18458   isolate->ContextDisposedNotification();
18459   for (gc_count = 1; gc_count < 10; gc_count++) {
18460     other_context->Enter();
18461     CompileRun(source_eval);
18462     other_context->Exit();
18463     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18464     if (GetGlobalObjectsCount() == 1) break;
18465   }
18466   CHECK_GE(2, gc_count);
18467   CHECK_EQ(1, GetGlobalObjectsCount());
18468
18469   // Looking up the line number for an exception creates reference from the
18470   // compilation cache to the global object.
18471   const char* source_exception = "function f(){throw 1;} f()";
18472   {
18473     v8::HandleScope scope(isolate);
18474     v8::Local<Context> context = Context::New(isolate);
18475
18476     context->Enter();
18477     v8::TryCatch try_catch;
18478     CompileRun(source_exception);
18479     CHECK(try_catch.HasCaught());
18480     v8::Handle<v8::Message> message = try_catch.Message();
18481     CHECK(!message.IsEmpty());
18482     CHECK_EQ(1, message->GetLineNumber());
18483     context->Exit();
18484   }
18485   isolate->ContextDisposedNotification();
18486   for (gc_count = 1; gc_count < 10; gc_count++) {
18487     other_context->Enter();
18488     CompileRun(source_exception);
18489     other_context->Exit();
18490     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18491     if (GetGlobalObjectsCount() == 1) break;
18492   }
18493   CHECK_GE(2, gc_count);
18494   CHECK_EQ(1, GetGlobalObjectsCount());
18495
18496   isolate->ContextDisposedNotification();
18497 }
18498
18499
18500 THREADED_TEST(ScriptOrigin) {
18501   LocalContext env;
18502   v8::HandleScope scope(env->GetIsolate());
18503   v8::ScriptOrigin origin =
18504       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18505   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18506       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18507   v8::Script::Compile(script, &origin)->Run();
18508   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18509       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18510   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18511       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18512
18513   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18514   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18515   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18516
18517   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18518   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18519   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18520 }
18521
18522
18523 THREADED_TEST(FunctionGetInferredName) {
18524   LocalContext env;
18525   v8::HandleScope scope(env->GetIsolate());
18526   v8::ScriptOrigin origin =
18527       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18528   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18529       env->GetIsolate(),
18530       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
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   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18535 }
18536
18537
18538 THREADED_TEST(FunctionGetDisplayName) {
18539   LocalContext env;
18540   v8::HandleScope scope(env->GetIsolate());
18541   const char* code = "var error = false;"
18542                      "function a() { this.x = 1; };"
18543                      "a.displayName = 'display_a';"
18544                      "var b = (function() {"
18545                      "  var f = function() { this.x = 2; };"
18546                      "  f.displayName = 'display_b';"
18547                      "  return f;"
18548                      "})();"
18549                      "var c = function() {};"
18550                      "c.__defineGetter__('displayName', function() {"
18551                      "  error = true;"
18552                      "  throw new Error();"
18553                      "});"
18554                      "function d() {};"
18555                      "d.__defineGetter__('displayName', function() {"
18556                      "  error = true;"
18557                      "  return 'wrong_display_name';"
18558                      "});"
18559                      "function e() {};"
18560                      "e.displayName = 'wrong_display_name';"
18561                      "e.__defineSetter__('displayName', function() {"
18562                      "  error = true;"
18563                      "  throw new Error();"
18564                      "});"
18565                      "function f() {};"
18566                      "f.displayName = { 'foo': 6, toString: function() {"
18567                      "  error = true;"
18568                      "  return 'wrong_display_name';"
18569                      "}};"
18570                      "var g = function() {"
18571                      "  arguments.callee.displayName = 'set_in_runtime';"
18572                      "}; g();"
18573                      ;
18574   v8::ScriptOrigin origin =
18575       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18576   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18577       ->Run();
18578   v8::Local<v8::Value> error =
18579       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18580   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18581       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18582   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18583       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18584   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18585       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18586   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18587       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18588   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18589       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18590   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18591       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18592   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18593       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18594   CHECK_EQ(false, error->BooleanValue());
18595   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18596   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18597   CHECK(c->GetDisplayName()->IsUndefined());
18598   CHECK(d->GetDisplayName()->IsUndefined());
18599   CHECK(e->GetDisplayName()->IsUndefined());
18600   CHECK(f->GetDisplayName()->IsUndefined());
18601   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18602 }
18603
18604
18605 THREADED_TEST(ScriptLineNumber) {
18606   LocalContext env;
18607   v8::HandleScope scope(env->GetIsolate());
18608   v8::ScriptOrigin origin =
18609       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18610   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18611       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18612   v8::Script::Compile(script, &origin)->Run();
18613   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18614       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18615   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18616       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18617   CHECK_EQ(0, f->GetScriptLineNumber());
18618   CHECK_EQ(2, g->GetScriptLineNumber());
18619 }
18620
18621
18622 THREADED_TEST(ScriptColumnNumber) {
18623   LocalContext env;
18624   v8::Isolate* isolate = env->GetIsolate();
18625   v8::HandleScope scope(isolate);
18626   v8::ScriptOrigin origin =
18627       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18628                        v8::Integer::New(isolate, 3),
18629                        v8::Integer::New(isolate, 2));
18630   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18631       isolate, "function foo() {}\n\n     function bar() {}");
18632   v8::Script::Compile(script, &origin)->Run();
18633   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18634       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18635   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18636       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18637   CHECK_EQ(14, foo->GetScriptColumnNumber());
18638   CHECK_EQ(17, bar->GetScriptColumnNumber());
18639 }
18640
18641
18642 THREADED_TEST(FunctionIsBuiltin) {
18643   LocalContext env;
18644   v8::Isolate* isolate = env->GetIsolate();
18645   v8::HandleScope scope(isolate);
18646   v8::Local<v8::Function> f;
18647   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18648   CHECK(f->IsBuiltin());
18649   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18650   CHECK(f->IsBuiltin());
18651   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18652   CHECK(f->IsBuiltin());
18653   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18654   CHECK(f->IsBuiltin());
18655   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18656   CHECK(!f->IsBuiltin());
18657 }
18658
18659
18660 THREADED_TEST(FunctionGetScriptId) {
18661   LocalContext env;
18662   v8::Isolate* isolate = env->GetIsolate();
18663   v8::HandleScope scope(isolate);
18664   v8::ScriptOrigin origin =
18665       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18666                        v8::Integer::New(isolate, 3),
18667                        v8::Integer::New(isolate, 2));
18668   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18669       isolate, "function foo() {}\n\n     function bar() {}");
18670   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18671   script->Run();
18672   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18673       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18674   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18675       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18676   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18677   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18678 }
18679
18680
18681 THREADED_TEST(FunctionGetBoundFunction) {
18682   LocalContext env;
18683   v8::HandleScope scope(env->GetIsolate());
18684   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18685       env->GetIsolate(), "test"));
18686   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18687       env->GetIsolate(),
18688       "var a = new Object();\n"
18689       "a.x = 1;\n"
18690       "function f () { return this.x };\n"
18691       "var g = f.bind(a);\n"
18692       "var b = g();");
18693   v8::Script::Compile(script, &origin)->Run();
18694   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18695       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18696   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18697       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18698   CHECK(g->GetBoundFunction()->IsFunction());
18699   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18700       g->GetBoundFunction());
18701   CHECK_EQ(f->GetName(), original_function->GetName());
18702   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18703   CHECK_EQ(f->GetScriptColumnNumber(),
18704            original_function->GetScriptColumnNumber());
18705 }
18706
18707
18708 static void GetterWhichReturns42(
18709     Local<String> name,
18710     const v8::PropertyCallbackInfo<v8::Value>& info) {
18711   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18712   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18713   info.GetReturnValue().Set(v8_num(42));
18714 }
18715
18716
18717 static void SetterWhichSetsYOnThisTo23(
18718     Local<String> name,
18719     Local<Value> value,
18720     const v8::PropertyCallbackInfo<void>& info) {
18721   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18722   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18723   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18724 }
18725
18726
18727 void FooGetInterceptor(Local<String> name,
18728                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18729   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18730   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18731   if (!name->Equals(v8_str("foo"))) return;
18732   info.GetReturnValue().Set(v8_num(42));
18733 }
18734
18735
18736 void FooSetInterceptor(Local<String> name,
18737                        Local<Value> value,
18738                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18739   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18740   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18741   if (!name->Equals(v8_str("foo"))) return;
18742   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18743   info.GetReturnValue().Set(v8_num(23));
18744 }
18745
18746
18747 TEST(SetterOnConstructorPrototype) {
18748   v8::Isolate* isolate = CcTest::isolate();
18749   v8::HandleScope scope(isolate);
18750   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18751   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18752                      SetterWhichSetsYOnThisTo23);
18753   LocalContext context;
18754   context->Global()->Set(v8_str("P"), templ->NewInstance());
18755   CompileRun("function C1() {"
18756              "  this.x = 23;"
18757              "};"
18758              "C1.prototype = P;"
18759              "function C2() {"
18760              "  this.x = 23"
18761              "};"
18762              "C2.prototype = { };"
18763              "C2.prototype.__proto__ = P;");
18764
18765   v8::Local<v8::Script> script;
18766   script = v8_compile("new C1();");
18767   for (int i = 0; i < 10; i++) {
18768     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18769     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18770     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18771   }
18772
18773 script = v8_compile("new C2();");
18774   for (int i = 0; i < 10; i++) {
18775     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18776     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18777     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18778   }
18779 }
18780
18781
18782 static void NamedPropertyGetterWhichReturns42(
18783     Local<String> name,
18784     const v8::PropertyCallbackInfo<v8::Value>& info) {
18785   info.GetReturnValue().Set(v8_num(42));
18786 }
18787
18788
18789 static void NamedPropertySetterWhichSetsYOnThisTo23(
18790     Local<String> name,
18791     Local<Value> value,
18792     const v8::PropertyCallbackInfo<v8::Value>& info) {
18793   if (name->Equals(v8_str("x"))) {
18794     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18795   }
18796 }
18797
18798
18799 THREADED_TEST(InterceptorOnConstructorPrototype) {
18800   v8::Isolate* isolate = CcTest::isolate();
18801   v8::HandleScope scope(isolate);
18802   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18803   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18804                                  NamedPropertySetterWhichSetsYOnThisTo23);
18805   LocalContext context;
18806   context->Global()->Set(v8_str("P"), templ->NewInstance());
18807   CompileRun("function C1() {"
18808              "  this.x = 23;"
18809              "};"
18810              "C1.prototype = P;"
18811              "function C2() {"
18812              "  this.x = 23"
18813              "};"
18814              "C2.prototype = { };"
18815              "C2.prototype.__proto__ = P;");
18816
18817   v8::Local<v8::Script> script;
18818   script = v8_compile("new C1();");
18819   for (int i = 0; i < 10; i++) {
18820     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18821     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18822     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18823   }
18824
18825   script = v8_compile("new C2();");
18826   for (int i = 0; i < 10; i++) {
18827     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18828     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18829     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18830   }
18831 }
18832
18833
18834 TEST(Regress618) {
18835   const char* source = "function C1() {"
18836                        "  this.x = 23;"
18837                        "};"
18838                        "C1.prototype = P;";
18839
18840   LocalContext context;
18841   v8::Isolate* isolate = context->GetIsolate();
18842   v8::HandleScope scope(isolate);
18843   v8::Local<v8::Script> script;
18844
18845   // Use a simple object as prototype.
18846   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18847   prototype->Set(v8_str("y"), v8_num(42));
18848   context->Global()->Set(v8_str("P"), prototype);
18849
18850   // This compile will add the code to the compilation cache.
18851   CompileRun(source);
18852
18853   script = v8_compile("new C1();");
18854   // Allow enough iterations for the inobject slack tracking logic
18855   // to finalize instance size and install the fast construct stub.
18856   for (int i = 0; i < 256; i++) {
18857     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18858     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18859     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18860   }
18861
18862   // Use an API object with accessors as prototype.
18863   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18864   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18865                      SetterWhichSetsYOnThisTo23);
18866   context->Global()->Set(v8_str("P"), templ->NewInstance());
18867
18868   // This compile will get the code from the compilation cache.
18869   CompileRun(source);
18870
18871   script = v8_compile("new C1();");
18872   for (int i = 0; i < 10; i++) {
18873     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18874     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18875     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18876   }
18877 }
18878
18879 v8::Isolate* gc_callbacks_isolate = NULL;
18880 int prologue_call_count = 0;
18881 int epilogue_call_count = 0;
18882 int prologue_call_count_second = 0;
18883 int epilogue_call_count_second = 0;
18884 int prologue_call_count_alloc = 0;
18885 int epilogue_call_count_alloc = 0;
18886
18887 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18888   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18889   ++prologue_call_count;
18890 }
18891
18892
18893 void PrologueCallback(v8::Isolate* isolate,
18894                       v8::GCType,
18895                       v8::GCCallbackFlags flags) {
18896   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18897   CHECK_EQ(gc_callbacks_isolate, isolate);
18898   ++prologue_call_count;
18899 }
18900
18901
18902 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18903   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18904   ++epilogue_call_count;
18905 }
18906
18907
18908 void EpilogueCallback(v8::Isolate* isolate,
18909                       v8::GCType,
18910                       v8::GCCallbackFlags flags) {
18911   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18912   CHECK_EQ(gc_callbacks_isolate, isolate);
18913   ++epilogue_call_count;
18914 }
18915
18916
18917 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18918   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18919   ++prologue_call_count_second;
18920 }
18921
18922
18923 void PrologueCallbackSecond(v8::Isolate* isolate,
18924                             v8::GCType,
18925                             v8::GCCallbackFlags flags) {
18926   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18927   CHECK_EQ(gc_callbacks_isolate, isolate);
18928   ++prologue_call_count_second;
18929 }
18930
18931
18932 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18933   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18934   ++epilogue_call_count_second;
18935 }
18936
18937
18938 void EpilogueCallbackSecond(v8::Isolate* isolate,
18939                             v8::GCType,
18940                             v8::GCCallbackFlags flags) {
18941   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18942   CHECK_EQ(gc_callbacks_isolate, isolate);
18943   ++epilogue_call_count_second;
18944 }
18945
18946
18947 void PrologueCallbackAlloc(v8::Isolate* isolate,
18948                            v8::GCType,
18949                            v8::GCCallbackFlags flags) {
18950   v8::HandleScope scope(isolate);
18951
18952   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18953   CHECK_EQ(gc_callbacks_isolate, isolate);
18954   ++prologue_call_count_alloc;
18955
18956   // Simulate full heap to see if we will reenter this callback
18957   SimulateFullSpace(CcTest::heap()->new_space());
18958
18959   Local<Object> obj = Object::New(isolate);
18960   CHECK(!obj.IsEmpty());
18961
18962   CcTest::heap()->CollectAllGarbage(
18963       i::Heap::kAbortIncrementalMarkingMask);
18964 }
18965
18966
18967 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18968                            v8::GCType,
18969                            v8::GCCallbackFlags flags) {
18970   v8::HandleScope scope(isolate);
18971
18972   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18973   CHECK_EQ(gc_callbacks_isolate, isolate);
18974   ++epilogue_call_count_alloc;
18975
18976   // Simulate full heap to see if we will reenter this callback
18977   SimulateFullSpace(CcTest::heap()->new_space());
18978
18979   Local<Object> obj = Object::New(isolate);
18980   CHECK(!obj.IsEmpty());
18981
18982   CcTest::heap()->CollectAllGarbage(
18983       i::Heap::kAbortIncrementalMarkingMask);
18984 }
18985
18986
18987 TEST(GCCallbacksOld) {
18988   LocalContext context;
18989
18990   v8::V8::AddGCPrologueCallback(PrologueCallback);
18991   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18992   CHECK_EQ(0, prologue_call_count);
18993   CHECK_EQ(0, epilogue_call_count);
18994   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18995   CHECK_EQ(1, prologue_call_count);
18996   CHECK_EQ(1, epilogue_call_count);
18997   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18998   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18999   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19000   CHECK_EQ(2, prologue_call_count);
19001   CHECK_EQ(2, epilogue_call_count);
19002   CHECK_EQ(1, prologue_call_count_second);
19003   CHECK_EQ(1, epilogue_call_count_second);
19004   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
19005   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
19006   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19007   CHECK_EQ(2, prologue_call_count);
19008   CHECK_EQ(2, epilogue_call_count);
19009   CHECK_EQ(2, prologue_call_count_second);
19010   CHECK_EQ(2, epilogue_call_count_second);
19011   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
19012   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19013   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19014   CHECK_EQ(2, prologue_call_count);
19015   CHECK_EQ(2, epilogue_call_count);
19016   CHECK_EQ(2, prologue_call_count_second);
19017   CHECK_EQ(2, epilogue_call_count_second);
19018 }
19019
19020
19021 TEST(GCCallbacks) {
19022   LocalContext context;
19023   v8::Isolate* isolate = context->GetIsolate();
19024   gc_callbacks_isolate = isolate;
19025   isolate->AddGCPrologueCallback(PrologueCallback);
19026   isolate->AddGCEpilogueCallback(EpilogueCallback);
19027   CHECK_EQ(0, prologue_call_count);
19028   CHECK_EQ(0, epilogue_call_count);
19029   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19030   CHECK_EQ(1, prologue_call_count);
19031   CHECK_EQ(1, epilogue_call_count);
19032   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19033   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19034   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19035   CHECK_EQ(2, prologue_call_count);
19036   CHECK_EQ(2, epilogue_call_count);
19037   CHECK_EQ(1, prologue_call_count_second);
19038   CHECK_EQ(1, epilogue_call_count_second);
19039   isolate->RemoveGCPrologueCallback(PrologueCallback);
19040   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19041   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19042   CHECK_EQ(2, prologue_call_count);
19043   CHECK_EQ(2, epilogue_call_count);
19044   CHECK_EQ(2, prologue_call_count_second);
19045   CHECK_EQ(2, epilogue_call_count_second);
19046   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19047   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19048   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19049   CHECK_EQ(2, prologue_call_count);
19050   CHECK_EQ(2, epilogue_call_count);
19051   CHECK_EQ(2, prologue_call_count_second);
19052   CHECK_EQ(2, epilogue_call_count_second);
19053
19054   CHECK_EQ(0, prologue_call_count_alloc);
19055   CHECK_EQ(0, epilogue_call_count_alloc);
19056   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19057   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19058   CcTest::heap()->CollectAllGarbage(
19059       i::Heap::kAbortIncrementalMarkingMask);
19060   CHECK_EQ(1, prologue_call_count_alloc);
19061   CHECK_EQ(1, epilogue_call_count_alloc);
19062   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19063   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19064 }
19065
19066
19067 THREADED_TEST(AddToJSFunctionResultCache) {
19068   i::FLAG_stress_compaction = false;
19069   i::FLAG_allow_natives_syntax = true;
19070   v8::HandleScope scope(CcTest::isolate());
19071
19072   LocalContext context;
19073
19074   const char* code =
19075       "(function() {"
19076       "  var key0 = 'a';"
19077       "  var key1 = 'b';"
19078       "  var r0 = %_GetFromCache(0, key0);"
19079       "  var r1 = %_GetFromCache(0, key1);"
19080       "  var r0_ = %_GetFromCache(0, key0);"
19081       "  if (r0 !== r0_)"
19082       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
19083       "  var r1_ = %_GetFromCache(0, key1);"
19084       "  if (r1 !== r1_)"
19085       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
19086       "  return 'PASSED';"
19087       "})()";
19088   CcTest::heap()->ClearJSFunctionResultCaches();
19089   ExpectString(code, "PASSED");
19090 }
19091
19092
19093 THREADED_TEST(FillJSFunctionResultCache) {
19094   i::FLAG_allow_natives_syntax = true;
19095   LocalContext context;
19096   v8::HandleScope scope(context->GetIsolate());
19097
19098   const char* code =
19099       "(function() {"
19100       "  var k = 'a';"
19101       "  var r = %_GetFromCache(0, k);"
19102       "  for (var i = 0; i < 16; i++) {"
19103       "    %_GetFromCache(0, 'a' + i);"
19104       "  };"
19105       "  if (r === %_GetFromCache(0, k))"
19106       "    return 'FAILED: k0CacheSize is too small';"
19107       "  return 'PASSED';"
19108       "})()";
19109   CcTest::heap()->ClearJSFunctionResultCaches();
19110   ExpectString(code, "PASSED");
19111 }
19112
19113
19114 THREADED_TEST(RoundRobinGetFromCache) {
19115   i::FLAG_allow_natives_syntax = true;
19116   LocalContext context;
19117   v8::HandleScope scope(context->GetIsolate());
19118
19119   const char* code =
19120       "(function() {"
19121       "  var keys = [];"
19122       "  for (var i = 0; i < 16; i++) keys.push(i);"
19123       "  var values = [];"
19124       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19125       "  for (var i = 0; i < 16; i++) {"
19126       "    var v = %_GetFromCache(0, keys[i]);"
19127       "    if (v.toString() !== values[i].toString())"
19128       "      return 'Wrong value for ' + "
19129       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
19130       "  };"
19131       "  return 'PASSED';"
19132       "})()";
19133   CcTest::heap()->ClearJSFunctionResultCaches();
19134   ExpectString(code, "PASSED");
19135 }
19136
19137
19138 THREADED_TEST(ReverseGetFromCache) {
19139   i::FLAG_allow_natives_syntax = true;
19140   LocalContext context;
19141   v8::HandleScope scope(context->GetIsolate());
19142
19143   const char* code =
19144       "(function() {"
19145       "  var keys = [];"
19146       "  for (var i = 0; i < 16; i++) keys.push(i);"
19147       "  var values = [];"
19148       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19149       "  for (var i = 15; i >= 16; i--) {"
19150       "    var v = %_GetFromCache(0, keys[i]);"
19151       "    if (v !== values[i])"
19152       "      return 'Wrong value for ' + "
19153       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
19154       "  };"
19155       "  return 'PASSED';"
19156       "})()";
19157   CcTest::heap()->ClearJSFunctionResultCaches();
19158   ExpectString(code, "PASSED");
19159 }
19160
19161
19162 THREADED_TEST(TestEviction) {
19163   i::FLAG_allow_natives_syntax = true;
19164   LocalContext context;
19165   v8::HandleScope scope(context->GetIsolate());
19166
19167   const char* code =
19168       "(function() {"
19169       "  for (var i = 0; i < 2*16; i++) {"
19170       "    %_GetFromCache(0, 'a' + i);"
19171       "  };"
19172       "  return 'PASSED';"
19173       "})()";
19174   CcTest::heap()->ClearJSFunctionResultCaches();
19175   ExpectString(code, "PASSED");
19176 }
19177
19178
19179 THREADED_TEST(TwoByteStringInOneByteCons) {
19180   // See Chromium issue 47824.
19181   LocalContext context;
19182   v8::HandleScope scope(context->GetIsolate());
19183
19184   const char* init_code =
19185       "var str1 = 'abelspendabel';"
19186       "var str2 = str1 + str1 + str1;"
19187       "str2;";
19188   Local<Value> result = CompileRun(init_code);
19189
19190   Local<Value> indexof = CompileRun("str2.indexOf('els')");
19191   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19192
19193   CHECK(result->IsString());
19194   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19195   int length = string->length();
19196   CHECK(string->IsOneByteRepresentation());
19197
19198   i::Handle<i::String> flat_string = i::String::Flatten(string);
19199
19200   CHECK(string->IsOneByteRepresentation());
19201   CHECK(flat_string->IsOneByteRepresentation());
19202
19203   // Create external resource.
19204   uint16_t* uc16_buffer = new uint16_t[length + 1];
19205
19206   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19207   uc16_buffer[length] = 0;
19208
19209   TestResource resource(uc16_buffer);
19210
19211   flat_string->MakeExternal(&resource);
19212
19213   CHECK(flat_string->IsTwoByteRepresentation());
19214
19215   // If the cons string has been short-circuited, skip the following checks.
19216   if (!string.is_identical_to(flat_string)) {
19217     // At this point, we should have a Cons string which is flat and one-byte,
19218     // with a first half that is a two-byte string (although it only contains
19219     // one-byte characters). This is a valid sequence of steps, and it can
19220     // happen in real pages.
19221     CHECK(string->IsOneByteRepresentation());
19222     i::ConsString* cons = i::ConsString::cast(*string);
19223     CHECK_EQ(0, cons->second()->length());
19224     CHECK(cons->first()->IsTwoByteRepresentation());
19225   }
19226
19227   // Check that some string operations work.
19228
19229   // Atom RegExp.
19230   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19231   CHECK_EQ(6, reresult->Int32Value());
19232
19233   // Nonatom RegExp.
19234   reresult = CompileRun("str2.match(/abe./g).length;");
19235   CHECK_EQ(6, reresult->Int32Value());
19236
19237   reresult = CompileRun("str2.search(/bel/g);");
19238   CHECK_EQ(1, reresult->Int32Value());
19239
19240   reresult = CompileRun("str2.search(/be./g);");
19241   CHECK_EQ(1, reresult->Int32Value());
19242
19243   ExpectTrue("/bel/g.test(str2);");
19244
19245   ExpectTrue("/be./g.test(str2);");
19246
19247   reresult = CompileRun("/bel/g.exec(str2);");
19248   CHECK(!reresult->IsNull());
19249
19250   reresult = CompileRun("/be./g.exec(str2);");
19251   CHECK(!reresult->IsNull());
19252
19253   ExpectString("str2.substring(2, 10);", "elspenda");
19254
19255   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19256
19257   ExpectString("str2.charAt(2);", "e");
19258
19259   ExpectObject("str2.indexOf('els');", indexof);
19260
19261   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19262
19263   reresult = CompileRun("str2.charCodeAt(2);");
19264   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19265 }
19266
19267
19268 TEST(ContainsOnlyOneByte) {
19269   v8::V8::Initialize();
19270   v8::Isolate* isolate = CcTest::isolate();
19271   v8::HandleScope scope(isolate);
19272   // Make a buffer long enough that it won't automatically be converted.
19273   const int length = 512;
19274   // Ensure word aligned assignment.
19275   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19276   i::SmartArrayPointer<uintptr_t>
19277   aligned_contents(new uintptr_t[aligned_length]);
19278   uint16_t* string_contents =
19279       reinterpret_cast<uint16_t*>(aligned_contents.get());
19280   // Set to contain only one byte.
19281   for (int i = 0; i < length-1; i++) {
19282     string_contents[i] = 0x41;
19283   }
19284   string_contents[length-1] = 0;
19285   // Simple case.
19286   Handle<String> string =
19287       String::NewExternal(isolate,
19288                           new TestResource(string_contents, NULL, false));
19289   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19290   // Counter example.
19291   string = String::NewFromTwoByte(isolate, string_contents);
19292   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19293   // Test left right and balanced cons strings.
19294   Handle<String> base = String::NewFromUtf8(isolate, "a");
19295   Handle<String> left = base;
19296   Handle<String> right = base;
19297   for (int i = 0; i < 1000; i++) {
19298     left = String::Concat(base, left);
19299     right = String::Concat(right, base);
19300   }
19301   Handle<String> balanced = String::Concat(left, base);
19302   balanced = String::Concat(balanced, right);
19303   Handle<String> cons_strings[] = {left, balanced, right};
19304   Handle<String> two_byte =
19305       String::NewExternal(isolate,
19306                           new TestResource(string_contents, NULL, false));
19307   USE(two_byte); USE(cons_strings);
19308   for (size_t i = 0; i < arraysize(cons_strings); i++) {
19309     // Base assumptions.
19310     string = cons_strings[i];
19311     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19312     // Test left and right concatentation.
19313     string = String::Concat(two_byte, cons_strings[i]);
19314     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19315     string = String::Concat(cons_strings[i], two_byte);
19316     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19317   }
19318   // Set bits in different positions
19319   // for strings of different lengths and alignments.
19320   for (int alignment = 0; alignment < 7; alignment++) {
19321     for (int size = 2; alignment + size < length; size *= 2) {
19322       int zero_offset = size + alignment;
19323       string_contents[zero_offset] = 0;
19324       for (int i = 0; i < size; i++) {
19325         int shift = 8 + (i % 7);
19326         string_contents[alignment + i] = 1 << shift;
19327         string = String::NewExternal(
19328             isolate,
19329             new TestResource(string_contents + alignment, NULL, false));
19330         CHECK_EQ(size, string->Length());
19331         CHECK(!string->ContainsOnlyOneByte());
19332         string_contents[alignment + i] = 0x41;
19333       }
19334       string_contents[zero_offset] = 0x41;
19335     }
19336   }
19337 }
19338
19339
19340 // Failed access check callback that performs a GC on each invocation.
19341 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19342                                  v8::AccessType type,
19343                                  Local<v8::Value> data) {
19344   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19345 }
19346
19347
19348 TEST(GCInFailedAccessCheckCallback) {
19349   // Install a failed access check callback that performs a GC on each
19350   // invocation. Then force the callback to be called from va
19351
19352   v8::V8::Initialize();
19353   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19354
19355   v8::Isolate* isolate = CcTest::isolate();
19356   v8::HandleScope scope(isolate);
19357
19358   // Create an ObjectTemplate for global objects and install access
19359   // check callbacks that will block access.
19360   v8::Handle<v8::ObjectTemplate> global_template =
19361       v8::ObjectTemplate::New(isolate);
19362   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19363                                            IndexedGetAccessBlocker,
19364                                            v8::Handle<v8::Value>(),
19365                                            false);
19366
19367   // Create a context and set an x property on it's global object.
19368   LocalContext context0(NULL, global_template);
19369   context0->Global()->Set(v8_str("x"), v8_num(42));
19370   v8::Handle<v8::Object> global0 = context0->Global();
19371
19372   // Create a context with a different security token so that the
19373   // failed access check callback will be called on each access.
19374   LocalContext context1(NULL, global_template);
19375   context1->Global()->Set(v8_str("other"), global0);
19376
19377   // Get property with failed access check.
19378   ExpectUndefined("other.x");
19379
19380   // Get element with failed access check.
19381   ExpectUndefined("other[0]");
19382
19383   // Set property with failed access check.
19384   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19385   CHECK(result->IsObject());
19386
19387   // Set element with failed access check.
19388   result = CompileRun("other[0] = new Object()");
19389   CHECK(result->IsObject());
19390
19391   // Get property attribute with failed access check.
19392   ExpectFalse("\'x\' in other");
19393
19394   // Get property attribute for element with failed access check.
19395   ExpectFalse("0 in other");
19396
19397   // Delete property.
19398   ExpectFalse("delete other.x");
19399
19400   // Delete element.
19401   CHECK_EQ(false, global0->Delete(0));
19402
19403   // DefineAccessor.
19404   CHECK_EQ(false,
19405            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19406
19407   // Define JavaScript accessor.
19408   ExpectUndefined("Object.prototype.__defineGetter__.call("
19409                   "    other, \'x\', function() { return 42; })");
19410
19411   // LookupAccessor.
19412   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19413                   "    other, \'x\')");
19414
19415   // HasOwnElement.
19416   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19417
19418   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19419   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19420   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19421
19422   // Reset the failed access check callback so it does not influence
19423   // the other tests.
19424   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19425 }
19426
19427
19428 TEST(IsolateNewDispose) {
19429   v8::Isolate* current_isolate = CcTest::isolate();
19430   v8::Isolate* isolate = v8::Isolate::New();
19431   CHECK(isolate != NULL);
19432   CHECK(current_isolate != isolate);
19433   CHECK(current_isolate == CcTest::isolate());
19434
19435   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19436   last_location = last_message = NULL;
19437   isolate->Dispose();
19438   CHECK_EQ(last_location, NULL);
19439   CHECK_EQ(last_message, NULL);
19440 }
19441
19442
19443 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19444   v8::Isolate* isolate = v8::Isolate::New();
19445   {
19446     v8::Isolate::Scope i_scope(isolate);
19447     v8::HandleScope scope(isolate);
19448     LocalContext context(isolate);
19449     // Run something in this isolate.
19450     ExpectTrue("true");
19451     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19452     last_location = last_message = NULL;
19453     // Still entered, should fail.
19454     isolate->Dispose();
19455     CHECK_NE(last_location, NULL);
19456     CHECK_NE(last_message, NULL);
19457   }
19458   isolate->Dispose();
19459 }
19460
19461
19462 TEST(RunTwoIsolatesOnSingleThread) {
19463   // Run isolate 1.
19464   v8::Isolate* isolate1 = v8::Isolate::New();
19465   isolate1->Enter();
19466   v8::Persistent<v8::Context> context1;
19467   {
19468     v8::HandleScope scope(isolate1);
19469     context1.Reset(isolate1, Context::New(isolate1));
19470   }
19471
19472   {
19473     v8::HandleScope scope(isolate1);
19474     v8::Local<v8::Context> context =
19475         v8::Local<v8::Context>::New(isolate1, context1);
19476     v8::Context::Scope context_scope(context);
19477     // Run something in new isolate.
19478     CompileRun("var foo = 'isolate 1';");
19479     ExpectString("function f() { return foo; }; f()", "isolate 1");
19480   }
19481
19482   // Run isolate 2.
19483   v8::Isolate* isolate2 = v8::Isolate::New();
19484   v8::Persistent<v8::Context> context2;
19485
19486   {
19487     v8::Isolate::Scope iscope(isolate2);
19488     v8::HandleScope scope(isolate2);
19489     context2.Reset(isolate2, Context::New(isolate2));
19490     v8::Local<v8::Context> context =
19491         v8::Local<v8::Context>::New(isolate2, context2);
19492     v8::Context::Scope context_scope(context);
19493
19494     // Run something in new isolate.
19495     CompileRun("var foo = 'isolate 2';");
19496     ExpectString("function f() { return foo; }; f()", "isolate 2");
19497   }
19498
19499   {
19500     v8::HandleScope scope(isolate1);
19501     v8::Local<v8::Context> context =
19502         v8::Local<v8::Context>::New(isolate1, context1);
19503     v8::Context::Scope context_scope(context);
19504     // Now again in isolate 1
19505     ExpectString("function f() { return foo; }; f()", "isolate 1");
19506   }
19507
19508   isolate1->Exit();
19509
19510   // Run some stuff in default isolate.
19511   v8::Persistent<v8::Context> context_default;
19512   {
19513     v8::Isolate* isolate = CcTest::isolate();
19514     v8::Isolate::Scope iscope(isolate);
19515     v8::HandleScope scope(isolate);
19516     context_default.Reset(isolate, Context::New(isolate));
19517   }
19518
19519   {
19520     v8::HandleScope scope(CcTest::isolate());
19521     v8::Local<v8::Context> context =
19522         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19523     v8::Context::Scope context_scope(context);
19524     // Variables in other isolates should be not available, verify there
19525     // is an exception.
19526     ExpectTrue("function f() {"
19527                "  try {"
19528                "    foo;"
19529                "    return false;"
19530                "  } catch(e) {"
19531                "    return true;"
19532                "  }"
19533                "};"
19534                "var isDefaultIsolate = true;"
19535                "f()");
19536   }
19537
19538   isolate1->Enter();
19539
19540   {
19541     v8::Isolate::Scope iscope(isolate2);
19542     v8::HandleScope scope(isolate2);
19543     v8::Local<v8::Context> context =
19544         v8::Local<v8::Context>::New(isolate2, context2);
19545     v8::Context::Scope context_scope(context);
19546     ExpectString("function f() { return foo; }; f()", "isolate 2");
19547   }
19548
19549   {
19550     v8::HandleScope scope(v8::Isolate::GetCurrent());
19551     v8::Local<v8::Context> context =
19552         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19553     v8::Context::Scope context_scope(context);
19554     ExpectString("function f() { return foo; }; f()", "isolate 1");
19555   }
19556
19557   {
19558     v8::Isolate::Scope iscope(isolate2);
19559     context2.Reset();
19560   }
19561
19562   context1.Reset();
19563   isolate1->Exit();
19564
19565   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19566   last_location = last_message = NULL;
19567
19568   isolate1->Dispose();
19569   CHECK_EQ(last_location, NULL);
19570   CHECK_EQ(last_message, NULL);
19571
19572   isolate2->Dispose();
19573   CHECK_EQ(last_location, NULL);
19574   CHECK_EQ(last_message, NULL);
19575
19576   // Check that default isolate still runs.
19577   {
19578     v8::HandleScope scope(CcTest::isolate());
19579     v8::Local<v8::Context> context =
19580         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19581     v8::Context::Scope context_scope(context);
19582     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19583   }
19584 }
19585
19586
19587 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19588   v8::Isolate::Scope isolate_scope(isolate);
19589   v8::HandleScope scope(isolate);
19590   LocalContext context(isolate);
19591   i::ScopedVector<char> code(1024);
19592   i::SNPrintF(code, "function fib(n) {"
19593                     "  if (n <= 2) return 1;"
19594                     "  return fib(n-1) + fib(n-2);"
19595                     "}"
19596                     "fib(%d)", limit);
19597   Local<Value> value = CompileRun(code.start());
19598   CHECK(value->IsNumber());
19599   return static_cast<int>(value->NumberValue());
19600 }
19601
19602 class IsolateThread : public v8::base::Thread {
19603  public:
19604   explicit IsolateThread(int fib_limit)
19605       : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
19606
19607   void Run() {
19608     v8::Isolate* isolate = v8::Isolate::New();
19609     result_ = CalcFibonacci(isolate, fib_limit_);
19610     isolate->Dispose();
19611   }
19612
19613   int result() { return result_; }
19614
19615  private:
19616   int fib_limit_;
19617   int result_;
19618 };
19619
19620
19621 TEST(MultipleIsolatesOnIndividualThreads) {
19622   IsolateThread thread1(21);
19623   IsolateThread thread2(12);
19624
19625   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19626   thread1.Start();
19627   thread2.Start();
19628
19629   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19630   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19631
19632   thread1.Join();
19633   thread2.Join();
19634
19635   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19636   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19637   CHECK_EQ(result1, 10946);
19638   CHECK_EQ(result2, 144);
19639   CHECK_EQ(result1, thread1.result());
19640   CHECK_EQ(result2, thread2.result());
19641 }
19642
19643
19644 TEST(IsolateDifferentContexts) {
19645   v8::Isolate* isolate = v8::Isolate::New();
19646   Local<v8::Context> context;
19647   {
19648     v8::Isolate::Scope isolate_scope(isolate);
19649     v8::HandleScope handle_scope(isolate);
19650     context = v8::Context::New(isolate);
19651     v8::Context::Scope context_scope(context);
19652     Local<Value> v = CompileRun("2");
19653     CHECK(v->IsNumber());
19654     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19655   }
19656   {
19657     v8::Isolate::Scope isolate_scope(isolate);
19658     v8::HandleScope handle_scope(isolate);
19659     context = v8::Context::New(isolate);
19660     v8::Context::Scope context_scope(context);
19661     Local<Value> v = CompileRun("22");
19662     CHECK(v->IsNumber());
19663     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19664   }
19665   isolate->Dispose();
19666 }
19667
19668 class InitDefaultIsolateThread : public v8::base::Thread {
19669  public:
19670   enum TestCase {
19671     SetResourceConstraints,
19672     SetFatalHandler,
19673     SetCounterFunction,
19674     SetCreateHistogramFunction,
19675     SetAddHistogramSampleFunction
19676   };
19677
19678   explicit InitDefaultIsolateThread(TestCase testCase)
19679       : Thread(Options("InitDefaultIsolateThread")),
19680         testCase_(testCase),
19681         result_(false) {}
19682
19683   void Run() {
19684     v8::Isolate::CreateParams create_params;
19685     switch (testCase_) {
19686       case SetResourceConstraints: {
19687         create_params.constraints.set_max_semi_space_size(1);
19688         create_params.constraints.set_max_old_space_size(4);
19689         break;
19690       }
19691       default:
19692         break;
19693     }
19694     v8::Isolate* isolate = v8::Isolate::New(create_params);
19695     isolate->Enter();
19696     switch (testCase_) {
19697       case SetResourceConstraints:
19698         // Already handled in pre-Isolate-creation block.
19699         break;
19700
19701       case SetFatalHandler:
19702         v8::V8::SetFatalErrorHandler(NULL);
19703         break;
19704
19705       case SetCounterFunction:
19706         CcTest::isolate()->SetCounterFunction(NULL);
19707         break;
19708
19709       case SetCreateHistogramFunction:
19710         CcTest::isolate()->SetCreateHistogramFunction(NULL);
19711         break;
19712
19713       case SetAddHistogramSampleFunction:
19714         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19715         break;
19716     }
19717     isolate->Exit();
19718     isolate->Dispose();
19719     result_ = true;
19720   }
19721
19722   bool result() { return result_; }
19723
19724  private:
19725   TestCase testCase_;
19726   bool result_;
19727 };
19728
19729
19730 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19731   InitDefaultIsolateThread thread(testCase);
19732   thread.Start();
19733   thread.Join();
19734   CHECK_EQ(thread.result(), true);
19735 }
19736
19737
19738 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19739   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19740 }
19741
19742
19743 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19744   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19745 }
19746
19747
19748 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19749   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19750 }
19751
19752
19753 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19754   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19755 }
19756
19757
19758 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19759   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19760 }
19761
19762
19763 TEST(StringCheckMultipleContexts) {
19764   const char* code =
19765       "(function() { return \"a\".charAt(0); })()";
19766
19767   {
19768     // Run the code twice in the first context to initialize the call IC.
19769     LocalContext context1;
19770     v8::HandleScope scope(context1->GetIsolate());
19771     ExpectString(code, "a");
19772     ExpectString(code, "a");
19773   }
19774
19775   {
19776     // Change the String.prototype in the second context and check
19777     // that the right function gets called.
19778     LocalContext context2;
19779     v8::HandleScope scope(context2->GetIsolate());
19780     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19781     ExpectString(code, "not a");
19782   }
19783 }
19784
19785
19786 TEST(NumberCheckMultipleContexts) {
19787   const char* code =
19788       "(function() { return (42).toString(); })()";
19789
19790   {
19791     // Run the code twice in the first context to initialize the call IC.
19792     LocalContext context1;
19793     v8::HandleScope scope(context1->GetIsolate());
19794     ExpectString(code, "42");
19795     ExpectString(code, "42");
19796   }
19797
19798   {
19799     // Change the Number.prototype in the second context and check
19800     // that the right function gets called.
19801     LocalContext context2;
19802     v8::HandleScope scope(context2->GetIsolate());
19803     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19804     ExpectString(code, "not 42");
19805   }
19806 }
19807
19808
19809 TEST(BooleanCheckMultipleContexts) {
19810   const char* code =
19811       "(function() { return true.toString(); })()";
19812
19813   {
19814     // Run the code twice in the first context to initialize the call IC.
19815     LocalContext context1;
19816     v8::HandleScope scope(context1->GetIsolate());
19817     ExpectString(code, "true");
19818     ExpectString(code, "true");
19819   }
19820
19821   {
19822     // Change the Boolean.prototype in the second context and check
19823     // that the right function gets called.
19824     LocalContext context2;
19825     v8::HandleScope scope(context2->GetIsolate());
19826     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19827     ExpectString(code, "");
19828   }
19829 }
19830
19831
19832 TEST(DontDeleteCellLoadIC) {
19833   const char* function_code =
19834       "function readCell() { while (true) { return cell; } }";
19835
19836   {
19837     // Run the code twice in the first context to initialize the load
19838     // IC for a don't delete cell.
19839     LocalContext context1;
19840     v8::HandleScope scope(context1->GetIsolate());
19841     CompileRun("var cell = \"first\";");
19842     ExpectBoolean("delete cell", false);
19843     CompileRun(function_code);
19844     ExpectString("readCell()", "first");
19845     ExpectString("readCell()", "first");
19846   }
19847
19848   {
19849     // Use a deletable cell in the second context.
19850     LocalContext context2;
19851     v8::HandleScope scope(context2->GetIsolate());
19852     CompileRun("cell = \"second\";");
19853     CompileRun(function_code);
19854     ExpectString("readCell()", "second");
19855     ExpectBoolean("delete cell", true);
19856     ExpectString("(function() {"
19857                  "  try {"
19858                  "    return readCell();"
19859                  "  } catch(e) {"
19860                  "    return e.toString();"
19861                  "  }"
19862                  "})()",
19863                  "ReferenceError: cell is not defined");
19864     CompileRun("cell = \"new_second\";");
19865     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19866     ExpectString("readCell()", "new_second");
19867     ExpectString("readCell()", "new_second");
19868   }
19869 }
19870
19871
19872 TEST(DontDeleteCellLoadICForceDelete) {
19873   const char* function_code =
19874       "function readCell() { while (true) { return cell; } }";
19875
19876   // Run the code twice to initialize the load IC for a don't delete
19877   // cell.
19878   LocalContext context;
19879   v8::HandleScope scope(context->GetIsolate());
19880   CompileRun("var cell = \"value\";");
19881   ExpectBoolean("delete cell", false);
19882   CompileRun(function_code);
19883   ExpectString("readCell()", "value");
19884   ExpectString("readCell()", "value");
19885
19886   // Delete the cell using the API and check the inlined code works
19887   // correctly.
19888   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19889   ExpectString("(function() {"
19890                "  try {"
19891                "    return readCell();"
19892                "  } catch(e) {"
19893                "    return e.toString();"
19894                "  }"
19895                "})()",
19896                "ReferenceError: cell is not defined");
19897 }
19898
19899
19900 TEST(DontDeleteCellLoadICAPI) {
19901   const char* function_code =
19902       "function readCell() { while (true) { return cell; } }";
19903
19904   // Run the code twice to initialize the load IC for a don't delete
19905   // cell created using the API.
19906   LocalContext context;
19907   v8::HandleScope scope(context->GetIsolate());
19908   context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
19909   ExpectBoolean("delete cell", false);
19910   CompileRun(function_code);
19911   ExpectString("readCell()", "value");
19912   ExpectString("readCell()", "value");
19913
19914   // Delete the cell using the API and check the inlined code works
19915   // correctly.
19916   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19917   ExpectString("(function() {"
19918                "  try {"
19919                "    return readCell();"
19920                "  } catch(e) {"
19921                "    return e.toString();"
19922                "  }"
19923                "})()",
19924                "ReferenceError: cell is not defined");
19925 }
19926
19927
19928 class Visitor42 : public v8::PersistentHandleVisitor {
19929  public:
19930   explicit Visitor42(v8::Persistent<v8::Object>* object)
19931       : counter_(0), object_(object) { }
19932
19933   virtual void VisitPersistentHandle(Persistent<Value>* value,
19934                                      uint16_t class_id) {
19935     if (class_id != 42) return;
19936     CHECK_EQ(42, value->WrapperClassId());
19937     v8::Isolate* isolate = CcTest::isolate();
19938     v8::HandleScope handle_scope(isolate);
19939     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19940     v8::Handle<v8::Value> object =
19941         v8::Local<v8::Object>::New(isolate, *object_);
19942     CHECK(handle->IsObject());
19943     CHECK_EQ(Handle<Object>::Cast(handle), object);
19944     ++counter_;
19945   }
19946
19947   int counter_;
19948   v8::Persistent<v8::Object>* object_;
19949 };
19950
19951
19952 TEST(PersistentHandleVisitor) {
19953   LocalContext context;
19954   v8::Isolate* isolate = context->GetIsolate();
19955   v8::HandleScope scope(isolate);
19956   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19957   CHECK_EQ(0, object.WrapperClassId());
19958   object.SetWrapperClassId(42);
19959   CHECK_EQ(42, object.WrapperClassId());
19960
19961   Visitor42 visitor(&object);
19962   v8::V8::VisitHandlesWithClassIds(&visitor);
19963   CHECK_EQ(1, visitor.counter_);
19964
19965   object.Reset();
19966 }
19967
19968
19969 TEST(WrapperClassId) {
19970   LocalContext context;
19971   v8::Isolate* isolate = context->GetIsolate();
19972   v8::HandleScope scope(isolate);
19973   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19974   CHECK_EQ(0, object.WrapperClassId());
19975   object.SetWrapperClassId(65535);
19976   CHECK_EQ(65535, object.WrapperClassId());
19977   object.Reset();
19978 }
19979
19980
19981 TEST(PersistentHandleInNewSpaceVisitor) {
19982   LocalContext context;
19983   v8::Isolate* isolate = context->GetIsolate();
19984   v8::HandleScope scope(isolate);
19985   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19986   CHECK_EQ(0, object1.WrapperClassId());
19987   object1.SetWrapperClassId(42);
19988   CHECK_EQ(42, object1.WrapperClassId());
19989
19990   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19991   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19992
19993   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19994   CHECK_EQ(0, object2.WrapperClassId());
19995   object2.SetWrapperClassId(42);
19996   CHECK_EQ(42, object2.WrapperClassId());
19997
19998   Visitor42 visitor(&object2);
19999   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
20000   CHECK_EQ(1, visitor.counter_);
20001
20002   object1.Reset();
20003   object2.Reset();
20004 }
20005
20006
20007 TEST(RegExp) {
20008   LocalContext context;
20009   v8::HandleScope scope(context->GetIsolate());
20010
20011   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
20012   CHECK(re->IsRegExp());
20013   CHECK(re->GetSource()->Equals(v8_str("foo")));
20014   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20015
20016   re = v8::RegExp::New(v8_str("bar"),
20017                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20018                                                       v8::RegExp::kGlobal));
20019   CHECK(re->IsRegExp());
20020   CHECK(re->GetSource()->Equals(v8_str("bar")));
20021   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20022            static_cast<int>(re->GetFlags()));
20023
20024   re = v8::RegExp::New(v8_str("baz"),
20025                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20026                                                       v8::RegExp::kMultiline));
20027   CHECK(re->IsRegExp());
20028   CHECK(re->GetSource()->Equals(v8_str("baz")));
20029   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20030            static_cast<int>(re->GetFlags()));
20031
20032   re = CompileRun("/quux/").As<v8::RegExp>();
20033   CHECK(re->IsRegExp());
20034   CHECK(re->GetSource()->Equals(v8_str("quux")));
20035   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20036
20037   re = CompileRun("/quux/gm").As<v8::RegExp>();
20038   CHECK(re->IsRegExp());
20039   CHECK(re->GetSource()->Equals(v8_str("quux")));
20040   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20041            static_cast<int>(re->GetFlags()));
20042
20043   // Override the RegExp constructor and check the API constructor
20044   // still works.
20045   CompileRun("RegExp = function() {}");
20046
20047   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
20048   CHECK(re->IsRegExp());
20049   CHECK(re->GetSource()->Equals(v8_str("foobar")));
20050   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20051
20052   re = v8::RegExp::New(v8_str("foobarbaz"),
20053                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20054                                                       v8::RegExp::kMultiline));
20055   CHECK(re->IsRegExp());
20056   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
20057   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20058            static_cast<int>(re->GetFlags()));
20059
20060   context->Global()->Set(v8_str("re"), re);
20061   ExpectTrue("re.test('FoobarbaZ')");
20062
20063   // RegExps are objects on which you can set properties.
20064   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
20065   v8::Handle<v8::Value> value(CompileRun("re.property"));
20066   CHECK_EQ(32, value->Int32Value());
20067
20068   v8::TryCatch try_catch;
20069   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
20070   CHECK(re.IsEmpty());
20071   CHECK(try_catch.HasCaught());
20072   context->Global()->Set(v8_str("ex"), try_catch.Exception());
20073   ExpectTrue("ex instanceof SyntaxError");
20074 }
20075
20076
20077 THREADED_TEST(Equals) {
20078   LocalContext localContext;
20079   v8::HandleScope handleScope(localContext->GetIsolate());
20080
20081   v8::Handle<v8::Object> globalProxy = localContext->Global();
20082   v8::Handle<Value> global = globalProxy->GetPrototype();
20083
20084   CHECK(global->StrictEquals(global));
20085   CHECK(!global->StrictEquals(globalProxy));
20086   CHECK(!globalProxy->StrictEquals(global));
20087   CHECK(globalProxy->StrictEquals(globalProxy));
20088
20089   CHECK(global->Equals(global));
20090   CHECK(!global->Equals(globalProxy));
20091   CHECK(!globalProxy->Equals(global));
20092   CHECK(globalProxy->Equals(globalProxy));
20093 }
20094
20095
20096 static void Getter(v8::Local<v8::String> property,
20097                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
20098   info.GetReturnValue().Set(v8_str("42!"));
20099 }
20100
20101
20102 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20103   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
20104   result->Set(0, v8_str("universalAnswer"));
20105   info.GetReturnValue().Set(result);
20106 }
20107
20108
20109 TEST(NamedEnumeratorAndForIn) {
20110   LocalContext context;
20111   v8::Isolate* isolate = context->GetIsolate();
20112   v8::HandleScope handle_scope(isolate);
20113   v8::Context::Scope context_scope(context.local());
20114
20115   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20116   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
20117   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
20118   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
20119         "var result = []; for (var k in o) result.push(k); result"));
20120   CHECK_EQ(1, result->Length());
20121   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
20122 }
20123
20124
20125 TEST(DefinePropertyPostDetach) {
20126   LocalContext context;
20127   v8::HandleScope scope(context->GetIsolate());
20128   v8::Handle<v8::Object> proxy = context->Global();
20129   v8::Handle<v8::Function> define_property =
20130       CompileRun("(function() {"
20131                  "  Object.defineProperty("
20132                  "    this,"
20133                  "    1,"
20134                  "    { configurable: true, enumerable: true, value: 3 });"
20135                  "})").As<Function>();
20136   context->DetachGlobal();
20137   define_property->Call(proxy, 0, NULL);
20138 }
20139
20140
20141 static void InstallContextId(v8::Handle<Context> context, int id) {
20142   Context::Scope scope(context);
20143   CompileRun("Object.prototype").As<Object>()->
20144       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
20145 }
20146
20147
20148 static void CheckContextId(v8::Handle<Object> object, int expected) {
20149   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20150 }
20151
20152
20153 THREADED_TEST(CreationContext) {
20154   v8::Isolate* isolate = CcTest::isolate();
20155   HandleScope handle_scope(isolate);
20156   Handle<Context> context1 = Context::New(isolate);
20157   InstallContextId(context1, 1);
20158   Handle<Context> context2 = Context::New(isolate);
20159   InstallContextId(context2, 2);
20160   Handle<Context> context3 = Context::New(isolate);
20161   InstallContextId(context3, 3);
20162
20163   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20164
20165   Local<Object> object1;
20166   Local<Function> func1;
20167   {
20168     Context::Scope scope(context1);
20169     object1 = Object::New(isolate);
20170     func1 = tmpl->GetFunction();
20171   }
20172
20173   Local<Object> object2;
20174   Local<Function> func2;
20175   {
20176     Context::Scope scope(context2);
20177     object2 = Object::New(isolate);
20178     func2 = tmpl->GetFunction();
20179   }
20180
20181   Local<Object> instance1;
20182   Local<Object> instance2;
20183
20184   {
20185     Context::Scope scope(context3);
20186     instance1 = func1->NewInstance();
20187     instance2 = func2->NewInstance();
20188   }
20189
20190   CHECK(object1->CreationContext() == context1);
20191   CheckContextId(object1, 1);
20192   CHECK(func1->CreationContext() == context1);
20193   CheckContextId(func1, 1);
20194   CHECK(instance1->CreationContext() == context1);
20195   CheckContextId(instance1, 1);
20196   CHECK(object2->CreationContext() == context2);
20197   CheckContextId(object2, 2);
20198   CHECK(func2->CreationContext() == context2);
20199   CheckContextId(func2, 2);
20200   CHECK(instance2->CreationContext() == context2);
20201   CheckContextId(instance2, 2);
20202
20203   {
20204     Context::Scope scope(context1);
20205     CHECK(object1->CreationContext() == context1);
20206     CheckContextId(object1, 1);
20207     CHECK(func1->CreationContext() == context1);
20208     CheckContextId(func1, 1);
20209     CHECK(instance1->CreationContext() == context1);
20210     CheckContextId(instance1, 1);
20211     CHECK(object2->CreationContext() == context2);
20212     CheckContextId(object2, 2);
20213     CHECK(func2->CreationContext() == context2);
20214     CheckContextId(func2, 2);
20215     CHECK(instance2->CreationContext() == context2);
20216     CheckContextId(instance2, 2);
20217   }
20218
20219   {
20220     Context::Scope scope(context2);
20221     CHECK(object1->CreationContext() == context1);
20222     CheckContextId(object1, 1);
20223     CHECK(func1->CreationContext() == context1);
20224     CheckContextId(func1, 1);
20225     CHECK(instance1->CreationContext() == context1);
20226     CheckContextId(instance1, 1);
20227     CHECK(object2->CreationContext() == context2);
20228     CheckContextId(object2, 2);
20229     CHECK(func2->CreationContext() == context2);
20230     CheckContextId(func2, 2);
20231     CHECK(instance2->CreationContext() == context2);
20232     CheckContextId(instance2, 2);
20233   }
20234 }
20235
20236
20237 THREADED_TEST(CreationContextOfJsFunction) {
20238   HandleScope handle_scope(CcTest::isolate());
20239   Handle<Context> context = Context::New(CcTest::isolate());
20240   InstallContextId(context, 1);
20241
20242   Local<Object> function;
20243   {
20244     Context::Scope scope(context);
20245     function = CompileRun("function foo() {}; foo").As<Object>();
20246   }
20247
20248   CHECK(function->CreationContext() == context);
20249   CheckContextId(function, 1);
20250 }
20251
20252
20253 void HasOwnPropertyIndexedPropertyGetter(
20254     uint32_t index,
20255     const v8::PropertyCallbackInfo<v8::Value>& info) {
20256   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20257 }
20258
20259
20260 void HasOwnPropertyNamedPropertyGetter(
20261     Local<String> property,
20262     const v8::PropertyCallbackInfo<v8::Value>& info) {
20263   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20264 }
20265
20266
20267 void HasOwnPropertyIndexedPropertyQuery(
20268     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20269   if (index == 42) info.GetReturnValue().Set(1);
20270 }
20271
20272
20273 void HasOwnPropertyNamedPropertyQuery(
20274     Local<String> property,
20275     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20276   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20277 }
20278
20279
20280 void HasOwnPropertyNamedPropertyQuery2(
20281     Local<String> property,
20282     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20283   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20284 }
20285
20286
20287 void HasOwnPropertyAccessorGetter(
20288     Local<String> property,
20289     const v8::PropertyCallbackInfo<v8::Value>& info) {
20290   info.GetReturnValue().Set(v8_str("yes"));
20291 }
20292
20293
20294 TEST(HasOwnProperty) {
20295   LocalContext env;
20296   v8::Isolate* isolate = env->GetIsolate();
20297   v8::HandleScope scope(isolate);
20298   { // Check normal properties and defined getters.
20299     Handle<Value> value = CompileRun(
20300         "function Foo() {"
20301         "    this.foo = 11;"
20302         "    this.__defineGetter__('baz', function() { return 1; });"
20303         "};"
20304         "function Bar() { "
20305         "    this.bar = 13;"
20306         "    this.__defineGetter__('bla', function() { return 2; });"
20307         "};"
20308         "Bar.prototype = new Foo();"
20309         "new Bar();");
20310     CHECK(value->IsObject());
20311     Handle<Object> object = value->ToObject();
20312     CHECK(object->Has(v8_str("foo")));
20313     CHECK(!object->HasOwnProperty(v8_str("foo")));
20314     CHECK(object->HasOwnProperty(v8_str("bar")));
20315     CHECK(object->Has(v8_str("baz")));
20316     CHECK(!object->HasOwnProperty(v8_str("baz")));
20317     CHECK(object->HasOwnProperty(v8_str("bla")));
20318   }
20319   { // Check named getter interceptors.
20320     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20321     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20322     Handle<Object> instance = templ->NewInstance();
20323     CHECK(!instance->HasOwnProperty(v8_str("42")));
20324     CHECK(instance->HasOwnProperty(v8_str("foo")));
20325     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20326   }
20327   { // Check indexed getter interceptors.
20328     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20329     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20330     Handle<Object> instance = templ->NewInstance();
20331     CHECK(instance->HasOwnProperty(v8_str("42")));
20332     CHECK(!instance->HasOwnProperty(v8_str("43")));
20333     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20334   }
20335   { // Check named query interceptors.
20336     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20337     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20338     Handle<Object> instance = templ->NewInstance();
20339     CHECK(instance->HasOwnProperty(v8_str("foo")));
20340     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20341   }
20342   { // Check indexed query interceptors.
20343     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20344     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20345     Handle<Object> instance = templ->NewInstance();
20346     CHECK(instance->HasOwnProperty(v8_str("42")));
20347     CHECK(!instance->HasOwnProperty(v8_str("41")));
20348   }
20349   { // Check callbacks.
20350     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20351     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20352     Handle<Object> instance = templ->NewInstance();
20353     CHECK(instance->HasOwnProperty(v8_str("foo")));
20354     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20355   }
20356   { // Check that query wins on disagreement.
20357     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20358     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20359                                    0,
20360                                    HasOwnPropertyNamedPropertyQuery2);
20361     Handle<Object> instance = templ->NewInstance();
20362     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20363     CHECK(instance->HasOwnProperty(v8_str("bar")));
20364   }
20365 }
20366
20367
20368 TEST(IndexedInterceptorWithStringProto) {
20369   v8::Isolate* isolate = CcTest::isolate();
20370   v8::HandleScope scope(isolate);
20371   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20372   templ->SetIndexedPropertyHandler(NULL,
20373                                    NULL,
20374                                    HasOwnPropertyIndexedPropertyQuery);
20375   LocalContext context;
20376   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20377   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20378   // These should be intercepted.
20379   CHECK(CompileRun("42 in obj")->BooleanValue());
20380   CHECK(CompileRun("'42' in obj")->BooleanValue());
20381   // These should fall through to the String prototype.
20382   CHECK(CompileRun("0 in obj")->BooleanValue());
20383   CHECK(CompileRun("'0' in obj")->BooleanValue());
20384   // And these should both fail.
20385   CHECK(!CompileRun("32 in obj")->BooleanValue());
20386   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20387 }
20388
20389
20390 void CheckCodeGenerationAllowed() {
20391   Handle<Value> result = CompileRun("eval('42')");
20392   CHECK_EQ(42, result->Int32Value());
20393   result = CompileRun("(function(e) { return e('42'); })(eval)");
20394   CHECK_EQ(42, result->Int32Value());
20395   result = CompileRun("var f = new Function('return 42'); f()");
20396   CHECK_EQ(42, result->Int32Value());
20397 }
20398
20399
20400 void CheckCodeGenerationDisallowed() {
20401   TryCatch try_catch;
20402
20403   Handle<Value> result = CompileRun("eval('42')");
20404   CHECK(result.IsEmpty());
20405   CHECK(try_catch.HasCaught());
20406   try_catch.Reset();
20407
20408   result = CompileRun("(function(e) { return e('42'); })(eval)");
20409   CHECK(result.IsEmpty());
20410   CHECK(try_catch.HasCaught());
20411   try_catch.Reset();
20412
20413   result = CompileRun("var f = new Function('return 42'); f()");
20414   CHECK(result.IsEmpty());
20415   CHECK(try_catch.HasCaught());
20416 }
20417
20418
20419 bool CodeGenerationAllowed(Local<Context> context) {
20420   ApiTestFuzzer::Fuzz();
20421   return true;
20422 }
20423
20424
20425 bool CodeGenerationDisallowed(Local<Context> context) {
20426   ApiTestFuzzer::Fuzz();
20427   return false;
20428 }
20429
20430
20431 THREADED_TEST(AllowCodeGenFromStrings) {
20432   LocalContext context;
20433   v8::HandleScope scope(context->GetIsolate());
20434
20435   // eval and the Function constructor allowed by default.
20436   CHECK(context->IsCodeGenerationFromStringsAllowed());
20437   CheckCodeGenerationAllowed();
20438
20439   // Disallow eval and the Function constructor.
20440   context->AllowCodeGenerationFromStrings(false);
20441   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20442   CheckCodeGenerationDisallowed();
20443
20444   // Allow again.
20445   context->AllowCodeGenerationFromStrings(true);
20446   CheckCodeGenerationAllowed();
20447
20448   // Disallow but setting a global callback that will allow the calls.
20449   context->AllowCodeGenerationFromStrings(false);
20450   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20451   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20452   CheckCodeGenerationAllowed();
20453
20454   // Set a callback that disallows the code generation.
20455   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20456   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20457   CheckCodeGenerationDisallowed();
20458 }
20459
20460
20461 TEST(SetErrorMessageForCodeGenFromStrings) {
20462   LocalContext context;
20463   v8::HandleScope scope(context->GetIsolate());
20464   TryCatch try_catch;
20465
20466   Handle<String> message = v8_str("Message") ;
20467   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20468   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20469   context->AllowCodeGenerationFromStrings(false);
20470   context->SetErrorMessageForCodeGenerationFromStrings(message);
20471   Handle<Value> result = CompileRun("eval('42')");
20472   CHECK(result.IsEmpty());
20473   CHECK(try_catch.HasCaught());
20474   Handle<String> actual_message = try_catch.Message()->Get();
20475   CHECK(expected_message->Equals(actual_message));
20476 }
20477
20478
20479 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20480 }
20481
20482
20483 THREADED_TEST(CallAPIFunctionOnNonObject) {
20484   LocalContext context;
20485   v8::Isolate* isolate = context->GetIsolate();
20486   v8::HandleScope scope(isolate);
20487   Handle<FunctionTemplate> templ =
20488       v8::FunctionTemplate::New(isolate, NonObjectThis);
20489   Handle<Function> function = templ->GetFunction();
20490   context->Global()->Set(v8_str("f"), function);
20491   TryCatch try_catch;
20492   CompileRun("f.call(2)");
20493 }
20494
20495
20496 // Regression test for issue 1470.
20497 THREADED_TEST(ReadOnlyIndexedProperties) {
20498   v8::Isolate* isolate = CcTest::isolate();
20499   v8::HandleScope scope(isolate);
20500   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20501
20502   LocalContext context;
20503   Local<v8::Object> obj = templ->NewInstance();
20504   context->Global()->Set(v8_str("obj"), obj);
20505   obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20506   obj->Set(v8_str("1"), v8_str("foobar"));
20507   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20508   obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20509   obj->Set(v8_num(2), v8_str("foobar"));
20510   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20511
20512   // Test non-smi case.
20513   obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20514   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20515   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20516 }
20517
20518
20519 THREADED_TEST(Regress1516) {
20520   LocalContext context;
20521   v8::HandleScope scope(context->GetIsolate());
20522
20523   { v8::HandleScope temp_scope(context->GetIsolate());
20524     CompileRun("({'a': 0})");
20525   }
20526
20527   int elements;
20528   { i::MapCache* map_cache =
20529         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20530     elements = map_cache->NumberOfElements();
20531     CHECK_LE(1, elements);
20532   }
20533
20534   CcTest::heap()->CollectAllGarbage(
20535       i::Heap::kAbortIncrementalMarkingMask);
20536   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20537     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20538       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20539       CHECK_GT(elements, map_cache->NumberOfElements());
20540     }
20541   }
20542 }
20543
20544
20545 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20546                                                 Local<Value> name,
20547                                                 v8::AccessType type,
20548                                                 Local<Value> data) {
20549   // Only block read access to __proto__.
20550   if (type == v8::ACCESS_GET &&
20551       name->IsString() &&
20552       name->ToString()->Length() == 9 &&
20553       name->ToString()->Utf8Length() == 9) {
20554     char buffer[10];
20555     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20556     return strncmp(buffer, "__proto__", 9) != 0;
20557   }
20558
20559   return true;
20560 }
20561
20562
20563 THREADED_TEST(Regress93759) {
20564   v8::Isolate* isolate = CcTest::isolate();
20565   HandleScope scope(isolate);
20566
20567   // Template for object with security check.
20568   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20569   // We don't do indexing, so any callback can be used for that.
20570   no_proto_template->SetAccessCheckCallbacks(
20571       BlockProtoNamedSecurityTestCallback,
20572       IndexedSecurityTestCallback);
20573
20574   // Templates for objects with hidden prototypes and possibly security check.
20575   Local<FunctionTemplate> hidden_proto_template =
20576       v8::FunctionTemplate::New(isolate);
20577   hidden_proto_template->SetHiddenPrototype(true);
20578
20579   Local<FunctionTemplate> protected_hidden_proto_template =
20580       v8::FunctionTemplate::New(isolate);
20581   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20582       BlockProtoNamedSecurityTestCallback,
20583       IndexedSecurityTestCallback);
20584   protected_hidden_proto_template->SetHiddenPrototype(true);
20585
20586   // Context for "foreign" objects used in test.
20587   Local<Context> context = v8::Context::New(isolate);
20588   context->Enter();
20589
20590   // Plain object, no security check.
20591   Local<Object> simple_object = Object::New(isolate);
20592
20593   // Object with explicit security check.
20594   Local<Object> protected_object =
20595       no_proto_template->NewInstance();
20596
20597   // JSGlobalProxy object, always have security check.
20598   Local<Object> proxy_object =
20599       context->Global();
20600
20601   // Global object, the  prototype of proxy_object. No security checks.
20602   Local<Object> global_object =
20603       proxy_object->GetPrototype()->ToObject();
20604
20605   // Hidden prototype without security check.
20606   Local<Object> hidden_prototype =
20607       hidden_proto_template->GetFunction()->NewInstance();
20608   Local<Object> object_with_hidden =
20609     Object::New(isolate);
20610   object_with_hidden->SetPrototype(hidden_prototype);
20611
20612   // Hidden prototype with security check on the hidden prototype.
20613   Local<Object> protected_hidden_prototype =
20614       protected_hidden_proto_template->GetFunction()->NewInstance();
20615   Local<Object> object_with_protected_hidden =
20616     Object::New(isolate);
20617   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20618
20619   context->Exit();
20620
20621   // Template for object for second context. Values to test are put on it as
20622   // properties.
20623   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20624   global_template->Set(v8_str("simple"), simple_object);
20625   global_template->Set(v8_str("protected"), protected_object);
20626   global_template->Set(v8_str("global"), global_object);
20627   global_template->Set(v8_str("proxy"), proxy_object);
20628   global_template->Set(v8_str("hidden"), object_with_hidden);
20629   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20630
20631   LocalContext context2(NULL, global_template);
20632
20633   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20634   CHECK(result1->Equals(simple_object->GetPrototype()));
20635
20636   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20637   CHECK(result2.IsEmpty());
20638
20639   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20640   CHECK(result3->Equals(global_object->GetPrototype()));
20641
20642   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20643   CHECK(result4.IsEmpty());
20644
20645   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20646   CHECK(result5->Equals(
20647       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20648
20649   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20650   CHECK(result6.IsEmpty());
20651 }
20652
20653
20654 THREADED_TEST(Regress125988) {
20655   v8::HandleScope scope(CcTest::isolate());
20656   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20657   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20658   LocalContext env;
20659   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20660   CompileRun("var a = new Object();"
20661              "var b = new Intercept();"
20662              "var c = new Object();"
20663              "c.__proto__ = b;"
20664              "b.__proto__ = a;"
20665              "a.x = 23;"
20666              "for (var i = 0; i < 3; i++) c.x;");
20667   ExpectBoolean("c.hasOwnProperty('x')", false);
20668   ExpectInt32("c.x", 23);
20669   CompileRun("a.y = 42;"
20670              "for (var i = 0; i < 3; i++) c.x;");
20671   ExpectBoolean("c.hasOwnProperty('x')", false);
20672   ExpectInt32("c.x", 23);
20673   ExpectBoolean("c.hasOwnProperty('y')", false);
20674   ExpectInt32("c.y", 42);
20675 }
20676
20677
20678 static void TestReceiver(Local<Value> expected_result,
20679                          Local<Value> expected_receiver,
20680                          const char* code) {
20681   Local<Value> result = CompileRun(code);
20682   CHECK(result->IsObject());
20683   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20684   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20685 }
20686
20687
20688 THREADED_TEST(ForeignFunctionReceiver) {
20689   v8::Isolate* isolate = CcTest::isolate();
20690   HandleScope scope(isolate);
20691
20692   // Create two contexts with different "id" properties ('i' and 'o').
20693   // Call a function both from its own context and from a the foreign
20694   // context, and see what "this" is bound to (returning both "this"
20695   // and "this.id" for comparison).
20696
20697   Local<Context> foreign_context = v8::Context::New(isolate);
20698   foreign_context->Enter();
20699   Local<Value> foreign_function =
20700     CompileRun("function func() { return { 0: this.id, "
20701                "                           1: this, "
20702                "                           toString: function() { "
20703                "                               return this[0];"
20704                "                           }"
20705                "                         };"
20706                "}"
20707                "var id = 'i';"
20708                "func;");
20709   CHECK(foreign_function->IsFunction());
20710   foreign_context->Exit();
20711
20712   LocalContext context;
20713
20714   Local<String> password = v8_str("Password");
20715   // Don't get hit by security checks when accessing foreign_context's
20716   // global receiver (aka. global proxy).
20717   context->SetSecurityToken(password);
20718   foreign_context->SetSecurityToken(password);
20719
20720   Local<String> i = v8_str("i");
20721   Local<String> o = v8_str("o");
20722   Local<String> id = v8_str("id");
20723
20724   CompileRun("function ownfunc() { return { 0: this.id, "
20725              "                              1: this, "
20726              "                              toString: function() { "
20727              "                                  return this[0];"
20728              "                              }"
20729              "                             };"
20730              "}"
20731              "var id = 'o';"
20732              "ownfunc");
20733   context->Global()->Set(v8_str("func"), foreign_function);
20734
20735   // Sanity check the contexts.
20736   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20737   CHECK(o->Equals(context->Global()->Get(id)));
20738
20739   // Checking local function's receiver.
20740   // Calling function using its call/apply methods.
20741   TestReceiver(o, context->Global(), "ownfunc.call()");
20742   TestReceiver(o, context->Global(), "ownfunc.apply()");
20743   // Making calls through built-in functions.
20744   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20745   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20746   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20747   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20748   // Calling with environment record as base.
20749   TestReceiver(o, context->Global(), "ownfunc()");
20750   // Calling with no base.
20751   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20752
20753   // Checking foreign function return value.
20754   // Calling function using its call/apply methods.
20755   TestReceiver(i, foreign_context->Global(), "func.call()");
20756   TestReceiver(i, foreign_context->Global(), "func.apply()");
20757   // Calling function using another context's call/apply methods.
20758   TestReceiver(i, foreign_context->Global(),
20759                "Function.prototype.call.call(func)");
20760   TestReceiver(i, foreign_context->Global(),
20761                "Function.prototype.call.apply(func)");
20762   TestReceiver(i, foreign_context->Global(),
20763                "Function.prototype.apply.call(func)");
20764   TestReceiver(i, foreign_context->Global(),
20765                "Function.prototype.apply.apply(func)");
20766   // Making calls through built-in functions.
20767   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20768   // ToString(func()) is func()[0], i.e., the returned this.id.
20769   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20770   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20771   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20772
20773   // Calling with environment record as base.
20774   TestReceiver(i, foreign_context->Global(), "func()");
20775   // Calling with no base.
20776   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20777 }
20778
20779
20780 uint8_t callback_fired = 0;
20781
20782
20783 void CallCompletedCallback1() {
20784   v8::base::OS::Print("Firing callback 1.\n");
20785   callback_fired ^= 1;  // Toggle first bit.
20786 }
20787
20788
20789 void CallCompletedCallback2() {
20790   v8::base::OS::Print("Firing callback 2.\n");
20791   callback_fired ^= 2;  // Toggle second bit.
20792 }
20793
20794
20795 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20796   int32_t level = args[0]->Int32Value();
20797   if (level < 3) {
20798     level++;
20799     v8::base::OS::Print("Entering recursion level %d.\n", level);
20800     char script[64];
20801     i::Vector<char> script_vector(script, sizeof(script));
20802     i::SNPrintF(script_vector, "recursion(%d)", level);
20803     CompileRun(script_vector.start());
20804     v8::base::OS::Print("Leaving recursion level %d.\n", level);
20805     CHECK_EQ(0, callback_fired);
20806   } else {
20807     v8::base::OS::Print("Recursion ends.\n");
20808     CHECK_EQ(0, callback_fired);
20809   }
20810 }
20811
20812
20813 TEST(CallCompletedCallback) {
20814   LocalContext env;
20815   v8::HandleScope scope(env->GetIsolate());
20816   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20817       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20818   env->Global()->Set(v8_str("recursion"),
20819                      recursive_runtime->GetFunction());
20820   // Adding the same callback a second time has no effect.
20821   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20822   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20823   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20824   v8::base::OS::Print("--- Script (1) ---\n");
20825   Local<Script> script = v8::Script::Compile(
20826       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20827   script->Run();
20828   CHECK_EQ(3, callback_fired);
20829
20830   v8::base::OS::Print("\n--- Script (2) ---\n");
20831   callback_fired = 0;
20832   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20833   script->Run();
20834   CHECK_EQ(2, callback_fired);
20835
20836   v8::base::OS::Print("\n--- Function ---\n");
20837   callback_fired = 0;
20838   Local<Function> recursive_function =
20839       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20840   v8::Handle<Value> args[] = { v8_num(0) };
20841   recursive_function->Call(env->Global(), 1, args);
20842   CHECK_EQ(2, callback_fired);
20843 }
20844
20845
20846 void CallCompletedCallbackNoException() {
20847   v8::HandleScope scope(CcTest::isolate());
20848   CompileRun("1+1;");
20849 }
20850
20851
20852 void CallCompletedCallbackException() {
20853   v8::HandleScope scope(CcTest::isolate());
20854   CompileRun("throw 'second exception';");
20855 }
20856
20857
20858 TEST(CallCompletedCallbackOneException) {
20859   LocalContext env;
20860   v8::HandleScope scope(env->GetIsolate());
20861   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20862   CompileRun("throw 'exception';");
20863 }
20864
20865
20866 TEST(CallCompletedCallbackTwoExceptions) {
20867   LocalContext env;
20868   v8::HandleScope scope(env->GetIsolate());
20869   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20870   CompileRun("throw 'first exception';");
20871 }
20872
20873
20874 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20875   v8::HandleScope scope(info.GetIsolate());
20876   CompileRun("ext1Calls++;");
20877 }
20878
20879
20880 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20881   v8::HandleScope scope(info.GetIsolate());
20882   CompileRun("ext2Calls++;");
20883 }
20884
20885
20886 void* g_passed_to_three = NULL;
20887
20888
20889 static void MicrotaskThree(void* data) {
20890   g_passed_to_three = data;
20891 }
20892
20893
20894 TEST(EnqueueMicrotask) {
20895   LocalContext env;
20896   v8::HandleScope scope(env->GetIsolate());
20897   CompileRun(
20898       "var ext1Calls = 0;"
20899       "var ext2Calls = 0;");
20900   CompileRun("1+1;");
20901   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20902   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20903
20904   env->GetIsolate()->EnqueueMicrotask(
20905       Function::New(env->GetIsolate(), MicrotaskOne));
20906   CompileRun("1+1;");
20907   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20908   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20909
20910   env->GetIsolate()->EnqueueMicrotask(
20911       Function::New(env->GetIsolate(), MicrotaskOne));
20912   env->GetIsolate()->EnqueueMicrotask(
20913       Function::New(env->GetIsolate(), MicrotaskTwo));
20914   CompileRun("1+1;");
20915   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20916   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20917
20918   env->GetIsolate()->EnqueueMicrotask(
20919       Function::New(env->GetIsolate(), MicrotaskTwo));
20920   CompileRun("1+1;");
20921   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20922   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20923
20924   CompileRun("1+1;");
20925   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20926   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20927
20928   g_passed_to_three = NULL;
20929   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20930   CompileRun("1+1;");
20931   CHECK_EQ(NULL, g_passed_to_three);
20932   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20933   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20934
20935   int dummy;
20936   env->GetIsolate()->EnqueueMicrotask(
20937       Function::New(env->GetIsolate(), MicrotaskOne));
20938   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20939   env->GetIsolate()->EnqueueMicrotask(
20940       Function::New(env->GetIsolate(), MicrotaskTwo));
20941   CompileRun("1+1;");
20942   CHECK_EQ(&dummy, g_passed_to_three);
20943   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20944   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20945   g_passed_to_three = NULL;
20946 }
20947
20948
20949 static void MicrotaskExceptionOne(
20950     const v8::FunctionCallbackInfo<Value>& info) {
20951   v8::HandleScope scope(info.GetIsolate());
20952   CompileRun("exception1Calls++;");
20953   info.GetIsolate()->ThrowException(
20954       v8::Exception::Error(v8_str("first")));
20955 }
20956
20957
20958 static void MicrotaskExceptionTwo(
20959     const v8::FunctionCallbackInfo<Value>& info) {
20960   v8::HandleScope scope(info.GetIsolate());
20961   CompileRun("exception2Calls++;");
20962   info.GetIsolate()->ThrowException(
20963       v8::Exception::Error(v8_str("second")));
20964 }
20965
20966
20967 TEST(RunMicrotasksIgnoresThrownExceptions) {
20968   LocalContext env;
20969   v8::Isolate* isolate = env->GetIsolate();
20970   v8::HandleScope scope(isolate);
20971   CompileRun(
20972       "var exception1Calls = 0;"
20973       "var exception2Calls = 0;");
20974   isolate->EnqueueMicrotask(
20975       Function::New(isolate, MicrotaskExceptionOne));
20976   isolate->EnqueueMicrotask(
20977       Function::New(isolate, MicrotaskExceptionTwo));
20978   TryCatch try_catch;
20979   CompileRun("1+1;");
20980   CHECK(!try_catch.HasCaught());
20981   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20982   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20983 }
20984
20985
20986 TEST(SetAutorunMicrotasks) {
20987   LocalContext env;
20988   v8::HandleScope scope(env->GetIsolate());
20989   CompileRun(
20990       "var ext1Calls = 0;"
20991       "var ext2Calls = 0;");
20992   CompileRun("1+1;");
20993   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20994   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20995
20996   env->GetIsolate()->EnqueueMicrotask(
20997       Function::New(env->GetIsolate(), MicrotaskOne));
20998   CompileRun("1+1;");
20999   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21000   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21001
21002   env->GetIsolate()->SetAutorunMicrotasks(false);
21003   env->GetIsolate()->EnqueueMicrotask(
21004       Function::New(env->GetIsolate(), MicrotaskOne));
21005   env->GetIsolate()->EnqueueMicrotask(
21006       Function::New(env->GetIsolate(), MicrotaskTwo));
21007   CompileRun("1+1;");
21008   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21009   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21010
21011   env->GetIsolate()->RunMicrotasks();
21012   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21013   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21014
21015   env->GetIsolate()->EnqueueMicrotask(
21016       Function::New(env->GetIsolate(), MicrotaskTwo));
21017   CompileRun("1+1;");
21018   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21019   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21020
21021   env->GetIsolate()->RunMicrotasks();
21022   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21023   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21024
21025   env->GetIsolate()->SetAutorunMicrotasks(true);
21026   env->GetIsolate()->EnqueueMicrotask(
21027       Function::New(env->GetIsolate(), MicrotaskTwo));
21028   CompileRun("1+1;");
21029   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21030   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21031
21032   env->GetIsolate()->EnqueueMicrotask(
21033       Function::New(env->GetIsolate(), MicrotaskTwo));
21034   {
21035     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21036     CompileRun("1+1;");
21037     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21038     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21039   }
21040
21041   CompileRun("1+1;");
21042   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21043   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
21044 }
21045
21046
21047 TEST(RunMicrotasksWithoutEnteringContext) {
21048   v8::Isolate* isolate = CcTest::isolate();
21049   HandleScope handle_scope(isolate);
21050   isolate->SetAutorunMicrotasks(false);
21051   Handle<Context> context = Context::New(isolate);
21052   {
21053     Context::Scope context_scope(context);
21054     CompileRun("var ext1Calls = 0;");
21055     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
21056   }
21057   isolate->RunMicrotasks();
21058   {
21059     Context::Scope context_scope(context);
21060     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21061   }
21062   isolate->SetAutorunMicrotasks(true);
21063 }
21064
21065
21066 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
21067   v8::DebugEvent event = event_details.GetEvent();
21068   if (event != v8::Break) return;
21069   Handle<Object> exec_state = event_details.GetExecutionState();
21070   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
21071   CompileRun("function f(id) { new FrameDetails(id, 0); }");
21072   Handle<Function> fun = Handle<Function>::Cast(
21073       CcTest::global()->Get(v8_str("f"))->ToObject());
21074   fun->Call(CcTest::global(), 1, &break_id);
21075 }
21076
21077
21078 TEST(Regress385349) {
21079   i::FLAG_allow_natives_syntax = true;
21080   v8::Isolate* isolate = CcTest::isolate();
21081   HandleScope handle_scope(isolate);
21082   isolate->SetAutorunMicrotasks(false);
21083   Handle<Context> context = Context::New(isolate);
21084   v8::Debug::SetDebugEventListener(DebugEventInObserver);
21085   {
21086     Context::Scope context_scope(context);
21087     CompileRun("var obj = {};"
21088                "Object.observe(obj, function(changes) { debugger; });"
21089                "obj.a = 0;");
21090   }
21091   isolate->RunMicrotasks();
21092   isolate->SetAutorunMicrotasks(true);
21093   v8::Debug::SetDebugEventListener(NULL);
21094 }
21095
21096
21097 #ifdef DEBUG
21098 static int probes_counter = 0;
21099 static int misses_counter = 0;
21100 static int updates_counter = 0;
21101
21102
21103 static int* LookupCounter(const char* name) {
21104   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21105     return &probes_counter;
21106   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21107     return &misses_counter;
21108   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21109     return &updates_counter;
21110   }
21111   return NULL;
21112 }
21113
21114
21115 static const char* kMegamorphicTestProgram =
21116     "function ClassA() { };"
21117     "function ClassB() { };"
21118     "ClassA.prototype.foo = function() { };"
21119     "ClassB.prototype.foo = function() { };"
21120     "function fooify(obj) { obj.foo(); };"
21121     "var a = new ClassA();"
21122     "var b = new ClassB();"
21123     "for (var i = 0; i < 10000; i++) {"
21124     "  fooify(a);"
21125     "  fooify(b);"
21126     "}";
21127 #endif
21128
21129
21130 static void StubCacheHelper(bool primary) {
21131 #ifdef DEBUG
21132   i::FLAG_native_code_counters = true;
21133   if (primary) {
21134     i::FLAG_test_primary_stub_cache = true;
21135   } else {
21136     i::FLAG_test_secondary_stub_cache = true;
21137   }
21138   i::FLAG_crankshaft = false;
21139   LocalContext env;
21140   env->GetIsolate()->SetCounterFunction(LookupCounter);
21141   v8::HandleScope scope(env->GetIsolate());
21142   int initial_probes = probes_counter;
21143   int initial_misses = misses_counter;
21144   int initial_updates = updates_counter;
21145   CompileRun(kMegamorphicTestProgram);
21146   int probes = probes_counter - initial_probes;
21147   int misses = misses_counter - initial_misses;
21148   int updates = updates_counter - initial_updates;
21149   CHECK_LT(updates, 10);
21150   CHECK_LT(misses, 10);
21151   // TODO(verwaest): Update this test to overflow the degree of polymorphism
21152   // before megamorphism. The number of probes will only work once we teach the
21153   // serializer to embed references to counters in the stubs, given that the
21154   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
21155   CHECK_GE(probes, 0);
21156 #endif
21157 }
21158
21159
21160 TEST(SecondaryStubCache) {
21161   StubCacheHelper(true);
21162 }
21163
21164
21165 TEST(PrimaryStubCache) {
21166   StubCacheHelper(false);
21167 }
21168
21169
21170 #ifdef DEBUG
21171 static int cow_arrays_created_runtime = 0;
21172
21173
21174 static int* LookupCounterCOWArrays(const char* name) {
21175   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21176     return &cow_arrays_created_runtime;
21177   }
21178   return NULL;
21179 }
21180 #endif
21181
21182
21183 TEST(CheckCOWArraysCreatedRuntimeCounter) {
21184 #ifdef DEBUG
21185   i::FLAG_native_code_counters = true;
21186   LocalContext env;
21187   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21188   v8::HandleScope scope(env->GetIsolate());
21189   int initial_cow_arrays = cow_arrays_created_runtime;
21190   CompileRun("var o = [1, 2, 3];");
21191   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21192   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21193   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21194   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21195   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21196 #endif
21197 }
21198
21199
21200 TEST(StaticGetters) {
21201   LocalContext context;
21202   i::Factory* factory = CcTest::i_isolate()->factory();
21203   v8::Isolate* isolate = CcTest::isolate();
21204   v8::HandleScope scope(isolate);
21205   i::Handle<i::Object> undefined_value = factory->undefined_value();
21206   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21207   i::Handle<i::Object> null_value = factory->null_value();
21208   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21209   i::Handle<i::Object> true_value = factory->true_value();
21210   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21211   i::Handle<i::Object> false_value = factory->false_value();
21212   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21213 }
21214
21215
21216 UNINITIALIZED_TEST(IsolateEmbedderData) {
21217   CcTest::DisableAutomaticDispose();
21218   v8::Isolate* isolate = v8::Isolate::New();
21219   isolate->Enter();
21220   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21221   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21222     CHECK_EQ(NULL, isolate->GetData(slot));
21223     CHECK_EQ(NULL, i_isolate->GetData(slot));
21224   }
21225   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21226     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21227     isolate->SetData(slot, data);
21228   }
21229   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21230     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21231     CHECK_EQ(data, isolate->GetData(slot));
21232     CHECK_EQ(data, i_isolate->GetData(slot));
21233   }
21234   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21235     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21236     isolate->SetData(slot, data);
21237   }
21238   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21239     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21240     CHECK_EQ(data, isolate->GetData(slot));
21241     CHECK_EQ(data, i_isolate->GetData(slot));
21242   }
21243   isolate->Exit();
21244   isolate->Dispose();
21245 }
21246
21247
21248 TEST(StringEmpty) {
21249   LocalContext context;
21250   i::Factory* factory = CcTest::i_isolate()->factory();
21251   v8::Isolate* isolate = CcTest::isolate();
21252   v8::HandleScope scope(isolate);
21253   i::Handle<i::Object> empty_string = factory->empty_string();
21254   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21255 }
21256
21257
21258 static int instance_checked_getter_count = 0;
21259 static void InstanceCheckedGetter(
21260     Local<String> name,
21261     const v8::PropertyCallbackInfo<v8::Value>& info) {
21262   CHECK_EQ(name, v8_str("foo"));
21263   instance_checked_getter_count++;
21264   info.GetReturnValue().Set(v8_num(11));
21265 }
21266
21267
21268 static int instance_checked_setter_count = 0;
21269 static void InstanceCheckedSetter(Local<String> name,
21270                       Local<Value> value,
21271                       const v8::PropertyCallbackInfo<void>& info) {
21272   CHECK_EQ(name, v8_str("foo"));
21273   CHECK_EQ(value, v8_num(23));
21274   instance_checked_setter_count++;
21275 }
21276
21277
21278 static void CheckInstanceCheckedResult(int getters, int setters,
21279                                        bool expects_callbacks,
21280                                        TryCatch* try_catch) {
21281   if (expects_callbacks) {
21282     CHECK(!try_catch->HasCaught());
21283     CHECK_EQ(getters, instance_checked_getter_count);
21284     CHECK_EQ(setters, instance_checked_setter_count);
21285   } else {
21286     CHECK(try_catch->HasCaught());
21287     CHECK_EQ(0, instance_checked_getter_count);
21288     CHECK_EQ(0, instance_checked_setter_count);
21289   }
21290   try_catch->Reset();
21291 }
21292
21293
21294 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21295   instance_checked_getter_count = 0;
21296   instance_checked_setter_count = 0;
21297   TryCatch try_catch;
21298
21299   // Test path through generic runtime code.
21300   CompileRun("obj.foo");
21301   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21302   CompileRun("obj.foo = 23");
21303   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21304
21305   // Test path through generated LoadIC and StoredIC.
21306   CompileRun("function test_get(o) { o.foo; }"
21307              "test_get(obj);");
21308   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21309   CompileRun("test_get(obj);");
21310   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21311   CompileRun("test_get(obj);");
21312   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21313   CompileRun("function test_set(o) { o.foo = 23; }"
21314              "test_set(obj);");
21315   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21316   CompileRun("test_set(obj);");
21317   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21318   CompileRun("test_set(obj);");
21319   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21320
21321   // Test path through optimized code.
21322   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21323              "test_get(obj);");
21324   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21325   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21326              "test_set(obj);");
21327   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21328
21329   // Cleanup so that closures start out fresh in next check.
21330   CompileRun("%DeoptimizeFunction(test_get);"
21331              "%ClearFunctionTypeFeedback(test_get);"
21332              "%DeoptimizeFunction(test_set);"
21333              "%ClearFunctionTypeFeedback(test_set);");
21334 }
21335
21336
21337 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21338   v8::internal::FLAG_allow_natives_syntax = true;
21339   LocalContext context;
21340   v8::HandleScope scope(context->GetIsolate());
21341
21342   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21343   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21344   inst->SetAccessor(v8_str("foo"),
21345                     InstanceCheckedGetter, InstanceCheckedSetter,
21346                     Handle<Value>(),
21347                     v8::DEFAULT,
21348                     v8::None,
21349                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21350   context->Global()->Set(v8_str("f"), templ->GetFunction());
21351
21352   printf("Testing positive ...\n");
21353   CompileRun("var obj = new f();");
21354   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21355   CheckInstanceCheckedAccessors(true);
21356
21357   printf("Testing negative ...\n");
21358   CompileRun("var obj = {};"
21359              "obj.__proto__ = new f();");
21360   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21361   CheckInstanceCheckedAccessors(false);
21362 }
21363
21364
21365 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21366   v8::internal::FLAG_allow_natives_syntax = true;
21367   LocalContext context;
21368   v8::HandleScope scope(context->GetIsolate());
21369
21370   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21371   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21372   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21373   inst->SetAccessor(v8_str("foo"),
21374                     InstanceCheckedGetter, InstanceCheckedSetter,
21375                     Handle<Value>(),
21376                     v8::DEFAULT,
21377                     v8::None,
21378                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21379   context->Global()->Set(v8_str("f"), templ->GetFunction());
21380
21381   printf("Testing positive ...\n");
21382   CompileRun("var obj = new f();");
21383   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21384   CheckInstanceCheckedAccessors(true);
21385
21386   printf("Testing negative ...\n");
21387   CompileRun("var obj = {};"
21388              "obj.__proto__ = new f();");
21389   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21390   CheckInstanceCheckedAccessors(false);
21391 }
21392
21393
21394 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21395   v8::internal::FLAG_allow_natives_syntax = true;
21396   LocalContext context;
21397   v8::HandleScope scope(context->GetIsolate());
21398
21399   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21400   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21401   proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21402                      InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
21403                      v8::None,
21404                      v8::AccessorSignature::New(context->GetIsolate(), templ));
21405   context->Global()->Set(v8_str("f"), templ->GetFunction());
21406
21407   printf("Testing positive ...\n");
21408   CompileRun("var obj = new f();");
21409   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21410   CheckInstanceCheckedAccessors(true);
21411
21412   printf("Testing negative ...\n");
21413   CompileRun("var obj = {};"
21414              "obj.__proto__ = new f();");
21415   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21416   CheckInstanceCheckedAccessors(false);
21417
21418   printf("Testing positive with modified prototype chain ...\n");
21419   CompileRun("var obj = new f();"
21420              "var pro = {};"
21421              "pro.__proto__ = obj.__proto__;"
21422              "obj.__proto__ = pro;");
21423   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21424   CheckInstanceCheckedAccessors(true);
21425 }
21426
21427
21428 TEST(TryFinallyMessage) {
21429   LocalContext context;
21430   v8::HandleScope scope(context->GetIsolate());
21431   {
21432     // Test that the original error message is not lost if there is a
21433     // recursive call into Javascript is done in the finally block, e.g. to
21434     // initialize an IC. (crbug.com/129171)
21435     TryCatch try_catch;
21436     const char* trigger_ic =
21437         "try {                      \n"
21438         "  throw new Error('test'); \n"
21439         "} finally {                \n"
21440         "  var x = 0;               \n"
21441         "  x++;                     \n"  // Trigger an IC initialization here.
21442         "}                          \n";
21443     CompileRun(trigger_ic);
21444     CHECK(try_catch.HasCaught());
21445     Local<Message> message = try_catch.Message();
21446     CHECK(!message.IsEmpty());
21447     CHECK_EQ(2, message->GetLineNumber());
21448   }
21449
21450   {
21451     // Test that the original exception message is indeed overwritten if
21452     // a new error is thrown in the finally block.
21453     TryCatch try_catch;
21454     const char* throw_again =
21455         "try {                       \n"
21456         "  throw new Error('test');  \n"
21457         "} finally {                 \n"
21458         "  var x = 0;                \n"
21459         "  x++;                      \n"
21460         "  throw new Error('again'); \n"  // This is the new uncaught error.
21461         "}                           \n";
21462     CompileRun(throw_again);
21463     CHECK(try_catch.HasCaught());
21464     Local<Message> message = try_catch.Message();
21465     CHECK(!message.IsEmpty());
21466     CHECK_EQ(6, message->GetLineNumber());
21467   }
21468 }
21469
21470
21471 static void Helper137002(bool do_store,
21472                          bool polymorphic,
21473                          bool remove_accessor,
21474                          bool interceptor) {
21475   LocalContext context;
21476   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21477   if (interceptor) {
21478     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21479   } else {
21480     templ->SetAccessor(v8_str("foo"),
21481                        GetterWhichReturns42,
21482                        SetterWhichSetsYOnThisTo23);
21483   }
21484   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21485
21486   // Turn monomorphic on slow object with native accessor, then turn
21487   // polymorphic, finally optimize to create negative lookup and fail.
21488   CompileRun(do_store ?
21489              "function f(x) { x.foo = void 0; }" :
21490              "function f(x) { return x.foo; }");
21491   CompileRun("obj.y = void 0;");
21492   if (!interceptor) {
21493     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21494   }
21495   CompileRun("obj.__proto__ = null;"
21496              "f(obj); f(obj); f(obj);");
21497   if (polymorphic) {
21498     CompileRun("f({});");
21499   }
21500   CompileRun("obj.y = void 0;"
21501              "%OptimizeFunctionOnNextCall(f);");
21502   if (remove_accessor) {
21503     CompileRun("delete obj.foo;");
21504   }
21505   CompileRun("var result = f(obj);");
21506   if (do_store) {
21507     CompileRun("result = obj.y;");
21508   }
21509   if (remove_accessor && !interceptor) {
21510     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21511   } else {
21512     CHECK_EQ(do_store ? 23 : 42,
21513              context->Global()->Get(v8_str("result"))->Int32Value());
21514   }
21515 }
21516
21517
21518 THREADED_TEST(Regress137002a) {
21519   i::FLAG_allow_natives_syntax = true;
21520   i::FLAG_compilation_cache = false;
21521   v8::HandleScope scope(CcTest::isolate());
21522   for (int i = 0; i < 16; i++) {
21523     Helper137002(i & 8, i & 4, i & 2, i & 1);
21524   }
21525 }
21526
21527
21528 THREADED_TEST(Regress137002b) {
21529   i::FLAG_allow_natives_syntax = true;
21530   LocalContext context;
21531   v8::Isolate* isolate = context->GetIsolate();
21532   v8::HandleScope scope(isolate);
21533   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21534   templ->SetAccessor(v8_str("foo"),
21535                      GetterWhichReturns42,
21536                      SetterWhichSetsYOnThisTo23);
21537   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21538
21539   // Turn monomorphic on slow object with native accessor, then just
21540   // delete the property and fail.
21541   CompileRun("function load(x) { return x.foo; }"
21542              "function store(x) { x.foo = void 0; }"
21543              "function keyed_load(x, key) { return x[key]; }"
21544              // Second version of function has a different source (add void 0)
21545              // so that it does not share code with the first version.  This
21546              // ensures that the ICs are monomorphic.
21547              "function load2(x) { void 0; return x.foo; }"
21548              "function store2(x) { void 0; x.foo = void 0; }"
21549              "function keyed_load2(x, key) { void 0; return x[key]; }"
21550
21551              "obj.y = void 0;"
21552              "obj.__proto__ = null;"
21553              "var subobj = {};"
21554              "subobj.y = void 0;"
21555              "subobj.__proto__ = obj;"
21556              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21557
21558              // Make the ICs monomorphic.
21559              "load(obj); load(obj);"
21560              "load2(subobj); load2(subobj);"
21561              "store(obj); store(obj);"
21562              "store2(subobj); store2(subobj);"
21563              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21564              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21565
21566              // Actually test the shiny new ICs and better not crash. This
21567              // serves as a regression test for issue 142088 as well.
21568              "load(obj);"
21569              "load2(subobj);"
21570              "store(obj);"
21571              "store2(subobj);"
21572              "keyed_load(obj, 'foo');"
21573              "keyed_load2(subobj, 'foo');"
21574
21575              // Delete the accessor.  It better not be called any more now.
21576              "delete obj.foo;"
21577              "obj.y = void 0;"
21578              "subobj.y = void 0;"
21579
21580              "var load_result = load(obj);"
21581              "var load_result2 = load2(subobj);"
21582              "var keyed_load_result = keyed_load(obj, 'foo');"
21583              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21584              "store(obj);"
21585              "store2(subobj);"
21586              "var y_from_obj = obj.y;"
21587              "var y_from_subobj = subobj.y;");
21588   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21589   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21590   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21591   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21592   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21593   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21594 }
21595
21596
21597 THREADED_TEST(Regress142088) {
21598   i::FLAG_allow_natives_syntax = true;
21599   LocalContext context;
21600   v8::Isolate* isolate = context->GetIsolate();
21601   v8::HandleScope scope(isolate);
21602   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21603   templ->SetAccessor(v8_str("foo"),
21604                      GetterWhichReturns42,
21605                      SetterWhichSetsYOnThisTo23);
21606   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21607
21608   CompileRun("function load(x) { return x.foo; }"
21609              "var o = Object.create(obj);"
21610              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21611              "load(o); load(o); load(o); load(o);");
21612 }
21613
21614
21615 THREADED_TEST(Regress3337) {
21616   LocalContext context;
21617   v8::Isolate* isolate = context->GetIsolate();
21618   v8::HandleScope scope(isolate);
21619   Local<v8::Object> o1 = Object::New(isolate);
21620   Local<v8::Object> o2 = Object::New(isolate);
21621   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21622   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21623   CHECK(io1->map() == io2->map());
21624   o1->SetIndexedPropertiesToExternalArrayData(
21625       NULL, v8::kExternalUint32Array, 0);
21626   o2->SetIndexedPropertiesToExternalArrayData(
21627       NULL, v8::kExternalUint32Array, 0);
21628   CHECK(io1->map() == io2->map());
21629 }
21630
21631
21632 THREADED_TEST(Regress137496) {
21633   i::FLAG_expose_gc = true;
21634   LocalContext context;
21635   v8::HandleScope scope(context->GetIsolate());
21636
21637   // Compile a try-finally clause where the finally block causes a GC
21638   // while there still is a message pending for external reporting.
21639   TryCatch try_catch;
21640   try_catch.SetVerbose(true);
21641   CompileRun("try { throw new Error(); } finally { gc(); }");
21642   CHECK(try_catch.HasCaught());
21643 }
21644
21645
21646 THREADED_TEST(Regress149912) {
21647   LocalContext context;
21648   v8::HandleScope scope(context->GetIsolate());
21649   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21650   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21651   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21652   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21653 }
21654
21655
21656 THREADED_TEST(Regress157124) {
21657   LocalContext context;
21658   v8::Isolate* isolate = context->GetIsolate();
21659   v8::HandleScope scope(isolate);
21660   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21661   Local<Object> obj = templ->NewInstance();
21662   obj->GetIdentityHash();
21663   obj->DeleteHiddenValue(v8_str("Bug"));
21664 }
21665
21666
21667 THREADED_TEST(Regress2535) {
21668   LocalContext context;
21669   v8::HandleScope scope(context->GetIsolate());
21670   Local<Value> set_value = CompileRun("new Set();");
21671   Local<Object> set_object(Local<Object>::Cast(set_value));
21672   CHECK_EQ(0, set_object->InternalFieldCount());
21673   Local<Value> map_value = CompileRun("new Map();");
21674   Local<Object> map_object(Local<Object>::Cast(map_value));
21675   CHECK_EQ(0, map_object->InternalFieldCount());
21676 }
21677
21678
21679 THREADED_TEST(Regress2746) {
21680   LocalContext context;
21681   v8::Isolate* isolate = context->GetIsolate();
21682   v8::HandleScope scope(isolate);
21683   Local<Object> obj = Object::New(isolate);
21684   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21685   obj->SetHiddenValue(key, v8::Undefined(isolate));
21686   Local<Value> value = obj->GetHiddenValue(key);
21687   CHECK(!value.IsEmpty());
21688   CHECK(value->IsUndefined());
21689 }
21690
21691
21692 THREADED_TEST(Regress260106) {
21693   LocalContext context;
21694   v8::Isolate* isolate = context->GetIsolate();
21695   v8::HandleScope scope(isolate);
21696   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21697                                                         DummyCallHandler);
21698   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21699   Local<Function> function = templ->GetFunction();
21700   CHECK(!function.IsEmpty());
21701   CHECK(function->IsFunction());
21702 }
21703
21704
21705 THREADED_TEST(JSONParseObject) {
21706   LocalContext context;
21707   HandleScope scope(context->GetIsolate());
21708   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21709   Handle<Object> global = context->Global();
21710   global->Set(v8_str("obj"), obj);
21711   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21712 }
21713
21714
21715 THREADED_TEST(JSONParseNumber) {
21716   LocalContext context;
21717   HandleScope scope(context->GetIsolate());
21718   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21719   Handle<Object> global = context->Global();
21720   global->Set(v8_str("obj"), obj);
21721   ExpectString("JSON.stringify(obj)", "42");
21722 }
21723
21724
21725 #if V8_OS_POSIX && !V8_OS_NACL
21726 class ThreadInterruptTest {
21727  public:
21728   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21729   ~ThreadInterruptTest() {}
21730
21731   void RunTest() {
21732     InterruptThread i_thread(this);
21733     i_thread.Start();
21734
21735     sem_.Wait();
21736     CHECK_EQ(kExpectedValue, sem_value_);
21737   }
21738
21739  private:
21740   static const int kExpectedValue = 1;
21741
21742   class InterruptThread : public v8::base::Thread {
21743    public:
21744     explicit InterruptThread(ThreadInterruptTest* test)
21745         : Thread(Options("InterruptThread")), test_(test) {}
21746
21747     virtual void Run() {
21748       struct sigaction action;
21749
21750       // Ensure that we'll enter waiting condition
21751       v8::base::OS::Sleep(100);
21752
21753       // Setup signal handler
21754       memset(&action, 0, sizeof(action));
21755       action.sa_handler = SignalHandler;
21756       sigaction(SIGCHLD, &action, NULL);
21757
21758       // Send signal
21759       kill(getpid(), SIGCHLD);
21760
21761       // Ensure that if wait has returned because of error
21762       v8::base::OS::Sleep(100);
21763
21764       // Set value and signal semaphore
21765       test_->sem_value_ = 1;
21766       test_->sem_.Signal();
21767     }
21768
21769     static void SignalHandler(int signal) {
21770     }
21771
21772    private:
21773      ThreadInterruptTest* test_;
21774   };
21775
21776   v8::base::Semaphore sem_;
21777   volatile int sem_value_;
21778 };
21779
21780
21781 THREADED_TEST(SemaphoreInterruption) {
21782   ThreadInterruptTest().RunTest();
21783 }
21784
21785
21786 #endif  // V8_OS_POSIX
21787
21788
21789 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21790                                      Local<Value> name,
21791                                      v8::AccessType type,
21792                                      Local<Value> data) {
21793   i::PrintF("Named access blocked.\n");
21794   return false;
21795 }
21796
21797
21798 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21799                                      uint32_t key,
21800                                      v8::AccessType type,
21801                                      Local<Value> data) {
21802   i::PrintF("Indexed access blocked.\n");
21803   return false;
21804 }
21805
21806
21807 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21808   CHECK(false);
21809 }
21810
21811
21812 TEST(JSONStringifyAccessCheck) {
21813   v8::V8::Initialize();
21814   v8::Isolate* isolate = CcTest::isolate();
21815   v8::HandleScope scope(isolate);
21816
21817   // Create an ObjectTemplate for global objects and install access
21818   // check callbacks that will block access.
21819   v8::Handle<v8::ObjectTemplate> global_template =
21820       v8::ObjectTemplate::New(isolate);
21821   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21822                                            IndexAccessAlwaysBlocked);
21823
21824   // Create a context and set an x property on it's global object.
21825   LocalContext context0(NULL, global_template);
21826   v8::Handle<v8::Object> global0 = context0->Global();
21827   global0->Set(v8_str("x"), v8_num(42));
21828   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21829
21830   for (int i = 0; i < 2; i++) {
21831     if (i == 1) {
21832       // Install a toJSON function on the second run.
21833       v8::Handle<v8::FunctionTemplate> toJSON =
21834           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21835
21836       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21837     }
21838     // Create a context with a different security token so that the
21839     // failed access check callback will be called on each access.
21840     LocalContext context1(NULL, global_template);
21841     context1->Global()->Set(v8_str("other"), global0);
21842
21843     CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
21844     CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
21845     CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
21846
21847     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21848     array->Set(0, v8_str("a"));
21849     array->Set(1, v8_str("b"));
21850     context1->Global()->Set(v8_str("array"), array);
21851     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21852     array->TurnOnAccessCheck();
21853     CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
21854     CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
21855     CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
21856   }
21857 }
21858
21859
21860 bool access_check_fail_thrown = false;
21861 bool catch_callback_called = false;
21862
21863
21864 // Failed access check callback that performs a GC on each invocation.
21865 void FailedAccessCheckThrows(Local<v8::Object> target,
21866                              v8::AccessType type,
21867                              Local<v8::Value> data) {
21868   access_check_fail_thrown = true;
21869   i::PrintF("Access check failed. Error thrown.\n");
21870   CcTest::isolate()->ThrowException(
21871       v8::Exception::Error(v8_str("cross context")));
21872 }
21873
21874
21875 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21876   for (int i = 0; i < args.Length(); i++) {
21877     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21878   }
21879   catch_callback_called = true;
21880 }
21881
21882
21883 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21884   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21885 }
21886
21887
21888 void CheckCorrectThrow(const char* script) {
21889   // Test that the script, when wrapped into a try-catch, triggers the catch
21890   // clause due to failed access check throwing an exception.
21891   // The subsequent try-catch should run without any exception.
21892   access_check_fail_thrown = false;
21893   catch_callback_called = false;
21894   i::ScopedVector<char> source(1024);
21895   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21896   CompileRun(source.start());
21897   CHECK(access_check_fail_thrown);
21898   CHECK(catch_callback_called);
21899
21900   access_check_fail_thrown = false;
21901   catch_callback_called = false;
21902   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21903   CHECK(!access_check_fail_thrown);
21904   CHECK(!catch_callback_called);
21905 }
21906
21907
21908 TEST(AccessCheckThrows) {
21909   i::FLAG_allow_natives_syntax = true;
21910   v8::V8::Initialize();
21911   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21912   v8::Isolate* isolate = CcTest::isolate();
21913   v8::HandleScope scope(isolate);
21914
21915   // Create an ObjectTemplate for global objects and install access
21916   // check callbacks that will block access.
21917   v8::Handle<v8::ObjectTemplate> global_template =
21918       v8::ObjectTemplate::New(isolate);
21919   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21920                                            IndexAccessAlwaysBlocked);
21921
21922   // Create a context and set an x property on it's global object.
21923   LocalContext context0(NULL, global_template);
21924   v8::Handle<v8::Object> global0 = context0->Global();
21925
21926   // Create a context with a different security token so that the
21927   // failed access check callback will be called on each access.
21928   LocalContext context1(NULL, global_template);
21929   context1->Global()->Set(v8_str("other"), global0);
21930
21931   v8::Handle<v8::FunctionTemplate> catcher_fun =
21932       v8::FunctionTemplate::New(isolate, CatcherCallback);
21933   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21934
21935   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21936       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21937   context1->Global()->Set(v8_str("has_own_property"),
21938                           has_own_property_fun->GetFunction());
21939
21940   { v8::TryCatch try_catch;
21941     access_check_fail_thrown = false;
21942     CompileRun("other.x;");
21943     CHECK(access_check_fail_thrown);
21944     CHECK(try_catch.HasCaught());
21945   }
21946
21947   CheckCorrectThrow("other.x");
21948   CheckCorrectThrow("other[1]");
21949   CheckCorrectThrow("JSON.stringify(other)");
21950   CheckCorrectThrow("has_own_property(other, 'x')");
21951   CheckCorrectThrow("%GetProperty(other, 'x')");
21952   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
21953   CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
21954   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21955   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21956   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21957   CheckCorrectThrow("%HasProperty(other, 'x')");
21958   CheckCorrectThrow("%HasElement(other, 1)");
21959   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21960   CheckCorrectThrow("%GetPropertyNames(other)");
21961   // PROPERTY_ATTRIBUTES_NONE = 0
21962   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21963   CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
21964                         "other, 'x', null, null, 1)");
21965
21966   // Reset the failed access check callback so it does not influence
21967   // the other tests.
21968   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21969 }
21970
21971
21972 THREADED_TEST(Regress256330) {
21973   i::FLAG_allow_natives_syntax = true;
21974   LocalContext context;
21975   v8::HandleScope scope(context->GetIsolate());
21976   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21977   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21978   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21979   CompileRun("\"use strict\"; var o = new Bug;"
21980              "function f(o) { o.x = 10; };"
21981              "f(o); f(o); f(o);"
21982              "%OptimizeFunctionOnNextCall(f);"
21983              "f(o);");
21984   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21985 }
21986
21987
21988 THREADED_TEST(CrankshaftInterceptorSetter) {
21989   i::FLAG_allow_natives_syntax = true;
21990   v8::HandleScope scope(CcTest::isolate());
21991   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21992   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21993   LocalContext env;
21994   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21995   CompileRun("var obj = new Obj;"
21996              // Initialize fields to avoid transitions later.
21997              "obj.age = 0;"
21998              "obj.accessor_age = 42;"
21999              "function setter(i) { this.accessor_age = i; };"
22000              "function getter() { return this.accessor_age; };"
22001              "function setAge(i) { obj.age = i; };"
22002              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
22003              "setAge(1);"
22004              "setAge(2);"
22005              "setAge(3);"
22006              "%OptimizeFunctionOnNextCall(setAge);"
22007              "setAge(4);");
22008   // All stores went through the interceptor.
22009   ExpectInt32("obj.interceptor_age", 4);
22010   ExpectInt32("obj.accessor_age", 42);
22011 }
22012
22013
22014 THREADED_TEST(CrankshaftInterceptorGetter) {
22015   i::FLAG_allow_natives_syntax = true;
22016   v8::HandleScope scope(CcTest::isolate());
22017   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22018   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22019   LocalContext env;
22020   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22021   CompileRun("var obj = new Obj;"
22022              // Initialize fields to avoid transitions later.
22023              "obj.age = 1;"
22024              "obj.accessor_age = 42;"
22025              "function getter() { return this.accessor_age; };"
22026              "function getAge() { return obj.interceptor_age; };"
22027              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
22028              "getAge();"
22029              "getAge();"
22030              "getAge();"
22031              "%OptimizeFunctionOnNextCall(getAge);");
22032   // Access through interceptor.
22033   ExpectInt32("getAge()", 1);
22034 }
22035
22036
22037 THREADED_TEST(CrankshaftInterceptorFieldRead) {
22038   i::FLAG_allow_natives_syntax = true;
22039   v8::HandleScope scope(CcTest::isolate());
22040   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22041   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22042   LocalContext env;
22043   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22044   CompileRun("var obj = new Obj;"
22045              "obj.__proto__.interceptor_age = 42;"
22046              "obj.age = 100;"
22047              "function getAge() { return obj.interceptor_age; };");
22048   ExpectInt32("getAge();", 100);
22049   ExpectInt32("getAge();", 100);
22050   ExpectInt32("getAge();", 100);
22051   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
22052   // Access through interceptor.
22053   ExpectInt32("getAge();", 100);
22054 }
22055
22056
22057 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
22058   i::FLAG_allow_natives_syntax = true;
22059   v8::HandleScope scope(CcTest::isolate());
22060   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22061   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22062   LocalContext env;
22063   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22064   CompileRun("var obj = new Obj;"
22065              "obj.age = 100000;"
22066              "function setAge(i) { obj.age = i };"
22067              "setAge(100);"
22068              "setAge(101);"
22069              "setAge(102);"
22070              "%OptimizeFunctionOnNextCall(setAge);"
22071              "setAge(103);");
22072   ExpectInt32("obj.age", 100000);
22073   ExpectInt32("obj.interceptor_age", 103);
22074 }
22075
22076
22077 class RequestInterruptTestBase {
22078  public:
22079   RequestInterruptTestBase()
22080       : env_(),
22081         isolate_(env_->GetIsolate()),
22082         sem_(0),
22083         warmup_(20000),
22084         should_continue_(true) {
22085   }
22086
22087   virtual ~RequestInterruptTestBase() { }
22088
22089   virtual void StartInterruptThread() = 0;
22090
22091   virtual void TestBody() = 0;
22092
22093   void RunTest() {
22094     StartInterruptThread();
22095
22096     v8::HandleScope handle_scope(isolate_);
22097
22098     TestBody();
22099
22100     isolate_->ClearInterrupt();
22101
22102     // Verify we arrived here because interruptor was called
22103     // not due to a bug causing us to exit the loop too early.
22104     CHECK(!should_continue());
22105   }
22106
22107   void WakeUpInterruptor() {
22108     sem_.Signal();
22109   }
22110
22111   bool should_continue() const { return should_continue_; }
22112
22113   bool ShouldContinue() {
22114     if (warmup_ > 0) {
22115       if (--warmup_ == 0) {
22116         WakeUpInterruptor();
22117       }
22118     }
22119
22120     return should_continue_;
22121   }
22122
22123   static void ShouldContinueCallback(
22124       const v8::FunctionCallbackInfo<Value>& info) {
22125     RequestInterruptTestBase* test =
22126         reinterpret_cast<RequestInterruptTestBase*>(
22127             info.Data().As<v8::External>()->Value());
22128     info.GetReturnValue().Set(test->ShouldContinue());
22129   }
22130
22131   LocalContext env_;
22132   v8::Isolate* isolate_;
22133   v8::base::Semaphore sem_;
22134   int warmup_;
22135   bool should_continue_;
22136 };
22137
22138
22139 class RequestInterruptTestBaseWithSimpleInterrupt
22140     : public RequestInterruptTestBase {
22141  public:
22142   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22143
22144   virtual void StartInterruptThread() {
22145     i_thread.Start();
22146   }
22147
22148  private:
22149   class InterruptThread : public v8::base::Thread {
22150    public:
22151     explicit InterruptThread(RequestInterruptTestBase* test)
22152         : Thread(Options("RequestInterruptTest")), test_(test) {}
22153
22154     virtual void Run() {
22155       test_->sem_.Wait();
22156       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22157     }
22158
22159     static void OnInterrupt(v8::Isolate* isolate, void* data) {
22160       reinterpret_cast<RequestInterruptTestBase*>(data)->
22161           should_continue_ = false;
22162     }
22163
22164    private:
22165      RequestInterruptTestBase* test_;
22166   };
22167
22168   InterruptThread i_thread;
22169 };
22170
22171
22172 class RequestInterruptTestWithFunctionCall
22173     : public RequestInterruptTestBaseWithSimpleInterrupt {
22174  public:
22175   virtual void TestBody() {
22176     Local<Function> func = Function::New(
22177         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22178     env_->Global()->Set(v8_str("ShouldContinue"), func);
22179
22180     CompileRun("while (ShouldContinue()) { }");
22181   }
22182 };
22183
22184
22185 class RequestInterruptTestWithMethodCall
22186     : public RequestInterruptTestBaseWithSimpleInterrupt {
22187  public:
22188   virtual void TestBody() {
22189     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22190     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22191     proto->Set(v8_str("shouldContinue"), Function::New(
22192         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22193     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22194
22195     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22196   }
22197 };
22198
22199
22200 class RequestInterruptTestWithAccessor
22201     : public RequestInterruptTestBaseWithSimpleInterrupt {
22202  public:
22203   virtual void TestBody() {
22204     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22205     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22206     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22207         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22208     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22209
22210     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22211   }
22212 };
22213
22214
22215 class RequestInterruptTestWithNativeAccessor
22216     : public RequestInterruptTestBaseWithSimpleInterrupt {
22217  public:
22218   virtual void TestBody() {
22219     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22220     t->InstanceTemplate()->SetNativeDataProperty(
22221         v8_str("shouldContinue"),
22222         &ShouldContinueNativeGetter,
22223         NULL,
22224         v8::External::New(isolate_, this));
22225     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22226
22227     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22228   }
22229
22230  private:
22231   static void ShouldContinueNativeGetter(
22232       Local<String> property,
22233       const v8::PropertyCallbackInfo<v8::Value>& info) {
22234     RequestInterruptTestBase* test =
22235         reinterpret_cast<RequestInterruptTestBase*>(
22236             info.Data().As<v8::External>()->Value());
22237     info.GetReturnValue().Set(test->ShouldContinue());
22238   }
22239 };
22240
22241
22242 class RequestInterruptTestWithMethodCallAndInterceptor
22243     : public RequestInterruptTestBaseWithSimpleInterrupt {
22244  public:
22245   virtual void TestBody() {
22246     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22247     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22248     proto->Set(v8_str("shouldContinue"), Function::New(
22249         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22250     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22251     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22252
22253     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22254
22255     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22256   }
22257
22258  private:
22259   static void EmptyInterceptor(
22260       Local<String> property,
22261       const v8::PropertyCallbackInfo<v8::Value>& info) {
22262   }
22263 };
22264
22265
22266 class RequestInterruptTestWithMathAbs
22267     : public RequestInterruptTestBaseWithSimpleInterrupt {
22268  public:
22269   virtual void TestBody() {
22270     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22271         isolate_,
22272         WakeUpInterruptorCallback,
22273         v8::External::New(isolate_, this)));
22274
22275     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22276         isolate_,
22277         ShouldContinueCallback,
22278         v8::External::New(isolate_, this)));
22279
22280     i::FLAG_allow_natives_syntax = true;
22281     CompileRun("function loopish(o) {"
22282                "  var pre = 10;"
22283                "  while (o.abs(1) > 0) {"
22284                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22285                "    if (pre > 0) {"
22286                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
22287                "    }"
22288                "  }"
22289                "}"
22290                "var i = 50;"
22291                "var obj = {abs: function () { return i-- }, x: null};"
22292                "delete obj.x;"
22293                "loopish(obj);"
22294                "%OptimizeFunctionOnNextCall(loopish);"
22295                "loopish(Math);");
22296
22297     i::FLAG_allow_natives_syntax = false;
22298   }
22299
22300  private:
22301   static void WakeUpInterruptorCallback(
22302       const v8::FunctionCallbackInfo<Value>& info) {
22303     if (!info[0]->BooleanValue()) return;
22304
22305     RequestInterruptTestBase* test =
22306         reinterpret_cast<RequestInterruptTestBase*>(
22307             info.Data().As<v8::External>()->Value());
22308     test->WakeUpInterruptor();
22309   }
22310
22311   static void ShouldContinueCallback(
22312       const v8::FunctionCallbackInfo<Value>& info) {
22313     RequestInterruptTestBase* test =
22314         reinterpret_cast<RequestInterruptTestBase*>(
22315             info.Data().As<v8::External>()->Value());
22316     info.GetReturnValue().Set(test->should_continue());
22317   }
22318 };
22319
22320
22321 TEST(RequestInterruptTestWithFunctionCall) {
22322   RequestInterruptTestWithFunctionCall().RunTest();
22323 }
22324
22325
22326 TEST(RequestInterruptTestWithMethodCall) {
22327   RequestInterruptTestWithMethodCall().RunTest();
22328 }
22329
22330
22331 TEST(RequestInterruptTestWithAccessor) {
22332   RequestInterruptTestWithAccessor().RunTest();
22333 }
22334
22335
22336 TEST(RequestInterruptTestWithNativeAccessor) {
22337   RequestInterruptTestWithNativeAccessor().RunTest();
22338 }
22339
22340
22341 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22342   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22343 }
22344
22345
22346 TEST(RequestInterruptTestWithMathAbs) {
22347   RequestInterruptTestWithMathAbs().RunTest();
22348 }
22349
22350
22351 class ClearInterruptFromAnotherThread
22352     : public RequestInterruptTestBase {
22353  public:
22354   ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22355
22356   virtual void StartInterruptThread() {
22357     i_thread.Start();
22358   }
22359
22360   virtual void TestBody() {
22361     Local<Function> func = Function::New(
22362         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22363     env_->Global()->Set(v8_str("ShouldContinue"), func);
22364
22365     CompileRun("while (ShouldContinue()) { }");
22366   }
22367
22368  private:
22369   class InterruptThread : public v8::base::Thread {
22370    public:
22371     explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22372         : Thread(Options("RequestInterruptTest")), test_(test) {}
22373
22374     virtual void Run() {
22375       test_->sem_.Wait();
22376       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22377       test_->sem_.Wait();
22378       test_->isolate_->ClearInterrupt();
22379       test_->sem2_.Signal();
22380     }
22381
22382     static void OnInterrupt(v8::Isolate* isolate, void* data) {
22383       ClearInterruptFromAnotherThread* test =
22384           reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22385       test->sem_.Signal();
22386       bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
22387       // Crash instead of timeout to make this failure more prominent.
22388       CHECK(success);
22389       test->should_continue_ = false;
22390     }
22391
22392    private:
22393      ClearInterruptFromAnotherThread* test_;
22394   };
22395
22396   InterruptThread i_thread;
22397   v8::base::Semaphore sem2_;
22398 };
22399
22400
22401 TEST(ClearInterruptFromAnotherThread) {
22402   ClearInterruptFromAnotherThread().RunTest();
22403 }
22404
22405
22406 static Local<Value> function_new_expected_env;
22407 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22408   CHECK_EQ(function_new_expected_env, info.Data());
22409   info.GetReturnValue().Set(17);
22410 }
22411
22412
22413 THREADED_TEST(FunctionNew) {
22414   LocalContext env;
22415   v8::Isolate* isolate = env->GetIsolate();
22416   v8::HandleScope scope(isolate);
22417   Local<Object> data = v8::Object::New(isolate);
22418   function_new_expected_env = data;
22419   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22420   env->Global()->Set(v8_str("func"), func);
22421   Local<Value> result = CompileRun("func();");
22422   CHECK_EQ(v8::Integer::New(isolate, 17), result);
22423   // Verify function not cached
22424   int serial_number =
22425       i::Smi::cast(v8::Utils::OpenHandle(*func)
22426           ->shared()->get_api_func_data()->serial_number())->value();
22427   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22428   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22429   i::Handle<i::Object> elm =
22430       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22431   CHECK(elm->IsUndefined());
22432   // Verify that each Function::New creates a new function instance
22433   Local<Object> data2 = v8::Object::New(isolate);
22434   function_new_expected_env = data2;
22435   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22436   CHECK(!func2->IsNull());
22437   CHECK_NE(func, func2);
22438   env->Global()->Set(v8_str("func2"), func2);
22439   Local<Value> result2 = CompileRun("func2();");
22440   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22441 }
22442
22443
22444 TEST(EscapeableHandleScope) {
22445   HandleScope outer_scope(CcTest::isolate());
22446   LocalContext context;
22447   const int runs = 10;
22448   Local<String> values[runs];
22449   for (int i = 0; i < runs; i++) {
22450     v8::EscapableHandleScope inner_scope(CcTest::isolate());
22451     Local<String> value;
22452     if (i != 0) value = v8_str("escape value");
22453     values[i] = inner_scope.Escape(value);
22454   }
22455   for (int i = 0; i < runs; i++) {
22456     Local<String> expected;
22457     if (i != 0) {
22458       CHECK_EQ(v8_str("escape value"), values[i]);
22459     } else {
22460       CHECK(values[i].IsEmpty());
22461     }
22462   }
22463 }
22464
22465
22466 static void SetterWhichExpectsThisAndHolderToDiffer(
22467     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22468   CHECK(info.Holder() != info.This());
22469 }
22470
22471
22472 TEST(Regress239669) {
22473   LocalContext context;
22474   v8::Isolate* isolate = context->GetIsolate();
22475   v8::HandleScope scope(isolate);
22476   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22477   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22478   context->Global()->Set(v8_str("P"), templ->NewInstance());
22479   CompileRun(
22480       "function C1() {"
22481       "  this.x = 23;"
22482       "};"
22483       "C1.prototype = P;"
22484       "for (var i = 0; i < 4; i++ ) {"
22485       "  new C1();"
22486       "}");
22487 }
22488
22489
22490 class ApiCallOptimizationChecker {
22491  private:
22492   static Local<Object> data;
22493   static Local<Object> receiver;
22494   static Local<Object> holder;
22495   static Local<Object> callee;
22496   static int count;
22497
22498   static void OptimizationCallback(
22499       const v8::FunctionCallbackInfo<v8::Value>& info) {
22500     CHECK(callee == info.Callee());
22501     CHECK(data == info.Data());
22502     CHECK(receiver == info.This());
22503     if (info.Length() == 1) {
22504       CHECK_EQ(v8_num(1), info[0]);
22505     }
22506     CHECK(holder == info.Holder());
22507     count++;
22508     info.GetReturnValue().Set(v8_str("returned"));
22509   }
22510
22511  public:
22512   enum SignatureType {
22513     kNoSignature,
22514     kSignatureOnReceiver,
22515     kSignatureOnPrototype
22516   };
22517
22518   void RunAll() {
22519     SignatureType signature_types[] =
22520       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22521     for (unsigned i = 0; i < arraysize(signature_types); i++) {
22522       SignatureType signature_type = signature_types[i];
22523       for (int j = 0; j < 2; j++) {
22524         bool global = j == 0;
22525         int key = signature_type +
22526             arraysize(signature_types) * (global ? 1 : 0);
22527         Run(signature_type, global, key);
22528       }
22529     }
22530   }
22531
22532   void Run(SignatureType signature_type, bool global, int key) {
22533     v8::Isolate* isolate = CcTest::isolate();
22534     v8::HandleScope scope(isolate);
22535     // Build a template for signature checks.
22536     Local<v8::ObjectTemplate> signature_template;
22537     Local<v8::Signature> signature;
22538     {
22539       Local<v8::FunctionTemplate> parent_template =
22540         FunctionTemplate::New(isolate);
22541       parent_template->SetHiddenPrototype(true);
22542       Local<v8::FunctionTemplate> function_template
22543           = FunctionTemplate::New(isolate);
22544       function_template->Inherit(parent_template);
22545       switch (signature_type) {
22546         case kNoSignature:
22547           break;
22548         case kSignatureOnReceiver:
22549           signature = v8::Signature::New(isolate, function_template);
22550           break;
22551         case kSignatureOnPrototype:
22552           signature = v8::Signature::New(isolate, parent_template);
22553           break;
22554       }
22555       signature_template = function_template->InstanceTemplate();
22556     }
22557     // Global object must pass checks.
22558     Local<v8::Context> context =
22559         v8::Context::New(isolate, NULL, signature_template);
22560     v8::Context::Scope context_scope(context);
22561     // Install regular object that can pass signature checks.
22562     Local<Object> function_receiver = signature_template->NewInstance();
22563     context->Global()->Set(v8_str("function_receiver"), function_receiver);
22564     // Get the holder objects.
22565     Local<Object> inner_global =
22566         Local<Object>::Cast(context->Global()->GetPrototype());
22567     // Install functions on hidden prototype object if there is one.
22568     data = Object::New(isolate);
22569     Local<FunctionTemplate> function_template = FunctionTemplate::New(
22570         isolate, OptimizationCallback, data, signature);
22571     Local<Function> function = function_template->GetFunction();
22572     Local<Object> global_holder = inner_global;
22573     Local<Object> function_holder = function_receiver;
22574     if (signature_type == kSignatureOnPrototype) {
22575       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22576       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22577     }
22578     global_holder->Set(v8_str("g_f"), function);
22579     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22580     function_holder->Set(v8_str("f"), function);
22581     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22582     // Initialize expected values.
22583     callee = function;
22584     count = 0;
22585     if (global) {
22586       receiver = context->Global();
22587       holder = inner_global;
22588     } else {
22589       holder = function_receiver;
22590       // If not using a signature, add something else to the prototype chain
22591       // to test the case that holder != receiver
22592       if (signature_type == kNoSignature) {
22593         receiver = Local<Object>::Cast(CompileRun(
22594             "var receiver_subclass = {};\n"
22595             "receiver_subclass.__proto__ = function_receiver;\n"
22596             "receiver_subclass"));
22597       } else {
22598         receiver = Local<Object>::Cast(CompileRun(
22599           "var receiver_subclass = function_receiver;\n"
22600           "receiver_subclass"));
22601       }
22602     }
22603     // With no signature, the holder is not set.
22604     if (signature_type == kNoSignature) holder = receiver;
22605     // build wrap_function
22606     i::ScopedVector<char> wrap_function(200);
22607     if (global) {
22608       i::SNPrintF(
22609           wrap_function,
22610           "function wrap_f_%d() { var f = g_f; return f(); }\n"
22611           "function wrap_get_%d() { return this.g_acc; }\n"
22612           "function wrap_set_%d() { return this.g_acc = 1; }\n",
22613           key, key, key);
22614     } else {
22615       i::SNPrintF(
22616           wrap_function,
22617           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22618           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22619           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22620           key, key, key);
22621     }
22622     // build source string
22623     i::ScopedVector<char> source(1000);
22624     i::SNPrintF(
22625         source,
22626         "%s\n"  // wrap functions
22627         "function wrap_f() { return wrap_f_%d(); }\n"
22628         "function wrap_get() { return wrap_get_%d(); }\n"
22629         "function wrap_set() { return wrap_set_%d(); }\n"
22630         "check = function(returned) {\n"
22631         "  if (returned !== 'returned') { throw returned; }\n"
22632         "}\n"
22633         "\n"
22634         "check(wrap_f());\n"
22635         "check(wrap_f());\n"
22636         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22637         "check(wrap_f());\n"
22638         "\n"
22639         "check(wrap_get());\n"
22640         "check(wrap_get());\n"
22641         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22642         "check(wrap_get());\n"
22643         "\n"
22644         "check = function(returned) {\n"
22645         "  if (returned !== 1) { throw returned; }\n"
22646         "}\n"
22647         "check(wrap_set());\n"
22648         "check(wrap_set());\n"
22649         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22650         "check(wrap_set());\n",
22651         wrap_function.start(), key, key, key, key, key, key);
22652     v8::TryCatch try_catch;
22653     CompileRun(source.start());
22654     DCHECK(!try_catch.HasCaught());
22655     CHECK_EQ(9, count);
22656   }
22657 };
22658
22659
22660 Local<Object> ApiCallOptimizationChecker::data;
22661 Local<Object> ApiCallOptimizationChecker::receiver;
22662 Local<Object> ApiCallOptimizationChecker::holder;
22663 Local<Object> ApiCallOptimizationChecker::callee;
22664 int ApiCallOptimizationChecker::count = 0;
22665
22666
22667 TEST(TestFunctionCallOptimization) {
22668   i::FLAG_allow_natives_syntax = true;
22669   ApiCallOptimizationChecker checker;
22670   checker.RunAll();
22671 }
22672
22673
22674 static const char* last_event_message;
22675 static int last_event_status;
22676 void StoringEventLoggerCallback(const char* message, int status) {
22677     last_event_message = message;
22678     last_event_status = status;
22679 }
22680
22681
22682 TEST(EventLogging) {
22683   v8::Isolate* isolate = CcTest::isolate();
22684   isolate->SetEventLogger(StoringEventLoggerCallback);
22685   v8::internal::HistogramTimer histogramTimer(
22686       "V8.Test", 0, 10000, 50,
22687       reinterpret_cast<v8::internal::Isolate*>(isolate));
22688   histogramTimer.Start();
22689   CHECK_EQ("V8.Test", last_event_message);
22690   CHECK_EQ(0, last_event_status);
22691   histogramTimer.Stop();
22692   CHECK_EQ("V8.Test", last_event_message);
22693   CHECK_EQ(1, last_event_status);
22694 }
22695
22696
22697 TEST(Promises) {
22698   LocalContext context;
22699   v8::Isolate* isolate = context->GetIsolate();
22700   v8::HandleScope scope(isolate);
22701   Handle<Object> global = context->Global();
22702
22703   // Creation.
22704   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22705   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22706   Handle<v8::Promise> p = pr->GetPromise();
22707   Handle<v8::Promise> r = rr->GetPromise();
22708
22709   // IsPromise predicate.
22710   CHECK(p->IsPromise());
22711   CHECK(r->IsPromise());
22712   Handle<Value> o = v8::Object::New(isolate);
22713   CHECK(!o->IsPromise());
22714
22715   // Resolution and rejection.
22716   pr->Resolve(v8::Integer::New(isolate, 1));
22717   CHECK(p->IsPromise());
22718   rr->Reject(v8::Integer::New(isolate, 2));
22719   CHECK(r->IsPromise());
22720
22721   // Chaining non-pending promises.
22722   CompileRun(
22723       "var x1 = 0;\n"
22724       "var x2 = 0;\n"
22725       "function f1(x) { x1 = x; return x+1 };\n"
22726       "function f2(x) { x2 = x; return x+1 };\n");
22727   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22728   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22729
22730   p->Chain(f1);
22731   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22732   isolate->RunMicrotasks();
22733   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22734
22735   p->Catch(f2);
22736   isolate->RunMicrotasks();
22737   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22738
22739   r->Catch(f2);
22740   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22741   isolate->RunMicrotasks();
22742   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22743
22744   r->Chain(f1);
22745   isolate->RunMicrotasks();
22746   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22747
22748   // Chaining pending promises.
22749   CompileRun("x1 = x2 = 0;");
22750   pr = v8::Promise::Resolver::New(isolate);
22751   rr = v8::Promise::Resolver::New(isolate);
22752
22753   pr->GetPromise()->Chain(f1);
22754   rr->GetPromise()->Catch(f2);
22755   isolate->RunMicrotasks();
22756   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22757   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22758
22759   pr->Resolve(v8::Integer::New(isolate, 1));
22760   rr->Reject(v8::Integer::New(isolate, 2));
22761   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22762   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22763
22764   isolate->RunMicrotasks();
22765   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22766   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22767
22768   // Multi-chaining.
22769   CompileRun("x1 = x2 = 0;");
22770   pr = v8::Promise::Resolver::New(isolate);
22771   pr->GetPromise()->Chain(f1)->Chain(f2);
22772   pr->Resolve(v8::Integer::New(isolate, 3));
22773   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22774   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22775   isolate->RunMicrotasks();
22776   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22777   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22778
22779   CompileRun("x1 = x2 = 0;");
22780   rr = v8::Promise::Resolver::New(isolate);
22781   rr->GetPromise()->Catch(f1)->Chain(f2);
22782   rr->Reject(v8::Integer::New(isolate, 3));
22783   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22784   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22785   isolate->RunMicrotasks();
22786   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22787   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22788 }
22789
22790
22791 TEST(PromiseThen) {
22792   LocalContext context;
22793   v8::Isolate* isolate = context->GetIsolate();
22794   v8::HandleScope scope(isolate);
22795   Handle<Object> global = context->Global();
22796
22797   // Creation.
22798   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22799   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22800   Handle<v8::Promise> p = pr->GetPromise();
22801   Handle<v8::Promise> q = qr->GetPromise();
22802
22803   CHECK(p->IsPromise());
22804   CHECK(q->IsPromise());
22805
22806   pr->Resolve(v8::Integer::New(isolate, 1));
22807   qr->Resolve(p);
22808
22809   // Chaining non-pending promises.
22810   CompileRun(
22811       "var x1 = 0;\n"
22812       "var x2 = 0;\n"
22813       "function f1(x) { x1 = x; return x+1 };\n"
22814       "function f2(x) { x2 = x; return x+1 };\n");
22815   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22816   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22817
22818   // Chain
22819   q->Chain(f1);
22820   CHECK(global->Get(v8_str("x1"))->IsNumber());
22821   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22822   isolate->RunMicrotasks();
22823   CHECK(!global->Get(v8_str("x1"))->IsNumber());
22824   CHECK_EQ(p, global->Get(v8_str("x1")));
22825
22826   // Then
22827   CompileRun("x1 = x2 = 0;");
22828   q->Then(f1);
22829   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22830   isolate->RunMicrotasks();
22831   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22832
22833   // Then
22834   CompileRun("x1 = x2 = 0;");
22835   pr = v8::Promise::Resolver::New(isolate);
22836   qr = v8::Promise::Resolver::New(isolate);
22837
22838   qr->Resolve(pr);
22839   qr->GetPromise()->Then(f1)->Then(f2);
22840
22841   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22842   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22843   isolate->RunMicrotasks();
22844   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22845   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22846
22847   pr->Resolve(v8::Integer::New(isolate, 3));
22848
22849   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22850   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22851   isolate->RunMicrotasks();
22852   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22853   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22854 }
22855
22856
22857 TEST(DisallowJavascriptExecutionScope) {
22858   LocalContext context;
22859   v8::Isolate* isolate = context->GetIsolate();
22860   v8::HandleScope scope(isolate);
22861   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22862       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22863   CompileRun("2+2");
22864 }
22865
22866
22867 TEST(AllowJavascriptExecutionScope) {
22868   LocalContext context;
22869   v8::Isolate* isolate = context->GetIsolate();
22870   v8::HandleScope scope(isolate);
22871   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22872       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22873   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22874       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22875   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22876     CompileRun("1+1");
22877   }
22878 }
22879
22880
22881 TEST(ThrowOnJavascriptExecution) {
22882   LocalContext context;
22883   v8::Isolate* isolate = context->GetIsolate();
22884   v8::HandleScope scope(isolate);
22885   v8::TryCatch try_catch;
22886   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22887       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22888   CompileRun("1+1");
22889   CHECK(try_catch.HasCaught());
22890 }
22891
22892
22893 TEST(Regress354123) {
22894   LocalContext current;
22895   v8::Isolate* isolate = current->GetIsolate();
22896   v8::HandleScope scope(isolate);
22897
22898   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22899   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22900   current->Global()->Set(v8_str("friend"), templ->NewInstance());
22901
22902   // Test access using __proto__ from the prototype chain.
22903   named_access_count = 0;
22904   CompileRun("friend.__proto__ = {};");
22905   CHECK_EQ(2, named_access_count);
22906   CompileRun("friend.__proto__;");
22907   CHECK_EQ(4, named_access_count);
22908
22909   // Test access using __proto__ as a hijacked function (A).
22910   named_access_count = 0;
22911   CompileRun("var p = Object.prototype;"
22912              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22913              "f.call(friend, {});");
22914   CHECK_EQ(1, named_access_count);
22915   CompileRun("var p = Object.prototype;"
22916              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22917              "f.call(friend);");
22918   CHECK_EQ(2, named_access_count);
22919
22920   // Test access using __proto__ as a hijacked function (B).
22921   named_access_count = 0;
22922   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22923              "f.call(friend, {});");
22924   CHECK_EQ(1, named_access_count);
22925   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22926              "f.call(friend);");
22927   CHECK_EQ(2, named_access_count);
22928
22929   // Test access using Object.setPrototypeOf reflective method.
22930   named_access_count = 0;
22931   CompileRun("Object.setPrototypeOf(friend, {});");
22932   CHECK_EQ(1, named_access_count);
22933   CompileRun("Object.getPrototypeOf(friend);");
22934   CHECK_EQ(2, named_access_count);
22935 }
22936
22937
22938 TEST(CaptureStackTraceForStackOverflow) {
22939   v8::internal::FLAG_stack_size = 150;
22940   LocalContext current;
22941   v8::Isolate* isolate = current->GetIsolate();
22942   v8::HandleScope scope(isolate);
22943   V8::SetCaptureStackTraceForUncaughtExceptions(
22944       true, 10, v8::StackTrace::kDetailed);
22945   v8::TryCatch try_catch;
22946   CompileRun("(function f(x) { f(x+1); })(0)");
22947   CHECK(try_catch.HasCaught());
22948 }
22949
22950
22951 TEST(ScriptNameAndLineNumber) {
22952   LocalContext env;
22953   v8::Isolate* isolate = env->GetIsolate();
22954   v8::HandleScope scope(isolate);
22955   const char* url = "http://www.foo.com/foo.js";
22956   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22957   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22958   Local<Script> script = v8::ScriptCompiler::Compile(
22959       isolate, &script_source);
22960   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22961   CHECK(!script_name.IsEmpty());
22962   CHECK(script_name->IsString());
22963   String::Utf8Value utf8_name(script_name);
22964   CHECK_EQ(url, *utf8_name);
22965   int line_number = script->GetUnboundScript()->GetLineNumber(0);
22966   CHECK_EQ(13, line_number);
22967 }
22968
22969
22970 void SourceURLHelper(const char* source, const char* expected_source_url,
22971                      const char* expected_source_mapping_url) {
22972   Local<Script> script = v8_compile(source);
22973   if (expected_source_url != NULL) {
22974     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
22975     CHECK_EQ(expected_source_url, *url);
22976   } else {
22977     CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
22978   }
22979   if (expected_source_mapping_url != NULL) {
22980     v8::String::Utf8Value url(
22981         script->GetUnboundScript()->GetSourceMappingURL());
22982     CHECK_EQ(expected_source_mapping_url, *url);
22983   } else {
22984     CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
22985   }
22986 }
22987
22988
22989 TEST(ScriptSourceURLAndSourceMappingURL) {
22990   LocalContext env;
22991   v8::Isolate* isolate = env->GetIsolate();
22992   v8::HandleScope scope(isolate);
22993   SourceURLHelper("function foo() {}\n"
22994                   "//# sourceURL=bar1.js\n", "bar1.js", NULL);
22995   SourceURLHelper("function foo() {}\n"
22996                   "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
22997
22998   // Both sourceURL and sourceMappingURL.
22999   SourceURLHelper("function foo() {}\n"
23000                   "//# sourceURL=bar3.js\n"
23001                   "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
23002
23003   // Two source URLs; the first one is ignored.
23004   SourceURLHelper("function foo() {}\n"
23005                   "//# sourceURL=ignoreme.js\n"
23006                   "//# sourceURL=bar5.js\n", "bar5.js", NULL);
23007   SourceURLHelper("function foo() {}\n"
23008                   "//# sourceMappingURL=ignoreme.js\n"
23009                   "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
23010
23011   // SourceURL or sourceMappingURL in the middle of the script.
23012   SourceURLHelper("function foo() {}\n"
23013                   "//# sourceURL=bar7.js\n"
23014                   "function baz() {}\n", "bar7.js", NULL);
23015   SourceURLHelper("function foo() {}\n"
23016                   "//# sourceMappingURL=bar8.js\n"
23017                   "function baz() {}\n", NULL, "bar8.js");
23018
23019   // Too much whitespace.
23020   SourceURLHelper("function foo() {}\n"
23021                   "//#  sourceURL=bar9.js\n"
23022                   "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
23023   SourceURLHelper("function foo() {}\n"
23024                   "//# sourceURL =bar11.js\n"
23025                   "//# sourceMappingURL =bar12.js\n", NULL, NULL);
23026
23027   // Disallowed characters in value.
23028   SourceURLHelper("function foo() {}\n"
23029                   "//# sourceURL=bar13 .js   \n"
23030                   "//# sourceMappingURL=bar14 .js \n",
23031                   NULL, NULL);
23032   SourceURLHelper("function foo() {}\n"
23033                   "//# sourceURL=bar15\t.js   \n"
23034                   "//# sourceMappingURL=bar16\t.js \n",
23035                   NULL, NULL);
23036   SourceURLHelper("function foo() {}\n"
23037                   "//# sourceURL=bar17'.js   \n"
23038                   "//# sourceMappingURL=bar18'.js \n",
23039                   NULL, NULL);
23040   SourceURLHelper("function foo() {}\n"
23041                   "//# sourceURL=bar19\".js   \n"
23042                   "//# sourceMappingURL=bar20\".js \n",
23043                   NULL, NULL);
23044
23045   // Not too much whitespace.
23046   SourceURLHelper("function foo() {}\n"
23047                   "//# sourceURL=  bar21.js   \n"
23048                   "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
23049 }
23050
23051
23052 TEST(GetOwnPropertyDescriptor) {
23053   LocalContext env;
23054   v8::Isolate* isolate = env->GetIsolate();
23055   v8::HandleScope scope(isolate);
23056   CompileRun(
23057     "var x = { value : 13};"
23058     "Object.defineProperty(x, 'p0', {value : 12});"
23059     "Object.defineProperty(x, 'p1', {"
23060     "  set : function(value) { this.value = value; },"
23061     "  get : function() { return this.value; },"
23062     "});");
23063   Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
23064   Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
23065   CHECK(desc->IsUndefined());
23066   desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
23067   CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
23068   desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
23069   Local<Function> set =
23070     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
23071   Local<Function> get =
23072     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
23073   CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
23074   Handle<Value> args[] = { v8_num(14) };
23075   set->Call(x, 1, args);
23076   CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
23077 }
23078
23079
23080 TEST(Regress411877) {
23081   v8::Isolate* isolate = CcTest::isolate();
23082   v8::HandleScope handle_scope(isolate);
23083   v8::Handle<v8::ObjectTemplate> object_template =
23084       v8::ObjectTemplate::New(isolate);
23085   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23086                                            IndexedAccessCounter);
23087
23088   v8::Handle<Context> context = Context::New(isolate);
23089   v8::Context::Scope context_scope(context);
23090
23091   context->Global()->Set(v8_str("o"), object_template->NewInstance());
23092   CompileRun("Object.getOwnPropertyNames(o)");
23093 }
23094
23095
23096 TEST(GetHiddenPropertyTableAfterAccessCheck) {
23097   v8::Isolate* isolate = CcTest::isolate();
23098   v8::HandleScope handle_scope(isolate);
23099   v8::Handle<v8::ObjectTemplate> object_template =
23100       v8::ObjectTemplate::New(isolate);
23101   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23102                                            IndexedAccessCounter);
23103
23104   v8::Handle<Context> context = Context::New(isolate);
23105   v8::Context::Scope context_scope(context);
23106
23107   v8::Handle<v8::Object> obj = object_template->NewInstance();
23108   obj->Set(v8_str("key"), v8_str("value"));
23109   obj->Delete(v8_str("key"));
23110
23111   obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
23112 }
23113
23114
23115 TEST(Regress411793) {
23116   v8::Isolate* isolate = CcTest::isolate();
23117   v8::HandleScope handle_scope(isolate);
23118   v8::Handle<v8::ObjectTemplate> object_template =
23119       v8::ObjectTemplate::New(isolate);
23120   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23121                                            IndexedAccessCounter);
23122
23123   v8::Handle<Context> context = Context::New(isolate);
23124   v8::Context::Scope context_scope(context);
23125
23126   context->Global()->Set(v8_str("o"), object_template->NewInstance());
23127   CompileRun(
23128       "Object.defineProperty(o, 'key', "
23129       "    { get: function() {}, set: function() {} });");
23130 }
23131
23132 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23133  public:
23134   explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23135
23136   virtual size_t GetMoreData(const uint8_t** src) {
23137     // Unlike in real use cases, this function will never block.
23138     if (chunks_[index_] == NULL) {
23139       return 0;
23140     }
23141     // Copy the data, since the caller takes ownership of it.
23142     size_t len = strlen(chunks_[index_]);
23143     // We don't need to zero-terminate since we return the length.
23144     uint8_t* copy = new uint8_t[len];
23145     memcpy(copy, chunks_[index_], len);
23146     *src = copy;
23147     ++index_;
23148     return len;
23149   }
23150
23151   // Helper for constructing a string from chunks (the compilation needs it
23152   // too).
23153   static char* FullSourceString(const char** chunks) {
23154     size_t total_len = 0;
23155     for (size_t i = 0; chunks[i] != NULL; ++i) {
23156       total_len += strlen(chunks[i]);
23157     }
23158     char* full_string = new char[total_len + 1];
23159     size_t offset = 0;
23160     for (size_t i = 0; chunks[i] != NULL; ++i) {
23161       size_t len = strlen(chunks[i]);
23162       memcpy(full_string + offset, chunks[i], len);
23163       offset += len;
23164     }
23165     full_string[total_len] = 0;
23166     return full_string;
23167   }
23168
23169  private:
23170   const char** chunks_;
23171   unsigned index_;
23172 };
23173
23174
23175 // Helper function for running streaming tests.
23176 void RunStreamingTest(const char** chunks,
23177                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
23178                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23179                       bool expected_success = true) {
23180   LocalContext env;
23181   v8::Isolate* isolate = env->GetIsolate();
23182   v8::HandleScope scope(isolate);
23183   v8::TryCatch try_catch;
23184
23185   v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23186                                             encoding);
23187   v8::ScriptCompiler::ScriptStreamingTask* task =
23188       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23189
23190   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23191   // task here in the main thread.
23192   task->Run();
23193   delete task;
23194
23195   v8::ScriptOrigin origin(v8_str("http://foo.com"));
23196   char* full_source = TestSourceStream::FullSourceString(chunks);
23197
23198   // The possible errors are only produced while compiling.
23199   CHECK_EQ(false, try_catch.HasCaught());
23200
23201   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
23202       isolate, &source, v8_str(full_source), origin);
23203   if (expected_success) {
23204     CHECK(!script.IsEmpty());
23205     v8::Handle<Value> result(script->Run());
23206     // All scripts are supposed to return the fixed value 13 when ran.
23207     CHECK_EQ(13, result->Int32Value());
23208   } else {
23209     CHECK(script.IsEmpty());
23210     CHECK(try_catch.HasCaught());
23211   }
23212   delete[] full_source;
23213 }
23214
23215
23216 TEST(StreamingSimpleScript) {
23217   // This script is unrealistically small, since no one chunk is enough to fill
23218   // the backing buffer of Scanner, let alone overflow it.
23219   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23220                           NULL};
23221   RunStreamingTest(chunks);
23222 }
23223
23224
23225 TEST(StreamingBiggerScript) {
23226   const char* chunk1 =
23227       "function foo() {\n"
23228       "  // Make this chunk sufficiently long so that it will overflow the\n"
23229       "  // backing buffer of the Scanner.\n"
23230       "  var i = 0;\n"
23231       "  var result = 0;\n"
23232       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23233       "  result = 0;\n"
23234       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23235       "  result = 0;\n"
23236       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23237       "  result = 0;\n"
23238       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23239       "  return result;\n"
23240       "}\n";
23241   const char* chunks[] = {chunk1, "foo(); ", NULL};
23242   RunStreamingTest(chunks);
23243 }
23244
23245
23246 TEST(StreamingScriptWithParseError) {
23247   // Test that parse errors from streamed scripts are propagated correctly.
23248   {
23249     char chunk1[] =
23250         "  // This will result in a parse error.\n"
23251         "  var if else then foo";
23252     char chunk2[] = "  13\n";
23253     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23254
23255     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23256                      false);
23257   }
23258   // Test that the next script succeeds normally.
23259   {
23260     char chunk1[] =
23261         "  // This will be parsed successfully.\n"
23262         "  function foo() { return ";
23263     char chunk2[] = "  13; }\n";
23264     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23265
23266     RunStreamingTest(chunks);
23267   }
23268 }
23269
23270
23271 TEST(StreamingUtf8Script) {
23272   // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
23273   // don't like it.
23274   const char* chunk1 =
23275       "function foo() {\n"
23276       "  // This function will contain an UTF-8 character which is not in\n"
23277       "  // ASCII.\n"
23278       "  var foob\xeb\x91\x80r = 13;\n"
23279       "  return foob\xeb\x91\x80r;\n"
23280       "}\n";
23281   const char* chunks[] = {chunk1, "foo(); ", NULL};
23282   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23283 }
23284
23285
23286 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23287   // A sanity check to prove that the approach of splitting UTF-8
23288   // characters is correct. Here is an UTF-8 character which will take three
23289   // bytes.
23290   const char* reference = "\xeb\x91\x80";
23291   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
23292
23293   char chunk1[] =
23294       "function foo() {\n"
23295       "  // This function will contain an UTF-8 character which is not in\n"
23296       "  // ASCII.\n"
23297       "  var foob";
23298   char chunk2[] =
23299       "XXXr = 13;\n"
23300       "  return foob\xeb\x91\x80r;\n"
23301       "}\n";
23302   for (int i = 0; i < 3; ++i) {
23303     chunk2[i] = reference[i];
23304   }
23305   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23306   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23307 }
23308
23309
23310 TEST(StreamingUtf8ScriptWithSplitCharacters) {
23311   // Stream data where a multi-byte UTF-8 character is split between two data
23312   // chunks.
23313   const char* reference = "\xeb\x91\x80";
23314   char chunk1[] =
23315       "function foo() {\n"
23316       "  // This function will contain an UTF-8 character which is not in\n"
23317       "  // ASCII.\n"
23318       "  var foobX";
23319   char chunk2[] =
23320       "XXr = 13;\n"
23321       "  return foob\xeb\x91\x80r;\n"
23322       "}\n";
23323   chunk1[strlen(chunk1) - 1] = reference[0];
23324   chunk2[0] = reference[1];
23325   chunk2[1] = reference[2];
23326   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23327   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23328 }
23329
23330
23331 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
23332   // Tests edge cases which should still be decoded correctly.
23333
23334   // Case 1: a chunk contains only bytes for a split character (and no other
23335   // data). This kind of a chunk would be exceptionally small, but we should
23336   // still decode it correctly.
23337   const char* reference = "\xeb\x91\x80";
23338   // The small chunk is at the beginning of the split character
23339   {
23340     char chunk1[] =
23341         "function foo() {\n"
23342         "  // This function will contain an UTF-8 character which is not in\n"
23343         "  // ASCII.\n"
23344         "  var foob";
23345     char chunk2[] = "XX";
23346     char chunk3[] =
23347         "Xr = 13;\n"
23348         "  return foob\xeb\x91\x80r;\n"
23349         "}\n";
23350     chunk2[0] = reference[0];
23351     chunk2[1] = reference[1];
23352     chunk3[0] = reference[2];
23353     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23354     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23355   }
23356   // The small chunk is at the end of a character
23357   {
23358     char chunk1[] =
23359         "function foo() {\n"
23360         "  // This function will contain an UTF-8 character which is not in\n"
23361         "  // ASCII.\n"
23362         "  var foobX";
23363     char chunk2[] = "XX";
23364     char chunk3[] =
23365         "r = 13;\n"
23366         "  return foob\xeb\x91\x80r;\n"
23367         "}\n";
23368     chunk1[strlen(chunk1) - 1] = reference[0];
23369     chunk2[0] = reference[1];
23370     chunk2[1] = reference[2];
23371     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23372     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23373   }
23374   // Case 2: the script ends with a multi-byte character. Make sure that it's
23375   // decoded correctly and not just ignored.
23376   {
23377     char chunk1[] =
23378         "var foob\xeb\x91\x80 = 13;\n"
23379         "foob\xeb\x91\x80";
23380     const char* chunks[] = {chunk1, NULL};
23381     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23382   }
23383 }
23384
23385
23386 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
23387   // Test cases where a UTF-8 character is split over several chunks. Those
23388   // cases are not supported (the embedder should give the data in big enough
23389   // chunks), but we shouldn't crash, just produce a parse error.
23390   const char* reference = "\xeb\x91\x80";
23391   char chunk1[] =
23392       "function foo() {\n"
23393       "  // This function will contain an UTF-8 character which is not in\n"
23394       "  // ASCII.\n"
23395       "  var foobX";
23396   char chunk2[] = "X";
23397   char chunk3[] =
23398       "Xr = 13;\n"
23399       "  return foob\xeb\x91\x80r;\n"
23400       "}\n";
23401   chunk1[strlen(chunk1) - 1] = reference[0];
23402   chunk2[0] = reference[1];
23403   chunk3[0] = reference[2];
23404   const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
23405
23406   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23407 }
23408
23409
23410 TEST(StreamingProducesParserCache) {
23411   i::FLAG_min_preparse_length = 0;
23412   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23413                           NULL};
23414
23415   LocalContext env;
23416   v8::Isolate* isolate = env->GetIsolate();
23417   v8::HandleScope scope(isolate);
23418
23419   v8::ScriptCompiler::StreamedSource source(
23420       new TestSourceStream(chunks),
23421       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
23422   v8::ScriptCompiler::ScriptStreamingTask* task =
23423       v8::ScriptCompiler::StartStreamingScript(
23424           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
23425
23426   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23427   // task here in the main thread.
23428   task->Run();
23429   delete task;
23430
23431   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
23432   CHECK(cached_data != NULL);
23433   CHECK(cached_data->data != NULL);
23434   CHECK_GT(cached_data->length, 0);
23435 }
23436
23437
23438 TEST(StreamingScriptWithInvalidUtf8) {
23439   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
23440   // chunk don't produce a crash.
23441   const char* reference = "\xeb\x91\x80\x80\x80";
23442   char chunk1[] =
23443       "function foo() {\n"
23444       "  // This function will contain an UTF-8 character which is not in\n"
23445       "  // ASCII.\n"
23446       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
23447   char chunk2[] =
23448       "r = 13;\n"
23449       "  return foob\xeb\x91\x80\x80\x80r;\n"
23450       "}\n";
23451   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
23452
23453   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23454   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
23455 }