Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <string>
31 #include <map>
32
33 #include "v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "api.h"
40 #include "arguments.h"
41 #include "cctest.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
45 #include "isolate.h"
46 #include "objects.h"
47 #include "parser.h"
48 #include "platform.h"
49 #include "snapshot.h"
50 #include "unicode-inl.h"
51 #include "utils.h"
52 #include "vm-state.h"
53
54 static const bool kLogThreading = false;
55
56 using ::v8::Boolean;
57 using ::v8::BooleanObject;
58 using ::v8::Context;
59 using ::v8::Extension;
60 using ::v8::Function;
61 using ::v8::FunctionTemplate;
62 using ::v8::Handle;
63 using ::v8::HandleScope;
64 using ::v8::Local;
65 using ::v8::Message;
66 using ::v8::MessageCallback;
67 using ::v8::Object;
68 using ::v8::ObjectTemplate;
69 using ::v8::Persistent;
70 using ::v8::Script;
71 using ::v8::StackTrace;
72 using ::v8::String;
73 using ::v8::TryCatch;
74 using ::v8::Undefined;
75 using ::v8::UniqueId;
76 using ::v8::V8;
77 using ::v8::Value;
78
79
80 #define THREADED_PROFILED_TEST(Name)                                 \
81   static void Test##Name();                                          \
82   TEST(Name##WithProfiler) {                                         \
83     RunWithProfiler(&Test##Name);                                    \
84   }                                                                  \
85   THREADED_TEST(Name)
86
87
88 void RunWithProfiler(void (*test)()) {
89   LocalContext env;
90   v8::HandleScope scope(env->GetIsolate());
91   v8::Local<v8::String> profile_name =
92       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
93   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
94
95   cpu_profiler->StartCpuProfiling(profile_name);
96   (*test)();
97   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
98 }
99
100
101 static void ExpectString(const char* code, const char* expected) {
102   Local<Value> result = CompileRun(code);
103   CHECK(result->IsString());
104   String::Utf8Value utf8(result);
105   CHECK_EQ(expected, *utf8);
106 }
107
108
109 static void ExpectInt32(const char* code, int expected) {
110   Local<Value> result = CompileRun(code);
111   CHECK(result->IsInt32());
112   CHECK_EQ(expected, result->Int32Value());
113 }
114
115
116 static void ExpectBoolean(const char* code, bool expected) {
117   Local<Value> result = CompileRun(code);
118   CHECK(result->IsBoolean());
119   CHECK_EQ(expected, result->BooleanValue());
120 }
121
122
123 static void ExpectTrue(const char* code) {
124   ExpectBoolean(code, true);
125 }
126
127
128 static void ExpectFalse(const char* code) {
129   ExpectBoolean(code, false);
130 }
131
132
133 static void ExpectObject(const char* code, Local<Value> expected) {
134   Local<Value> result = CompileRun(code);
135   CHECK(result->Equals(expected));
136 }
137
138
139 static void ExpectUndefined(const char* code) {
140   Local<Value> result = CompileRun(code);
141   CHECK(result->IsUndefined());
142 }
143
144
145 static int signature_callback_count;
146 static Local<Value> signature_expected_receiver;
147 static void IncrementingSignatureCallback(
148     const v8::FunctionCallbackInfo<v8::Value>& args) {
149   ApiTestFuzzer::Fuzz();
150   signature_callback_count++;
151   CHECK_EQ(signature_expected_receiver, args.Holder());
152   CHECK_EQ(signature_expected_receiver, args.This());
153   v8::Handle<v8::Array> result =
154       v8::Array::New(args.GetIsolate(), args.Length());
155   for (int i = 0; i < args.Length(); i++)
156     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
157   args.GetReturnValue().Set(result);
158 }
159
160
161 static void SignatureCallback(
162     const v8::FunctionCallbackInfo<v8::Value>& args) {
163   ApiTestFuzzer::Fuzz();
164   v8::Handle<v8::Array> result =
165       v8::Array::New(args.GetIsolate(), args.Length());
166   for (int i = 0; i < args.Length(); i++) {
167     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
168   }
169   args.GetReturnValue().Set(result);
170 }
171
172
173 // Tests that call v8::V8::Dispose() cannot be threaded.
174 TEST(InitializeAndDisposeOnce) {
175   CHECK(v8::V8::Initialize());
176   CHECK(v8::V8::Dispose());
177 }
178
179
180 // Tests that call v8::V8::Dispose() cannot be threaded.
181 TEST(InitializeAndDisposeMultiple) {
182   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
183   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
184   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
185   // TODO(mstarzinger): This should fail gracefully instead of asserting.
186   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
187   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
188 }
189
190
191 THREADED_TEST(Handles) {
192   v8::HandleScope scope(CcTest::isolate());
193   Local<Context> local_env;
194   {
195     LocalContext env;
196     local_env = env.local();
197   }
198
199   // Local context should still be live.
200   CHECK(!local_env.IsEmpty());
201   local_env->Enter();
202
203   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
204   CHECK(!undef.IsEmpty());
205   CHECK(undef->IsUndefined());
206
207   const char* c_source = "1 + 2 + 3";
208   Local<String> source = String::NewFromUtf8(CcTest::isolate(), c_source);
209   Local<Script> script = Script::Compile(source);
210   CHECK_EQ(6, script->Run()->Int32Value());
211
212   local_env->Exit();
213 }
214
215
216 THREADED_TEST(IsolateOfContext) {
217   v8::HandleScope scope(CcTest::isolate());
218   v8::Handle<Context> env = Context::New(CcTest::isolate());
219
220   CHECK(!env->GetIsolate()->InContext());
221   CHECK(env->GetIsolate() == CcTest::isolate());
222   env->Enter();
223   CHECK(env->GetIsolate()->InContext());
224   CHECK(env->GetIsolate() == CcTest::isolate());
225   env->Exit();
226   CHECK(!env->GetIsolate()->InContext());
227   CHECK(env->GetIsolate() == CcTest::isolate());
228 }
229
230
231 static void TestSignature(const char* loop_js, Local<Value> receiver) {
232   i::ScopedVector<char> source(200);
233   i::OS::SNPrintF(source,
234                   "for (var i = 0; i < 10; i++) {"
235                   "  %s"
236                   "}",
237                   loop_js);
238   signature_callback_count = 0;
239   signature_expected_receiver = receiver;
240   bool expected_to_throw = receiver.IsEmpty();
241   v8::TryCatch try_catch;
242   CompileRun(source.start());
243   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
244   if (!expected_to_throw) {
245     CHECK_EQ(10, signature_callback_count);
246   } else {
247     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
248              try_catch.Exception()->ToString());
249   }
250 }
251
252
253 THREADED_TEST(ReceiverSignature) {
254   LocalContext env;
255   v8::Isolate* isolate = env->GetIsolate();
256   v8::HandleScope scope(isolate);
257   // Setup templates.
258   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
259   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
260   v8::Handle<v8::FunctionTemplate> callback_sig =
261       v8::FunctionTemplate::New(
262           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
263   v8::Handle<v8::FunctionTemplate> callback =
264       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
265   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
266   sub_fun->Inherit(fun);
267   v8::Handle<v8::FunctionTemplate> unrel_fun =
268       v8::FunctionTemplate::New(isolate);
269   // Install properties.
270   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
271   fun_proto->Set(v8_str("prop_sig"), callback_sig);
272   fun_proto->Set(v8_str("prop"), callback);
273   fun_proto->SetAccessorProperty(
274       v8_str("accessor_sig"), callback_sig, callback_sig);
275   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
276   // Instantiate templates.
277   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
278   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
279   // Setup global variables.
280   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
281   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
282   env->Global()->Set(v8_str("fun_instance"), fun_instance);
283   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
284   CompileRun(
285       "var accessor_sig_key = 'accessor_sig';"
286       "var accessor_key = 'accessor';"
287       "var prop_sig_key = 'prop_sig';"
288       "var prop_key = 'prop';"
289       ""
290       "function copy_props(obj) {"
291       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
292       "  var source = Fun.prototype;"
293       "  for (var i in keys) {"
294       "    var key = keys[i];"
295       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
296       "    Object.defineProperty(obj, key, desc);"
297       "  }"
298       "}"
299       ""
300       "var obj = {};"
301       "copy_props(obj);"
302       "var unrel = new UnrelFun();"
303       "copy_props(unrel);");
304   // Test with and without ICs
305   const char* test_objects[] = {
306       "fun_instance", "sub_fun_instance", "obj", "unrel" };
307   unsigned bad_signature_start_offset = 2;
308   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
309     i::ScopedVector<char> source(200);
310     i::OS::SNPrintF(
311         source, "var test_object = %s; test_object", test_objects[i]);
312     Local<Value> test_object = CompileRun(source.start());
313     TestSignature("test_object.prop();", test_object);
314     TestSignature("test_object.accessor;", test_object);
315     TestSignature("test_object[accessor_key];", test_object);
316     TestSignature("test_object.accessor = 1;", test_object);
317     TestSignature("test_object[accessor_key] = 1;", test_object);
318     if (i >= bad_signature_start_offset) test_object = Local<Value>();
319     TestSignature("test_object.prop_sig();", test_object);
320     TestSignature("test_object.accessor_sig;", test_object);
321     TestSignature("test_object[accessor_sig_key];", test_object);
322     TestSignature("test_object.accessor_sig = 1;", test_object);
323     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
324   }
325 }
326
327
328 THREADED_TEST(ArgumentSignature) {
329   LocalContext env;
330   v8::Isolate* isolate = env->GetIsolate();
331   v8::HandleScope scope(isolate);
332   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
333   cons->SetClassName(v8_str("Cons"));
334   v8::Handle<v8::Signature> sig = v8::Signature::New(
335       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
336   v8::Handle<v8::FunctionTemplate> fun =
337       v8::FunctionTemplate::New(isolate,
338                                 SignatureCallback,
339                                 v8::Handle<Value>(),
340                                 sig);
341   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
342   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
343
344   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
345   CHECK(value1->IsTrue());
346
347   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
348   CHECK(value2->IsTrue());
349
350   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
351   CHECK(value3->IsTrue());
352
353   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
354   cons1->SetClassName(v8_str("Cons1"));
355   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
356   cons2->SetClassName(v8_str("Cons2"));
357   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
358   cons3->SetClassName(v8_str("Cons3"));
359
360   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
361   v8::Handle<v8::Signature> wsig = v8::Signature::New(
362       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
363   v8::Handle<v8::FunctionTemplate> fun2 =
364       v8::FunctionTemplate::New(isolate,
365                                 SignatureCallback,
366                                 v8::Handle<Value>(),
367                                 wsig);
368
369   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
370   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
371   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
372   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
373   v8::Handle<Value> value4 = CompileRun(
374       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
375       "'[object Cons1],[object Cons2],[object Cons3]'");
376   CHECK(value4->IsTrue());
377
378   v8::Handle<Value> value5 = CompileRun(
379       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
380   CHECK(value5->IsTrue());
381
382   v8::Handle<Value> value6 = CompileRun(
383       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
384   CHECK(value6->IsTrue());
385
386   v8::Handle<Value> value7 = CompileRun(
387       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
388       "'[object Cons1],[object Cons2],[object Cons3],d';");
389   CHECK(value7->IsTrue());
390
391   v8::Handle<Value> value8 = CompileRun(
392       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
393   CHECK(value8->IsTrue());
394 }
395
396
397 THREADED_TEST(HulIgennem) {
398   LocalContext env;
399   v8::Isolate* isolate = env->GetIsolate();
400   v8::HandleScope scope(isolate);
401   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
402   Local<String> undef_str = undef->ToString();
403   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
404   undef_str->WriteUtf8(value);
405   CHECK_EQ(0, strcmp(value, "undefined"));
406   i::DeleteArray(value);
407 }
408
409
410 THREADED_TEST(Access) {
411   LocalContext env;
412   v8::Isolate* isolate = env->GetIsolate();
413   v8::HandleScope scope(isolate);
414   Local<v8::Object> obj = v8::Object::New(isolate);
415   Local<Value> foo_before = obj->Get(v8_str("foo"));
416   CHECK(foo_before->IsUndefined());
417   Local<String> bar_str = v8_str("bar");
418   obj->Set(v8_str("foo"), bar_str);
419   Local<Value> foo_after = obj->Get(v8_str("foo"));
420   CHECK(!foo_after->IsUndefined());
421   CHECK(foo_after->IsString());
422   CHECK_EQ(bar_str, foo_after);
423 }
424
425
426 THREADED_TEST(AccessElement) {
427   LocalContext env;
428   v8::HandleScope scope(env->GetIsolate());
429   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
430   Local<Value> before = obj->Get(1);
431   CHECK(before->IsUndefined());
432   Local<String> bar_str = v8_str("bar");
433   obj->Set(1, bar_str);
434   Local<Value> after = obj->Get(1);
435   CHECK(!after->IsUndefined());
436   CHECK(after->IsString());
437   CHECK_EQ(bar_str, after);
438
439   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
440   CHECK_EQ(v8_str("a"), value->Get(0));
441   CHECK_EQ(v8_str("b"), value->Get(1));
442 }
443
444
445 THREADED_TEST(Script) {
446   LocalContext env;
447   v8::HandleScope scope(env->GetIsolate());
448   const char* c_source = "1 + 2 + 3";
449   Local<String> source = String::NewFromUtf8(env->GetIsolate(), c_source);
450   Local<Script> script = Script::Compile(source);
451   CHECK_EQ(6, script->Run()->Int32Value());
452 }
453
454
455 static uint16_t* AsciiToTwoByteString(const char* source) {
456   int array_length = i::StrLength(source) + 1;
457   uint16_t* converted = i::NewArray<uint16_t>(array_length);
458   for (int i = 0; i < array_length; i++) converted[i] = source[i];
459   return converted;
460 }
461
462
463 class TestResource: public String::ExternalStringResource {
464  public:
465   TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
466       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
467     while (data[length_]) ++length_;
468   }
469
470   ~TestResource() {
471     if (owning_data_) i::DeleteArray(data_);
472     if (counter_ != NULL) ++*counter_;
473   }
474
475   const uint16_t* data() const {
476     return data_;
477   }
478
479   size_t length() const {
480     return length_;
481   }
482
483  private:
484   uint16_t* data_;
485   size_t length_;
486   int* counter_;
487   bool owning_data_;
488 };
489
490
491 class TestAsciiResource: public String::ExternalAsciiStringResource {
492  public:
493   TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
494       : orig_data_(data),
495         data_(data + offset),
496         length_(strlen(data) - offset),
497         counter_(counter) { }
498
499   ~TestAsciiResource() {
500     i::DeleteArray(orig_data_);
501     if (counter_ != NULL) ++*counter_;
502   }
503
504   const char* data() const {
505     return data_;
506   }
507
508   size_t length() const {
509     return length_;
510   }
511
512  private:
513   const char* orig_data_;
514   const char* data_;
515   size_t length_;
516   int* counter_;
517 };
518
519
520 THREADED_TEST(ScriptUsingStringResource) {
521   int dispose_count = 0;
522   const char* c_source = "1 + 2 * 3";
523   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
524   {
525     LocalContext env;
526     v8::HandleScope scope(env->GetIsolate());
527     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
528     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
529     Local<Script> script = Script::Compile(source);
530     Local<Value> value = script->Run();
531     CHECK(value->IsNumber());
532     CHECK_EQ(7, value->Int32Value());
533     CHECK(source->IsExternal());
534     CHECK_EQ(resource,
535              static_cast<TestResource*>(source->GetExternalStringResource()));
536     String::Encoding encoding = String::UNKNOWN_ENCODING;
537     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
538              source->GetExternalStringResourceBase(&encoding));
539     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
540     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
541     CHECK_EQ(0, dispose_count);
542   }
543   CcTest::i_isolate()->compilation_cache()->Clear();
544   CcTest::heap()->CollectAllAvailableGarbage();
545   CHECK_EQ(1, dispose_count);
546 }
547
548
549 THREADED_TEST(ScriptUsingAsciiStringResource) {
550   int dispose_count = 0;
551   const char* c_source = "1 + 2 * 3";
552   {
553     LocalContext env;
554     v8::HandleScope scope(env->GetIsolate());
555     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
556                                                         &dispose_count);
557     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
558     CHECK(source->IsExternalAscii());
559     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
560              source->GetExternalAsciiStringResource());
561     String::Encoding encoding = String::UNKNOWN_ENCODING;
562     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
563              source->GetExternalStringResourceBase(&encoding));
564     CHECK_EQ(String::ASCII_ENCODING, encoding);
565     Local<Script> script = Script::Compile(source);
566     Local<Value> value = script->Run();
567     CHECK(value->IsNumber());
568     CHECK_EQ(7, value->Int32Value());
569     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
570     CHECK_EQ(0, dispose_count);
571   }
572   CcTest::i_isolate()->compilation_cache()->Clear();
573   CcTest::heap()->CollectAllAvailableGarbage();
574   CHECK_EQ(1, dispose_count);
575 }
576
577
578 THREADED_TEST(ScriptMakingExternalString) {
579   int dispose_count = 0;
580   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
581   {
582     LocalContext env;
583     v8::HandleScope scope(env->GetIsolate());
584     Local<String> source =
585         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
586     // Trigger GCs so that the newly allocated string moves to old gen.
587     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
588     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
589     CHECK_EQ(source->IsExternal(), false);
590     CHECK_EQ(source->IsExternalAscii(), false);
591     String::Encoding encoding = String::UNKNOWN_ENCODING;
592     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
593     CHECK_EQ(String::ASCII_ENCODING, encoding);
594     bool success = source->MakeExternal(new TestResource(two_byte_source,
595                                                          &dispose_count));
596     CHECK(success);
597     Local<Script> script = Script::Compile(source);
598     Local<Value> value = script->Run();
599     CHECK(value->IsNumber());
600     CHECK_EQ(7, value->Int32Value());
601     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
602     CHECK_EQ(0, dispose_count);
603   }
604   CcTest::i_isolate()->compilation_cache()->Clear();
605   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
606   CHECK_EQ(1, dispose_count);
607 }
608
609
610 THREADED_TEST(ScriptMakingExternalAsciiString) {
611   int dispose_count = 0;
612   const char* c_source = "1 + 2 * 3";
613   {
614     LocalContext env;
615     v8::HandleScope scope(env->GetIsolate());
616     Local<String> source = v8_str(c_source);
617     // Trigger GCs so that the newly allocated string moves to old gen.
618     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
619     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
620     bool success = source->MakeExternal(
621         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
622     CHECK(success);
623     Local<Script> script = Script::Compile(source);
624     Local<Value> value = script->Run();
625     CHECK(value->IsNumber());
626     CHECK_EQ(7, value->Int32Value());
627     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
628     CHECK_EQ(0, dispose_count);
629   }
630   CcTest::i_isolate()->compilation_cache()->Clear();
631   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
632   CHECK_EQ(1, dispose_count);
633 }
634
635
636 TEST(MakingExternalStringConditions) {
637   LocalContext env;
638   v8::HandleScope scope(env->GetIsolate());
639
640   // Free some space in the new space so that we can check freshness.
641   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
643
644   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
645   Local<String> small_string =
646       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
647   i::DeleteArray(two_byte_string);
648
649   // We should refuse to externalize newly created small string.
650   CHECK(!small_string->CanMakeExternal());
651   // Trigger GCs so that the newly allocated string moves to old gen.
652   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
653   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
654   // Old space strings should be accepted.
655   CHECK(small_string->CanMakeExternal());
656
657   two_byte_string = AsciiToTwoByteString("small string 2");
658   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
659   i::DeleteArray(two_byte_string);
660
661   // We should refuse externalizing newly created small string.
662   CHECK(!small_string->CanMakeExternal());
663   for (int i = 0; i < 100; i++) {
664     String::Value value(small_string);
665   }
666   // Frequently used strings should be accepted.
667   CHECK(small_string->CanMakeExternal());
668
669   const int buf_size = 10 * 1024;
670   char* buf = i::NewArray<char>(buf_size);
671   memset(buf, 'a', buf_size);
672   buf[buf_size - 1] = '\0';
673
674   two_byte_string = AsciiToTwoByteString(buf);
675   Local<String> large_string =
676       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
677   i::DeleteArray(buf);
678   i::DeleteArray(two_byte_string);
679   // Large strings should be immediately accepted.
680   CHECK(large_string->CanMakeExternal());
681 }
682
683
684 TEST(MakingExternalAsciiStringConditions) {
685   LocalContext env;
686   v8::HandleScope scope(env->GetIsolate());
687
688   // Free some space in the new space so that we can check freshness.
689   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
690   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
691
692   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
693   // We should refuse to externalize newly created small string.
694   CHECK(!small_string->CanMakeExternal());
695   // Trigger GCs so that the newly allocated string moves to old gen.
696   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
697   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
698   // Old space strings should be accepted.
699   CHECK(small_string->CanMakeExternal());
700
701   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
702   // We should refuse externalizing newly created small string.
703   CHECK(!small_string->CanMakeExternal());
704   for (int i = 0; i < 100; i++) {
705     String::Value value(small_string);
706   }
707   // Frequently used strings should be accepted.
708   CHECK(small_string->CanMakeExternal());
709
710   const int buf_size = 10 * 1024;
711   char* buf = i::NewArray<char>(buf_size);
712   memset(buf, 'a', buf_size);
713   buf[buf_size - 1] = '\0';
714   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
715   i::DeleteArray(buf);
716   // Large strings should be immediately accepted.
717   CHECK(large_string->CanMakeExternal());
718 }
719
720
721 TEST(MakingExternalUnalignedAsciiString) {
722   LocalContext env;
723   v8::HandleScope scope(env->GetIsolate());
724
725   CompileRun("function cons(a, b) { return a + b; }"
726              "function slice(a) { return a.substring(1); }");
727   // Create a cons string that will land in old pointer space.
728   Local<String> cons = Local<String>::Cast(CompileRun(
729       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
730   // Create a sliced string that will land in old pointer space.
731   Local<String> slice = Local<String>::Cast(CompileRun(
732       "slice('abcdefghijklmnopqrstuvwxyz');"));
733
734   // Trigger GCs so that the newly allocated string moves to old gen.
735   SimulateFullSpace(CcTest::heap()->old_pointer_space());
736   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
737   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
738
739   // Turn into external string with unaligned resource data.
740   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
741   bool success = cons->MakeExternal(
742       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
743   CHECK(success);
744   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
745   success = slice->MakeExternal(
746       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
747   CHECK(success);
748
749   // Trigger GCs and force evacuation.
750   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
751   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
752 }
753
754
755 THREADED_TEST(UsingExternalString) {
756   i::Factory* factory = CcTest::i_isolate()->factory();
757   {
758     v8::HandleScope scope(CcTest::isolate());
759     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
760     Local<String> string = String::NewExternal(
761         CcTest::isolate(), new TestResource(two_byte_string));
762     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
763     // Trigger GCs so that the newly allocated string moves to old gen.
764     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
765     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
766     i::Handle<i::String> isymbol =
767         factory->InternalizedStringFromString(istring);
768     CHECK(isymbol->IsInternalizedString());
769   }
770   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
771   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
772 }
773
774
775 THREADED_TEST(UsingExternalAsciiString) {
776   i::Factory* factory = CcTest::i_isolate()->factory();
777   {
778     v8::HandleScope scope(CcTest::isolate());
779     const char* one_byte_string = "test string";
780     Local<String> string = String::NewExternal(
781         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
782     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
783     // Trigger GCs so that the newly allocated string moves to old gen.
784     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
785     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
786     i::Handle<i::String> isymbol =
787         factory->InternalizedStringFromString(istring);
788     CHECK(isymbol->IsInternalizedString());
789   }
790   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
791   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
792 }
793
794
795 THREADED_TEST(ScavengeExternalString) {
796   i::FLAG_stress_compaction = false;
797   i::FLAG_gc_global = false;
798   int dispose_count = 0;
799   bool in_new_space = false;
800   {
801     v8::HandleScope scope(CcTest::isolate());
802     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
803     Local<String> string = String::NewExternal(
804         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
805     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
806     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
807     in_new_space = CcTest::heap()->InNewSpace(*istring);
808     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
809     CHECK_EQ(0, dispose_count);
810   }
811   CcTest::heap()->CollectGarbage(
812       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
813   CHECK_EQ(1, dispose_count);
814 }
815
816
817 THREADED_TEST(ScavengeExternalAsciiString) {
818   i::FLAG_stress_compaction = false;
819   i::FLAG_gc_global = false;
820   int dispose_count = 0;
821   bool in_new_space = false;
822   {
823     v8::HandleScope scope(CcTest::isolate());
824     const char* one_byte_string = "test string";
825     Local<String> string = String::NewExternal(
826         CcTest::isolate(),
827         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
828     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
829     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
830     in_new_space = CcTest::heap()->InNewSpace(*istring);
831     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
832     CHECK_EQ(0, dispose_count);
833   }
834   CcTest::heap()->CollectGarbage(
835       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
836   CHECK_EQ(1, dispose_count);
837 }
838
839
840 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
841  public:
842   // Only used by non-threaded tests, so it can use static fields.
843   static int dispose_calls;
844   static int dispose_count;
845
846   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
847       : TestAsciiResource(data, &dispose_count),
848         dispose_(dispose) { }
849
850   void Dispose() {
851     ++dispose_calls;
852     if (dispose_) delete this;
853   }
854  private:
855   bool dispose_;
856 };
857
858
859 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
860 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
861
862
863 TEST(ExternalStringWithDisposeHandling) {
864   const char* c_source = "1 + 2 * 3";
865
866   // Use a stack allocated external string resource allocated object.
867   TestAsciiResourceWithDisposeControl::dispose_count = 0;
868   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
869   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
870   {
871     LocalContext env;
872     v8::HandleScope scope(env->GetIsolate());
873     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
874     Local<Script> script = Script::Compile(source);
875     Local<Value> value = script->Run();
876     CHECK(value->IsNumber());
877     CHECK_EQ(7, value->Int32Value());
878     CcTest::heap()->CollectAllAvailableGarbage();
879     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
880   }
881   CcTest::i_isolate()->compilation_cache()->Clear();
882   CcTest::heap()->CollectAllAvailableGarbage();
883   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
884   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
885
886   // Use a heap allocated external string resource allocated object.
887   TestAsciiResourceWithDisposeControl::dispose_count = 0;
888   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
889   TestAsciiResource* res_heap =
890       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
891   {
892     LocalContext env;
893     v8::HandleScope scope(env->GetIsolate());
894     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
895     Local<Script> script = Script::Compile(source);
896     Local<Value> value = script->Run();
897     CHECK(value->IsNumber());
898     CHECK_EQ(7, value->Int32Value());
899     CcTest::heap()->CollectAllAvailableGarbage();
900     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
901   }
902   CcTest::i_isolate()->compilation_cache()->Clear();
903   CcTest::heap()->CollectAllAvailableGarbage();
904   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
905   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
906 }
907
908
909 THREADED_TEST(StringConcat) {
910   {
911     LocalContext env;
912     v8::HandleScope scope(env->GetIsolate());
913     const char* one_byte_string_1 = "function a_times_t";
914     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
915     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
916     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
917     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
919     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
920     Local<String> left = v8_str(one_byte_string_1);
921
922     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
923     Local<String> right =
924         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
925     i::DeleteArray(two_byte_source);
926
927     Local<String> source = String::Concat(left, right);
928     right = String::NewExternal(
929         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
930     source = String::Concat(source, right);
931     right = String::NewExternal(
932         env->GetIsolate(),
933         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
934     source = String::Concat(source, right);
935     right = v8_str(one_byte_string_2);
936     source = String::Concat(source, right);
937
938     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
939     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
940     i::DeleteArray(two_byte_source);
941
942     source = String::Concat(source, right);
943     right = String::NewExternal(
944         env->GetIsolate(),
945         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
946     source = String::Concat(source, right);
947     Local<Script> script = Script::Compile(source);
948     Local<Value> value = script->Run();
949     CHECK(value->IsNumber());
950     CHECK_EQ(68, value->Int32Value());
951   }
952   CcTest::i_isolate()->compilation_cache()->Clear();
953   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
954   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
955 }
956
957
958 THREADED_TEST(GlobalProperties) {
959   LocalContext env;
960   v8::HandleScope scope(env->GetIsolate());
961   v8::Handle<v8::Object> global = env->Global();
962   global->Set(v8_str("pi"), v8_num(3.1415926));
963   Local<Value> pi = global->Get(v8_str("pi"));
964   CHECK_EQ(3.1415926, pi->NumberValue());
965 }
966
967
968 template<typename T>
969 static void CheckReturnValue(const T& t, i::Address callback) {
970   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
971   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
972   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
973   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
974   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
975   // Verify reset
976   bool is_runtime = (*o)->IsTheHole();
977   rv.Set(true);
978   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
979   rv.Set(v8::Handle<v8::Object>());
980   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
981   CHECK_EQ(is_runtime, (*o)->IsTheHole());
982
983   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
984   // If CPU profiler is active check that when API callback is invoked
985   // VMState is set to EXTERNAL.
986   if (isolate->cpu_profiler()->is_profiling()) {
987     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
988     CHECK(isolate->external_callback_scope());
989     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
990   }
991 }
992
993
994 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
995                                  i::Address callback) {
996   ApiTestFuzzer::Fuzz();
997   CheckReturnValue(info, callback);
998   info.GetReturnValue().Set(v8_str("bad value"));
999   info.GetReturnValue().Set(v8_num(102));
1000 }
1001
1002
1003 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1004   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1005 }
1006
1007
1008 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1009   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1010 }
1011
1012 static void construct_callback(
1013     const v8::FunctionCallbackInfo<Value>& info) {
1014   ApiTestFuzzer::Fuzz();
1015   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1016   info.This()->Set(v8_str("x"), v8_num(1));
1017   info.This()->Set(v8_str("y"), v8_num(2));
1018   info.GetReturnValue().Set(v8_str("bad value"));
1019   info.GetReturnValue().Set(info.This());
1020 }
1021
1022
1023 static void Return239Callback(
1024     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1025   ApiTestFuzzer::Fuzz();
1026   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1027   info.GetReturnValue().Set(v8_str("bad value"));
1028   info.GetReturnValue().Set(v8_num(239));
1029 }
1030
1031
1032 template<typename Handler>
1033 static void TestFunctionTemplateInitializer(Handler handler,
1034                                             Handler handler_2) {
1035   // Test constructor calls.
1036   {
1037     LocalContext env;
1038     v8::Isolate* isolate = env->GetIsolate();
1039     v8::HandleScope scope(isolate);
1040
1041     Local<v8::FunctionTemplate> fun_templ =
1042         v8::FunctionTemplate::New(isolate, handler);
1043     Local<Function> fun = fun_templ->GetFunction();
1044     env->Global()->Set(v8_str("obj"), fun);
1045     Local<Script> script = v8_compile("obj()");
1046     for (int i = 0; i < 30; i++) {
1047       CHECK_EQ(102, script->Run()->Int32Value());
1048     }
1049   }
1050   // Use SetCallHandler to initialize a function template, should work like
1051   // the previous one.
1052   {
1053     LocalContext env;
1054     v8::Isolate* isolate = env->GetIsolate();
1055     v8::HandleScope scope(isolate);
1056
1057     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1058     fun_templ->SetCallHandler(handler_2);
1059     Local<Function> fun = fun_templ->GetFunction();
1060     env->Global()->Set(v8_str("obj"), fun);
1061     Local<Script> script = v8_compile("obj()");
1062     for (int i = 0; i < 30; i++) {
1063       CHECK_EQ(102, script->Run()->Int32Value());
1064     }
1065   }
1066 }
1067
1068
1069 template<typename Constructor, typename Accessor>
1070 static void TestFunctionTemplateAccessor(Constructor constructor,
1071                                          Accessor accessor) {
1072   LocalContext env;
1073   v8::HandleScope scope(env->GetIsolate());
1074
1075   Local<v8::FunctionTemplate> fun_templ =
1076       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1077   fun_templ->SetClassName(v8_str("funky"));
1078   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1079   Local<Function> fun = fun_templ->GetFunction();
1080   env->Global()->Set(v8_str("obj"), fun);
1081   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1082   CHECK_EQ(v8_str("[object funky]"), result);
1083   CompileRun("var obj_instance = new obj();");
1084   Local<Script> script;
1085   script = v8_compile("obj_instance.x");
1086   for (int i = 0; i < 30; i++) {
1087     CHECK_EQ(1, script->Run()->Int32Value());
1088   }
1089   script = v8_compile("obj_instance.m");
1090   for (int i = 0; i < 30; i++) {
1091     CHECK_EQ(239, script->Run()->Int32Value());
1092   }
1093 }
1094
1095
1096 THREADED_PROFILED_TEST(FunctionTemplate) {
1097   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1098   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1099 }
1100
1101
1102 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1103   ApiTestFuzzer::Fuzz();
1104   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1105   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1106 }
1107
1108
1109 template<typename Callback>
1110 static void TestSimpleCallback(Callback callback) {
1111   LocalContext env;
1112   v8::Isolate* isolate = env->GetIsolate();
1113   v8::HandleScope scope(isolate);
1114
1115   v8::Handle<v8::ObjectTemplate> object_template =
1116       v8::ObjectTemplate::New(isolate);
1117   object_template->Set(isolate, "callback",
1118                        v8::FunctionTemplate::New(isolate, callback));
1119   v8::Local<v8::Object> object = object_template->NewInstance();
1120   (*env)->Global()->Set(v8_str("callback_object"), object);
1121   v8::Handle<v8::Script> script;
1122   script = v8_compile("callback_object.callback(17)");
1123   for (int i = 0; i < 30; i++) {
1124     CHECK_EQ(51424, script->Run()->Int32Value());
1125   }
1126   script = v8_compile("callback_object.callback(17, 24)");
1127   for (int i = 0; i < 30; i++) {
1128     CHECK_EQ(51425, script->Run()->Int32Value());
1129   }
1130 }
1131
1132
1133 THREADED_PROFILED_TEST(SimpleCallback) {
1134   TestSimpleCallback(SimpleCallback);
1135 }
1136
1137
1138 template<typename T>
1139 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1140
1141 // constant return values
1142 static int32_t fast_return_value_int32 = 471;
1143 static uint32_t fast_return_value_uint32 = 571;
1144 static const double kFastReturnValueDouble = 2.7;
1145 // variable return values
1146 static bool fast_return_value_bool = false;
1147 enum ReturnValueOddball {
1148   kNullReturnValue,
1149   kUndefinedReturnValue,
1150   kEmptyStringReturnValue
1151 };
1152 static ReturnValueOddball fast_return_value_void;
1153 static bool fast_return_value_object_is_empty = false;
1154
1155 // Helper function to avoid compiler error: insufficient contextual information
1156 // to determine type when applying FUNCTION_ADDR to a template function.
1157 static i::Address address_of(v8::FunctionCallback callback) {
1158   return FUNCTION_ADDR(callback);
1159 }
1160
1161 template<>
1162 void FastReturnValueCallback<int32_t>(
1163     const v8::FunctionCallbackInfo<v8::Value>& info) {
1164   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1165   info.GetReturnValue().Set(fast_return_value_int32);
1166 }
1167
1168 template<>
1169 void FastReturnValueCallback<uint32_t>(
1170     const v8::FunctionCallbackInfo<v8::Value>& info) {
1171   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1172   info.GetReturnValue().Set(fast_return_value_uint32);
1173 }
1174
1175 template<>
1176 void FastReturnValueCallback<double>(
1177     const v8::FunctionCallbackInfo<v8::Value>& info) {
1178   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1179   info.GetReturnValue().Set(kFastReturnValueDouble);
1180 }
1181
1182 template<>
1183 void FastReturnValueCallback<bool>(
1184     const v8::FunctionCallbackInfo<v8::Value>& info) {
1185   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1186   info.GetReturnValue().Set(fast_return_value_bool);
1187 }
1188
1189 template<>
1190 void FastReturnValueCallback<void>(
1191     const v8::FunctionCallbackInfo<v8::Value>& info) {
1192   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1193   switch (fast_return_value_void) {
1194     case kNullReturnValue:
1195       info.GetReturnValue().SetNull();
1196       break;
1197     case kUndefinedReturnValue:
1198       info.GetReturnValue().SetUndefined();
1199       break;
1200     case kEmptyStringReturnValue:
1201       info.GetReturnValue().SetEmptyString();
1202       break;
1203   }
1204 }
1205
1206 template<>
1207 void FastReturnValueCallback<Object>(
1208     const v8::FunctionCallbackInfo<v8::Value>& info) {
1209   v8::Handle<v8::Object> object;
1210   if (!fast_return_value_object_is_empty) {
1211     object = Object::New(info.GetIsolate());
1212   }
1213   info.GetReturnValue().Set(object);
1214 }
1215
1216 template<typename T>
1217 Handle<Value> TestFastReturnValues() {
1218   LocalContext env;
1219   v8::Isolate* isolate = env->GetIsolate();
1220   v8::EscapableHandleScope scope(isolate);
1221   v8::Handle<v8::ObjectTemplate> object_template =
1222       v8::ObjectTemplate::New(isolate);
1223   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1224   object_template->Set(isolate, "callback",
1225                        v8::FunctionTemplate::New(isolate, callback));
1226   v8::Local<v8::Object> object = object_template->NewInstance();
1227   (*env)->Global()->Set(v8_str("callback_object"), object);
1228   return scope.Escape(CompileRun("callback_object.callback()"));
1229 }
1230
1231
1232 THREADED_PROFILED_TEST(FastReturnValues) {
1233   LocalContext env;
1234   v8::HandleScope scope(CcTest::isolate());
1235   v8::Handle<v8::Value> value;
1236   // check int32_t and uint32_t
1237   int32_t int_values[] = {
1238       0, 234, -723,
1239       i::Smi::kMinValue, i::Smi::kMaxValue
1240   };
1241   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1242     for (int modifier = -1; modifier <= 1; modifier++) {
1243       int int_value = int_values[i] + modifier;
1244       // check int32_t
1245       fast_return_value_int32 = int_value;
1246       value = TestFastReturnValues<int32_t>();
1247       CHECK(value->IsInt32());
1248       CHECK(fast_return_value_int32 == value->Int32Value());
1249       // check uint32_t
1250       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1251       value = TestFastReturnValues<uint32_t>();
1252       CHECK(value->IsUint32());
1253       CHECK(fast_return_value_uint32 == value->Uint32Value());
1254     }
1255   }
1256   // check double
1257   value = TestFastReturnValues<double>();
1258   CHECK(value->IsNumber());
1259   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1260   // check bool values
1261   for (int i = 0; i < 2; i++) {
1262     fast_return_value_bool = i == 0;
1263     value = TestFastReturnValues<bool>();
1264     CHECK(value->IsBoolean());
1265     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1266   }
1267   // check oddballs
1268   ReturnValueOddball oddballs[] = {
1269       kNullReturnValue,
1270       kUndefinedReturnValue,
1271       kEmptyStringReturnValue
1272   };
1273   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1274     fast_return_value_void = oddballs[i];
1275     value = TestFastReturnValues<void>();
1276     switch (fast_return_value_void) {
1277       case kNullReturnValue:
1278         CHECK(value->IsNull());
1279         break;
1280       case kUndefinedReturnValue:
1281         CHECK(value->IsUndefined());
1282         break;
1283       case kEmptyStringReturnValue:
1284         CHECK(value->IsString());
1285         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1286         break;
1287     }
1288   }
1289   // check handles
1290   fast_return_value_object_is_empty = false;
1291   value = TestFastReturnValues<Object>();
1292   CHECK(value->IsObject());
1293   fast_return_value_object_is_empty = true;
1294   value = TestFastReturnValues<Object>();
1295   CHECK(value->IsUndefined());
1296 }
1297
1298
1299 THREADED_TEST(FunctionTemplateSetLength) {
1300   LocalContext env;
1301   v8::Isolate* isolate = env->GetIsolate();
1302   v8::HandleScope scope(isolate);
1303   {
1304     Local<v8::FunctionTemplate> fun_templ =
1305         v8::FunctionTemplate::New(isolate,
1306                                   handle_callback,
1307                                   Handle<v8::Value>(),
1308                                   Handle<v8::Signature>(),
1309                                   23);
1310     Local<Function> fun = fun_templ->GetFunction();
1311     env->Global()->Set(v8_str("obj"), fun);
1312     Local<Script> script = v8_compile("obj.length");
1313     CHECK_EQ(23, script->Run()->Int32Value());
1314   }
1315   {
1316     Local<v8::FunctionTemplate> fun_templ =
1317         v8::FunctionTemplate::New(isolate, handle_callback);
1318     fun_templ->SetLength(22);
1319     Local<Function> fun = fun_templ->GetFunction();
1320     env->Global()->Set(v8_str("obj"), fun);
1321     Local<Script> script = v8_compile("obj.length");
1322     CHECK_EQ(22, script->Run()->Int32Value());
1323   }
1324   {
1325     // Without setting length it defaults to 0.
1326     Local<v8::FunctionTemplate> fun_templ =
1327         v8::FunctionTemplate::New(isolate, handle_callback);
1328     Local<Function> fun = fun_templ->GetFunction();
1329     env->Global()->Set(v8_str("obj"), fun);
1330     Local<Script> script = v8_compile("obj.length");
1331     CHECK_EQ(0, script->Run()->Int32Value());
1332   }
1333 }
1334
1335
1336 static void* expected_ptr;
1337 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1338   void* ptr = v8::External::Cast(*args.Data())->Value();
1339   CHECK_EQ(expected_ptr, ptr);
1340   args.GetReturnValue().Set(true);
1341 }
1342
1343
1344 static void TestExternalPointerWrapping() {
1345   LocalContext env;
1346   v8::Isolate* isolate = env->GetIsolate();
1347   v8::HandleScope scope(isolate);
1348
1349   v8::Handle<v8::Value> data =
1350       v8::External::New(isolate, expected_ptr);
1351
1352   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1353   obj->Set(v8_str("func"),
1354            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1355   env->Global()->Set(v8_str("obj"), obj);
1356
1357   CHECK(CompileRun(
1358         "function foo() {\n"
1359         "  for (var i = 0; i < 13; i++) obj.func();\n"
1360         "}\n"
1361         "foo(), true")->BooleanValue());
1362 }
1363
1364
1365 THREADED_TEST(ExternalWrap) {
1366   // Check heap allocated object.
1367   int* ptr = new int;
1368   expected_ptr = ptr;
1369   TestExternalPointerWrapping();
1370   delete ptr;
1371
1372   // Check stack allocated object.
1373   int foo;
1374   expected_ptr = &foo;
1375   TestExternalPointerWrapping();
1376
1377   // Check not aligned addresses.
1378   const int n = 100;
1379   char* s = new char[n];
1380   for (int i = 0; i < n; i++) {
1381     expected_ptr = s + i;
1382     TestExternalPointerWrapping();
1383   }
1384
1385   delete[] s;
1386
1387   // Check several invalid addresses.
1388   expected_ptr = reinterpret_cast<void*>(1);
1389   TestExternalPointerWrapping();
1390
1391   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1392   TestExternalPointerWrapping();
1393
1394   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1395   TestExternalPointerWrapping();
1396
1397 #if defined(V8_HOST_ARCH_X64)
1398   // Check a value with a leading 1 bit in x64 Smi encoding.
1399   expected_ptr = reinterpret_cast<void*>(0x400000000);
1400   TestExternalPointerWrapping();
1401
1402   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1403   TestExternalPointerWrapping();
1404
1405   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1406   TestExternalPointerWrapping();
1407 #endif
1408 }
1409
1410
1411 THREADED_TEST(FindInstanceInPrototypeChain) {
1412   LocalContext env;
1413   v8::Isolate* isolate = env->GetIsolate();
1414   v8::HandleScope scope(isolate);
1415
1416   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1417   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1418   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1419   derived->Inherit(base);
1420
1421   Local<v8::Function> base_function = base->GetFunction();
1422   Local<v8::Function> derived_function = derived->GetFunction();
1423   Local<v8::Function> other_function = other->GetFunction();
1424
1425   Local<v8::Object> base_instance = base_function->NewInstance();
1426   Local<v8::Object> derived_instance = derived_function->NewInstance();
1427   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1428   Local<v8::Object> other_instance = other_function->NewInstance();
1429   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1430   other_instance->Set(v8_str("__proto__"), derived_instance2);
1431
1432   // base_instance is only an instance of base.
1433   CHECK_EQ(base_instance,
1434            base_instance->FindInstanceInPrototypeChain(base));
1435   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1436   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1437
1438   // derived_instance is an instance of base and derived.
1439   CHECK_EQ(derived_instance,
1440            derived_instance->FindInstanceInPrototypeChain(base));
1441   CHECK_EQ(derived_instance,
1442            derived_instance->FindInstanceInPrototypeChain(derived));
1443   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1444
1445   // other_instance is an instance of other and its immediate
1446   // prototype derived_instance2 is an instance of base and derived.
1447   // Note, derived_instance is an instance of base and derived too,
1448   // but it comes after derived_instance2 in the prototype chain of
1449   // other_instance.
1450   CHECK_EQ(derived_instance2,
1451            other_instance->FindInstanceInPrototypeChain(base));
1452   CHECK_EQ(derived_instance2,
1453            other_instance->FindInstanceInPrototypeChain(derived));
1454   CHECK_EQ(other_instance,
1455            other_instance->FindInstanceInPrototypeChain(other));
1456 }
1457
1458
1459 THREADED_TEST(TinyInteger) {
1460   LocalContext env;
1461   v8::Isolate* isolate = env->GetIsolate();
1462   v8::HandleScope scope(isolate);
1463
1464   int32_t value = 239;
1465   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1466   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1467
1468   value_obj = v8::Integer::New(isolate, value);
1469   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1470 }
1471
1472
1473 THREADED_TEST(BigSmiInteger) {
1474   LocalContext env;
1475   v8::HandleScope scope(env->GetIsolate());
1476   v8::Isolate* isolate = CcTest::isolate();
1477
1478   int32_t value = i::Smi::kMaxValue;
1479   // We cannot add one to a Smi::kMaxValue without wrapping.
1480   if (i::SmiValuesAre31Bits()) {
1481     CHECK(i::Smi::IsValid(value));
1482     CHECK(!i::Smi::IsValid(value + 1));
1483
1484     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1485     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1486
1487     value_obj = v8::Integer::New(isolate, value);
1488     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1489   }
1490 }
1491
1492
1493 THREADED_TEST(BigInteger) {
1494   LocalContext env;
1495   v8::HandleScope scope(env->GetIsolate());
1496   v8::Isolate* isolate = CcTest::isolate();
1497
1498   // We cannot add one to a Smi::kMaxValue without wrapping.
1499   if (i::SmiValuesAre31Bits()) {
1500     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1501     // The code will not be run in that case, due to the "if" guard.
1502     int32_t value =
1503         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1504     CHECK(value > i::Smi::kMaxValue);
1505     CHECK(!i::Smi::IsValid(value));
1506
1507     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1508     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1509
1510     value_obj = v8::Integer::New(isolate, value);
1511     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1512   }
1513 }
1514
1515
1516 THREADED_TEST(TinyUnsignedInteger) {
1517   LocalContext env;
1518   v8::HandleScope scope(env->GetIsolate());
1519   v8::Isolate* isolate = CcTest::isolate();
1520
1521   uint32_t value = 239;
1522
1523   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1525
1526   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1527   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1528 }
1529
1530
1531 THREADED_TEST(BigUnsignedSmiInteger) {
1532   LocalContext env;
1533   v8::HandleScope scope(env->GetIsolate());
1534   v8::Isolate* isolate = CcTest::isolate();
1535
1536   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1537   CHECK(i::Smi::IsValid(value));
1538   CHECK(!i::Smi::IsValid(value + 1));
1539
1540   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1541   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1542
1543   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1544   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1545 }
1546
1547
1548 THREADED_TEST(BigUnsignedInteger) {
1549   LocalContext env;
1550   v8::HandleScope scope(env->GetIsolate());
1551   v8::Isolate* isolate = CcTest::isolate();
1552
1553   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1554   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1555   CHECK(!i::Smi::IsValid(value));
1556
1557   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1558   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1559
1560   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1561   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1562 }
1563
1564
1565 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1566   LocalContext env;
1567   v8::HandleScope scope(env->GetIsolate());
1568   v8::Isolate* isolate = CcTest::isolate();
1569
1570   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1571   uint32_t value = INT32_MAX_AS_UINT + 1;
1572   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1573
1574   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1575   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1576
1577   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1578   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1579 }
1580
1581
1582 THREADED_TEST(IsNativeError) {
1583   LocalContext env;
1584   v8::HandleScope scope(env->GetIsolate());
1585   v8::Handle<Value> syntax_error = CompileRun(
1586       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1587   CHECK(syntax_error->IsNativeError());
1588   v8::Handle<Value> not_error = CompileRun("{a:42}");
1589   CHECK(!not_error->IsNativeError());
1590   v8::Handle<Value> not_object = CompileRun("42");
1591   CHECK(!not_object->IsNativeError());
1592 }
1593
1594
1595 THREADED_TEST(StringObject) {
1596   LocalContext env;
1597   v8::HandleScope scope(env->GetIsolate());
1598   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1599   CHECK(boxed_string->IsStringObject());
1600   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1601   CHECK(!unboxed_string->IsStringObject());
1602   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1603   CHECK(!boxed_not_string->IsStringObject());
1604   v8::Handle<Value> not_object = CompileRun("0");
1605   CHECK(!not_object->IsStringObject());
1606   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1607   CHECK(!as_boxed.IsEmpty());
1608   Local<v8::String> the_string = as_boxed->ValueOf();
1609   CHECK(!the_string.IsEmpty());
1610   ExpectObject("\"test\"", the_string);
1611   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1612   CHECK(new_boxed_string->IsStringObject());
1613   as_boxed = new_boxed_string.As<v8::StringObject>();
1614   the_string = as_boxed->ValueOf();
1615   CHECK(!the_string.IsEmpty());
1616   ExpectObject("\"test\"", the_string);
1617 }
1618
1619
1620 THREADED_TEST(NumberObject) {
1621   LocalContext env;
1622   v8::HandleScope scope(env->GetIsolate());
1623   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1624   CHECK(boxed_number->IsNumberObject());
1625   v8::Handle<Value> unboxed_number = CompileRun("42");
1626   CHECK(!unboxed_number->IsNumberObject());
1627   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1628   CHECK(!boxed_not_number->IsNumberObject());
1629   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1630   CHECK(!as_boxed.IsEmpty());
1631   double the_number = as_boxed->ValueOf();
1632   CHECK_EQ(42.0, the_number);
1633   v8::Handle<v8::Value> new_boxed_number =
1634       v8::NumberObject::New(env->GetIsolate(), 43);
1635   CHECK(new_boxed_number->IsNumberObject());
1636   as_boxed = new_boxed_number.As<v8::NumberObject>();
1637   the_number = as_boxed->ValueOf();
1638   CHECK_EQ(43.0, the_number);
1639 }
1640
1641
1642 THREADED_TEST(BooleanObject) {
1643   LocalContext env;
1644   v8::HandleScope scope(env->GetIsolate());
1645   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1646   CHECK(boxed_boolean->IsBooleanObject());
1647   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1648   CHECK(!unboxed_boolean->IsBooleanObject());
1649   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1650   CHECK(!boxed_not_boolean->IsBooleanObject());
1651   v8::Handle<v8::BooleanObject> as_boxed =
1652       boxed_boolean.As<v8::BooleanObject>();
1653   CHECK(!as_boxed.IsEmpty());
1654   bool the_boolean = as_boxed->ValueOf();
1655   CHECK_EQ(true, the_boolean);
1656   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1657   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1658   CHECK(boxed_true->IsBooleanObject());
1659   CHECK(boxed_false->IsBooleanObject());
1660   as_boxed = boxed_true.As<v8::BooleanObject>();
1661   CHECK_EQ(true, as_boxed->ValueOf());
1662   as_boxed = boxed_false.As<v8::BooleanObject>();
1663   CHECK_EQ(false, as_boxed->ValueOf());
1664 }
1665
1666
1667 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1668   LocalContext env;
1669   v8::HandleScope scope(env->GetIsolate());
1670
1671   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1672   CHECK(primitive_false->IsBoolean());
1673   CHECK(!primitive_false->IsBooleanObject());
1674   CHECK(!primitive_false->BooleanValue());
1675   CHECK(!primitive_false->IsTrue());
1676   CHECK(primitive_false->IsFalse());
1677
1678   Local<Value> false_value = BooleanObject::New(false);
1679   CHECK(!false_value->IsBoolean());
1680   CHECK(false_value->IsBooleanObject());
1681   CHECK(false_value->BooleanValue());
1682   CHECK(!false_value->IsTrue());
1683   CHECK(!false_value->IsFalse());
1684
1685   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1686   CHECK(!false_boolean_object->IsBoolean());
1687   CHECK(false_boolean_object->IsBooleanObject());
1688   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1689   // CHECK(false_boolean_object->BooleanValue());
1690   CHECK(!false_boolean_object->ValueOf());
1691   CHECK(!false_boolean_object->IsTrue());
1692   CHECK(!false_boolean_object->IsFalse());
1693
1694   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1695   CHECK(primitive_true->IsBoolean());
1696   CHECK(!primitive_true->IsBooleanObject());
1697   CHECK(primitive_true->BooleanValue());
1698   CHECK(primitive_true->IsTrue());
1699   CHECK(!primitive_true->IsFalse());
1700
1701   Local<Value> true_value = BooleanObject::New(true);
1702   CHECK(!true_value->IsBoolean());
1703   CHECK(true_value->IsBooleanObject());
1704   CHECK(true_value->BooleanValue());
1705   CHECK(!true_value->IsTrue());
1706   CHECK(!true_value->IsFalse());
1707
1708   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1709   CHECK(!true_boolean_object->IsBoolean());
1710   CHECK(true_boolean_object->IsBooleanObject());
1711   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1712   // CHECK(true_boolean_object->BooleanValue());
1713   CHECK(true_boolean_object->ValueOf());
1714   CHECK(!true_boolean_object->IsTrue());
1715   CHECK(!true_boolean_object->IsFalse());
1716 }
1717
1718
1719 THREADED_TEST(Number) {
1720   LocalContext env;
1721   v8::HandleScope scope(env->GetIsolate());
1722   double PI = 3.1415926;
1723   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1724   CHECK_EQ(PI, pi_obj->NumberValue());
1725 }
1726
1727
1728 THREADED_TEST(ToNumber) {
1729   LocalContext env;
1730   v8::Isolate* isolate = CcTest::isolate();
1731   v8::HandleScope scope(isolate);
1732   Local<String> str = v8_str("3.1415926");
1733   CHECK_EQ(3.1415926, str->NumberValue());
1734   v8::Handle<v8::Boolean> t = v8::True(isolate);
1735   CHECK_EQ(1.0, t->NumberValue());
1736   v8::Handle<v8::Boolean> f = v8::False(isolate);
1737   CHECK_EQ(0.0, f->NumberValue());
1738 }
1739
1740
1741 THREADED_TEST(Date) {
1742   LocalContext env;
1743   v8::HandleScope scope(env->GetIsolate());
1744   double PI = 3.1415926;
1745   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1746   CHECK_EQ(3.0, date->NumberValue());
1747   date.As<v8::Date>()->Set(v8_str("property"),
1748                            v8::Integer::New(env->GetIsolate(), 42));
1749   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1750 }
1751
1752
1753 THREADED_TEST(Boolean) {
1754   LocalContext env;
1755   v8::Isolate* isolate = env->GetIsolate();
1756   v8::HandleScope scope(isolate);
1757   v8::Handle<v8::Boolean> t = v8::True(isolate);
1758   CHECK(t->Value());
1759   v8::Handle<v8::Boolean> f = v8::False(isolate);
1760   CHECK(!f->Value());
1761   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1762   CHECK(!u->BooleanValue());
1763   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1764   CHECK(!n->BooleanValue());
1765   v8::Handle<String> str1 = v8_str("");
1766   CHECK(!str1->BooleanValue());
1767   v8::Handle<String> str2 = v8_str("x");
1768   CHECK(str2->BooleanValue());
1769   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1770   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1771   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1772   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1773   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1774 }
1775
1776
1777 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1778   ApiTestFuzzer::Fuzz();
1779   args.GetReturnValue().Set(v8_num(13.4));
1780 }
1781
1782
1783 static void GetM(Local<String> name,
1784                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1785   ApiTestFuzzer::Fuzz();
1786   info.GetReturnValue().Set(v8_num(876));
1787 }
1788
1789
1790 THREADED_TEST(GlobalPrototype) {
1791   v8::Isolate* isolate = CcTest::isolate();
1792   v8::HandleScope scope(isolate);
1793   v8::Handle<v8::FunctionTemplate> func_templ =
1794       v8::FunctionTemplate::New(isolate);
1795   func_templ->PrototypeTemplate()->Set(
1796       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1797   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1798   templ->Set(isolate, "x", v8_num(200));
1799   templ->SetAccessor(v8_str("m"), GetM);
1800   LocalContext env(0, templ);
1801   v8::Handle<Script> script(v8_compile("dummy()"));
1802   v8::Handle<Value> result(script->Run());
1803   CHECK_EQ(13.4, result->NumberValue());
1804   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1805   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1806 }
1807
1808
1809 THREADED_TEST(ObjectTemplate) {
1810   v8::Isolate* isolate = CcTest::isolate();
1811   v8::HandleScope scope(isolate);
1812   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1813   templ1->Set(isolate, "x", v8_num(10));
1814   templ1->Set(isolate, "y", v8_num(13));
1815   LocalContext env;
1816   Local<v8::Object> instance1 = templ1->NewInstance();
1817   env->Global()->Set(v8_str("p"), instance1);
1818   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1819   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1820   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1821   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1822   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1823   templ2->Set(isolate, "a", v8_num(12));
1824   templ2->Set(isolate, "b", templ1);
1825   Local<v8::Object> instance2 = templ2->NewInstance();
1826   env->Global()->Set(v8_str("q"), instance2);
1827   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1828   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1829   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1830   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1831 }
1832
1833
1834 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1835   ApiTestFuzzer::Fuzz();
1836   args.GetReturnValue().Set(v8_num(17.2));
1837 }
1838
1839
1840 static void GetKnurd(Local<String> property,
1841                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1842   ApiTestFuzzer::Fuzz();
1843   info.GetReturnValue().Set(v8_num(15.2));
1844 }
1845
1846
1847 THREADED_TEST(DescriptorInheritance) {
1848   v8::Isolate* isolate = CcTest::isolate();
1849   v8::HandleScope scope(isolate);
1850   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1851   super->PrototypeTemplate()->Set(isolate, "flabby",
1852                                   v8::FunctionTemplate::New(isolate,
1853                                                             GetFlabby));
1854   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1855
1856   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1857
1858   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1859   base1->Inherit(super);
1860   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1861
1862   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1863   base2->Inherit(super);
1864   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1865
1866   LocalContext env;
1867
1868   env->Global()->Set(v8_str("s"), super->GetFunction());
1869   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1870   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1871
1872   // Checks right __proto__ chain.
1873   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1874   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1875
1876   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1877
1878   // Instance accessor should not be visible on function object or its prototype
1879   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1880   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1881   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1882
1883   env->Global()->Set(v8_str("obj"),
1884                      base1->GetFunction()->NewInstance());
1885   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1886   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1887   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1888   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1889   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1890
1891   env->Global()->Set(v8_str("obj2"),
1892                      base2->GetFunction()->NewInstance());
1893   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1894   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1895   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1896   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1897   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1898
1899   // base1 and base2 cannot cross reference to each's prototype
1900   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1901   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1902 }
1903
1904
1905 int echo_named_call_count;
1906
1907
1908 static void EchoNamedProperty(Local<String> name,
1909                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1910   ApiTestFuzzer::Fuzz();
1911   CHECK_EQ(v8_str("data"), info.Data());
1912   echo_named_call_count++;
1913   info.GetReturnValue().Set(name);
1914 }
1915
1916
1917 // Helper functions for Interceptor/Accessor interaction tests
1918
1919 void SimpleAccessorGetter(Local<String> name,
1920                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1921   Handle<Object> self = info.This();
1922   info.GetReturnValue().Set(
1923       self->Get(String::Concat(v8_str("accessor_"), name)));
1924 }
1925
1926 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1927                           const v8::PropertyCallbackInfo<void>& info) {
1928   Handle<Object> self = info.This();
1929   self->Set(String::Concat(v8_str("accessor_"), name), value);
1930 }
1931
1932 void EmptyInterceptorGetter(Local<String> name,
1933                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1934 }
1935
1936 void EmptyInterceptorSetter(Local<String> name,
1937                             Local<Value> value,
1938                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1939 }
1940
1941 void InterceptorGetter(Local<String> name,
1942                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1943   // Intercept names that start with 'interceptor_'.
1944   String::Utf8Value utf8(name);
1945   char* name_str = *utf8;
1946   char prefix[] = "interceptor_";
1947   int i;
1948   for (i = 0; name_str[i] && prefix[i]; ++i) {
1949     if (name_str[i] != prefix[i]) return;
1950   }
1951   Handle<Object> self = info.This();
1952   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1953 }
1954
1955 void InterceptorSetter(Local<String> name,
1956                        Local<Value> value,
1957                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1958   // Intercept accesses that set certain integer values, for which the name does
1959   // not start with 'accessor_'.
1960   String::Utf8Value utf8(name);
1961   char* name_str = *utf8;
1962   char prefix[] = "accessor_";
1963   int i;
1964   for (i = 0; name_str[i] && prefix[i]; ++i) {
1965     if (name_str[i] != prefix[i]) break;
1966   }
1967   if (!prefix[i]) return;
1968
1969   if (value->IsInt32() && value->Int32Value() < 10000) {
1970     Handle<Object> self = info.This();
1971     self->SetHiddenValue(name, value);
1972     info.GetReturnValue().Set(value);
1973   }
1974 }
1975
1976 void AddAccessor(Handle<FunctionTemplate> templ,
1977                  Handle<String> name,
1978                  v8::AccessorGetterCallback getter,
1979                  v8::AccessorSetterCallback setter) {
1980   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1981 }
1982
1983 void AddInterceptor(Handle<FunctionTemplate> templ,
1984                     v8::NamedPropertyGetterCallback getter,
1985                     v8::NamedPropertySetterCallback setter) {
1986   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1987 }
1988
1989
1990 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1991   v8::HandleScope scope(CcTest::isolate());
1992   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1993   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1994   child->Inherit(parent);
1995   AddAccessor(parent, v8_str("age"),
1996               SimpleAccessorGetter, SimpleAccessorSetter);
1997   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1998   LocalContext env;
1999   env->Global()->Set(v8_str("Child"), child->GetFunction());
2000   CompileRun("var child = new Child;"
2001              "child.age = 10;");
2002   ExpectBoolean("child.hasOwnProperty('age')", false);
2003   ExpectInt32("child.age", 10);
2004   ExpectInt32("child.accessor_age", 10);
2005 }
2006
2007
2008 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2009   v8::HandleScope scope(CcTest::isolate());
2010   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2011   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2012   LocalContext env;
2013   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2014   CompileRun("var o1 = new Constructor;"
2015              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2016              "Object.defineProperty(o1, 'x', {value: 10});");
2017   CompileRun("var o2 = new Constructor;"
2018              "o2.a = 1;"
2019              "Object.defineProperty(o2, 'x', {value: 10});");
2020 }
2021
2022
2023 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2024   v8::Isolate* isolate = CcTest::isolate();
2025   v8::HandleScope scope(isolate);
2026   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2027   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2028   child->Inherit(parent);
2029   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2030   LocalContext env;
2031   env->Global()->Set(v8_str("Child"), child->GetFunction());
2032   CompileRun("var child = new Child;"
2033              "var parent = child.__proto__;"
2034              "Object.defineProperty(parent, 'age', "
2035              "  {get: function(){ return this.accessor_age; }, "
2036              "   set: function(v){ this.accessor_age = v; }, "
2037              "   enumerable: true, configurable: true});"
2038              "child.age = 10;");
2039   ExpectBoolean("child.hasOwnProperty('age')", false);
2040   ExpectInt32("child.age", 10);
2041   ExpectInt32("child.accessor_age", 10);
2042 }
2043
2044
2045 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2046   v8::Isolate* isolate = CcTest::isolate();
2047   v8::HandleScope scope(isolate);
2048   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2049   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2050   child->Inherit(parent);
2051   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2052   LocalContext env;
2053   env->Global()->Set(v8_str("Child"), child->GetFunction());
2054   CompileRun("var child = new Child;"
2055              "var parent = child.__proto__;"
2056              "parent.name = 'Alice';");
2057   ExpectBoolean("child.hasOwnProperty('name')", false);
2058   ExpectString("child.name", "Alice");
2059   CompileRun("child.name = 'Bob';");
2060   ExpectString("child.name", "Bob");
2061   ExpectBoolean("child.hasOwnProperty('name')", true);
2062   ExpectString("parent.name", "Alice");
2063 }
2064
2065
2066 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2067   v8::HandleScope scope(CcTest::isolate());
2068   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2069   AddAccessor(templ, v8_str("age"),
2070               SimpleAccessorGetter, SimpleAccessorSetter);
2071   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2072   LocalContext env;
2073   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2074   CompileRun("var obj = new Obj;"
2075              "function setAge(i){ obj.age = i; };"
2076              "for(var i = 0; i <= 10000; i++) setAge(i);");
2077   // All i < 10000 go to the interceptor.
2078   ExpectInt32("obj.interceptor_age", 9999);
2079   // The last i goes to the accessor.
2080   ExpectInt32("obj.accessor_age", 10000);
2081 }
2082
2083
2084 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2085   v8::HandleScope scope(CcTest::isolate());
2086   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2087   AddAccessor(templ, v8_str("age"),
2088               SimpleAccessorGetter, SimpleAccessorSetter);
2089   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2090   LocalContext env;
2091   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2092   CompileRun("var obj = new Obj;"
2093              "function setAge(i){ obj.age = i; };"
2094              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2095   // All i >= 10000 go to the accessor.
2096   ExpectInt32("obj.accessor_age", 10000);
2097   // The last i goes to the interceptor.
2098   ExpectInt32("obj.interceptor_age", 9999);
2099 }
2100
2101
2102 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2103   v8::HandleScope scope(CcTest::isolate());
2104   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2105   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2106   child->Inherit(parent);
2107   AddAccessor(parent, v8_str("age"),
2108               SimpleAccessorGetter, SimpleAccessorSetter);
2109   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2110   LocalContext env;
2111   env->Global()->Set(v8_str("Child"), child->GetFunction());
2112   CompileRun("var child = new Child;"
2113              "function setAge(i){ child.age = i; };"
2114              "for(var i = 0; i <= 10000; i++) setAge(i);");
2115   // All i < 10000 go to the interceptor.
2116   ExpectInt32("child.interceptor_age", 9999);
2117   // The last i goes to the accessor.
2118   ExpectInt32("child.accessor_age", 10000);
2119 }
2120
2121
2122 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2123   v8::HandleScope scope(CcTest::isolate());
2124   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2125   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2126   child->Inherit(parent);
2127   AddAccessor(parent, v8_str("age"),
2128               SimpleAccessorGetter, SimpleAccessorSetter);
2129   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2130   LocalContext env;
2131   env->Global()->Set(v8_str("Child"), child->GetFunction());
2132   CompileRun("var child = new Child;"
2133              "function setAge(i){ child.age = i; };"
2134              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2135   // All i >= 10000 go to the accessor.
2136   ExpectInt32("child.accessor_age", 10000);
2137   // The last i goes to the interceptor.
2138   ExpectInt32("child.interceptor_age", 9999);
2139 }
2140
2141
2142 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2143   v8::HandleScope scope(CcTest::isolate());
2144   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2145   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2146   LocalContext env;
2147   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2148   CompileRun("var obj = new Obj;"
2149              "function setter(i) { this.accessor_age = i; };"
2150              "function getter() { return this.accessor_age; };"
2151              "function setAge(i) { obj.age = i; };"
2152              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2153              "for(var i = 0; i <= 10000; i++) setAge(i);");
2154   // All i < 10000 go to the interceptor.
2155   ExpectInt32("obj.interceptor_age", 9999);
2156   // The last i goes to the JavaScript accessor.
2157   ExpectInt32("obj.accessor_age", 10000);
2158   // The installed JavaScript getter is still intact.
2159   // This last part is a regression test for issue 1651 and relies on the fact
2160   // that both interceptor and accessor are being installed on the same object.
2161   ExpectInt32("obj.age", 10000);
2162   ExpectBoolean("obj.hasOwnProperty('age')", true);
2163   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2164 }
2165
2166
2167 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2168   v8::HandleScope scope(CcTest::isolate());
2169   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2170   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2171   LocalContext env;
2172   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2173   CompileRun("var obj = new Obj;"
2174              "function setter(i) { this.accessor_age = i; };"
2175              "function getter() { return this.accessor_age; };"
2176              "function setAge(i) { obj.age = i; };"
2177              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2178              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2179   // All i >= 10000 go to the accessor.
2180   ExpectInt32("obj.accessor_age", 10000);
2181   // The last i goes to the interceptor.
2182   ExpectInt32("obj.interceptor_age", 9999);
2183   // The installed JavaScript getter is still intact.
2184   // This last part is a regression test for issue 1651 and relies on the fact
2185   // that both interceptor and accessor are being installed on the same object.
2186   ExpectInt32("obj.age", 10000);
2187   ExpectBoolean("obj.hasOwnProperty('age')", true);
2188   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2189 }
2190
2191
2192 THREADED_TEST(SwitchFromInterceptorToProperty) {
2193   v8::HandleScope scope(CcTest::isolate());
2194   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2195   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2196   child->Inherit(parent);
2197   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2198   LocalContext env;
2199   env->Global()->Set(v8_str("Child"), child->GetFunction());
2200   CompileRun("var child = new Child;"
2201              "function setAge(i){ child.age = i; };"
2202              "for(var i = 0; i <= 10000; i++) setAge(i);");
2203   // All i < 10000 go to the interceptor.
2204   ExpectInt32("child.interceptor_age", 9999);
2205   // The last i goes to child's own property.
2206   ExpectInt32("child.age", 10000);
2207 }
2208
2209
2210 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2211   v8::HandleScope scope(CcTest::isolate());
2212   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2213   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2214   child->Inherit(parent);
2215   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2216   LocalContext env;
2217   env->Global()->Set(v8_str("Child"), child->GetFunction());
2218   CompileRun("var child = new Child;"
2219              "function setAge(i){ child.age = i; };"
2220              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2221   // All i >= 10000 go to child's own property.
2222   ExpectInt32("child.age", 10000);
2223   // The last i goes to the interceptor.
2224   ExpectInt32("child.interceptor_age", 9999);
2225 }
2226
2227
2228 THREADED_TEST(NamedPropertyHandlerGetter) {
2229   echo_named_call_count = 0;
2230   v8::HandleScope scope(CcTest::isolate());
2231   v8::Handle<v8::FunctionTemplate> templ =
2232       v8::FunctionTemplate::New(CcTest::isolate());
2233   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2234                                                      0, 0, 0, 0,
2235                                                      v8_str("data"));
2236   LocalContext env;
2237   env->Global()->Set(v8_str("obj"),
2238                      templ->GetFunction()->NewInstance());
2239   CHECK_EQ(echo_named_call_count, 0);
2240   v8_compile("obj.x")->Run();
2241   CHECK_EQ(echo_named_call_count, 1);
2242   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2243   v8::Handle<Value> str = CompileRun(code);
2244   String::Utf8Value value(str);
2245   CHECK_EQ(*value, "oddlepoddle");
2246   // Check default behavior
2247   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2248   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2249   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2250 }
2251
2252
2253 int echo_indexed_call_count = 0;
2254
2255
2256 static void EchoIndexedProperty(
2257     uint32_t index,
2258     const v8::PropertyCallbackInfo<v8::Value>& info) {
2259   ApiTestFuzzer::Fuzz();
2260   CHECK_EQ(v8_num(637), info.Data());
2261   echo_indexed_call_count++;
2262   info.GetReturnValue().Set(v8_num(index));
2263 }
2264
2265
2266 THREADED_TEST(IndexedPropertyHandlerGetter) {
2267   v8::Isolate* isolate = CcTest::isolate();
2268   v8::HandleScope scope(isolate);
2269   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2270   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2271                                                        0, 0, 0, 0,
2272                                                        v8_num(637));
2273   LocalContext env;
2274   env->Global()->Set(v8_str("obj"),
2275                      templ->GetFunction()->NewInstance());
2276   Local<Script> script = v8_compile("obj[900]");
2277   CHECK_EQ(script->Run()->Int32Value(), 900);
2278 }
2279
2280
2281 v8::Handle<v8::Object> bottom;
2282
2283 static void CheckThisIndexedPropertyHandler(
2284     uint32_t index,
2285     const v8::PropertyCallbackInfo<v8::Value>& info) {
2286   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2287   ApiTestFuzzer::Fuzz();
2288   CHECK(info.This()->Equals(bottom));
2289 }
2290
2291 static void CheckThisNamedPropertyHandler(
2292     Local<String> name,
2293     const v8::PropertyCallbackInfo<v8::Value>& info) {
2294   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2295   ApiTestFuzzer::Fuzz();
2296   CHECK(info.This()->Equals(bottom));
2297 }
2298
2299 void CheckThisIndexedPropertySetter(
2300     uint32_t index,
2301     Local<Value> value,
2302     const v8::PropertyCallbackInfo<v8::Value>& info) {
2303   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2304   ApiTestFuzzer::Fuzz();
2305   CHECK(info.This()->Equals(bottom));
2306 }
2307
2308
2309 void CheckThisNamedPropertySetter(
2310     Local<String> property,
2311     Local<Value> value,
2312     const v8::PropertyCallbackInfo<v8::Value>& info) {
2313   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2314   ApiTestFuzzer::Fuzz();
2315   CHECK(info.This()->Equals(bottom));
2316 }
2317
2318 void CheckThisIndexedPropertyQuery(
2319     uint32_t index,
2320     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2321   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2322   ApiTestFuzzer::Fuzz();
2323   CHECK(info.This()->Equals(bottom));
2324 }
2325
2326
2327 void CheckThisNamedPropertyQuery(
2328     Local<String> property,
2329     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2330   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2331   ApiTestFuzzer::Fuzz();
2332   CHECK(info.This()->Equals(bottom));
2333 }
2334
2335
2336 void CheckThisIndexedPropertyDeleter(
2337     uint32_t index,
2338     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2339   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2340   ApiTestFuzzer::Fuzz();
2341   CHECK(info.This()->Equals(bottom));
2342 }
2343
2344
2345 void CheckThisNamedPropertyDeleter(
2346     Local<String> property,
2347     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2348   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2349   ApiTestFuzzer::Fuzz();
2350   CHECK(info.This()->Equals(bottom));
2351 }
2352
2353
2354 void CheckThisIndexedPropertyEnumerator(
2355     const v8::PropertyCallbackInfo<v8::Array>& info) {
2356   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2357   ApiTestFuzzer::Fuzz();
2358   CHECK(info.This()->Equals(bottom));
2359 }
2360
2361
2362 void CheckThisNamedPropertyEnumerator(
2363     const v8::PropertyCallbackInfo<v8::Array>& info) {
2364   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2365   ApiTestFuzzer::Fuzz();
2366   CHECK(info.This()->Equals(bottom));
2367 }
2368
2369
2370 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2371   LocalContext env;
2372   v8::Isolate* isolate = env->GetIsolate();
2373   v8::HandleScope scope(isolate);
2374
2375   // Set up a prototype chain with three interceptors.
2376   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2377   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2378       CheckThisIndexedPropertyHandler,
2379       CheckThisIndexedPropertySetter,
2380       CheckThisIndexedPropertyQuery,
2381       CheckThisIndexedPropertyDeleter,
2382       CheckThisIndexedPropertyEnumerator);
2383
2384   templ->InstanceTemplate()->SetNamedPropertyHandler(
2385       CheckThisNamedPropertyHandler,
2386       CheckThisNamedPropertySetter,
2387       CheckThisNamedPropertyQuery,
2388       CheckThisNamedPropertyDeleter,
2389       CheckThisNamedPropertyEnumerator);
2390
2391   bottom = templ->GetFunction()->NewInstance();
2392   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2393   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2394
2395   bottom->SetPrototype(middle);
2396   middle->SetPrototype(top);
2397   env->Global()->Set(v8_str("obj"), bottom);
2398
2399   // Indexed and named get.
2400   Script::Compile(v8_str("obj[0]"))->Run();
2401   Script::Compile(v8_str("obj.x"))->Run();
2402
2403   // Indexed and named set.
2404   Script::Compile(v8_str("obj[1] = 42"))->Run();
2405   Script::Compile(v8_str("obj.y = 42"))->Run();
2406
2407   // Indexed and named query.
2408   Script::Compile(v8_str("0 in obj"))->Run();
2409   Script::Compile(v8_str("'x' in obj"))->Run();
2410
2411   // Indexed and named deleter.
2412   Script::Compile(v8_str("delete obj[0]"))->Run();
2413   Script::Compile(v8_str("delete obj.x"))->Run();
2414
2415   // Enumerators.
2416   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2417 }
2418
2419
2420 static void PrePropertyHandlerGet(
2421     Local<String> key,
2422     const v8::PropertyCallbackInfo<v8::Value>& info) {
2423   ApiTestFuzzer::Fuzz();
2424   if (v8_str("pre")->Equals(key)) {
2425     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2426   }
2427 }
2428
2429
2430 static void PrePropertyHandlerQuery(
2431     Local<String> key,
2432     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2433   if (v8_str("pre")->Equals(key)) {
2434     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2435   }
2436 }
2437
2438
2439 THREADED_TEST(PrePropertyHandler) {
2440   v8::Isolate* isolate = CcTest::isolate();
2441   v8::HandleScope scope(isolate);
2442   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2443   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2444                                                     0,
2445                                                     PrePropertyHandlerQuery);
2446   LocalContext env(NULL, desc->InstanceTemplate());
2447   Script::Compile(v8_str(
2448       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2449   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2450   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2451   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2452   CHECK_EQ(v8_str("Object: on"), result_on);
2453   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2454   CHECK(result_post.IsEmpty());
2455 }
2456
2457
2458 THREADED_TEST(UndefinedIsNotEnumerable) {
2459   LocalContext env;
2460   v8::HandleScope scope(env->GetIsolate());
2461   v8::Handle<Value> result = Script::Compile(v8_str(
2462       "this.propertyIsEnumerable(undefined)"))->Run();
2463   CHECK(result->IsFalse());
2464 }
2465
2466
2467 v8::Handle<Script> call_recursively_script;
2468 static const int kTargetRecursionDepth = 200;  // near maximum
2469
2470
2471 static void CallScriptRecursivelyCall(
2472     const v8::FunctionCallbackInfo<v8::Value>& args) {
2473   ApiTestFuzzer::Fuzz();
2474   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2475   if (depth == kTargetRecursionDepth) return;
2476   args.This()->Set(v8_str("depth"),
2477                    v8::Integer::New(args.GetIsolate(), depth + 1));
2478   args.GetReturnValue().Set(call_recursively_script->Run());
2479 }
2480
2481
2482 static void CallFunctionRecursivelyCall(
2483     const v8::FunctionCallbackInfo<v8::Value>& args) {
2484   ApiTestFuzzer::Fuzz();
2485   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2486   if (depth == kTargetRecursionDepth) {
2487     printf("[depth = %d]\n", depth);
2488     return;
2489   }
2490   args.This()->Set(v8_str("depth"),
2491                    v8::Integer::New(args.GetIsolate(), depth + 1));
2492   v8::Handle<Value> function =
2493       args.This()->Get(v8_str("callFunctionRecursively"));
2494   args.GetReturnValue().Set(
2495       function.As<Function>()->Call(args.This(), 0, NULL));
2496 }
2497
2498
2499 THREADED_TEST(DeepCrossLanguageRecursion) {
2500   v8::Isolate* isolate = CcTest::isolate();
2501   v8::HandleScope scope(isolate);
2502   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2503   global->Set(v8_str("callScriptRecursively"),
2504               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2505   global->Set(v8_str("callFunctionRecursively"),
2506               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2507   LocalContext env(NULL, global);
2508
2509   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2510   call_recursively_script = v8_compile("callScriptRecursively()");
2511   call_recursively_script->Run();
2512   call_recursively_script = v8::Handle<Script>();
2513
2514   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2515   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2516 }
2517
2518
2519 static void ThrowingPropertyHandlerGet(
2520     Local<String> key,
2521     const v8::PropertyCallbackInfo<v8::Value>& info) {
2522   ApiTestFuzzer::Fuzz();
2523   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2524 }
2525
2526
2527 static void ThrowingPropertyHandlerSet(
2528     Local<String> key,
2529     Local<Value>,
2530     const v8::PropertyCallbackInfo<v8::Value>& info) {
2531   info.GetIsolate()->ThrowException(key);
2532   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2533 }
2534
2535
2536 THREADED_TEST(CallbackExceptionRegression) {
2537   v8::Isolate* isolate = CcTest::isolate();
2538   v8::HandleScope scope(isolate);
2539   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2540   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2541                                ThrowingPropertyHandlerSet);
2542   LocalContext env;
2543   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2544   v8::Handle<Value> otto = Script::Compile(v8_str(
2545       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2546   CHECK_EQ(v8_str("otto"), otto);
2547   v8::Handle<Value> netto = Script::Compile(v8_str(
2548       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2549   CHECK_EQ(v8_str("netto"), netto);
2550 }
2551
2552
2553 THREADED_TEST(FunctionPrototype) {
2554   v8::Isolate* isolate = CcTest::isolate();
2555   v8::HandleScope scope(isolate);
2556   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2557   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2558   LocalContext env;
2559   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2560   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2561   CHECK_EQ(script->Run()->Int32Value(), 321);
2562 }
2563
2564
2565 THREADED_TEST(InternalFields) {
2566   LocalContext env;
2567   v8::Isolate* isolate = env->GetIsolate();
2568   v8::HandleScope scope(isolate);
2569
2570   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2571   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2572   instance_templ->SetInternalFieldCount(1);
2573   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2574   CHECK_EQ(1, obj->InternalFieldCount());
2575   CHECK(obj->GetInternalField(0)->IsUndefined());
2576   obj->SetInternalField(0, v8_num(17));
2577   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2578 }
2579
2580
2581 THREADED_TEST(GlobalObjectInternalFields) {
2582   v8::Isolate* isolate = CcTest::isolate();
2583   v8::HandleScope scope(isolate);
2584   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2585   global_template->SetInternalFieldCount(1);
2586   LocalContext env(NULL, global_template);
2587   v8::Handle<v8::Object> global_proxy = env->Global();
2588   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2589   CHECK_EQ(1, global->InternalFieldCount());
2590   CHECK(global->GetInternalField(0)->IsUndefined());
2591   global->SetInternalField(0, v8_num(17));
2592   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2593 }
2594
2595
2596 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2597   LocalContext env;
2598   v8::HandleScope scope(CcTest::isolate());
2599
2600   v8::Local<v8::Object> global = env->Global();
2601   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2602   CHECK(global->HasRealIndexedProperty(0));
2603 }
2604
2605
2606 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2607                                                void* value) {
2608   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2609   obj->SetAlignedPointerInInternalField(0, value);
2610   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2611   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2612 }
2613
2614
2615 THREADED_TEST(InternalFieldsAlignedPointers) {
2616   LocalContext env;
2617   v8::Isolate* isolate = env->GetIsolate();
2618   v8::HandleScope scope(isolate);
2619
2620   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2621   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2622   instance_templ->SetInternalFieldCount(1);
2623   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2624   CHECK_EQ(1, obj->InternalFieldCount());
2625
2626   CheckAlignedPointerInInternalField(obj, NULL);
2627
2628   int* heap_allocated = new int[100];
2629   CheckAlignedPointerInInternalField(obj, heap_allocated);
2630   delete[] heap_allocated;
2631
2632   int stack_allocated[100];
2633   CheckAlignedPointerInInternalField(obj, stack_allocated);
2634
2635   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2636   CheckAlignedPointerInInternalField(obj, huge);
2637 }
2638
2639
2640 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2641                                               int index,
2642                                               void* value) {
2643   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2644   (*env)->SetAlignedPointerInEmbedderData(index, value);
2645   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2646   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2647 }
2648
2649
2650 static void* AlignedTestPointer(int i) {
2651   return reinterpret_cast<void*>(i * 1234);
2652 }
2653
2654
2655 THREADED_TEST(EmbedderDataAlignedPointers) {
2656   LocalContext env;
2657   v8::HandleScope scope(env->GetIsolate());
2658
2659   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2660
2661   int* heap_allocated = new int[100];
2662   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2663   delete[] heap_allocated;
2664
2665   int stack_allocated[100];
2666   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2667
2668   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2669   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2670
2671   // Test growing of the embedder data's backing store.
2672   for (int i = 0; i < 100; i++) {
2673     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2674   }
2675   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2676   for (int i = 0; i < 100; i++) {
2677     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2678   }
2679 }
2680
2681
2682 static void CheckEmbedderData(LocalContext* env,
2683                               int index,
2684                               v8::Handle<Value> data) {
2685   (*env)->SetEmbedderData(index, data);
2686   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2687 }
2688
2689
2690 THREADED_TEST(EmbedderData) {
2691   LocalContext env;
2692   v8::Isolate* isolate = env->GetIsolate();
2693   v8::HandleScope scope(isolate);
2694
2695   CheckEmbedderData(
2696       &env, 3,
2697       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2698   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2699                                                      "over the lazy dog."));
2700   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2701   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2702 }
2703
2704
2705 THREADED_TEST(IdentityHash) {
2706   LocalContext env;
2707   v8::Isolate* isolate = env->GetIsolate();
2708   v8::HandleScope scope(isolate);
2709
2710   // Ensure that the test starts with an fresh heap to test whether the hash
2711   // code is based on the address.
2712   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2713   Local<v8::Object> obj = v8::Object::New(isolate);
2714   int hash = obj->GetIdentityHash();
2715   int hash1 = obj->GetIdentityHash();
2716   CHECK_EQ(hash, hash1);
2717   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2718   // Since the identity hash is essentially a random number two consecutive
2719   // objects should not be assigned the same hash code. If the test below fails
2720   // the random number generator should be evaluated.
2721   CHECK_NE(hash, hash2);
2722   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2723   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2724   // Make sure that the identity hash is not based on the initial address of
2725   // the object alone. If the test below fails the random number generator
2726   // should be evaluated.
2727   CHECK_NE(hash, hash3);
2728   int hash4 = obj->GetIdentityHash();
2729   CHECK_EQ(hash, hash4);
2730
2731   // Check identity hashes behaviour in the presence of JS accessors.
2732   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2733   {
2734     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2735     Local<v8::Object> o1 = v8::Object::New(isolate);
2736     Local<v8::Object> o2 = v8::Object::New(isolate);
2737     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2738   }
2739   {
2740     CompileRun(
2741         "function cnst() { return 42; };\n"
2742         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2743     Local<v8::Object> o1 = v8::Object::New(isolate);
2744     Local<v8::Object> o2 = v8::Object::New(isolate);
2745     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2746   }
2747 }
2748
2749
2750 THREADED_TEST(SymbolProperties) {
2751   i::FLAG_harmony_symbols = true;
2752
2753   LocalContext env;
2754   v8::Isolate* isolate = env->GetIsolate();
2755   v8::HandleScope scope(isolate);
2756
2757   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2758   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2759   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2760
2761   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2762
2763   // Check basic symbol functionality.
2764   CHECK(sym1->IsSymbol());
2765   CHECK(sym2->IsSymbol());
2766   CHECK(!obj->IsSymbol());
2767
2768   CHECK(sym1->Equals(sym1));
2769   CHECK(sym2->Equals(sym2));
2770   CHECK(!sym1->Equals(sym2));
2771   CHECK(!sym2->Equals(sym1));
2772   CHECK(sym1->StrictEquals(sym1));
2773   CHECK(sym2->StrictEquals(sym2));
2774   CHECK(!sym1->StrictEquals(sym2));
2775   CHECK(!sym2->StrictEquals(sym1));
2776
2777   CHECK(sym2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-symbol")));
2778
2779   v8::Local<v8::Value> sym_val = sym2;
2780   CHECK(sym_val->IsSymbol());
2781   CHECK(sym_val->Equals(sym2));
2782   CHECK(sym_val->StrictEquals(sym2));
2783   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2784
2785   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2786   CHECK(sym_obj->IsSymbolObject());
2787   CHECK(!sym2->IsSymbolObject());
2788   CHECK(!obj->IsSymbolObject());
2789   CHECK(sym_obj->Equals(sym2));
2790   CHECK(!sym_obj->StrictEquals(sym2));
2791   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2792   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2793
2794   // Make sure delete of a non-existent symbol property works.
2795   CHECK(obj->Delete(sym1));
2796   CHECK(!obj->Has(sym1));
2797
2798   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2799   CHECK(obj->Has(sym1));
2800   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2801   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2802   CHECK(obj->Has(sym1));
2803   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2804   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2805
2806   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2807   int num_props = obj->GetPropertyNames()->Length();
2808   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2809                  v8::Integer::New(isolate, 20)));
2810   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2811   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2812
2813   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2814
2815   // Add another property and delete it afterwards to force the object in
2816   // slow case.
2817   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2818   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2819   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2820   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2821   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2822
2823   CHECK(obj->Has(sym1));
2824   CHECK(obj->Has(sym2));
2825   CHECK(obj->Delete(sym2));
2826   CHECK(obj->Has(sym1));
2827   CHECK(!obj->Has(sym2));
2828   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2829   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2830
2831   // Symbol properties are inherited.
2832   v8::Local<v8::Object> child = v8::Object::New(isolate);
2833   child->SetPrototype(obj);
2834   CHECK(child->Has(sym1));
2835   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2836   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2837 }
2838
2839
2840 THREADED_TEST(PrivateProperties) {
2841   LocalContext env;
2842   v8::Isolate* isolate = env->GetIsolate();
2843   v8::HandleScope scope(isolate);
2844
2845   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2846   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2847   v8::Local<v8::Private> priv2 = v8::Private::New(isolate, "my-private");
2848
2849   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2850
2851   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2852
2853   // Make sure delete of a non-existent private symbol property works.
2854   CHECK(obj->DeletePrivate(priv1));
2855   CHECK(!obj->HasPrivate(priv1));
2856
2857   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2858   CHECK(obj->HasPrivate(priv1));
2859   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2860   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2861   CHECK(obj->HasPrivate(priv1));
2862   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2863
2864   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2865   int num_props = obj->GetPropertyNames()->Length();
2866   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2867                  v8::Integer::New(isolate, 20)));
2868   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2869   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2870
2871   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2872
2873   // Add another property and delete it afterwards to force the object in
2874   // slow case.
2875   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2876   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2877   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2878   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2879   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2880
2881   CHECK(obj->HasPrivate(priv1));
2882   CHECK(obj->HasPrivate(priv2));
2883   CHECK(obj->DeletePrivate(priv2));
2884   CHECK(obj->HasPrivate(priv1));
2885   CHECK(!obj->HasPrivate(priv2));
2886   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2887   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2888
2889   // Private properties are inherited (for the time being).
2890   v8::Local<v8::Object> child = v8::Object::New(isolate);
2891   child->SetPrototype(obj);
2892   CHECK(child->HasPrivate(priv1));
2893   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2894   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2895 }
2896
2897
2898 class ScopedArrayBufferContents {
2899  public:
2900   explicit ScopedArrayBufferContents(
2901       const v8::ArrayBuffer::Contents& contents)
2902     : contents_(contents) {}
2903   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2904   void* Data() const { return contents_.Data(); }
2905   size_t ByteLength() const { return contents_.ByteLength(); }
2906  private:
2907   const v8::ArrayBuffer::Contents contents_;
2908 };
2909
2910 template <typename T>
2911 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2912   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2913   for (int i = 0; i < value->InternalFieldCount(); i++) {
2914     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2915   }
2916 }
2917
2918
2919 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2920   LocalContext env;
2921   v8::Isolate* isolate = env->GetIsolate();
2922   v8::HandleScope handle_scope(isolate);
2923
2924   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2925   CheckInternalFieldsAreZero(ab);
2926   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2927   CHECK(!ab->IsExternal());
2928   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2929
2930   ScopedArrayBufferContents ab_contents(ab->Externalize());
2931   CHECK(ab->IsExternal());
2932
2933   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2934   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2935   ASSERT(data != NULL);
2936   env->Global()->Set(v8_str("ab"), ab);
2937
2938   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2939   CHECK_EQ(1024, result->Int32Value());
2940
2941   result = CompileRun("var u8 = new Uint8Array(ab);"
2942                       "u8[0] = 0xFF;"
2943                       "u8[1] = 0xAA;"
2944                       "u8.length");
2945   CHECK_EQ(1024, result->Int32Value());
2946   CHECK_EQ(0xFF, data[0]);
2947   CHECK_EQ(0xAA, data[1]);
2948   data[0] = 0xCC;
2949   data[1] = 0x11;
2950   result = CompileRun("u8[0] + u8[1]");
2951   CHECK_EQ(0xDD, result->Int32Value());
2952 }
2953
2954
2955 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2956   LocalContext env;
2957   v8::Isolate* isolate = env->GetIsolate();
2958   v8::HandleScope handle_scope(isolate);
2959
2960
2961   v8::Local<v8::Value> result =
2962       CompileRun("var ab1 = new ArrayBuffer(2);"
2963                  "var u8_a = new Uint8Array(ab1);"
2964                  "u8_a[0] = 0xAA;"
2965                  "u8_a[1] = 0xFF; u8_a.buffer");
2966   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2967   CheckInternalFieldsAreZero(ab1);
2968   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2969   CHECK(!ab1->IsExternal());
2970   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2971   CHECK(ab1->IsExternal());
2972
2973   result = CompileRun("ab1.byteLength");
2974   CHECK_EQ(2, result->Int32Value());
2975   result = CompileRun("u8_a[0]");
2976   CHECK_EQ(0xAA, result->Int32Value());
2977   result = CompileRun("u8_a[1]");
2978   CHECK_EQ(0xFF, result->Int32Value());
2979   result = CompileRun("var u8_b = new Uint8Array(ab1);"
2980                       "u8_b[0] = 0xBB;"
2981                       "u8_a[0]");
2982   CHECK_EQ(0xBB, result->Int32Value());
2983   result = CompileRun("u8_b[1]");
2984   CHECK_EQ(0xFF, result->Int32Value());
2985
2986   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2987   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2988   CHECK_EQ(0xBB, ab1_data[0]);
2989   CHECK_EQ(0xFF, ab1_data[1]);
2990   ab1_data[0] = 0xCC;
2991   ab1_data[1] = 0x11;
2992   result = CompileRun("u8_a[0] + u8_a[1]");
2993   CHECK_EQ(0xDD, result->Int32Value());
2994 }
2995
2996
2997 THREADED_TEST(ArrayBuffer_External) {
2998   LocalContext env;
2999   v8::Isolate* isolate = env->GetIsolate();
3000   v8::HandleScope handle_scope(isolate);
3001
3002   i::ScopedVector<uint8_t> my_data(100);
3003   memset(my_data.start(), 0, 100);
3004   Local<v8::ArrayBuffer> ab3 =
3005       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3006   CheckInternalFieldsAreZero(ab3);
3007   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3008   CHECK(ab3->IsExternal());
3009
3010   env->Global()->Set(v8_str("ab3"), ab3);
3011
3012   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3013   CHECK_EQ(100, result->Int32Value());
3014
3015   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3016                       "u8_b[0] = 0xBB;"
3017                       "u8_b[1] = 0xCC;"
3018                       "u8_b.length");
3019   CHECK_EQ(100, result->Int32Value());
3020   CHECK_EQ(0xBB, my_data[0]);
3021   CHECK_EQ(0xCC, my_data[1]);
3022   my_data[0] = 0xCC;
3023   my_data[1] = 0x11;
3024   result = CompileRun("u8_b[0] + u8_b[1]");
3025   CHECK_EQ(0xDD, result->Int32Value());
3026 }
3027
3028
3029 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3030   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3031   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3032 }
3033
3034
3035 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3036   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3037   CHECK_EQ(0, static_cast<int>(ta->Length()));
3038   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3039 }
3040
3041
3042 static void CheckIsTypedArrayVarNeutered(const char* name) {
3043   i::ScopedVector<char> source(1024);
3044   i::OS::SNPrintF(source,
3045       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3046       name, name, name);
3047   CHECK(CompileRun(source.start())->IsTrue());
3048   v8::Handle<v8::TypedArray> ta =
3049     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3050   CheckIsNeutered(ta);
3051 }
3052
3053
3054 template <typename TypedArray, int kElementSize>
3055 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3056                                          int byteOffset,
3057                                          int length) {
3058   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3059   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3060   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3061   CHECK_EQ(length, static_cast<int>(ta->Length()));
3062   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3063   return ta;
3064 }
3065
3066
3067 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3068   LocalContext env;
3069   v8::Isolate* isolate = env->GetIsolate();
3070   v8::HandleScope handle_scope(isolate);
3071
3072   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3073
3074   v8::Handle<v8::Uint8Array> u8a =
3075     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3076   v8::Handle<v8::Uint8ClampedArray> u8c =
3077     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3078   v8::Handle<v8::Int8Array> i8a =
3079     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3080
3081   v8::Handle<v8::Uint16Array> u16a =
3082     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3083   v8::Handle<v8::Int16Array> i16a =
3084     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3085
3086   v8::Handle<v8::Uint32Array> u32a =
3087     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3088   v8::Handle<v8::Int32Array> i32a =
3089     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3090
3091   v8::Handle<v8::Float32Array> f32a =
3092     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3093   v8::Handle<v8::Float64Array> f64a =
3094     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3095
3096   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3097   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3098   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3099   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3100
3101   ScopedArrayBufferContents contents(buffer->Externalize());
3102   buffer->Neuter();
3103   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3104   CheckIsNeutered(u8a);
3105   CheckIsNeutered(u8c);
3106   CheckIsNeutered(i8a);
3107   CheckIsNeutered(u16a);
3108   CheckIsNeutered(i16a);
3109   CheckIsNeutered(u32a);
3110   CheckIsNeutered(i32a);
3111   CheckIsNeutered(f32a);
3112   CheckIsNeutered(f64a);
3113   CheckDataViewIsNeutered(dv);
3114 }
3115
3116
3117 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3118   LocalContext env;
3119   v8::Isolate* isolate = env->GetIsolate();
3120   v8::HandleScope handle_scope(isolate);
3121
3122   CompileRun(
3123       "var ab = new ArrayBuffer(1024);"
3124       "var u8a = new Uint8Array(ab, 1, 1023);"
3125       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3126       "var i8a = new Int8Array(ab, 1, 1023);"
3127       "var u16a = new Uint16Array(ab, 2, 511);"
3128       "var i16a = new Int16Array(ab, 2, 511);"
3129       "var u32a = new Uint32Array(ab, 4, 255);"
3130       "var i32a = new Int32Array(ab, 4, 255);"
3131       "var f32a = new Float32Array(ab, 4, 255);"
3132       "var f64a = new Float64Array(ab, 8, 127);"
3133       "var dv = new DataView(ab, 1, 1023);");
3134
3135   v8::Handle<v8::ArrayBuffer> ab =
3136       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3137
3138   v8::Handle<v8::DataView> dv =
3139     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3140
3141   ScopedArrayBufferContents contents(ab->Externalize());
3142   ab->Neuter();
3143   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3144   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3145
3146   CheckIsTypedArrayVarNeutered("u8a");
3147   CheckIsTypedArrayVarNeutered("u8c");
3148   CheckIsTypedArrayVarNeutered("i8a");
3149   CheckIsTypedArrayVarNeutered("u16a");
3150   CheckIsTypedArrayVarNeutered("i16a");
3151   CheckIsTypedArrayVarNeutered("u32a");
3152   CheckIsTypedArrayVarNeutered("i32a");
3153   CheckIsTypedArrayVarNeutered("f32a");
3154   CheckIsTypedArrayVarNeutered("f64a");
3155
3156   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3157   CheckDataViewIsNeutered(dv);
3158 }
3159
3160
3161
3162 THREADED_TEST(HiddenProperties) {
3163   LocalContext env;
3164   v8::Isolate* isolate = env->GetIsolate();
3165   v8::HandleScope scope(isolate);
3166
3167   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3168   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3169   v8::Local<v8::String> empty = v8_str("");
3170   v8::Local<v8::String> prop_name = v8_str("prop_name");
3171
3172   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3173
3174   // Make sure delete of a non-existent hidden value works
3175   CHECK(obj->DeleteHiddenValue(key));
3176
3177   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3178   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3179   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3180   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3181
3182   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3183
3184   // Make sure we do not find the hidden property.
3185   CHECK(!obj->Has(empty));
3186   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3187   CHECK(obj->Get(empty)->IsUndefined());
3188   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3189   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3190   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3191   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3192
3193   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3194
3195   // Add another property and delete it afterwards to force the object in
3196   // slow case.
3197   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3198   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3199   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3200   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3201   CHECK(obj->Delete(prop_name));
3202   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3203
3204   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3205
3206   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3207   CHECK(obj->GetHiddenValue(key).IsEmpty());
3208
3209   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3210   CHECK(obj->DeleteHiddenValue(key));
3211   CHECK(obj->GetHiddenValue(key).IsEmpty());
3212 }
3213
3214
3215 THREADED_TEST(Regress97784) {
3216   // Regression test for crbug.com/97784
3217   // Messing with the Object.prototype should not have effect on
3218   // hidden properties.
3219   LocalContext env;
3220   v8::HandleScope scope(env->GetIsolate());
3221
3222   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3223   v8::Local<v8::String> key = v8_str("hidden");
3224
3225   CompileRun(
3226       "set_called = false;"
3227       "Object.defineProperty("
3228       "    Object.prototype,"
3229       "    'hidden',"
3230       "    {get: function() { return 45; },"
3231       "     set: function() { set_called = true; }})");
3232
3233   CHECK(obj->GetHiddenValue(key).IsEmpty());
3234   // Make sure that the getter and setter from Object.prototype is not invoked.
3235   // If it did we would have full access to the hidden properties in
3236   // the accessor.
3237   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3238   ExpectFalse("set_called");
3239   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3240 }
3241
3242
3243 static bool interceptor_for_hidden_properties_called;
3244 static void InterceptorForHiddenProperties(
3245     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3246   interceptor_for_hidden_properties_called = true;
3247 }
3248
3249
3250 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3251   LocalContext context;
3252   v8::Isolate* isolate = context->GetIsolate();
3253   v8::HandleScope scope(isolate);
3254
3255   interceptor_for_hidden_properties_called = false;
3256
3257   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3258
3259   // Associate an interceptor with an object and start setting hidden values.
3260   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3261   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3262   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3263   Local<v8::Function> function = fun_templ->GetFunction();
3264   Local<v8::Object> obj = function->NewInstance();
3265   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3266   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3267   CHECK(!interceptor_for_hidden_properties_called);
3268 }
3269
3270
3271 THREADED_TEST(External) {
3272   v8::HandleScope scope(CcTest::isolate());
3273   int x = 3;
3274   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3275   LocalContext env;
3276   env->Global()->Set(v8_str("ext"), ext);
3277   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3278   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3279   int* ptr = static_cast<int*>(reext->Value());
3280   CHECK_EQ(x, 3);
3281   *ptr = 10;
3282   CHECK_EQ(x, 10);
3283
3284   // Make sure unaligned pointers are wrapped properly.
3285   char* data = i::StrDup("0123456789");
3286   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3287   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3288   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3289   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3290
3291   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3292   CHECK_EQ('0', *char_ptr);
3293   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3294   CHECK_EQ('1', *char_ptr);
3295   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3296   CHECK_EQ('2', *char_ptr);
3297   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3298   CHECK_EQ('3', *char_ptr);
3299   i::DeleteArray(data);
3300 }
3301
3302
3303 THREADED_TEST(GlobalHandle) {
3304   v8::Isolate* isolate = CcTest::isolate();
3305   v8::Persistent<String> global;
3306   {
3307     v8::HandleScope scope(isolate);
3308     global.Reset(isolate, v8_str("str"));
3309   }
3310   {
3311     v8::HandleScope scope(isolate);
3312     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3313   }
3314   global.Reset();
3315   {
3316     v8::HandleScope scope(isolate);
3317     global.Reset(isolate, v8_str("str"));
3318   }
3319   {
3320     v8::HandleScope scope(isolate);
3321     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3322   }
3323   global.Reset();
3324 }
3325
3326
3327 THREADED_TEST(ResettingGlobalHandle) {
3328   v8::Isolate* isolate = CcTest::isolate();
3329   v8::Persistent<String> global;
3330   {
3331     v8::HandleScope scope(isolate);
3332     global.Reset(isolate, v8_str("str"));
3333   }
3334   v8::internal::GlobalHandles* global_handles =
3335       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3336   int initial_handle_count = global_handles->global_handles_count();
3337   {
3338     v8::HandleScope scope(isolate);
3339     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3340   }
3341   {
3342     v8::HandleScope scope(isolate);
3343     global.Reset(isolate, v8_str("longer"));
3344   }
3345   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3346   {
3347     v8::HandleScope scope(isolate);
3348     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3349   }
3350   global.Reset();
3351   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3352 }
3353
3354
3355 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3356   v8::Isolate* isolate = CcTest::isolate();
3357   v8::Persistent<String> global;
3358   {
3359     v8::HandleScope scope(isolate);
3360     global.Reset(isolate, v8_str("str"));
3361   }
3362   v8::internal::GlobalHandles* global_handles =
3363       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3364   int initial_handle_count = global_handles->global_handles_count();
3365   {
3366     v8::HandleScope scope(isolate);
3367     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3368   }
3369   {
3370     v8::HandleScope scope(isolate);
3371     Local<String> empty;
3372     global.Reset(isolate, empty);
3373   }
3374   CHECK(global.IsEmpty());
3375   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3376 }
3377
3378
3379 template<class T>
3380 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3381   return unique.Pass();
3382 }
3383
3384
3385 template<class T>
3386 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3387                                             const v8::Persistent<T> & global) {
3388   v8::UniquePersistent<String> unique(isolate, global);
3389   return unique.Pass();
3390 }
3391
3392
3393 THREADED_TEST(UniquePersistent) {
3394   v8::Isolate* isolate = CcTest::isolate();
3395   v8::Persistent<String> global;
3396   {
3397     v8::HandleScope scope(isolate);
3398     global.Reset(isolate, v8_str("str"));
3399   }
3400   v8::internal::GlobalHandles* global_handles =
3401       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3402   int initial_handle_count = global_handles->global_handles_count();
3403   {
3404     v8::UniquePersistent<String> unique(isolate, global);
3405     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3406     // Test assignment via Pass
3407     {
3408       v8::UniquePersistent<String> copy = unique.Pass();
3409       CHECK(unique.IsEmpty());
3410       CHECK(copy == global);
3411       CHECK_EQ(initial_handle_count + 1,
3412                global_handles->global_handles_count());
3413       unique = copy.Pass();
3414     }
3415     // Test ctor via Pass
3416     {
3417       v8::UniquePersistent<String> copy(unique.Pass());
3418       CHECK(unique.IsEmpty());
3419       CHECK(copy == global);
3420       CHECK_EQ(initial_handle_count + 1,
3421                global_handles->global_handles_count());
3422       unique = copy.Pass();
3423     }
3424     // Test pass through function call
3425     {
3426       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3427       CHECK(unique.IsEmpty());
3428       CHECK(copy == global);
3429       CHECK_EQ(initial_handle_count + 1,
3430                global_handles->global_handles_count());
3431       unique = copy.Pass();
3432     }
3433     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3434   }
3435   // Test pass from function call
3436   {
3437     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3438     CHECK(unique == global);
3439     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3440   }
3441   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3442   global.Reset();
3443 }
3444
3445
3446 THREADED_TEST(GlobalHandleUpcast) {
3447   v8::Isolate* isolate = CcTest::isolate();
3448   v8::HandleScope scope(isolate);
3449   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3450   v8::Persistent<String> global_string(isolate, local);
3451   v8::Persistent<Value>& global_value =
3452       v8::Persistent<Value>::Cast(global_string);
3453   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3454   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3455   global_string.Reset();
3456 }
3457
3458
3459 THREADED_TEST(HandleEquality) {
3460   v8::Isolate* isolate = CcTest::isolate();
3461   v8::Persistent<String> global1;
3462   v8::Persistent<String> global2;
3463   {
3464     v8::HandleScope scope(isolate);
3465     global1.Reset(isolate, v8_str("str"));
3466     global2.Reset(isolate, v8_str("str2"));
3467   }
3468   CHECK_EQ(global1 == global1, true);
3469   CHECK_EQ(global1 != global1, false);
3470   {
3471     v8::HandleScope scope(isolate);
3472     Local<String> local1 = Local<String>::New(isolate, global1);
3473     Local<String> local2 = Local<String>::New(isolate, global2);
3474
3475     CHECK_EQ(global1 == local1, true);
3476     CHECK_EQ(global1 != local1, false);
3477     CHECK_EQ(local1 == global1, true);
3478     CHECK_EQ(local1 != global1, false);
3479
3480     CHECK_EQ(global1 == local2, false);
3481     CHECK_EQ(global1 != local2, true);
3482     CHECK_EQ(local2 == global1, false);
3483     CHECK_EQ(local2 != global1, true);
3484
3485     CHECK_EQ(local1 == local2, false);
3486     CHECK_EQ(local1 != local2, true);
3487
3488     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3489     CHECK_EQ(local1 == anotherLocal1, true);
3490     CHECK_EQ(local1 != anotherLocal1, false);
3491   }
3492   global1.Reset();
3493   global2.Reset();
3494 }
3495
3496
3497 THREADED_TEST(LocalHandle) {
3498   v8::HandleScope scope(CcTest::isolate());
3499   v8::Local<String> local =
3500       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3501   CHECK_EQ(local->Length(), 3);
3502 }
3503
3504
3505 class WeakCallCounter {
3506  public:
3507   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3508   int id() { return id_; }
3509   void increment() { number_of_weak_calls_++; }
3510   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3511  private:
3512   int id_;
3513   int number_of_weak_calls_;
3514 };
3515
3516
3517 template<typename T>
3518 struct WeakCallCounterAndPersistent {
3519   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3520       : counter(counter) {}
3521   WeakCallCounter* counter;
3522   v8::Persistent<T> handle;
3523 };
3524
3525
3526 template <typename T>
3527 static void WeakPointerCallback(
3528     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3529   CHECK_EQ(1234, data.GetParameter()->counter->id());
3530   data.GetParameter()->counter->increment();
3531   data.GetParameter()->handle.Reset();
3532 }
3533
3534
3535 template<typename T>
3536 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3537   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3538 }
3539
3540
3541 THREADED_TEST(ApiObjectGroups) {
3542   LocalContext env;
3543   v8::Isolate* iso = env->GetIsolate();
3544   HandleScope scope(iso);
3545
3546   WeakCallCounter counter(1234);
3547
3548   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3549   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3550   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3551   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3552   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3553   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3554
3555   {
3556     HandleScope scope(iso);
3557     g1s1.handle.Reset(iso, Object::New(iso));
3558     g1s2.handle.Reset(iso, Object::New(iso));
3559     g1c1.handle.Reset(iso, Object::New(iso));
3560     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3561     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3562     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3563
3564     g2s1.handle.Reset(iso, Object::New(iso));
3565     g2s2.handle.Reset(iso, Object::New(iso));
3566     g2c1.handle.Reset(iso, Object::New(iso));
3567     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3568     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3569     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3570   }
3571
3572   WeakCallCounterAndPersistent<Value> root(&counter);
3573   root.handle.Reset(iso, g1s1.handle);  // make a root.
3574
3575   // Connect group 1 and 2, make a cycle.
3576   {
3577     HandleScope scope(iso);
3578     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3579             Set(0, Local<Value>::New(iso, g2s2.handle)));
3580     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3581             Set(0, Local<Value>::New(iso, g1s1.handle)));
3582   }
3583
3584   {
3585     UniqueId id1 = MakeUniqueId(g1s1.handle);
3586     UniqueId id2 = MakeUniqueId(g2s2.handle);
3587     iso->SetObjectGroupId(g1s1.handle, id1);
3588     iso->SetObjectGroupId(g1s2.handle, id1);
3589     iso->SetReferenceFromGroup(id1, g1c1.handle);
3590     iso->SetObjectGroupId(g2s1.handle, id2);
3591     iso->SetObjectGroupId(g2s2.handle, id2);
3592     iso->SetReferenceFromGroup(id2, g2c1.handle);
3593   }
3594   // Do a single full GC, ensure incremental marking is stopped.
3595   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3596       iso)->heap();
3597   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3598
3599   // All object should be alive.
3600   CHECK_EQ(0, counter.NumberOfWeakCalls());
3601
3602   // Weaken the root.
3603   root.handle.SetWeak(&root, &WeakPointerCallback);
3604   // But make children strong roots---all the objects (except for children)
3605   // should be collectable now.
3606   g1c1.handle.ClearWeak();
3607   g2c1.handle.ClearWeak();
3608
3609   // Groups are deleted, rebuild groups.
3610   {
3611     UniqueId id1 = MakeUniqueId(g1s1.handle);
3612     UniqueId id2 = MakeUniqueId(g2s2.handle);
3613     iso->SetObjectGroupId(g1s1.handle, id1);
3614     iso->SetObjectGroupId(g1s2.handle, id1);
3615     iso->SetReferenceFromGroup(id1, g1c1.handle);
3616     iso->SetObjectGroupId(g2s1.handle, id2);
3617     iso->SetObjectGroupId(g2s2.handle, id2);
3618     iso->SetReferenceFromGroup(id2, g2c1.handle);
3619   }
3620
3621   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3622
3623   // All objects should be gone. 5 global handles in total.
3624   CHECK_EQ(5, counter.NumberOfWeakCalls());
3625
3626   // And now make children weak again and collect them.
3627   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3628   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3629
3630   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3631   CHECK_EQ(7, counter.NumberOfWeakCalls());
3632 }
3633
3634
3635 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3636   LocalContext env;
3637   v8::Isolate* iso = env->GetIsolate();
3638   HandleScope scope(iso);
3639
3640   WeakCallCounter counter(1234);
3641
3642   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3643   WeakCallCounterAndPersistent<String> g1s2(&counter);
3644   WeakCallCounterAndPersistent<String> g1c1(&counter);
3645   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3646   WeakCallCounterAndPersistent<String> g2s2(&counter);
3647   WeakCallCounterAndPersistent<String> g2c1(&counter);
3648
3649   {
3650     HandleScope scope(iso);
3651     g1s1.handle.Reset(iso, Object::New(iso));
3652     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3653     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3654     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3655     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3656     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3657
3658     g2s1.handle.Reset(iso, Object::New(iso));
3659     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3660     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3661     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3662     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3663     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3664   }
3665
3666   WeakCallCounterAndPersistent<Value> root(&counter);
3667   root.handle.Reset(iso, g1s1.handle);  // make a root.
3668
3669   // Connect group 1 and 2, make a cycle.
3670   {
3671     HandleScope scope(iso);
3672     CHECK(Local<Object>::New(iso, g1s1.handle)
3673               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3674     CHECK(Local<Object>::New(iso, g2s1.handle)
3675               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3676   }
3677
3678   {
3679     UniqueId id1 = MakeUniqueId(g1s1.handle);
3680     UniqueId id2 = MakeUniqueId(g2s2.handle);
3681     iso->SetObjectGroupId(g1s1.handle, id1);
3682     iso->SetObjectGroupId(g1s2.handle, id1);
3683     iso->SetReference(g1s1.handle, g1c1.handle);
3684     iso->SetObjectGroupId(g2s1.handle, id2);
3685     iso->SetObjectGroupId(g2s2.handle, id2);
3686     iso->SetReferenceFromGroup(id2, g2c1.handle);
3687   }
3688   // Do a single full GC, ensure incremental marking is stopped.
3689   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3690       iso)->heap();
3691   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3692
3693   // All object should be alive.
3694   CHECK_EQ(0, counter.NumberOfWeakCalls());
3695
3696   // Weaken the root.
3697   root.handle.SetWeak(&root, &WeakPointerCallback);
3698   // But make children strong roots---all the objects (except for children)
3699   // should be collectable now.
3700   g1c1.handle.ClearWeak();
3701   g2c1.handle.ClearWeak();
3702
3703   // Groups are deleted, rebuild groups.
3704   {
3705     UniqueId id1 = MakeUniqueId(g1s1.handle);
3706     UniqueId id2 = MakeUniqueId(g2s2.handle);
3707     iso->SetObjectGroupId(g1s1.handle, id1);
3708     iso->SetObjectGroupId(g1s2.handle, id1);
3709     iso->SetReference(g1s1.handle, g1c1.handle);
3710     iso->SetObjectGroupId(g2s1.handle, id2);
3711     iso->SetObjectGroupId(g2s2.handle, id2);
3712     iso->SetReferenceFromGroup(id2, g2c1.handle);
3713   }
3714
3715   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3716
3717   // All objects should be gone. 5 global handles in total.
3718   CHECK_EQ(5, counter.NumberOfWeakCalls());
3719
3720   // And now make children weak again and collect them.
3721   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3722   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3723
3724   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3725   CHECK_EQ(7, counter.NumberOfWeakCalls());
3726 }
3727
3728
3729 THREADED_TEST(ApiObjectGroupsCycle) {
3730   LocalContext env;
3731   v8::Isolate* iso = env->GetIsolate();
3732   HandleScope scope(iso);
3733
3734   WeakCallCounter counter(1234);
3735
3736   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3737   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3738   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3739   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3740   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3741   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3742   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3743   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3744
3745   {
3746     HandleScope scope(iso);
3747     g1s1.handle.Reset(iso, Object::New(iso));
3748     g1s2.handle.Reset(iso, Object::New(iso));
3749     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3750     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3751     CHECK(g1s1.handle.IsWeak());
3752     CHECK(g1s2.handle.IsWeak());
3753
3754     g2s1.handle.Reset(iso, Object::New(iso));
3755     g2s2.handle.Reset(iso, Object::New(iso));
3756     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3757     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3758     CHECK(g2s1.handle.IsWeak());
3759     CHECK(g2s2.handle.IsWeak());
3760
3761     g3s1.handle.Reset(iso, Object::New(iso));
3762     g3s2.handle.Reset(iso, Object::New(iso));
3763     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3764     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3765     CHECK(g3s1.handle.IsWeak());
3766     CHECK(g3s2.handle.IsWeak());
3767
3768     g4s1.handle.Reset(iso, Object::New(iso));
3769     g4s2.handle.Reset(iso, Object::New(iso));
3770     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3771     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3772     CHECK(g4s1.handle.IsWeak());
3773     CHECK(g4s2.handle.IsWeak());
3774   }
3775
3776   WeakCallCounterAndPersistent<Value> root(&counter);
3777   root.handle.Reset(iso, g1s1.handle);  // make a root.
3778
3779   // Connect groups.  We're building the following cycle:
3780   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3781   // groups.
3782   {
3783     UniqueId id1 = MakeUniqueId(g1s1.handle);
3784     UniqueId id2 = MakeUniqueId(g2s1.handle);
3785     UniqueId id3 = MakeUniqueId(g3s1.handle);
3786     UniqueId id4 = MakeUniqueId(g4s1.handle);
3787     iso->SetObjectGroupId(g1s1.handle, id1);
3788     iso->SetObjectGroupId(g1s2.handle, id1);
3789     iso->SetReferenceFromGroup(id1, g2s1.handle);
3790     iso->SetObjectGroupId(g2s1.handle, id2);
3791     iso->SetObjectGroupId(g2s2.handle, id2);
3792     iso->SetReferenceFromGroup(id2, g3s1.handle);
3793     iso->SetObjectGroupId(g3s1.handle, id3);
3794     iso->SetObjectGroupId(g3s2.handle, id3);
3795     iso->SetReferenceFromGroup(id3, g4s1.handle);
3796     iso->SetObjectGroupId(g4s1.handle, id4);
3797     iso->SetObjectGroupId(g4s2.handle, id4);
3798     iso->SetReferenceFromGroup(id4, g1s1.handle);
3799   }
3800   // Do a single full GC
3801   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3802       iso)->heap();
3803   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3804
3805   // All object should be alive.
3806   CHECK_EQ(0, counter.NumberOfWeakCalls());
3807
3808   // Weaken the root.
3809   root.handle.SetWeak(&root, &WeakPointerCallback);
3810
3811   // Groups are deleted, rebuild groups.
3812   {
3813     UniqueId id1 = MakeUniqueId(g1s1.handle);
3814     UniqueId id2 = MakeUniqueId(g2s1.handle);
3815     UniqueId id3 = MakeUniqueId(g3s1.handle);
3816     UniqueId id4 = MakeUniqueId(g4s1.handle);
3817     iso->SetObjectGroupId(g1s1.handle, id1);
3818     iso->SetObjectGroupId(g1s2.handle, id1);
3819     iso->SetReferenceFromGroup(id1, g2s1.handle);
3820     iso->SetObjectGroupId(g2s1.handle, id2);
3821     iso->SetObjectGroupId(g2s2.handle, id2);
3822     iso->SetReferenceFromGroup(id2, g3s1.handle);
3823     iso->SetObjectGroupId(g3s1.handle, id3);
3824     iso->SetObjectGroupId(g3s2.handle, id3);
3825     iso->SetReferenceFromGroup(id3, g4s1.handle);
3826     iso->SetObjectGroupId(g4s1.handle, id4);
3827     iso->SetObjectGroupId(g4s2.handle, id4);
3828     iso->SetReferenceFromGroup(id4, g1s1.handle);
3829   }
3830
3831   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3832
3833   // All objects should be gone. 9 global handles in total.
3834   CHECK_EQ(9, counter.NumberOfWeakCalls());
3835 }
3836
3837
3838 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3839 // on the buildbots, so was made non-threaded for the time being.
3840 TEST(ApiObjectGroupsCycleForScavenger) {
3841   i::FLAG_stress_compaction = false;
3842   i::FLAG_gc_global = false;
3843   LocalContext env;
3844   v8::Isolate* iso = env->GetIsolate();
3845   HandleScope scope(iso);
3846
3847   WeakCallCounter counter(1234);
3848
3849   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3850   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3851   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3852   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3853   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3854   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3855
3856   {
3857     HandleScope scope(iso);
3858     g1s1.handle.Reset(iso, Object::New(iso));
3859     g1s2.handle.Reset(iso, Object::New(iso));
3860     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3861     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3862
3863     g2s1.handle.Reset(iso, Object::New(iso));
3864     g2s2.handle.Reset(iso, Object::New(iso));
3865     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3866     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3867
3868     g3s1.handle.Reset(iso, Object::New(iso));
3869     g3s2.handle.Reset(iso, Object::New(iso));
3870     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3871     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3872   }
3873
3874   // Make a root.
3875   WeakCallCounterAndPersistent<Value> root(&counter);
3876   root.handle.Reset(iso, g1s1.handle);
3877   root.handle.MarkPartiallyDependent();
3878
3879   // Connect groups.  We're building the following cycle:
3880   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3881   // groups.
3882   {
3883     HandleScope handle_scope(iso);
3884     g1s1.handle.MarkPartiallyDependent();
3885     g1s2.handle.MarkPartiallyDependent();
3886     g2s1.handle.MarkPartiallyDependent();
3887     g2s2.handle.MarkPartiallyDependent();
3888     g3s1.handle.MarkPartiallyDependent();
3889     g3s2.handle.MarkPartiallyDependent();
3890     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3891     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3892     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3893         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3894     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3895     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3896     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3897         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3898     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3899     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3900     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3901         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3902   }
3903
3904   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3905       iso)->heap();
3906   heap->CollectGarbage(i::NEW_SPACE);
3907
3908   // All objects should be alive.
3909   CHECK_EQ(0, counter.NumberOfWeakCalls());
3910
3911   // Weaken the root.
3912   root.handle.SetWeak(&root, &WeakPointerCallback);
3913   root.handle.MarkPartiallyDependent();
3914
3915   // Groups are deleted, rebuild groups.
3916   {
3917     HandleScope handle_scope(iso);
3918     g1s1.handle.MarkPartiallyDependent();
3919     g1s2.handle.MarkPartiallyDependent();
3920     g2s1.handle.MarkPartiallyDependent();
3921     g2s2.handle.MarkPartiallyDependent();
3922     g3s1.handle.MarkPartiallyDependent();
3923     g3s2.handle.MarkPartiallyDependent();
3924     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3925     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3926     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3927         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3928     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3929     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3930     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3931         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3932     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3933     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3934     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3935         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3936   }
3937
3938   heap->CollectGarbage(i::NEW_SPACE);
3939
3940   // All objects should be gone. 7 global handles in total.
3941   CHECK_EQ(7, counter.NumberOfWeakCalls());
3942 }
3943
3944
3945 THREADED_TEST(ScriptException) {
3946   LocalContext env;
3947   v8::HandleScope scope(env->GetIsolate());
3948   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3949   v8::TryCatch try_catch;
3950   Local<Value> result = script->Run();
3951   CHECK(result.IsEmpty());
3952   CHECK(try_catch.HasCaught());
3953   String::Utf8Value exception_value(try_catch.Exception());
3954   CHECK_EQ(*exception_value, "panama!");
3955 }
3956
3957
3958 TEST(TryCatchCustomException) {
3959   LocalContext env;
3960   v8::HandleScope scope(env->GetIsolate());
3961   v8::TryCatch try_catch;
3962   CompileRun("function CustomError() { this.a = 'b'; }"
3963              "(function f() { throw new CustomError(); })();");
3964   CHECK(try_catch.HasCaught());
3965   CHECK(try_catch.Exception()->ToObject()->
3966             Get(v8_str("a"))->Equals(v8_str("b")));
3967 }
3968
3969
3970 bool message_received;
3971
3972
3973 static void check_message_0(v8::Handle<v8::Message> message,
3974                             v8::Handle<Value> data) {
3975   CHECK_EQ(5.76, data->NumberValue());
3976   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3977   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3978   CHECK(!message->IsSharedCrossOrigin());
3979   message_received = true;
3980 }
3981
3982
3983 THREADED_TEST(MessageHandler0) {
3984   message_received = false;
3985   v8::HandleScope scope(CcTest::isolate());
3986   CHECK(!message_received);
3987   LocalContext context;
3988   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3989   v8::ScriptOrigin origin =
3990       v8::ScriptOrigin(v8_str("6.75"));
3991   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3992                                                   &origin);
3993   script->SetData(v8_str("7.56"));
3994   script->Run();
3995   CHECK(message_received);
3996   // clear out the message listener
3997   v8::V8::RemoveMessageListeners(check_message_0);
3998 }
3999
4000
4001 static void check_message_1(v8::Handle<v8::Message> message,
4002                             v8::Handle<Value> data) {
4003   CHECK(data->IsNumber());
4004   CHECK_EQ(1337, data->Int32Value());
4005   CHECK(!message->IsSharedCrossOrigin());
4006   message_received = true;
4007 }
4008
4009
4010 TEST(MessageHandler1) {
4011   message_received = false;
4012   v8::HandleScope scope(CcTest::isolate());
4013   CHECK(!message_received);
4014   v8::V8::AddMessageListener(check_message_1);
4015   LocalContext context;
4016   CompileRun("throw 1337;");
4017   CHECK(message_received);
4018   // clear out the message listener
4019   v8::V8::RemoveMessageListeners(check_message_1);
4020 }
4021
4022
4023 static void check_message_2(v8::Handle<v8::Message> message,
4024                             v8::Handle<Value> data) {
4025   LocalContext context;
4026   CHECK(data->IsObject());
4027   v8::Local<v8::Value> hidden_property =
4028       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4029   CHECK(v8_str("hidden value")->Equals(hidden_property));
4030   CHECK(!message->IsSharedCrossOrigin());
4031   message_received = true;
4032 }
4033
4034
4035 TEST(MessageHandler2) {
4036   message_received = false;
4037   v8::HandleScope scope(CcTest::isolate());
4038   CHECK(!message_received);
4039   v8::V8::AddMessageListener(check_message_2);
4040   LocalContext context;
4041   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4042   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4043                                            v8_str("hidden value"));
4044   context->Global()->Set(v8_str("error"), error);
4045   CompileRun("throw error;");
4046   CHECK(message_received);
4047   // clear out the message listener
4048   v8::V8::RemoveMessageListeners(check_message_2);
4049 }
4050
4051
4052 static void check_message_3(v8::Handle<v8::Message> message,
4053                             v8::Handle<Value> data) {
4054   CHECK(message->IsSharedCrossOrigin());
4055   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4056   message_received = true;
4057 }
4058
4059
4060 TEST(MessageHandler3) {
4061   message_received = false;
4062   v8::Isolate* isolate = CcTest::isolate();
4063   v8::HandleScope scope(isolate);
4064   CHECK(!message_received);
4065   v8::V8::AddMessageListener(check_message_3);
4066   LocalContext context;
4067   v8::ScriptOrigin origin =
4068       v8::ScriptOrigin(v8_str("6.75"),
4069                        v8::Integer::New(isolate, 1),
4070                        v8::Integer::New(isolate, 2),
4071                        v8::True(isolate));
4072   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4073                                                   &origin);
4074   script->Run();
4075   CHECK(message_received);
4076   // clear out the message listener
4077   v8::V8::RemoveMessageListeners(check_message_3);
4078 }
4079
4080
4081 static void check_message_4(v8::Handle<v8::Message> message,
4082                             v8::Handle<Value> data) {
4083   CHECK(!message->IsSharedCrossOrigin());
4084   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4085   message_received = true;
4086 }
4087
4088
4089 TEST(MessageHandler4) {
4090   message_received = false;
4091   v8::Isolate* isolate = CcTest::isolate();
4092   v8::HandleScope scope(isolate);
4093   CHECK(!message_received);
4094   v8::V8::AddMessageListener(check_message_4);
4095   LocalContext context;
4096   v8::ScriptOrigin origin =
4097       v8::ScriptOrigin(v8_str("6.75"),
4098                        v8::Integer::New(isolate, 1),
4099                        v8::Integer::New(isolate, 2),
4100                        v8::False(isolate));
4101   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4102                                                   &origin);
4103   script->Run();
4104   CHECK(message_received);
4105   // clear out the message listener
4106   v8::V8::RemoveMessageListeners(check_message_4);
4107 }
4108
4109
4110 static void check_message_5a(v8::Handle<v8::Message> message,
4111                             v8::Handle<Value> data) {
4112   CHECK(message->IsSharedCrossOrigin());
4113   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4114   message_received = true;
4115 }
4116
4117
4118 static void check_message_5b(v8::Handle<v8::Message> message,
4119                             v8::Handle<Value> data) {
4120   CHECK(!message->IsSharedCrossOrigin());
4121   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4122   message_received = true;
4123 }
4124
4125
4126 TEST(MessageHandler5) {
4127   message_received = false;
4128   v8::Isolate* isolate = CcTest::isolate();
4129   v8::HandleScope scope(isolate);
4130   CHECK(!message_received);
4131   v8::V8::AddMessageListener(check_message_5a);
4132   LocalContext context;
4133   v8::ScriptOrigin origin =
4134       v8::ScriptOrigin(v8_str("6.75"),
4135                        v8::Integer::New(isolate, 1),
4136                        v8::Integer::New(isolate, 2),
4137                        v8::True(isolate));
4138   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4139                                                   &origin);
4140   script->Run();
4141   CHECK(message_received);
4142   // clear out the message listener
4143   v8::V8::RemoveMessageListeners(check_message_5a);
4144
4145   message_received = false;
4146   v8::V8::AddMessageListener(check_message_5b);
4147   origin =
4148       v8::ScriptOrigin(v8_str("6.75"),
4149                        v8::Integer::New(isolate, 1),
4150                        v8::Integer::New(isolate, 2),
4151                        v8::False(isolate));
4152   script = Script::Compile(v8_str("throw 'error'"),
4153                            &origin);
4154   script->Run();
4155   CHECK(message_received);
4156   // clear out the message listener
4157   v8::V8::RemoveMessageListeners(check_message_5b);
4158 }
4159
4160
4161 THREADED_TEST(GetSetProperty) {
4162   LocalContext context;
4163   v8::Isolate* isolate = context->GetIsolate();
4164   v8::HandleScope scope(isolate);
4165   context->Global()->Set(v8_str("foo"), v8_num(14));
4166   context->Global()->Set(v8_str("12"), v8_num(92));
4167   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4168   context->Global()->Set(v8_num(13), v8_num(56));
4169   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
4170   CHECK_EQ(14, foo->Int32Value());
4171   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
4172   CHECK_EQ(92, twelve->Int32Value());
4173   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
4174   CHECK_EQ(32, sixteen->Int32Value());
4175   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
4176   CHECK_EQ(56, thirteen->Int32Value());
4177   CHECK_EQ(92,
4178            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4179   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4180   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4181   CHECK_EQ(32,
4182            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4183   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4184   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4185   CHECK_EQ(56,
4186            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4187   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4188   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4189 }
4190
4191
4192 THREADED_TEST(PropertyAttributes) {
4193   LocalContext context;
4194   v8::HandleScope scope(context->GetIsolate());
4195   // none
4196   Local<String> prop = v8_str("none");
4197   context->Global()->Set(prop, v8_num(7));
4198   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4199   // read-only
4200   prop = v8_str("read_only");
4201   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4202   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4203   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4204   Script::Compile(v8_str("read_only = 9"))->Run();
4205   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4206   context->Global()->Set(prop, v8_num(10));
4207   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4208   // dont-delete
4209   prop = v8_str("dont_delete");
4210   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4211   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4212   Script::Compile(v8_str("delete dont_delete"))->Run();
4213   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4214   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4215   // dont-enum
4216   prop = v8_str("dont_enum");
4217   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4218   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4219   // absent
4220   prop = v8_str("absent");
4221   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4222   Local<Value> fake_prop = v8_num(1);
4223   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4224   // exception
4225   TryCatch try_catch;
4226   Local<Value> exception =
4227       CompileRun("({ toString: function() { throw 'exception';} })");
4228   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4229   CHECK(try_catch.HasCaught());
4230   String::Utf8Value exception_value(try_catch.Exception());
4231   CHECK_EQ("exception", *exception_value);
4232   try_catch.Reset();
4233 }
4234
4235
4236 THREADED_TEST(Array) {
4237   LocalContext context;
4238   v8::HandleScope scope(context->GetIsolate());
4239   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4240   CHECK_EQ(0, array->Length());
4241   CHECK(array->Get(0)->IsUndefined());
4242   CHECK(!array->Has(0));
4243   CHECK(array->Get(100)->IsUndefined());
4244   CHECK(!array->Has(100));
4245   array->Set(2, v8_num(7));
4246   CHECK_EQ(3, array->Length());
4247   CHECK(!array->Has(0));
4248   CHECK(!array->Has(1));
4249   CHECK(array->Has(2));
4250   CHECK_EQ(7, array->Get(2)->Int32Value());
4251   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
4252   Local<v8::Array> arr = obj.As<v8::Array>();
4253   CHECK_EQ(3, arr->Length());
4254   CHECK_EQ(1, arr->Get(0)->Int32Value());
4255   CHECK_EQ(2, arr->Get(1)->Int32Value());
4256   CHECK_EQ(3, arr->Get(2)->Int32Value());
4257   array = v8::Array::New(context->GetIsolate(), 27);
4258   CHECK_EQ(27, array->Length());
4259   array = v8::Array::New(context->GetIsolate(), -27);
4260   CHECK_EQ(0, array->Length());
4261 }
4262
4263
4264 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4265   v8::EscapableHandleScope scope(args.GetIsolate());
4266   ApiTestFuzzer::Fuzz();
4267   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4268   for (int i = 0; i < args.Length(); i++)
4269     result->Set(i, args[i]);
4270   args.GetReturnValue().Set(scope.Escape(result));
4271 }
4272
4273
4274 THREADED_TEST(Vector) {
4275   v8::Isolate* isolate = CcTest::isolate();
4276   v8::HandleScope scope(isolate);
4277   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4278   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4279   LocalContext context(0, global);
4280
4281   const char* fun = "f()";
4282   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4283   CHECK_EQ(0, a0->Length());
4284
4285   const char* fun2 = "f(11)";
4286   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4287   CHECK_EQ(1, a1->Length());
4288   CHECK_EQ(11, a1->Get(0)->Int32Value());
4289
4290   const char* fun3 = "f(12, 13)";
4291   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4292   CHECK_EQ(2, a2->Length());
4293   CHECK_EQ(12, a2->Get(0)->Int32Value());
4294   CHECK_EQ(13, a2->Get(1)->Int32Value());
4295
4296   const char* fun4 = "f(14, 15, 16)";
4297   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4298   CHECK_EQ(3, a3->Length());
4299   CHECK_EQ(14, a3->Get(0)->Int32Value());
4300   CHECK_EQ(15, a3->Get(1)->Int32Value());
4301   CHECK_EQ(16, a3->Get(2)->Int32Value());
4302
4303   const char* fun5 = "f(17, 18, 19, 20)";
4304   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4305   CHECK_EQ(4, a4->Length());
4306   CHECK_EQ(17, a4->Get(0)->Int32Value());
4307   CHECK_EQ(18, a4->Get(1)->Int32Value());
4308   CHECK_EQ(19, a4->Get(2)->Int32Value());
4309   CHECK_EQ(20, a4->Get(3)->Int32Value());
4310 }
4311
4312
4313 THREADED_TEST(FunctionCall) {
4314   LocalContext context;
4315   v8::Isolate* isolate = context->GetIsolate();
4316   v8::HandleScope scope(isolate);
4317   CompileRun(
4318     "function Foo() {"
4319     "  var result = [];"
4320     "  for (var i = 0; i < arguments.length; i++) {"
4321     "    result.push(arguments[i]);"
4322     "  }"
4323     "  return result;"
4324     "}"
4325     "function ReturnThisSloppy() {"
4326     "  return this;"
4327     "}"
4328     "function ReturnThisStrict() {"
4329     "  'use strict';"
4330     "  return this;"
4331     "}");
4332   Local<Function> Foo =
4333       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4334   Local<Function> ReturnThisSloppy =
4335       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4336   Local<Function> ReturnThisStrict =
4337       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4338
4339   v8::Handle<Value>* args0 = NULL;
4340   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4341   CHECK_EQ(0, a0->Length());
4342
4343   v8::Handle<Value> args1[] = { v8_num(1.1) };
4344   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4345   CHECK_EQ(1, a1->Length());
4346   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4347
4348   v8::Handle<Value> args2[] = { v8_num(2.2),
4349                                 v8_num(3.3) };
4350   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4351   CHECK_EQ(2, a2->Length());
4352   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4353   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4354
4355   v8::Handle<Value> args3[] = { v8_num(4.4),
4356                                 v8_num(5.5),
4357                                 v8_num(6.6) };
4358   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4359   CHECK_EQ(3, a3->Length());
4360   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4361   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4362   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4363
4364   v8::Handle<Value> args4[] = { v8_num(7.7),
4365                                 v8_num(8.8),
4366                                 v8_num(9.9),
4367                                 v8_num(10.11) };
4368   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4369   CHECK_EQ(4, a4->Length());
4370   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4371   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4372   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4373   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4374
4375   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4376   CHECK(r1->StrictEquals(context->Global()));
4377   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4378   CHECK(r2->StrictEquals(context->Global()));
4379   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4380   CHECK(r3->IsNumberObject());
4381   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4382   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4383   CHECK(r4->IsStringObject());
4384   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4385   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4386   CHECK(r5->IsBooleanObject());
4387   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4388
4389   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4390   CHECK(r6->IsUndefined());
4391   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4392   CHECK(r7->IsNull());
4393   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4394   CHECK(r8->StrictEquals(v8_num(42)));
4395   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4396   CHECK(r9->StrictEquals(v8_str("hello")));
4397   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4398   CHECK(r10->StrictEquals(v8::True(isolate)));
4399 }
4400
4401
4402 static const char* js_code_causing_out_of_memory =
4403     "var a = new Array(); while(true) a.push(a);";
4404
4405
4406 // These tests run for a long time and prevent us from running tests
4407 // that come after them so they cannot run in parallel.
4408 TEST(OutOfMemory) {
4409   // It's not possible to read a snapshot into a heap with different dimensions.
4410   if (i::Snapshot::IsEnabled()) return;
4411   // Set heap limits.
4412   static const int K = 1024;
4413   v8::ResourceConstraints constraints;
4414   constraints.set_max_young_space_size(256 * K);
4415   constraints.set_max_old_space_size(5 * K * K);
4416   v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4417
4418   // Execute a script that causes out of memory.
4419   LocalContext context;
4420   v8::HandleScope scope(context->GetIsolate());
4421   v8::V8::IgnoreOutOfMemoryException();
4422   Local<Script> script = Script::Compile(String::NewFromUtf8(
4423       context->GetIsolate(), js_code_causing_out_of_memory));
4424   Local<Value> result = script->Run();
4425
4426   // Check for out of memory state.
4427   CHECK(result.IsEmpty());
4428   CHECK(context->HasOutOfMemoryException());
4429 }
4430
4431
4432 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4433   ApiTestFuzzer::Fuzz();
4434
4435   LocalContext context;
4436   v8::HandleScope scope(context->GetIsolate());
4437   Local<Script> script = Script::Compile(String::NewFromUtf8(
4438       context->GetIsolate(), js_code_causing_out_of_memory));
4439   Local<Value> result = script->Run();
4440
4441   // Check for out of memory state.
4442   CHECK(result.IsEmpty());
4443   CHECK(context->HasOutOfMemoryException());
4444
4445   args.GetReturnValue().Set(result);
4446 }
4447
4448
4449 TEST(OutOfMemoryNested) {
4450   // It's not possible to read a snapshot into a heap with different dimensions.
4451   if (i::Snapshot::IsEnabled()) return;
4452   // Set heap limits.
4453   static const int K = 1024;
4454   v8::ResourceConstraints constraints;
4455   constraints.set_max_young_space_size(256 * K);
4456   constraints.set_max_old_space_size(5 * K * K);
4457   v8::Isolate* isolate = CcTest::isolate();
4458   v8::SetResourceConstraints(isolate, &constraints);
4459
4460   v8::HandleScope scope(isolate);
4461   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4462   templ->Set(v8_str("ProvokeOutOfMemory"),
4463              v8::FunctionTemplate::New(isolate, ProvokeOutOfMemory));
4464   LocalContext context(0, templ);
4465   v8::V8::IgnoreOutOfMemoryException();
4466   Local<Value> result = CompileRun(
4467     "var thrown = false;"
4468     "try {"
4469     "  ProvokeOutOfMemory();"
4470     "} catch (e) {"
4471     "  thrown = true;"
4472     "}");
4473   // Check for out of memory state.
4474   CHECK(result.IsEmpty());
4475   CHECK(context->HasOutOfMemoryException());
4476 }
4477
4478
4479 void OOMCallback(const char* location, const char* message) {
4480   exit(0);
4481 }
4482
4483
4484 TEST(HugeConsStringOutOfMemory) {
4485   // It's not possible to read a snapshot into a heap with different dimensions.
4486   if (i::Snapshot::IsEnabled()) return;
4487   // Set heap limits.
4488   static const int K = 1024;
4489   v8::ResourceConstraints constraints;
4490   constraints.set_max_young_space_size(256 * K);
4491   constraints.set_max_old_space_size(4 * K * K);
4492   v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4493
4494   // Execute a script that causes out of memory.
4495   v8::V8::SetFatalErrorHandler(OOMCallback);
4496
4497   LocalContext context;
4498   v8::HandleScope scope(context->GetIsolate());
4499
4500   // Build huge string. This should fail with out of memory exception.
4501   CompileRun(
4502     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4503     "for (var i = 0; i < 22; i++) { str = str + str; }");
4504
4505   CHECK(false);  // Should not return.
4506 }
4507
4508
4509 THREADED_TEST(ConstructCall) {
4510   LocalContext context;
4511   v8::Isolate* isolate = context->GetIsolate();
4512   v8::HandleScope scope(isolate);
4513   CompileRun(
4514     "function Foo() {"
4515     "  var result = [];"
4516     "  for (var i = 0; i < arguments.length; i++) {"
4517     "    result.push(arguments[i]);"
4518     "  }"
4519     "  return result;"
4520     "}");
4521   Local<Function> Foo =
4522       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4523
4524   v8::Handle<Value>* args0 = NULL;
4525   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4526   CHECK_EQ(0, a0->Length());
4527
4528   v8::Handle<Value> args1[] = { v8_num(1.1) };
4529   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4530   CHECK_EQ(1, a1->Length());
4531   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4532
4533   v8::Handle<Value> args2[] = { v8_num(2.2),
4534                                 v8_num(3.3) };
4535   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4536   CHECK_EQ(2, a2->Length());
4537   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4538   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4539
4540   v8::Handle<Value> args3[] = { v8_num(4.4),
4541                                 v8_num(5.5),
4542                                 v8_num(6.6) };
4543   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4544   CHECK_EQ(3, a3->Length());
4545   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4546   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4547   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4548
4549   v8::Handle<Value> args4[] = { v8_num(7.7),
4550                                 v8_num(8.8),
4551                                 v8_num(9.9),
4552                                 v8_num(10.11) };
4553   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4554   CHECK_EQ(4, a4->Length());
4555   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4556   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4557   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4558   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4559 }
4560
4561
4562 static void CheckUncle(v8::TryCatch* try_catch) {
4563   CHECK(try_catch->HasCaught());
4564   String::Utf8Value str_value(try_catch->Exception());
4565   CHECK_EQ(*str_value, "uncle?");
4566   try_catch->Reset();
4567 }
4568
4569
4570 THREADED_TEST(ConversionNumber) {
4571   LocalContext env;
4572   v8::HandleScope scope(env->GetIsolate());
4573   // Very large number.
4574   CompileRun("var obj = Math.pow(2,32) * 1237;");
4575   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4576   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4577   CHECK_EQ(0, obj->ToInt32()->Value());
4578   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4579   // Large number.
4580   CompileRun("var obj = -1234567890123;");
4581   obj = env->Global()->Get(v8_str("obj"));
4582   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4583   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4584   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4585   // Small positive integer.
4586   CompileRun("var obj = 42;");
4587   obj = env->Global()->Get(v8_str("obj"));
4588   CHECK_EQ(42.0, obj->ToNumber()->Value());
4589   CHECK_EQ(42, obj->ToInt32()->Value());
4590   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4591   // Negative integer.
4592   CompileRun("var obj = -37;");
4593   obj = env->Global()->Get(v8_str("obj"));
4594   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4595   CHECK_EQ(-37, obj->ToInt32()->Value());
4596   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4597   // Positive non-int32 integer.
4598   CompileRun("var obj = 0x81234567;");
4599   obj = env->Global()->Get(v8_str("obj"));
4600   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4601   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4602   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4603   // Fraction.
4604   CompileRun("var obj = 42.3;");
4605   obj = env->Global()->Get(v8_str("obj"));
4606   CHECK_EQ(42.3, obj->ToNumber()->Value());
4607   CHECK_EQ(42, obj->ToInt32()->Value());
4608   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4609   // Large negative fraction.
4610   CompileRun("var obj = -5726623061.75;");
4611   obj = env->Global()->Get(v8_str("obj"));
4612   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4613   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4614   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4615 }
4616
4617
4618 THREADED_TEST(isNumberType) {
4619   LocalContext env;
4620   v8::HandleScope scope(env->GetIsolate());
4621   // Very large number.
4622   CompileRun("var obj = Math.pow(2,32) * 1237;");
4623   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4624   CHECK(!obj->IsInt32());
4625   CHECK(!obj->IsUint32());
4626   // Large negative number.
4627   CompileRun("var obj = -1234567890123;");
4628   obj = env->Global()->Get(v8_str("obj"));
4629   CHECK(!obj->IsInt32());
4630   CHECK(!obj->IsUint32());
4631   // Small positive integer.
4632   CompileRun("var obj = 42;");
4633   obj = env->Global()->Get(v8_str("obj"));
4634   CHECK(obj->IsInt32());
4635   CHECK(obj->IsUint32());
4636   // Negative integer.
4637   CompileRun("var obj = -37;");
4638   obj = env->Global()->Get(v8_str("obj"));
4639   CHECK(obj->IsInt32());
4640   CHECK(!obj->IsUint32());
4641   // Positive non-int32 integer.
4642   CompileRun("var obj = 0x81234567;");
4643   obj = env->Global()->Get(v8_str("obj"));
4644   CHECK(!obj->IsInt32());
4645   CHECK(obj->IsUint32());
4646   // Fraction.
4647   CompileRun("var obj = 42.3;");
4648   obj = env->Global()->Get(v8_str("obj"));
4649   CHECK(!obj->IsInt32());
4650   CHECK(!obj->IsUint32());
4651   // Large negative fraction.
4652   CompileRun("var obj = -5726623061.75;");
4653   obj = env->Global()->Get(v8_str("obj"));
4654   CHECK(!obj->IsInt32());
4655   CHECK(!obj->IsUint32());
4656   // Positive zero
4657   CompileRun("var obj = 0.0;");
4658   obj = env->Global()->Get(v8_str("obj"));
4659   CHECK(obj->IsInt32());
4660   CHECK(obj->IsUint32());
4661   // Positive zero
4662   CompileRun("var obj = -0.0;");
4663   obj = env->Global()->Get(v8_str("obj"));
4664   CHECK(!obj->IsInt32());
4665   CHECK(!obj->IsUint32());
4666 }
4667
4668
4669 THREADED_TEST(ConversionException) {
4670   LocalContext env;
4671   v8::Isolate* isolate = env->GetIsolate();
4672   v8::HandleScope scope(isolate);
4673   CompileRun(
4674     "function TestClass() { };"
4675     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4676     "var obj = new TestClass();");
4677   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4678
4679   v8::TryCatch try_catch;
4680
4681   Local<Value> to_string_result = obj->ToString();
4682   CHECK(to_string_result.IsEmpty());
4683   CheckUncle(&try_catch);
4684
4685   Local<Value> to_number_result = obj->ToNumber();
4686   CHECK(to_number_result.IsEmpty());
4687   CheckUncle(&try_catch);
4688
4689   Local<Value> to_integer_result = obj->ToInteger();
4690   CHECK(to_integer_result.IsEmpty());
4691   CheckUncle(&try_catch);
4692
4693   Local<Value> to_uint32_result = obj->ToUint32();
4694   CHECK(to_uint32_result.IsEmpty());
4695   CheckUncle(&try_catch);
4696
4697   Local<Value> to_int32_result = obj->ToInt32();
4698   CHECK(to_int32_result.IsEmpty());
4699   CheckUncle(&try_catch);
4700
4701   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4702   CHECK(to_object_result.IsEmpty());
4703   CHECK(try_catch.HasCaught());
4704   try_catch.Reset();
4705
4706   int32_t int32_value = obj->Int32Value();
4707   CHECK_EQ(0, int32_value);
4708   CheckUncle(&try_catch);
4709
4710   uint32_t uint32_value = obj->Uint32Value();
4711   CHECK_EQ(0, uint32_value);
4712   CheckUncle(&try_catch);
4713
4714   double number_value = obj->NumberValue();
4715   CHECK_NE(0, std::isnan(number_value));
4716   CheckUncle(&try_catch);
4717
4718   int64_t integer_value = obj->IntegerValue();
4719   CHECK_EQ(0.0, static_cast<double>(integer_value));
4720   CheckUncle(&try_catch);
4721 }
4722
4723
4724 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4725   ApiTestFuzzer::Fuzz();
4726   args.GetIsolate()->ThrowException(v8_str("konto"));
4727 }
4728
4729
4730 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4731   if (args.Length() < 1) {
4732     args.GetReturnValue().Set(false);
4733     return;
4734   }
4735   v8::HandleScope scope(args.GetIsolate());
4736   v8::TryCatch try_catch;
4737   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4738   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4739   args.GetReturnValue().Set(try_catch.HasCaught());
4740 }
4741
4742
4743 THREADED_TEST(APICatch) {
4744   v8::Isolate* isolate = CcTest::isolate();
4745   v8::HandleScope scope(isolate);
4746   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4747   templ->Set(v8_str("ThrowFromC"),
4748              v8::FunctionTemplate::New(isolate, ThrowFromC));
4749   LocalContext context(0, templ);
4750   CompileRun(
4751     "var thrown = false;"
4752     "try {"
4753     "  ThrowFromC();"
4754     "} catch (e) {"
4755     "  thrown = true;"
4756     "}");
4757   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4758   CHECK(thrown->BooleanValue());
4759 }
4760
4761
4762 THREADED_TEST(APIThrowTryCatch) {
4763   v8::Isolate* isolate = CcTest::isolate();
4764   v8::HandleScope scope(isolate);
4765   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4766   templ->Set(v8_str("ThrowFromC"),
4767              v8::FunctionTemplate::New(isolate, ThrowFromC));
4768   LocalContext context(0, templ);
4769   v8::TryCatch try_catch;
4770   CompileRun("ThrowFromC();");
4771   CHECK(try_catch.HasCaught());
4772 }
4773
4774
4775 // Test that a try-finally block doesn't shadow a try-catch block
4776 // when setting up an external handler.
4777 //
4778 // BUG(271): Some of the exception propagation does not work on the
4779 // ARM simulator because the simulator separates the C++ stack and the
4780 // JS stack.  This test therefore fails on the simulator.  The test is
4781 // not threaded to allow the threading tests to run on the simulator.
4782 TEST(TryCatchInTryFinally) {
4783   v8::Isolate* isolate = CcTest::isolate();
4784   v8::HandleScope scope(isolate);
4785   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4786   templ->Set(v8_str("CCatcher"),
4787              v8::FunctionTemplate::New(isolate, CCatcher));
4788   LocalContext context(0, templ);
4789   Local<Value> result = CompileRun("try {"
4790                                    "  try {"
4791                                    "    CCatcher('throw 7;');"
4792                                    "  } finally {"
4793                                    "  }"
4794                                    "} catch (e) {"
4795                                    "}");
4796   CHECK(result->IsTrue());
4797 }
4798
4799
4800 static void check_reference_error_message(
4801     v8::Handle<v8::Message> message,
4802     v8::Handle<v8::Value> data) {
4803   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4804   CHECK(message->Get()->Equals(v8_str(reference_error)));
4805 }
4806
4807
4808 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4809   ApiTestFuzzer::Fuzz();
4810   CHECK(false);
4811 }
4812
4813
4814 // Test that overwritten methods are not invoked on uncaught exception
4815 // formatting. However, they are invoked when performing normal error
4816 // string conversions.
4817 TEST(APIThrowMessageOverwrittenToString) {
4818   v8::Isolate* isolate = CcTest::isolate();
4819   v8::HandleScope scope(isolate);
4820   v8::V8::AddMessageListener(check_reference_error_message);
4821   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4822   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4823   LocalContext context(NULL, templ);
4824   CompileRun("asdf;");
4825   CompileRun("var limit = {};"
4826              "limit.valueOf = fail;"
4827              "Error.stackTraceLimit = limit;");
4828   CompileRun("asdf");
4829   CompileRun("Array.prototype.pop = fail;");
4830   CompileRun("Object.prototype.hasOwnProperty = fail;");
4831   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4832   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4833   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4834   CompileRun("ReferenceError.prototype.toString ="
4835              "  function() { return 'Whoops' }");
4836   CompileRun("asdf;");
4837   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4838   CompileRun("asdf;");
4839   CompileRun("ReferenceError.prototype.constructor = void 0;");
4840   CompileRun("asdf;");
4841   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4842   CompileRun("asdf;");
4843   CompileRun("ReferenceError.prototype = new Object();");
4844   CompileRun("asdf;");
4845   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4846   CHECK(string->Equals(v8_str("Whoops")));
4847   CompileRun("ReferenceError.prototype.constructor = new Object();"
4848              "ReferenceError.prototype.constructor.name = 1;"
4849              "Number.prototype.toString = function() { return 'Whoops'; };"
4850              "ReferenceError.prototype.toString = Object.prototype.toString;");
4851   CompileRun("asdf;");
4852   v8::V8::RemoveMessageListeners(check_reference_error_message);
4853 }
4854
4855
4856 static void check_custom_error_tostring(
4857     v8::Handle<v8::Message> message,
4858     v8::Handle<v8::Value> data) {
4859   const char* uncaught_error = "Uncaught MyError toString";
4860   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4861 }
4862
4863
4864 TEST(CustomErrorToString) {
4865   LocalContext context;
4866   v8::HandleScope scope(context->GetIsolate());
4867   v8::V8::AddMessageListener(check_custom_error_tostring);
4868   CompileRun(
4869     "function MyError(name, message) {                   "
4870     "  this.name = name;                                 "
4871     "  this.message = message;                           "
4872     "}                                                   "
4873     "MyError.prototype = Object.create(Error.prototype); "
4874     "MyError.prototype.toString = function() {           "
4875     "  return 'MyError toString';                        "
4876     "};                                                  "
4877     "throw new MyError('my name', 'my message');         ");
4878   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4879 }
4880
4881
4882 static void check_custom_error_message(
4883     v8::Handle<v8::Message> message,
4884     v8::Handle<v8::Value> data) {
4885   const char* uncaught_error = "Uncaught MyError: my message";
4886   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4887   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4888 }
4889
4890
4891 TEST(CustomErrorMessage) {
4892   LocalContext context;
4893   v8::HandleScope scope(context->GetIsolate());
4894   v8::V8::AddMessageListener(check_custom_error_message);
4895
4896   // Handlebars.
4897   CompileRun(
4898     "function MyError(msg) {                             "
4899     "  this.name = 'MyError';                            "
4900     "  this.message = msg;                               "
4901     "}                                                   "
4902     "MyError.prototype = new Error();                    "
4903     "throw new MyError('my message');                    ");
4904
4905   // Closure.
4906   CompileRun(
4907     "function MyError(msg) {                             "
4908     "  this.name = 'MyError';                            "
4909     "  this.message = msg;                               "
4910     "}                                                   "
4911     "inherits = function(childCtor, parentCtor) {        "
4912     "    function tempCtor() {};                         "
4913     "    tempCtor.prototype = parentCtor.prototype;      "
4914     "    childCtor.superClass_ = parentCtor.prototype;   "
4915     "    childCtor.prototype = new tempCtor();           "
4916     "    childCtor.prototype.constructor = childCtor;    "
4917     "};                                                  "
4918     "inherits(MyError, Error);                           "
4919     "throw new MyError('my message');                    ");
4920
4921   // Object.create.
4922   CompileRun(
4923     "function MyError(msg) {                             "
4924     "  this.name = 'MyError';                            "
4925     "  this.message = msg;                               "
4926     "}                                                   "
4927     "MyError.prototype = Object.create(Error.prototype); "
4928     "throw new MyError('my message');                    ");
4929
4930   v8::V8::RemoveMessageListeners(check_custom_error_message);
4931 }
4932
4933
4934 static void receive_message(v8::Handle<v8::Message> message,
4935                             v8::Handle<v8::Value> data) {
4936   message->Get();
4937   message_received = true;
4938 }
4939
4940
4941 TEST(APIThrowMessage) {
4942   message_received = false;
4943   v8::Isolate* isolate = CcTest::isolate();
4944   v8::HandleScope scope(isolate);
4945   v8::V8::AddMessageListener(receive_message);
4946   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4947   templ->Set(v8_str("ThrowFromC"),
4948              v8::FunctionTemplate::New(isolate, ThrowFromC));
4949   LocalContext context(0, templ);
4950   CompileRun("ThrowFromC();");
4951   CHECK(message_received);
4952   v8::V8::RemoveMessageListeners(receive_message);
4953 }
4954
4955
4956 TEST(APIThrowMessageAndVerboseTryCatch) {
4957   message_received = false;
4958   v8::Isolate* isolate = CcTest::isolate();
4959   v8::HandleScope scope(isolate);
4960   v8::V8::AddMessageListener(receive_message);
4961   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4962   templ->Set(v8_str("ThrowFromC"),
4963              v8::FunctionTemplate::New(isolate, ThrowFromC));
4964   LocalContext context(0, templ);
4965   v8::TryCatch try_catch;
4966   try_catch.SetVerbose(true);
4967   Local<Value> result = CompileRun("ThrowFromC();");
4968   CHECK(try_catch.HasCaught());
4969   CHECK(result.IsEmpty());
4970   CHECK(message_received);
4971   v8::V8::RemoveMessageListeners(receive_message);
4972 }
4973
4974
4975 TEST(APIStackOverflowAndVerboseTryCatch) {
4976   message_received = false;
4977   LocalContext context;
4978   v8::HandleScope scope(context->GetIsolate());
4979   v8::V8::AddMessageListener(receive_message);
4980   v8::TryCatch try_catch;
4981   try_catch.SetVerbose(true);
4982   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4983   CHECK(try_catch.HasCaught());
4984   CHECK(result.IsEmpty());
4985   CHECK(message_received);
4986   v8::V8::RemoveMessageListeners(receive_message);
4987 }
4988
4989
4990 THREADED_TEST(ExternalScriptException) {
4991   v8::Isolate* isolate = CcTest::isolate();
4992   v8::HandleScope scope(isolate);
4993   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4994   templ->Set(v8_str("ThrowFromC"),
4995              v8::FunctionTemplate::New(isolate, ThrowFromC));
4996   LocalContext context(0, templ);
4997
4998   v8::TryCatch try_catch;
4999   Local<Script> script
5000       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
5001   Local<Value> result = script->Run();
5002   CHECK(result.IsEmpty());
5003   CHECK(try_catch.HasCaught());
5004   String::Utf8Value exception_value(try_catch.Exception());
5005   CHECK_EQ("konto", *exception_value);
5006 }
5007
5008
5009
5010 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5011   ApiTestFuzzer::Fuzz();
5012   CHECK_EQ(4, args.Length());
5013   int count = args[0]->Int32Value();
5014   int cInterval = args[2]->Int32Value();
5015   if (count == 0) {
5016     args.GetIsolate()->ThrowException(v8_str("FromC"));
5017     return;
5018   } else {
5019     Local<v8::Object> global =
5020         args.GetIsolate()->GetCurrentContext()->Global();
5021     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5022     v8::Handle<Value> argv[] = { v8_num(count - 1),
5023                                  args[1],
5024                                  args[2],
5025                                  args[3] };
5026     if (count % cInterval == 0) {
5027       v8::TryCatch try_catch;
5028       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5029       int expected = args[3]->Int32Value();
5030       if (try_catch.HasCaught()) {
5031         CHECK_EQ(expected, count);
5032         CHECK(result.IsEmpty());
5033         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5034       } else {
5035         CHECK_NE(expected, count);
5036       }
5037       args.GetReturnValue().Set(result);
5038       return;
5039     } else {
5040       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5041       return;
5042     }
5043   }
5044 }
5045
5046
5047 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5048   ApiTestFuzzer::Fuzz();
5049   CHECK_EQ(3, args.Length());
5050   bool equality = args[0]->BooleanValue();
5051   int count = args[1]->Int32Value();
5052   int expected = args[2]->Int32Value();
5053   if (equality) {
5054     CHECK_EQ(count, expected);
5055   } else {
5056     CHECK_NE(count, expected);
5057   }
5058 }
5059
5060
5061 THREADED_TEST(EvalInTryFinally) {
5062   LocalContext context;
5063   v8::HandleScope scope(context->GetIsolate());
5064   v8::TryCatch try_catch;
5065   CompileRun("(function() {"
5066              "  try {"
5067              "    eval('asldkf (*&^&*^');"
5068              "  } finally {"
5069              "    return;"
5070              "  }"
5071              "})()");
5072   CHECK(!try_catch.HasCaught());
5073 }
5074
5075
5076 // This test works by making a stack of alternating JavaScript and C
5077 // activations.  These activations set up exception handlers with regular
5078 // intervals, one interval for C activations and another for JavaScript
5079 // activations.  When enough activations have been created an exception is
5080 // thrown and we check that the right activation catches the exception and that
5081 // no other activations do.  The right activation is always the topmost one with
5082 // a handler, regardless of whether it is in JavaScript or C.
5083 //
5084 // The notation used to describe a test case looks like this:
5085 //
5086 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5087 //
5088 // Each entry is an activation, either JS or C.  The index is the count at that
5089 // level.  Stars identify activations with exception handlers, the @ identifies
5090 // the exception handler that should catch the exception.
5091 //
5092 // BUG(271): Some of the exception propagation does not work on the
5093 // ARM simulator because the simulator separates the C++ stack and the
5094 // JS stack.  This test therefore fails on the simulator.  The test is
5095 // not threaded to allow the threading tests to run on the simulator.
5096 TEST(ExceptionOrder) {
5097   v8::Isolate* isolate = CcTest::isolate();
5098   v8::HandleScope scope(isolate);
5099   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5100   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5101   templ->Set(v8_str("CThrowCountDown"),
5102              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5103   LocalContext context(0, templ);
5104   CompileRun(
5105     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5106     "  if (count == 0) throw 'FromJS';"
5107     "  if (count % jsInterval == 0) {"
5108     "    try {"
5109     "      var value = CThrowCountDown(count - 1,"
5110     "                                  jsInterval,"
5111     "                                  cInterval,"
5112     "                                  expected);"
5113     "      check(false, count, expected);"
5114     "      return value;"
5115     "    } catch (e) {"
5116     "      check(true, count, expected);"
5117     "    }"
5118     "  } else {"
5119     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5120     "  }"
5121     "}");
5122   Local<Function> fun =
5123       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5124
5125   const int argc = 4;
5126   //                             count      jsInterval cInterval  expected
5127
5128   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5129   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5130   fun->Call(fun, argc, a0);
5131
5132   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5133   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5134   fun->Call(fun, argc, a1);
5135
5136   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5137   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5138   fun->Call(fun, argc, a2);
5139
5140   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5141   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5142   fun->Call(fun, argc, a3);
5143
5144   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5145   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5146   fun->Call(fun, argc, a4);
5147
5148   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5149   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5150   fun->Call(fun, argc, a5);
5151 }
5152
5153
5154 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5155   ApiTestFuzzer::Fuzz();
5156   CHECK_EQ(1, args.Length());
5157   args.GetIsolate()->ThrowException(args[0]);
5158 }
5159
5160
5161 THREADED_TEST(ThrowValues) {
5162   v8::Isolate* isolate = CcTest::isolate();
5163   v8::HandleScope scope(isolate);
5164   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5165   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5166   LocalContext context(0, templ);
5167   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5168     "function Run(obj) {"
5169     "  try {"
5170     "    Throw(obj);"
5171     "  } catch (e) {"
5172     "    return e;"
5173     "  }"
5174     "  return 'no exception';"
5175     "}"
5176     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5177   CHECK_EQ(5, result->Length());
5178   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5179   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5180   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5181   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5182   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5183   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5184   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5185 }
5186
5187
5188 THREADED_TEST(CatchZero) {
5189   LocalContext context;
5190   v8::HandleScope scope(context->GetIsolate());
5191   v8::TryCatch try_catch;
5192   CHECK(!try_catch.HasCaught());
5193   Script::Compile(v8_str("throw 10"))->Run();
5194   CHECK(try_catch.HasCaught());
5195   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5196   try_catch.Reset();
5197   CHECK(!try_catch.HasCaught());
5198   Script::Compile(v8_str("throw 0"))->Run();
5199   CHECK(try_catch.HasCaught());
5200   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5201 }
5202
5203
5204 THREADED_TEST(CatchExceptionFromWith) {
5205   LocalContext context;
5206   v8::HandleScope scope(context->GetIsolate());
5207   v8::TryCatch try_catch;
5208   CHECK(!try_catch.HasCaught());
5209   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
5210   CHECK(try_catch.HasCaught());
5211 }
5212
5213
5214 THREADED_TEST(TryCatchAndFinallyHidingException) {
5215   LocalContext context;
5216   v8::HandleScope scope(context->GetIsolate());
5217   v8::TryCatch try_catch;
5218   CHECK(!try_catch.HasCaught());
5219   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5220   CompileRun("f({toString: function() { throw 42; }});");
5221   CHECK(!try_catch.HasCaught());
5222 }
5223
5224
5225 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5226   v8::TryCatch try_catch;
5227 }
5228
5229
5230 THREADED_TEST(TryCatchAndFinally) {
5231   LocalContext context;
5232   v8::Isolate* isolate = context->GetIsolate();
5233   v8::HandleScope scope(isolate);
5234   context->Global()->Set(
5235       v8_str("native_with_try_catch"),
5236       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5237   v8::TryCatch try_catch;
5238   CHECK(!try_catch.HasCaught());
5239   CompileRun(
5240       "try {\n"
5241       "  throw new Error('a');\n"
5242       "} finally {\n"
5243       "  native_with_try_catch();\n"
5244       "}\n");
5245   CHECK(try_catch.HasCaught());
5246 }
5247
5248
5249 static void TryCatchNestedHelper(int depth) {
5250   if (depth > 0) {
5251     v8::TryCatch try_catch;
5252     try_catch.SetVerbose(true);
5253     TryCatchNestedHelper(depth - 1);
5254     CHECK(try_catch.HasCaught());
5255     try_catch.ReThrow();
5256   } else {
5257     CcTest::isolate()->ThrowException(v8_str("back"));
5258   }
5259 }
5260
5261
5262 TEST(TryCatchNested) {
5263   v8::V8::Initialize();
5264   LocalContext context;
5265   v8::HandleScope scope(context->GetIsolate());
5266   v8::TryCatch try_catch;
5267   TryCatchNestedHelper(5);
5268   CHECK(try_catch.HasCaught());
5269   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5270 }
5271
5272
5273 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5274   CHECK(try_catch->HasCaught());
5275   Handle<Message> message = try_catch->Message();
5276   Handle<Value> resource = message->GetScriptResourceName();
5277   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5278   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5279                      "Uncaught Error: a"));
5280   CHECK_EQ(1, message->GetLineNumber());
5281   CHECK_EQ(6, message->GetStartColumn());
5282 }
5283
5284
5285 void TryCatchMixedNestingHelper(
5286     const v8::FunctionCallbackInfo<v8::Value>& args) {
5287   ApiTestFuzzer::Fuzz();
5288   v8::TryCatch try_catch;
5289   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5290   CHECK(try_catch.HasCaught());
5291   TryCatchMixedNestingCheck(&try_catch);
5292   try_catch.ReThrow();
5293 }
5294
5295
5296 // This test ensures that an outer TryCatch in the following situation:
5297 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5298 // does not clobber the Message object generated for the inner TryCatch.
5299 // This exercises the ability of TryCatch.ReThrow() to restore the
5300 // inner pending Message before throwing the exception again.
5301 TEST(TryCatchMixedNesting) {
5302   v8::Isolate* isolate = CcTest::isolate();
5303   v8::HandleScope scope(isolate);
5304   v8::V8::Initialize();
5305   v8::TryCatch try_catch;
5306   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5307   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5308              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5309   LocalContext context(0, templ);
5310   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5311   TryCatchMixedNestingCheck(&try_catch);
5312 }
5313
5314
5315 THREADED_TEST(Equality) {
5316   LocalContext context;
5317   v8::Isolate* isolate = context->GetIsolate();
5318   v8::HandleScope scope(context->GetIsolate());
5319   // Check that equality works at all before relying on CHECK_EQ
5320   CHECK(v8_str("a")->Equals(v8_str("a")));
5321   CHECK(!v8_str("a")->Equals(v8_str("b")));
5322
5323   CHECK_EQ(v8_str("a"), v8_str("a"));
5324   CHECK_NE(v8_str("a"), v8_str("b"));
5325   CHECK_EQ(v8_num(1), v8_num(1));
5326   CHECK_EQ(v8_num(1.00), v8_num(1));
5327   CHECK_NE(v8_num(1), v8_num(2));
5328
5329   // Assume String is not internalized.
5330   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5331   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5332   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5333   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5334   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5335   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5336   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5337   CHECK(!not_a_number->StrictEquals(not_a_number));
5338   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5339   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5340
5341   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5342   v8::Persistent<v8::Object> alias(isolate, obj);
5343   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5344   alias.Reset();
5345
5346   CHECK(v8_str("a")->SameValue(v8_str("a")));
5347   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5348   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5349   CHECK(v8_num(1)->SameValue(v8_num(1)));
5350   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5351   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5352   CHECK(not_a_number->SameValue(not_a_number));
5353   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5354   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5355 }
5356
5357
5358 THREADED_TEST(MultiRun) {
5359   LocalContext context;
5360   v8::HandleScope scope(context->GetIsolate());
5361   Local<Script> script = Script::Compile(v8_str("x"));
5362   for (int i = 0; i < 10; i++)
5363     script->Run();
5364 }
5365
5366
5367 static void GetXValue(Local<String> name,
5368                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5369   ApiTestFuzzer::Fuzz();
5370   CHECK_EQ(info.Data(), v8_str("donut"));
5371   CHECK_EQ(name, v8_str("x"));
5372   info.GetReturnValue().Set(name);
5373 }
5374
5375
5376 THREADED_TEST(SimplePropertyRead) {
5377   LocalContext context;
5378   v8::Isolate* isolate = context->GetIsolate();
5379   v8::HandleScope scope(isolate);
5380   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5381   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5382   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5383   Local<Script> script = Script::Compile(v8_str("obj.x"));
5384   for (int i = 0; i < 10; i++) {
5385     Local<Value> result = script->Run();
5386     CHECK_EQ(result, v8_str("x"));
5387   }
5388 }
5389
5390
5391 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5392   LocalContext context;
5393   v8::Isolate* isolate = context->GetIsolate();
5394   v8::HandleScope scope(isolate);
5395   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5396   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5397   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5398
5399   // Uses getOwnPropertyDescriptor to check the configurable status
5400   Local<Script> script_desc
5401     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5402                              "obj, 'x');"
5403                              "prop.configurable;"));
5404   Local<Value> result = script_desc->Run();
5405   CHECK_EQ(result->BooleanValue(), true);
5406
5407   // Redefine get - but still configurable
5408   Local<Script> script_define
5409     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5410                              "            configurable: true };"
5411                              "Object.defineProperty(obj, 'x', desc);"
5412                              "obj.x"));
5413   result = script_define->Run();
5414   CHECK_EQ(result, v8_num(42));
5415
5416   // Check that the accessor is still configurable
5417   result = script_desc->Run();
5418   CHECK_EQ(result->BooleanValue(), true);
5419
5420   // Redefine to a non-configurable
5421   script_define
5422     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5423                              "             configurable: false };"
5424                              "Object.defineProperty(obj, 'x', desc);"
5425                              "obj.x"));
5426   result = script_define->Run();
5427   CHECK_EQ(result, v8_num(43));
5428   result = script_desc->Run();
5429   CHECK_EQ(result->BooleanValue(), false);
5430
5431   // Make sure that it is not possible to redefine again
5432   v8::TryCatch try_catch;
5433   result = script_define->Run();
5434   CHECK(try_catch.HasCaught());
5435   String::Utf8Value exception_value(try_catch.Exception());
5436   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5437 }
5438
5439
5440 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5441   v8::Isolate* isolate = CcTest::isolate();
5442   v8::HandleScope scope(isolate);
5443   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5444   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5445   LocalContext context;
5446   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5447
5448   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5449                                     "Object.getOwnPropertyDescriptor( "
5450                                     "obj, 'x');"
5451                                     "prop.configurable;"));
5452   Local<Value> result = script_desc->Run();
5453   CHECK_EQ(result->BooleanValue(), true);
5454
5455   Local<Script> script_define =
5456     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5457                            "            configurable: true };"
5458                            "Object.defineProperty(obj, 'x', desc);"
5459                            "obj.x"));
5460   result = script_define->Run();
5461   CHECK_EQ(result, v8_num(42));
5462
5463
5464   result = script_desc->Run();
5465   CHECK_EQ(result->BooleanValue(), true);
5466
5467
5468   script_define =
5469     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5470                            "            configurable: false };"
5471                            "Object.defineProperty(obj, 'x', desc);"
5472                            "obj.x"));
5473   result = script_define->Run();
5474   CHECK_EQ(result, v8_num(43));
5475   result = script_desc->Run();
5476
5477   CHECK_EQ(result->BooleanValue(), false);
5478
5479   v8::TryCatch try_catch;
5480   result = script_define->Run();
5481   CHECK(try_catch.HasCaught());
5482   String::Utf8Value exception_value(try_catch.Exception());
5483   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5484 }
5485
5486
5487 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5488                                                 char const* name) {
5489   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5490 }
5491
5492
5493 THREADED_TEST(DefineAPIAccessorOnObject) {
5494   v8::Isolate* isolate = CcTest::isolate();
5495   v8::HandleScope scope(isolate);
5496   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5497   LocalContext context;
5498
5499   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5500   CompileRun("var obj2 = {};");
5501
5502   CHECK(CompileRun("obj1.x")->IsUndefined());
5503   CHECK(CompileRun("obj2.x")->IsUndefined());
5504
5505   CHECK(GetGlobalProperty(&context, "obj1")->
5506       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5507
5508   ExpectString("obj1.x", "x");
5509   CHECK(CompileRun("obj2.x")->IsUndefined());
5510
5511   CHECK(GetGlobalProperty(&context, "obj2")->
5512       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5513
5514   ExpectString("obj1.x", "x");
5515   ExpectString("obj2.x", "x");
5516
5517   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5518   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5519
5520   CompileRun("Object.defineProperty(obj1, 'x',"
5521              "{ get: function() { return 'y'; }, configurable: true })");
5522
5523   ExpectString("obj1.x", "y");
5524   ExpectString("obj2.x", "x");
5525
5526   CompileRun("Object.defineProperty(obj2, 'x',"
5527              "{ get: function() { return 'y'; }, configurable: true })");
5528
5529   ExpectString("obj1.x", "y");
5530   ExpectString("obj2.x", "y");
5531
5532   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5533   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5534
5535   CHECK(GetGlobalProperty(&context, "obj1")->
5536       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5537   CHECK(GetGlobalProperty(&context, "obj2")->
5538       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5539
5540   ExpectString("obj1.x", "x");
5541   ExpectString("obj2.x", "x");
5542
5543   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5544   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5545
5546   // Define getters/setters, but now make them not configurable.
5547   CompileRun("Object.defineProperty(obj1, 'x',"
5548              "{ get: function() { return 'z'; }, configurable: false })");
5549   CompileRun("Object.defineProperty(obj2, 'x',"
5550              "{ get: function() { return 'z'; }, configurable: false })");
5551
5552   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5553   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5554
5555   ExpectString("obj1.x", "z");
5556   ExpectString("obj2.x", "z");
5557
5558   CHECK(!GetGlobalProperty(&context, "obj1")->
5559       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5560   CHECK(!GetGlobalProperty(&context, "obj2")->
5561       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5562
5563   ExpectString("obj1.x", "z");
5564   ExpectString("obj2.x", "z");
5565 }
5566
5567
5568 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5569   v8::Isolate* isolate = CcTest::isolate();
5570   v8::HandleScope scope(isolate);
5571   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5572   LocalContext context;
5573
5574   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5575   CompileRun("var obj2 = {};");
5576
5577   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5578         v8_str("x"),
5579         GetXValue, NULL,
5580         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5581   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5582         v8_str("x"),
5583         GetXValue, NULL,
5584         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5585
5586   ExpectString("obj1.x", "x");
5587   ExpectString("obj2.x", "x");
5588
5589   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5590   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5591
5592   CHECK(!GetGlobalProperty(&context, "obj1")->
5593       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5594   CHECK(!GetGlobalProperty(&context, "obj2")->
5595       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5596
5597   {
5598     v8::TryCatch try_catch;
5599     CompileRun("Object.defineProperty(obj1, 'x',"
5600         "{get: function() { return 'func'; }})");
5601     CHECK(try_catch.HasCaught());
5602     String::Utf8Value exception_value(try_catch.Exception());
5603     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5604   }
5605   {
5606     v8::TryCatch try_catch;
5607     CompileRun("Object.defineProperty(obj2, 'x',"
5608         "{get: function() { return 'func'; }})");
5609     CHECK(try_catch.HasCaught());
5610     String::Utf8Value exception_value(try_catch.Exception());
5611     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5612   }
5613 }
5614
5615
5616 static void Get239Value(Local<String> name,
5617                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5618   ApiTestFuzzer::Fuzz();
5619   CHECK_EQ(info.Data(), v8_str("donut"));
5620   CHECK_EQ(name, v8_str("239"));
5621   info.GetReturnValue().Set(name);
5622 }
5623
5624
5625 THREADED_TEST(ElementAPIAccessor) {
5626   v8::Isolate* isolate = CcTest::isolate();
5627   v8::HandleScope scope(isolate);
5628   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5629   LocalContext context;
5630
5631   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5632   CompileRun("var obj2 = {};");
5633
5634   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5635         v8_str("239"),
5636         Get239Value, NULL,
5637         v8_str("donut")));
5638   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5639         v8_str("239"),
5640         Get239Value, NULL,
5641         v8_str("donut")));
5642
5643   ExpectString("obj1[239]", "239");
5644   ExpectString("obj2[239]", "239");
5645   ExpectString("obj1['239']", "239");
5646   ExpectString("obj2['239']", "239");
5647 }
5648
5649
5650 v8::Persistent<Value> xValue;
5651
5652
5653 static void SetXValue(Local<String> name,
5654                       Local<Value> value,
5655                       const v8::PropertyCallbackInfo<void>& info) {
5656   CHECK_EQ(value, v8_num(4));
5657   CHECK_EQ(info.Data(), v8_str("donut"));
5658   CHECK_EQ(name, v8_str("x"));
5659   CHECK(xValue.IsEmpty());
5660   xValue.Reset(info.GetIsolate(), value);
5661 }
5662
5663
5664 THREADED_TEST(SimplePropertyWrite) {
5665   v8::Isolate* isolate = CcTest::isolate();
5666   v8::HandleScope scope(isolate);
5667   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5668   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5669   LocalContext context;
5670   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5671   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5672   for (int i = 0; i < 10; i++) {
5673     CHECK(xValue.IsEmpty());
5674     script->Run();
5675     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5676     xValue.Reset();
5677   }
5678 }
5679
5680
5681 THREADED_TEST(SetterOnly) {
5682   v8::Isolate* isolate = CcTest::isolate();
5683   v8::HandleScope scope(isolate);
5684   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5685   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5686   LocalContext context;
5687   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5688   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5689   for (int i = 0; i < 10; i++) {
5690     CHECK(xValue.IsEmpty());
5691     script->Run();
5692     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5693     xValue.Reset();
5694   }
5695 }
5696
5697
5698 THREADED_TEST(NoAccessors) {
5699   v8::Isolate* isolate = CcTest::isolate();
5700   v8::HandleScope scope(isolate);
5701   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5702   templ->SetAccessor(v8_str("x"),
5703                      static_cast<v8::AccessorGetterCallback>(NULL),
5704                      NULL,
5705                      v8_str("donut"));
5706   LocalContext context;
5707   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5708   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5709   for (int i = 0; i < 10; i++) {
5710     script->Run();
5711   }
5712 }
5713
5714
5715 static void XPropertyGetter(Local<String> property,
5716                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5717   ApiTestFuzzer::Fuzz();
5718   CHECK(info.Data()->IsUndefined());
5719   info.GetReturnValue().Set(property);
5720 }
5721
5722
5723 THREADED_TEST(NamedInterceptorPropertyRead) {
5724   v8::Isolate* isolate = CcTest::isolate();
5725   v8::HandleScope scope(isolate);
5726   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5727   templ->SetNamedPropertyHandler(XPropertyGetter);
5728   LocalContext context;
5729   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5730   Local<Script> script = Script::Compile(v8_str("obj.x"));
5731   for (int i = 0; i < 10; i++) {
5732     Local<Value> result = script->Run();
5733     CHECK_EQ(result, v8_str("x"));
5734   }
5735 }
5736
5737
5738 THREADED_TEST(NamedInterceptorDictionaryIC) {
5739   v8::Isolate* isolate = CcTest::isolate();
5740   v8::HandleScope scope(isolate);
5741   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5742   templ->SetNamedPropertyHandler(XPropertyGetter);
5743   LocalContext context;
5744   // Create an object with a named interceptor.
5745   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5746   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5747   for (int i = 0; i < 10; i++) {
5748     Local<Value> result = script->Run();
5749     CHECK_EQ(result, v8_str("x"));
5750   }
5751   // Create a slow case object and a function accessing a property in
5752   // that slow case object (with dictionary probing in generated
5753   // code). Then force object with a named interceptor into slow-case,
5754   // pass it to the function, and check that the interceptor is called
5755   // instead of accessing the local property.
5756   Local<Value> result =
5757       CompileRun("function get_x(o) { return o.x; };"
5758                  "var obj = { x : 42, y : 0 };"
5759                  "delete obj.y;"
5760                  "for (var i = 0; i < 10; i++) get_x(obj);"
5761                  "interceptor_obj.x = 42;"
5762                  "interceptor_obj.y = 10;"
5763                  "delete interceptor_obj.y;"
5764                  "get_x(interceptor_obj)");
5765   CHECK_EQ(result, v8_str("x"));
5766 }
5767
5768
5769 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5770   v8::Isolate* isolate = CcTest::isolate();
5771   v8::HandleScope scope(isolate);
5772   v8::Local<Context> context1 = Context::New(isolate);
5773
5774   context1->Enter();
5775   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5776   templ->SetNamedPropertyHandler(XPropertyGetter);
5777   // Create an object with a named interceptor.
5778   v8::Local<v8::Object> object = templ->NewInstance();
5779   context1->Global()->Set(v8_str("interceptor_obj"), object);
5780
5781   // Force the object into the slow case.
5782   CompileRun("interceptor_obj.y = 0;"
5783              "delete interceptor_obj.y;");
5784   context1->Exit();
5785
5786   {
5787     // Introduce the object into a different context.
5788     // Repeat named loads to exercise ICs.
5789     LocalContext context2;
5790     context2->Global()->Set(v8_str("interceptor_obj"), object);
5791     Local<Value> result =
5792       CompileRun("function get_x(o) { return o.x; }"
5793                  "interceptor_obj.x = 42;"
5794                  "for (var i=0; i != 10; i++) {"
5795                  "  get_x(interceptor_obj);"
5796                  "}"
5797                  "get_x(interceptor_obj)");
5798     // Check that the interceptor was actually invoked.
5799     CHECK_EQ(result, v8_str("x"));
5800   }
5801
5802   // Return to the original context and force some object to the slow case
5803   // to cause the NormalizedMapCache to verify.
5804   context1->Enter();
5805   CompileRun("var obj = { x : 0 }; delete obj.x;");
5806   context1->Exit();
5807 }
5808
5809
5810 static void SetXOnPrototypeGetter(
5811     Local<String> property,
5812     const v8::PropertyCallbackInfo<v8::Value>& info) {
5813   // Set x on the prototype object and do not handle the get request.
5814   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5815   proto.As<v8::Object>()->Set(v8_str("x"),
5816                               v8::Integer::New(info.GetIsolate(), 23));
5817 }
5818
5819
5820 // This is a regression test for http://crbug.com/20104. Map
5821 // transitions should not interfere with post interceptor lookup.
5822 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5823   v8::Isolate* isolate = CcTest::isolate();
5824   v8::HandleScope scope(isolate);
5825   Local<v8::FunctionTemplate> function_template =
5826       v8::FunctionTemplate::New(isolate);
5827   Local<v8::ObjectTemplate> instance_template
5828       = function_template->InstanceTemplate();
5829   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5830   LocalContext context;
5831   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5832   // Create an instance of F and introduce a map transition for x.
5833   CompileRun("var o = new F(); o.x = 23;");
5834   // Create an instance of F and invoke the getter. The result should be 23.
5835   Local<Value> result = CompileRun("o = new F(); o.x");
5836   CHECK_EQ(result->Int32Value(), 23);
5837 }
5838
5839
5840 static void IndexedPropertyGetter(
5841     uint32_t index,
5842     const v8::PropertyCallbackInfo<v8::Value>& info) {
5843   ApiTestFuzzer::Fuzz();
5844   if (index == 37) {
5845     info.GetReturnValue().Set(v8_num(625));
5846   }
5847 }
5848
5849
5850 static void IndexedPropertySetter(
5851     uint32_t index,
5852     Local<Value> value,
5853     const v8::PropertyCallbackInfo<v8::Value>& info) {
5854   ApiTestFuzzer::Fuzz();
5855   if (index == 39) {
5856     info.GetReturnValue().Set(value);
5857   }
5858 }
5859
5860
5861 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5862   v8::Isolate* isolate = CcTest::isolate();
5863   v8::HandleScope scope(isolate);
5864   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5865   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5866                                    IndexedPropertySetter);
5867   LocalContext context;
5868   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5869   Local<Script> getter_script = Script::Compile(v8_str(
5870       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5871   Local<Script> setter_script = Script::Compile(v8_str(
5872       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5873       "obj[17] = 23;"
5874       "obj.foo;"));
5875   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5876       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5877       "obj[39] = 47;"
5878       "obj.foo;"));  // This setter should not run, due to the interceptor.
5879   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5880       "obj[37];"));
5881   Local<Value> result = getter_script->Run();
5882   CHECK_EQ(v8_num(5), result);
5883   result = setter_script->Run();
5884   CHECK_EQ(v8_num(23), result);
5885   result = interceptor_setter_script->Run();
5886   CHECK_EQ(v8_num(23), result);
5887   result = interceptor_getter_script->Run();
5888   CHECK_EQ(v8_num(625), result);
5889 }
5890
5891
5892 static void UnboxedDoubleIndexedPropertyGetter(
5893     uint32_t index,
5894     const v8::PropertyCallbackInfo<v8::Value>& info) {
5895   ApiTestFuzzer::Fuzz();
5896   if (index < 25) {
5897     info.GetReturnValue().Set(v8_num(index));
5898   }
5899 }
5900
5901
5902 static void UnboxedDoubleIndexedPropertySetter(
5903     uint32_t index,
5904     Local<Value> value,
5905     const v8::PropertyCallbackInfo<v8::Value>& info) {
5906   ApiTestFuzzer::Fuzz();
5907   if (index < 25) {
5908     info.GetReturnValue().Set(v8_num(index));
5909   }
5910 }
5911
5912
5913 void UnboxedDoubleIndexedPropertyEnumerator(
5914     const v8::PropertyCallbackInfo<v8::Array>& info) {
5915   // Force the list of returned keys to be stored in a FastDoubleArray.
5916   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5917       "keys = new Array(); keys[125000] = 1;"
5918       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5919       "keys.length = 25; keys;"));
5920   Local<Value> result = indexed_property_names_script->Run();
5921   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5922 }
5923
5924
5925 // Make sure that the the interceptor code in the runtime properly handles
5926 // merging property name lists for double-array-backed arrays.
5927 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5928   v8::Isolate* isolate = CcTest::isolate();
5929   v8::HandleScope scope(isolate);
5930   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5931   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5932                                    UnboxedDoubleIndexedPropertySetter,
5933                                    0,
5934                                    0,
5935                                    UnboxedDoubleIndexedPropertyEnumerator);
5936   LocalContext context;
5937   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5938   // When obj is created, force it to be Stored in a FastDoubleArray.
5939   Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5940       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5941       "key_count = 0; "
5942       "for (x in obj) {key_count++;};"
5943       "obj;"));
5944   Local<Value> result = create_unboxed_double_script->Run();
5945   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5946   Local<Script> key_count_check = Script::Compile(v8_str(
5947       "key_count;"));
5948   result = key_count_check->Run();
5949   CHECK_EQ(v8_num(40013), result);
5950 }
5951
5952
5953 void NonStrictArgsIndexedPropertyEnumerator(
5954     const v8::PropertyCallbackInfo<v8::Array>& info) {
5955   // Force the list of returned keys to be stored in a Arguments object.
5956   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5957       "function f(w,x) {"
5958       " return arguments;"
5959       "}"
5960       "keys = f(0, 1, 2, 3);"
5961       "keys;"));
5962   Local<Object> result =
5963       Local<Object>::Cast(indexed_property_names_script->Run());
5964   // Have to populate the handle manually, as it's not Cast-able.
5965   i::Handle<i::JSObject> o =
5966       v8::Utils::OpenHandle<Object, i::JSObject>(result);
5967   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5968   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5969 }
5970
5971
5972 static void NonStrictIndexedPropertyGetter(
5973     uint32_t index,
5974     const v8::PropertyCallbackInfo<v8::Value>& info) {
5975   ApiTestFuzzer::Fuzz();
5976   if (index < 4) {
5977     info.GetReturnValue().Set(v8_num(index));
5978   }
5979 }
5980
5981
5982 // Make sure that the the interceptor code in the runtime properly handles
5983 // merging property name lists for non-string arguments arrays.
5984 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5985   v8::Isolate* isolate = CcTest::isolate();
5986   v8::HandleScope scope(isolate);
5987   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5988   templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5989                                    0,
5990                                    0,
5991                                    0,
5992                                    NonStrictArgsIndexedPropertyEnumerator);
5993   LocalContext context;
5994   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5995   Local<Script> create_args_script =
5996       Script::Compile(v8_str(
5997           "var key_count = 0;"
5998           "for (x in obj) {key_count++;} key_count;"));
5999   Local<Value> result = create_args_script->Run();
6000   CHECK_EQ(v8_num(4), result);
6001 }
6002
6003
6004 static void IdentityIndexedPropertyGetter(
6005     uint32_t index,
6006     const v8::PropertyCallbackInfo<v8::Value>& info) {
6007   info.GetReturnValue().Set(index);
6008 }
6009
6010
6011 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6012   v8::Isolate* isolate = CcTest::isolate();
6013   v8::HandleScope scope(isolate);
6014   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6015   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6016
6017   LocalContext context;
6018   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6019
6020   // Check fast object case.
6021   const char* fast_case_code =
6022       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6023   ExpectString(fast_case_code, "0");
6024
6025   // Check slow case.
6026   const char* slow_case_code =
6027       "obj.x = 1; delete obj.x;"
6028       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6029   ExpectString(slow_case_code, "1");
6030 }
6031
6032
6033 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6034   v8::Isolate* isolate = CcTest::isolate();
6035   v8::HandleScope scope(isolate);
6036   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6037   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6038
6039   LocalContext context;
6040   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6041
6042   const char* code =
6043       "try {"
6044       "  obj[0] = 239;"
6045       "  for (var i = 0; i < 100; i++) {"
6046       "    var v = obj[0];"
6047       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6048       "  }"
6049       "  'PASSED'"
6050       "} catch(e) {"
6051       "  e"
6052       "}";
6053   ExpectString(code, "PASSED");
6054 }
6055
6056
6057 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6058   v8::Isolate* isolate = CcTest::isolate();
6059   v8::HandleScope scope(isolate);
6060   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6061   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6062
6063   LocalContext context;
6064   Local<v8::Object> obj = templ->NewInstance();
6065   obj->TurnOnAccessCheck();
6066   context->Global()->Set(v8_str("obj"), obj);
6067
6068   const char* code =
6069       "try {"
6070       "  for (var i = 0; i < 100; i++) {"
6071       "    var v = obj[0];"
6072       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6073       "  }"
6074       "  'PASSED'"
6075       "} catch(e) {"
6076       "  e"
6077       "}";
6078   ExpectString(code, "PASSED");
6079 }
6080
6081
6082 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6083   i::FLAG_allow_natives_syntax = true;
6084   v8::Isolate* isolate = CcTest::isolate();
6085   v8::HandleScope scope(isolate);
6086   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6087   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6088
6089   LocalContext context;
6090   Local<v8::Object> obj = templ->NewInstance();
6091   context->Global()->Set(v8_str("obj"), obj);
6092
6093   const char* code =
6094       "try {"
6095       "  for (var i = 0; i < 100; i++) {"
6096       "    var expected = i;"
6097       "    if (i == 5) {"
6098       "      %EnableAccessChecks(obj);"
6099       "      expected = undefined;"
6100       "    }"
6101       "    var v = obj[i];"
6102       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6103       "    if (i == 5) %DisableAccessChecks(obj);"
6104       "  }"
6105       "  'PASSED'"
6106       "} catch(e) {"
6107       "  e"
6108       "}";
6109   ExpectString(code, "PASSED");
6110 }
6111
6112
6113 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6114   v8::Isolate* isolate = CcTest::isolate();
6115   v8::HandleScope scope(isolate);
6116   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6117   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6118
6119   LocalContext context;
6120   Local<v8::Object> obj = templ->NewInstance();
6121   context->Global()->Set(v8_str("obj"), obj);
6122
6123   const char* code =
6124       "try {"
6125       "  for (var i = 0; i < 100; i++) {"
6126       "    var v = obj[i];"
6127       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6128       "  }"
6129       "  'PASSED'"
6130       "} catch(e) {"
6131       "  e"
6132       "}";
6133   ExpectString(code, "PASSED");
6134 }
6135
6136
6137 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6138   v8::Isolate* isolate = CcTest::isolate();
6139   v8::HandleScope scope(isolate);
6140   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6141   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6142
6143   LocalContext context;
6144   Local<v8::Object> obj = templ->NewInstance();
6145   context->Global()->Set(v8_str("obj"), obj);
6146
6147   const char* code =
6148       "try {"
6149       "  for (var i = 0; i < 100; i++) {"
6150       "    var expected = i;"
6151       "    var key = i;"
6152       "    if (i == 25) {"
6153       "       key = -1;"
6154       "       expected = undefined;"
6155       "    }"
6156       "    if (i == 50) {"
6157       "       /* probe minimal Smi number on 32-bit platforms */"
6158       "       key = -(1 << 30);"
6159       "       expected = undefined;"
6160       "    }"
6161       "    if (i == 75) {"
6162       "       /* probe minimal Smi number on 64-bit platforms */"
6163       "       key = 1 << 31;"
6164       "       expected = undefined;"
6165       "    }"
6166       "    var v = obj[key];"
6167       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6168       "  }"
6169       "  'PASSED'"
6170       "} catch(e) {"
6171       "  e"
6172       "}";
6173   ExpectString(code, "PASSED");
6174 }
6175
6176
6177 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6178   v8::Isolate* isolate = CcTest::isolate();
6179   v8::HandleScope scope(isolate);
6180   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6181   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6182
6183   LocalContext context;
6184   Local<v8::Object> obj = templ->NewInstance();
6185   context->Global()->Set(v8_str("obj"), obj);
6186
6187   const char* code =
6188       "try {"
6189       "  for (var i = 0; i < 100; i++) {"
6190       "    var expected = i;"
6191       "    var key = i;"
6192       "    if (i == 50) {"
6193       "       key = 'foobar';"
6194       "       expected = undefined;"
6195       "    }"
6196       "    var v = obj[key];"
6197       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6198       "  }"
6199       "  'PASSED'"
6200       "} catch(e) {"
6201       "  e"
6202       "}";
6203   ExpectString(code, "PASSED");
6204 }
6205
6206
6207 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6208   v8::Isolate* isolate = CcTest::isolate();
6209   v8::HandleScope scope(isolate);
6210   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6211   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6212
6213   LocalContext context;
6214   Local<v8::Object> obj = templ->NewInstance();
6215   context->Global()->Set(v8_str("obj"), obj);
6216
6217   const char* code =
6218       "var original = obj;"
6219       "try {"
6220       "  for (var i = 0; i < 100; i++) {"
6221       "    var expected = i;"
6222       "    if (i == 50) {"
6223       "       obj = {50: 'foobar'};"
6224       "       expected = 'foobar';"
6225       "    }"
6226       "    var v = obj[i];"
6227       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6228       "    if (i == 50) obj = original;"
6229       "  }"
6230       "  'PASSED'"
6231       "} catch(e) {"
6232       "  e"
6233       "}";
6234   ExpectString(code, "PASSED");
6235 }
6236
6237
6238 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6239   v8::Isolate* isolate = CcTest::isolate();
6240   v8::HandleScope scope(isolate);
6241   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6242   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6243
6244   LocalContext context;
6245   Local<v8::Object> obj = templ->NewInstance();
6246   context->Global()->Set(v8_str("obj"), obj);
6247
6248   const char* code =
6249       "var original = obj;"
6250       "try {"
6251       "  for (var i = 0; i < 100; i++) {"
6252       "    var expected = i;"
6253       "    if (i == 5) {"
6254       "       obj = 239;"
6255       "       expected = undefined;"
6256       "    }"
6257       "    var v = obj[i];"
6258       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6259       "    if (i == 5) obj = original;"
6260       "  }"
6261       "  'PASSED'"
6262       "} catch(e) {"
6263       "  e"
6264       "}";
6265   ExpectString(code, "PASSED");
6266 }
6267
6268
6269 THREADED_TEST(IndexedInterceptorOnProto) {
6270   v8::Isolate* isolate = CcTest::isolate();
6271   v8::HandleScope scope(isolate);
6272   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6273   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6274
6275   LocalContext context;
6276   Local<v8::Object> obj = templ->NewInstance();
6277   context->Global()->Set(v8_str("obj"), obj);
6278
6279   const char* code =
6280       "var o = {__proto__: obj};"
6281       "try {"
6282       "  for (var i = 0; i < 100; i++) {"
6283       "    var v = o[i];"
6284       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6285       "  }"
6286       "  'PASSED'"
6287       "} catch(e) {"
6288       "  e"
6289       "}";
6290   ExpectString(code, "PASSED");
6291 }
6292
6293
6294 THREADED_TEST(MultiContexts) {
6295   v8::Isolate* isolate = CcTest::isolate();
6296   v8::HandleScope scope(isolate);
6297   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6298   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6299                                                         DummyCallHandler));
6300
6301   Local<String> password = v8_str("Password");
6302
6303   // Create an environment
6304   LocalContext context0(0, templ);
6305   context0->SetSecurityToken(password);
6306   v8::Handle<v8::Object> global0 = context0->Global();
6307   global0->Set(v8_str("custom"), v8_num(1234));
6308   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6309
6310   // Create an independent environment
6311   LocalContext context1(0, templ);
6312   context1->SetSecurityToken(password);
6313   v8::Handle<v8::Object> global1 = context1->Global();
6314   global1->Set(v8_str("custom"), v8_num(1234));
6315   CHECK_NE(global0, global1);
6316   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6317   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6318
6319   // Now create a new context with the old global
6320   LocalContext context2(0, templ, global1);
6321   context2->SetSecurityToken(password);
6322   v8::Handle<v8::Object> global2 = context2->Global();
6323   CHECK_EQ(global1, global2);
6324   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6325   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6326 }
6327
6328
6329 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6330   // Make sure that functions created by cloning boilerplates cannot
6331   // communicate through their __proto__ field.
6332
6333   v8::HandleScope scope(CcTest::isolate());
6334
6335   LocalContext env0;
6336   v8::Handle<v8::Object> global0 =
6337       env0->Global();
6338   v8::Handle<v8::Object> object0 =
6339       global0->Get(v8_str("Object")).As<v8::Object>();
6340   v8::Handle<v8::Object> tostring0 =
6341       object0->Get(v8_str("toString")).As<v8::Object>();
6342   v8::Handle<v8::Object> proto0 =
6343       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6344   proto0->Set(v8_str("custom"), v8_num(1234));
6345
6346   LocalContext env1;
6347   v8::Handle<v8::Object> global1 =
6348       env1->Global();
6349   v8::Handle<v8::Object> object1 =
6350       global1->Get(v8_str("Object")).As<v8::Object>();
6351   v8::Handle<v8::Object> tostring1 =
6352       object1->Get(v8_str("toString")).As<v8::Object>();
6353   v8::Handle<v8::Object> proto1 =
6354       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6355   CHECK(!proto1->Has(v8_str("custom")));
6356 }
6357
6358
6359 THREADED_TEST(Regress892105) {
6360   // Make sure that object and array literals created by cloning
6361   // boilerplates cannot communicate through their __proto__
6362   // field. This is rather difficult to check, but we try to add stuff
6363   // to Object.prototype and Array.prototype and create a new
6364   // environment. This should succeed.
6365
6366   v8::HandleScope scope(CcTest::isolate());
6367
6368   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6369                                 "Array.prototype.arr = 4567;"
6370                                 "8901");
6371
6372   LocalContext env0;
6373   Local<Script> script0 = Script::Compile(source);
6374   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6375
6376   LocalContext env1;
6377   Local<Script> script1 = Script::Compile(source);
6378   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6379 }
6380
6381
6382 THREADED_TEST(UndetectableObject) {
6383   LocalContext env;
6384   v8::HandleScope scope(env->GetIsolate());
6385
6386   Local<v8::FunctionTemplate> desc =
6387       v8::FunctionTemplate::New(env->GetIsolate());
6388   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6389
6390   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6391   env->Global()->Set(v8_str("undetectable"), obj);
6392
6393   ExpectString("undetectable.toString()", "[object Object]");
6394   ExpectString("typeof undetectable", "undefined");
6395   ExpectString("typeof(undetectable)", "undefined");
6396   ExpectBoolean("typeof undetectable == 'undefined'", true);
6397   ExpectBoolean("typeof undetectable == 'object'", false);
6398   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6399   ExpectBoolean("!undetectable", true);
6400
6401   ExpectObject("true&&undetectable", obj);
6402   ExpectBoolean("false&&undetectable", false);
6403   ExpectBoolean("true||undetectable", true);
6404   ExpectObject("false||undetectable", obj);
6405
6406   ExpectObject("undetectable&&true", obj);
6407   ExpectObject("undetectable&&false", obj);
6408   ExpectBoolean("undetectable||true", true);
6409   ExpectBoolean("undetectable||false", false);
6410
6411   ExpectBoolean("undetectable==null", true);
6412   ExpectBoolean("null==undetectable", true);
6413   ExpectBoolean("undetectable==undefined", true);
6414   ExpectBoolean("undefined==undetectable", true);
6415   ExpectBoolean("undetectable==undetectable", true);
6416
6417
6418   ExpectBoolean("undetectable===null", false);
6419   ExpectBoolean("null===undetectable", false);
6420   ExpectBoolean("undetectable===undefined", false);
6421   ExpectBoolean("undefined===undetectable", false);
6422   ExpectBoolean("undetectable===undetectable", true);
6423 }
6424
6425
6426 THREADED_TEST(VoidLiteral) {
6427   LocalContext env;
6428   v8::Isolate* isolate = env->GetIsolate();
6429   v8::HandleScope scope(isolate);
6430
6431   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6432   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6433
6434   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6435   env->Global()->Set(v8_str("undetectable"), obj);
6436
6437   ExpectBoolean("undefined == void 0", true);
6438   ExpectBoolean("undetectable == void 0", true);
6439   ExpectBoolean("null == void 0", true);
6440   ExpectBoolean("undefined === void 0", true);
6441   ExpectBoolean("undetectable === void 0", false);
6442   ExpectBoolean("null === void 0", false);
6443
6444   ExpectBoolean("void 0 == undefined", true);
6445   ExpectBoolean("void 0 == undetectable", true);
6446   ExpectBoolean("void 0 == null", true);
6447   ExpectBoolean("void 0 === undefined", true);
6448   ExpectBoolean("void 0 === undetectable", false);
6449   ExpectBoolean("void 0 === null", false);
6450
6451   ExpectString("(function() {"
6452                "  try {"
6453                "    return x === void 0;"
6454                "  } catch(e) {"
6455                "    return e.toString();"
6456                "  }"
6457                "})()",
6458                "ReferenceError: x is not defined");
6459   ExpectString("(function() {"
6460                "  try {"
6461                "    return void 0 === x;"
6462                "  } catch(e) {"
6463                "    return e.toString();"
6464                "  }"
6465                "})()",
6466                "ReferenceError: x is not defined");
6467 }
6468
6469
6470 THREADED_TEST(ExtensibleOnUndetectable) {
6471   LocalContext env;
6472   v8::Isolate* isolate = env->GetIsolate();
6473   v8::HandleScope scope(isolate);
6474
6475   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6476   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6477
6478   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6479   env->Global()->Set(v8_str("undetectable"), obj);
6480
6481   Local<String> source = v8_str("undetectable.x = 42;"
6482                                 "undetectable.x");
6483
6484   Local<Script> script = Script::Compile(source);
6485
6486   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6487
6488   ExpectBoolean("Object.isExtensible(undetectable)", true);
6489
6490   source = v8_str("Object.preventExtensions(undetectable);");
6491   script = Script::Compile(source);
6492   script->Run();
6493   ExpectBoolean("Object.isExtensible(undetectable)", false);
6494
6495   source = v8_str("undetectable.y = 2000;");
6496   script = Script::Compile(source);
6497   script->Run();
6498   ExpectBoolean("undetectable.y == undefined", true);
6499 }
6500
6501
6502
6503 THREADED_TEST(UndetectableString) {
6504   LocalContext env;
6505   v8::HandleScope scope(env->GetIsolate());
6506
6507   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6508                                           String::kUndetectableString);
6509   env->Global()->Set(v8_str("undetectable"), obj);
6510
6511   ExpectString("undetectable", "foo");
6512   ExpectString("typeof undetectable", "undefined");
6513   ExpectString("typeof(undetectable)", "undefined");
6514   ExpectBoolean("typeof undetectable == 'undefined'", true);
6515   ExpectBoolean("typeof undetectable == 'string'", false);
6516   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6517   ExpectBoolean("!undetectable", true);
6518
6519   ExpectObject("true&&undetectable", obj);
6520   ExpectBoolean("false&&undetectable", false);
6521   ExpectBoolean("true||undetectable", true);
6522   ExpectObject("false||undetectable", obj);
6523
6524   ExpectObject("undetectable&&true", obj);
6525   ExpectObject("undetectable&&false", obj);
6526   ExpectBoolean("undetectable||true", true);
6527   ExpectBoolean("undetectable||false", false);
6528
6529   ExpectBoolean("undetectable==null", true);
6530   ExpectBoolean("null==undetectable", true);
6531   ExpectBoolean("undetectable==undefined", true);
6532   ExpectBoolean("undefined==undetectable", true);
6533   ExpectBoolean("undetectable==undetectable", true);
6534
6535
6536   ExpectBoolean("undetectable===null", false);
6537   ExpectBoolean("null===undetectable", false);
6538   ExpectBoolean("undetectable===undefined", false);
6539   ExpectBoolean("undefined===undetectable", false);
6540   ExpectBoolean("undetectable===undetectable", true);
6541 }
6542
6543
6544 TEST(UndetectableOptimized) {
6545   i::FLAG_allow_natives_syntax = true;
6546   LocalContext env;
6547   v8::HandleScope scope(env->GetIsolate());
6548
6549   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6550                                           String::kUndetectableString);
6551   env->Global()->Set(v8_str("undetectable"), obj);
6552   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6553
6554   ExpectString(
6555       "function testBranch() {"
6556       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6557       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6558       "}\n"
6559       "function testBool() {"
6560       "  var b1 = !%_IsUndetectableObject(undetectable);"
6561       "  var b2 = %_IsUndetectableObject(detectable);"
6562       "  if (b1) throw 3;"
6563       "  if (b2) throw 4;"
6564       "  return b1 == b2;"
6565       "}\n"
6566       "%OptimizeFunctionOnNextCall(testBranch);"
6567       "%OptimizeFunctionOnNextCall(testBool);"
6568       "for (var i = 0; i < 10; i++) {"
6569       "  testBranch();"
6570       "  testBool();"
6571       "}\n"
6572       "\"PASS\"",
6573       "PASS");
6574 }
6575
6576
6577 template <typename T> static void USE(T) { }
6578
6579
6580 // The point of this test is type checking. We run it only so compilers
6581 // don't complain about an unused function.
6582 TEST(PersistentHandles) {
6583   LocalContext env;
6584   v8::Isolate* isolate = CcTest::isolate();
6585   v8::HandleScope scope(isolate);
6586   Local<String> str = v8_str("foo");
6587   v8::Persistent<String> p_str(isolate, str);
6588   p_str.Reset();
6589   Local<Script> scr = Script::Compile(v8_str(""));
6590   v8::Persistent<Script> p_scr(isolate, scr);
6591   p_scr.Reset();
6592   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6593   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6594   p_templ.Reset();
6595 }
6596
6597
6598 static void HandleLogDelegator(
6599     const v8::FunctionCallbackInfo<v8::Value>& args) {
6600   ApiTestFuzzer::Fuzz();
6601 }
6602
6603
6604 THREADED_TEST(GlobalObjectTemplate) {
6605   v8::Isolate* isolate = CcTest::isolate();
6606   v8::HandleScope handle_scope(isolate);
6607   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6608   global_template->Set(v8_str("JSNI_Log"),
6609                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6610   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6611   Context::Scope context_scope(context);
6612   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6613 }
6614
6615
6616 static const char* kSimpleExtensionSource =
6617   "function Foo() {"
6618   "  return 4;"
6619   "}";
6620
6621
6622 TEST(SimpleExtensions) {
6623   v8::HandleScope handle_scope(CcTest::isolate());
6624   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6625   const char* extension_names[] = { "simpletest" };
6626   v8::ExtensionConfiguration extensions(1, extension_names);
6627   v8::Handle<Context> context =
6628       Context::New(CcTest::isolate(), &extensions);
6629   Context::Scope lock(context);
6630   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6631   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6632 }
6633
6634
6635 TEST(NullExtensions) {
6636   v8::HandleScope handle_scope(CcTest::isolate());
6637   v8::RegisterExtension(new Extension("nulltest", NULL));
6638   const char* extension_names[] = { "nulltest" };
6639   v8::ExtensionConfiguration extensions(1, extension_names);
6640   v8::Handle<Context> context =
6641       Context::New(CcTest::isolate(), &extensions);
6642   Context::Scope lock(context);
6643   v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6644   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6645 }
6646
6647
6648 static const char* kEmbeddedExtensionSource =
6649     "function Ret54321(){return 54321;}~~@@$"
6650     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6651 static const int kEmbeddedExtensionSourceValidLen = 34;
6652
6653
6654 TEST(ExtensionMissingSourceLength) {
6655   v8::HandleScope handle_scope(CcTest::isolate());
6656   v8::RegisterExtension(new Extension("srclentest_fail",
6657                                       kEmbeddedExtensionSource));
6658   const char* extension_names[] = { "srclentest_fail" };
6659   v8::ExtensionConfiguration extensions(1, extension_names);
6660   v8::Handle<Context> context =
6661       Context::New(CcTest::isolate(), &extensions);
6662   CHECK_EQ(0, *context);
6663 }
6664
6665
6666 TEST(ExtensionWithSourceLength) {
6667   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6668        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6669     v8::HandleScope handle_scope(CcTest::isolate());
6670     i::ScopedVector<char> extension_name(32);
6671     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6672     v8::RegisterExtension(new Extension(extension_name.start(),
6673                                         kEmbeddedExtensionSource, 0, 0,
6674                                         source_len));
6675     const char* extension_names[1] = { extension_name.start() };
6676     v8::ExtensionConfiguration extensions(1, extension_names);
6677     v8::Handle<Context> context =
6678       Context::New(CcTest::isolate(), &extensions);
6679     if (source_len == kEmbeddedExtensionSourceValidLen) {
6680       Context::Scope lock(context);
6681       v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6682       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6683     } else {
6684       // Anything but exactly the right length should fail to compile.
6685       CHECK_EQ(0, *context);
6686     }
6687   }
6688 }
6689
6690
6691 static const char* kEvalExtensionSource1 =
6692   "function UseEval1() {"
6693   "  var x = 42;"
6694   "  return eval('x');"
6695   "}";
6696
6697
6698 static const char* kEvalExtensionSource2 =
6699   "(function() {"
6700   "  var x = 42;"
6701   "  function e() {"
6702   "    return eval('x');"
6703   "  }"
6704   "  this.UseEval2 = e;"
6705   "})()";
6706
6707
6708 TEST(UseEvalFromExtension) {
6709   v8::HandleScope handle_scope(CcTest::isolate());
6710   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6711   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6712   const char* extension_names[] = { "evaltest1", "evaltest2" };
6713   v8::ExtensionConfiguration extensions(2, extension_names);
6714   v8::Handle<Context> context =
6715       Context::New(CcTest::isolate(), &extensions);
6716   Context::Scope lock(context);
6717   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6718   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6719   result = Script::Compile(v8_str("UseEval2()"))->Run();
6720   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6721 }
6722
6723
6724 static const char* kWithExtensionSource1 =
6725   "function UseWith1() {"
6726   "  var x = 42;"
6727   "  with({x:87}) { return x; }"
6728   "}";
6729
6730
6731
6732 static const char* kWithExtensionSource2 =
6733   "(function() {"
6734   "  var x = 42;"
6735   "  function e() {"
6736   "    with ({x:87}) { return x; }"
6737   "  }"
6738   "  this.UseWith2 = e;"
6739   "})()";
6740
6741
6742 TEST(UseWithFromExtension) {
6743   v8::HandleScope handle_scope(CcTest::isolate());
6744   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6745   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6746   const char* extension_names[] = { "withtest1", "withtest2" };
6747   v8::ExtensionConfiguration extensions(2, extension_names);
6748   v8::Handle<Context> context =
6749       Context::New(CcTest::isolate(), &extensions);
6750   Context::Scope lock(context);
6751   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6752   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6753   result = Script::Compile(v8_str("UseWith2()"))->Run();
6754   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6755 }
6756
6757
6758 TEST(AutoExtensions) {
6759   v8::HandleScope handle_scope(CcTest::isolate());
6760   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6761   extension->set_auto_enable(true);
6762   v8::RegisterExtension(extension);
6763   v8::Handle<Context> context =
6764       Context::New(CcTest::isolate());
6765   Context::Scope lock(context);
6766   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6767   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6768 }
6769
6770
6771 static const char* kSyntaxErrorInExtensionSource =
6772     "[";
6773
6774
6775 // Test that a syntax error in an extension does not cause a fatal
6776 // error but results in an empty context.
6777 TEST(SyntaxErrorExtensions) {
6778   v8::HandleScope handle_scope(CcTest::isolate());
6779   v8::RegisterExtension(new Extension("syntaxerror",
6780                                       kSyntaxErrorInExtensionSource));
6781   const char* extension_names[] = { "syntaxerror" };
6782   v8::ExtensionConfiguration extensions(1, extension_names);
6783   v8::Handle<Context> context =
6784       Context::New(CcTest::isolate(), &extensions);
6785   CHECK(context.IsEmpty());
6786 }
6787
6788
6789 static const char* kExceptionInExtensionSource =
6790     "throw 42";
6791
6792
6793 // Test that an exception when installing an extension does not cause
6794 // a fatal error but results in an empty context.
6795 TEST(ExceptionExtensions) {
6796   v8::HandleScope handle_scope(CcTest::isolate());
6797   v8::RegisterExtension(new Extension("exception",
6798                                       kExceptionInExtensionSource));
6799   const char* extension_names[] = { "exception" };
6800   v8::ExtensionConfiguration extensions(1, extension_names);
6801   v8::Handle<Context> context =
6802       Context::New(CcTest::isolate(), &extensions);
6803   CHECK(context.IsEmpty());
6804 }
6805
6806
6807 static const char* kNativeCallInExtensionSource =
6808     "function call_runtime_last_index_of(x) {"
6809     "  return %StringLastIndexOf(x, 'bob', 10);"
6810     "}";
6811
6812
6813 static const char* kNativeCallTest =
6814     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6815
6816 // Test that a native runtime calls are supported in extensions.
6817 TEST(NativeCallInExtensions) {
6818   v8::HandleScope handle_scope(CcTest::isolate());
6819   v8::RegisterExtension(new Extension("nativecall",
6820                                       kNativeCallInExtensionSource));
6821   const char* extension_names[] = { "nativecall" };
6822   v8::ExtensionConfiguration extensions(1, extension_names);
6823   v8::Handle<Context> context =
6824       Context::New(CcTest::isolate(), &extensions);
6825   Context::Scope lock(context);
6826   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6827   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6828 }
6829
6830
6831 class NativeFunctionExtension : public Extension {
6832  public:
6833   NativeFunctionExtension(const char* name,
6834                           const char* source,
6835                           v8::FunctionCallback fun = &Echo)
6836       : Extension(name, source),
6837         function_(fun) { }
6838
6839   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6840       v8::Isolate* isolate,
6841       v8::Handle<v8::String> name) {
6842     return v8::FunctionTemplate::New(isolate, function_);
6843   }
6844
6845   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6846     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6847   }
6848  private:
6849   v8::FunctionCallback function_;
6850 };
6851
6852
6853 TEST(NativeFunctionDeclaration) {
6854   v8::HandleScope handle_scope(CcTest::isolate());
6855   const char* name = "nativedecl";
6856   v8::RegisterExtension(new NativeFunctionExtension(name,
6857                                                     "native function foo();"));
6858   const char* extension_names[] = { name };
6859   v8::ExtensionConfiguration extensions(1, extension_names);
6860   v8::Handle<Context> context =
6861       Context::New(CcTest::isolate(), &extensions);
6862   Context::Scope lock(context);
6863   v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6864   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6865 }
6866
6867
6868 TEST(NativeFunctionDeclarationError) {
6869   v8::HandleScope handle_scope(CcTest::isolate());
6870   const char* name = "nativedeclerr";
6871   // Syntax error in extension code.
6872   v8::RegisterExtension(new NativeFunctionExtension(name,
6873                                                     "native\nfunction foo();"));
6874   const char* extension_names[] = { name };
6875   v8::ExtensionConfiguration extensions(1, extension_names);
6876   v8::Handle<Context> context =
6877       Context::New(CcTest::isolate(), &extensions);
6878   CHECK(context.IsEmpty());
6879 }
6880
6881
6882 TEST(NativeFunctionDeclarationErrorEscape) {
6883   v8::HandleScope handle_scope(CcTest::isolate());
6884   const char* name = "nativedeclerresc";
6885   // Syntax error in extension code - escape code in "native" means that
6886   // it's not treated as a keyword.
6887   v8::RegisterExtension(new NativeFunctionExtension(
6888       name,
6889       "nativ\\u0065 function foo();"));
6890   const char* extension_names[] = { name };
6891   v8::ExtensionConfiguration extensions(1, extension_names);
6892   v8::Handle<Context> context =
6893       Context::New(CcTest::isolate(), &extensions);
6894   CHECK(context.IsEmpty());
6895 }
6896
6897
6898 static void CheckDependencies(const char* name, const char* expected) {
6899   v8::HandleScope handle_scope(CcTest::isolate());
6900   v8::ExtensionConfiguration config(1, &name);
6901   LocalContext context(&config);
6902   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6903            context->Global()->Get(v8_str("loaded")));
6904 }
6905
6906
6907 /*
6908  * Configuration:
6909  *
6910  *     /-- B <--\
6911  * A <-          -- D <-- E
6912  *     \-- C <--/
6913  */
6914 THREADED_TEST(ExtensionDependency) {
6915   static const char* kEDeps[] = { "D" };
6916   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6917   static const char* kDDeps[] = { "B", "C" };
6918   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6919   static const char* kBCDeps[] = { "A" };
6920   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6921   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6922   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6923   CheckDependencies("A", "undefinedA");
6924   CheckDependencies("B", "undefinedAB");
6925   CheckDependencies("C", "undefinedAC");
6926   CheckDependencies("D", "undefinedABCD");
6927   CheckDependencies("E", "undefinedABCDE");
6928   v8::HandleScope handle_scope(CcTest::isolate());
6929   static const char* exts[2] = { "C", "E" };
6930   v8::ExtensionConfiguration config(2, exts);
6931   LocalContext context(&config);
6932   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6933 }
6934
6935
6936 static const char* kExtensionTestScript =
6937   "native function A();"
6938   "native function B();"
6939   "native function C();"
6940   "function Foo(i) {"
6941   "  if (i == 0) return A();"
6942   "  if (i == 1) return B();"
6943   "  if (i == 2) return C();"
6944   "}";
6945
6946
6947 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6948   ApiTestFuzzer::Fuzz();
6949   if (args.IsConstructCall()) {
6950     args.This()->Set(v8_str("data"), args.Data());
6951     args.GetReturnValue().SetNull();
6952     return;
6953   }
6954   args.GetReturnValue().Set(args.Data());
6955 }
6956
6957
6958 class FunctionExtension : public Extension {
6959  public:
6960   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6961   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6962       v8::Isolate* isolate,
6963       v8::Handle<String> name);
6964 };
6965
6966
6967 static int lookup_count = 0;
6968 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6969     v8::Isolate* isolate, v8::Handle<String> name) {
6970   lookup_count++;
6971   if (name->Equals(v8_str("A"))) {
6972     return v8::FunctionTemplate::New(
6973         isolate, CallFun, v8::Integer::New(isolate, 8));
6974   } else if (name->Equals(v8_str("B"))) {
6975     return v8::FunctionTemplate::New(
6976         isolate, CallFun, v8::Integer::New(isolate, 7));
6977   } else if (name->Equals(v8_str("C"))) {
6978     return v8::FunctionTemplate::New(
6979         isolate, CallFun, v8::Integer::New(isolate, 6));
6980   } else {
6981     return v8::Handle<v8::FunctionTemplate>();
6982   }
6983 }
6984
6985
6986 THREADED_TEST(FunctionLookup) {
6987   v8::RegisterExtension(new FunctionExtension());
6988   v8::HandleScope handle_scope(CcTest::isolate());
6989   static const char* exts[1] = { "functiontest" };
6990   v8::ExtensionConfiguration config(1, exts);
6991   LocalContext context(&config);
6992   CHECK_EQ(3, lookup_count);
6993   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
6994            Script::Compile(v8_str("Foo(0)"))->Run());
6995   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
6996            Script::Compile(v8_str("Foo(1)"))->Run());
6997   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
6998            Script::Compile(v8_str("Foo(2)"))->Run());
6999 }
7000
7001
7002 THREADED_TEST(NativeFunctionConstructCall) {
7003   v8::RegisterExtension(new FunctionExtension());
7004   v8::HandleScope handle_scope(CcTest::isolate());
7005   static const char* exts[1] = { "functiontest" };
7006   v8::ExtensionConfiguration config(1, exts);
7007   LocalContext context(&config);
7008   for (int i = 0; i < 10; i++) {
7009     // Run a few times to ensure that allocation of objects doesn't
7010     // change behavior of a constructor function.
7011     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7012              Script::Compile(v8_str("(new A()).data"))->Run());
7013     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7014              Script::Compile(v8_str("(new B()).data"))->Run());
7015     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7016              Script::Compile(v8_str("(new C()).data"))->Run());
7017   }
7018 }
7019
7020
7021 static const char* last_location;
7022 static const char* last_message;
7023 void StoringErrorCallback(const char* location, const char* message) {
7024   if (last_location == NULL) {
7025     last_location = location;
7026     last_message = message;
7027   }
7028 }
7029
7030
7031 // ErrorReporting creates a circular extensions configuration and
7032 // tests that the fatal error handler gets called.  This renders V8
7033 // unusable and therefore this test cannot be run in parallel.
7034 TEST(ErrorReporting) {
7035   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7036   static const char* aDeps[] = { "B" };
7037   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7038   static const char* bDeps[] = { "A" };
7039   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7040   last_location = NULL;
7041   v8::ExtensionConfiguration config(1, bDeps);
7042   v8::Handle<Context> context =
7043       Context::New(CcTest::isolate(), &config);
7044   CHECK(context.IsEmpty());
7045   CHECK_NE(last_location, NULL);
7046 }
7047
7048
7049 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7050                                              v8::Handle<Value> data) {
7051   CHECK(message->GetScriptResourceName()->IsUndefined());
7052   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7053   message->GetLineNumber();
7054   message->GetSourceLine();
7055 }
7056
7057
7058 THREADED_TEST(ErrorWithMissingScriptInfo) {
7059   LocalContext context;
7060   v8::HandleScope scope(context->GetIsolate());
7061   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7062   Script::Compile(v8_str("throw Error()"))->Run();
7063   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7064 }
7065
7066
7067 struct FlagAndPersistent {
7068   bool flag;
7069   v8::Persistent<v8::Object> handle;
7070 };
7071
7072
7073 static void DisposeAndSetFlag(
7074     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7075   data.GetParameter()->handle.Reset();
7076   data.GetParameter()->flag = true;
7077 }
7078
7079
7080 THREADED_TEST(IndependentWeakHandle) {
7081   v8::Isolate* iso = CcTest::isolate();
7082   v8::HandleScope scope(iso);
7083   v8::Handle<Context> context = Context::New(iso);
7084   Context::Scope context_scope(context);
7085
7086   FlagAndPersistent object_a, object_b;
7087
7088   {
7089     v8::HandleScope handle_scope(iso);
7090     object_a.handle.Reset(iso, v8::Object::New(iso));
7091     object_b.handle.Reset(iso, v8::Object::New(iso));
7092   }
7093
7094   object_a.flag = false;
7095   object_b.flag = false;
7096   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7097   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7098   CHECK(!object_b.handle.IsIndependent());
7099   object_a.handle.MarkIndependent();
7100   object_b.handle.MarkIndependent();
7101   CHECK(object_b.handle.IsIndependent());
7102   CcTest::heap()->PerformScavenge();
7103   CHECK(object_a.flag);
7104   CHECK(object_b.flag);
7105 }
7106
7107
7108 static void InvokeScavenge() {
7109   CcTest::heap()->PerformScavenge();
7110 }
7111
7112
7113 static void InvokeMarkSweep() {
7114   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7115 }
7116
7117
7118 static void ForceScavenge(
7119     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7120   data.GetParameter()->handle.Reset();
7121   data.GetParameter()->flag = true;
7122   InvokeScavenge();
7123 }
7124
7125
7126 static void ForceMarkSweep(
7127     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7128   data.GetParameter()->handle.Reset();
7129   data.GetParameter()->flag = true;
7130   InvokeMarkSweep();
7131 }
7132
7133
7134 THREADED_TEST(GCFromWeakCallbacks) {
7135   v8::Isolate* isolate = CcTest::isolate();
7136   v8::HandleScope scope(isolate);
7137   v8::Handle<Context> context = Context::New(isolate);
7138   Context::Scope context_scope(context);
7139
7140   static const int kNumberOfGCTypes = 2;
7141   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7142       Callback;
7143   Callback gc_forcing_callback[kNumberOfGCTypes] =
7144       {&ForceScavenge, &ForceMarkSweep};
7145
7146   typedef void (*GCInvoker)();
7147   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7148
7149   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7150     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7151       FlagAndPersistent object;
7152       {
7153         v8::HandleScope handle_scope(isolate);
7154         object.handle.Reset(isolate, v8::Object::New(isolate));
7155       }
7156       object.flag = false;
7157       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7158       object.handle.MarkIndependent();
7159       invoke_gc[outer_gc]();
7160       CHECK(object.flag);
7161     }
7162   }
7163 }
7164
7165
7166 static void RevivingCallback(
7167     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7168   data.GetParameter()->handle.ClearWeak();
7169   data.GetParameter()->flag = true;
7170 }
7171
7172
7173 THREADED_TEST(IndependentHandleRevival) {
7174   v8::Isolate* isolate = CcTest::isolate();
7175   v8::HandleScope scope(isolate);
7176   v8::Handle<Context> context = Context::New(isolate);
7177   Context::Scope context_scope(context);
7178
7179   FlagAndPersistent object;
7180   {
7181     v8::HandleScope handle_scope(isolate);
7182     v8::Local<v8::Object> o = v8::Object::New(isolate);
7183     object.handle.Reset(isolate, o);
7184     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7185     v8::Local<String> y_str = v8_str("y");
7186     o->Set(y_str, y_str);
7187   }
7188   object.flag = false;
7189   object.handle.SetWeak(&object, &RevivingCallback);
7190   object.handle.MarkIndependent();
7191   CcTest::heap()->PerformScavenge();
7192   CHECK(object.flag);
7193   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7194   {
7195     v8::HandleScope handle_scope(isolate);
7196     v8::Local<v8::Object> o =
7197         v8::Local<v8::Object>::New(isolate, object.handle);
7198     v8::Local<String> y_str = v8_str("y");
7199     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7200     CHECK(o->Get(y_str)->Equals(y_str));
7201   }
7202 }
7203
7204
7205 v8::Handle<Function> args_fun;
7206
7207
7208 static void ArgumentsTestCallback(
7209     const v8::FunctionCallbackInfo<v8::Value>& args) {
7210   ApiTestFuzzer::Fuzz();
7211   v8::Isolate* isolate = args.GetIsolate();
7212   CHECK_EQ(args_fun, args.Callee());
7213   CHECK_EQ(3, args.Length());
7214   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7215   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7216   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7217   CHECK_EQ(v8::Undefined(isolate), args[3]);
7218   v8::HandleScope scope(args.GetIsolate());
7219   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7220 }
7221
7222
7223 THREADED_TEST(Arguments) {
7224   v8::Isolate* isolate = CcTest::isolate();
7225   v8::HandleScope scope(isolate);
7226   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7227   global->Set(v8_str("f"),
7228               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7229   LocalContext context(NULL, global);
7230   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7231   v8_compile("f(1, 2, 3)")->Run();
7232 }
7233
7234
7235 static void NoBlockGetterX(Local<String> name,
7236                            const v8::PropertyCallbackInfo<v8::Value>&) {
7237 }
7238
7239
7240 static void NoBlockGetterI(uint32_t index,
7241                            const v8::PropertyCallbackInfo<v8::Value>&) {
7242 }
7243
7244
7245 static void PDeleter(Local<String> name,
7246                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7247   if (!name->Equals(v8_str("foo"))) {
7248     return;  // not intercepted
7249   }
7250
7251   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7252 }
7253
7254
7255 static void IDeleter(uint32_t index,
7256                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7257   if (index != 2) {
7258     return;  // not intercepted
7259   }
7260
7261   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7262 }
7263
7264
7265 THREADED_TEST(Deleter) {
7266   v8::Isolate* isolate = CcTest::isolate();
7267   v8::HandleScope scope(isolate);
7268   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7269   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7270   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7271   LocalContext context;
7272   context->Global()->Set(v8_str("k"), obj->NewInstance());
7273   CompileRun(
7274     "k.foo = 'foo';"
7275     "k.bar = 'bar';"
7276     "k[2] = 2;"
7277     "k[4] = 4;");
7278   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7279   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7280
7281   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7282   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7283
7284   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7285   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7286
7287   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7288   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7289 }
7290
7291
7292 static void GetK(Local<String> name,
7293                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7294   ApiTestFuzzer::Fuzz();
7295   if (name->Equals(v8_str("foo")) ||
7296       name->Equals(v8_str("bar")) ||
7297       name->Equals(v8_str("baz"))) {
7298     info.GetReturnValue().SetUndefined();
7299   }
7300 }
7301
7302
7303 static void IndexedGetK(uint32_t index,
7304                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7305   ApiTestFuzzer::Fuzz();
7306   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7307 }
7308
7309
7310 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7311   ApiTestFuzzer::Fuzz();
7312   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7313   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7314   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7315   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7316   info.GetReturnValue().Set(result);
7317 }
7318
7319
7320 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7321   ApiTestFuzzer::Fuzz();
7322   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7323   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7324   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7325   info.GetReturnValue().Set(result);
7326 }
7327
7328
7329 THREADED_TEST(Enumerators) {
7330   v8::Isolate* isolate = CcTest::isolate();
7331   v8::HandleScope scope(isolate);
7332   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7333   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7334   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7335   LocalContext context;
7336   context->Global()->Set(v8_str("k"), obj->NewInstance());
7337   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7338     "k[10] = 0;"
7339     "k.a = 0;"
7340     "k[5] = 0;"
7341     "k.b = 0;"
7342     "k[4294967295] = 0;"
7343     "k.c = 0;"
7344     "k[4294967296] = 0;"
7345     "k.d = 0;"
7346     "k[140000] = 0;"
7347     "k.e = 0;"
7348     "k[30000000000] = 0;"
7349     "k.f = 0;"
7350     "var result = [];"
7351     "for (var prop in k) {"
7352     "  result.push(prop);"
7353     "}"
7354     "result"));
7355   // Check that we get all the property names returned including the
7356   // ones from the enumerators in the right order: indexed properties
7357   // in numerical order, indexed interceptor properties, named
7358   // properties in insertion order, named interceptor properties.
7359   // This order is not mandated by the spec, so this test is just
7360   // documenting our behavior.
7361   CHECK_EQ(17, result->Length());
7362   // Indexed properties in numerical order.
7363   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7364   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7365   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7366   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7367   // Indexed interceptor properties in the order they are returned
7368   // from the enumerator interceptor.
7369   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7370   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7371   // Named properties in insertion order.
7372   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7373   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7374   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7375   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7376   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7377   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7378   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7379   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7380   // Named interceptor properties.
7381   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7382   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7383   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7384 }
7385
7386
7387 int p_getter_count;
7388 int p_getter_count2;
7389
7390
7391 static void PGetter(Local<String> name,
7392                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7393   ApiTestFuzzer::Fuzz();
7394   p_getter_count++;
7395   v8::Handle<v8::Object> global =
7396       info.GetIsolate()->GetCurrentContext()->Global();
7397   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7398   if (name->Equals(v8_str("p1"))) {
7399     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7400   } else if (name->Equals(v8_str("p2"))) {
7401     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7402   } else if (name->Equals(v8_str("p3"))) {
7403     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7404   } else if (name->Equals(v8_str("p4"))) {
7405     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7406   }
7407 }
7408
7409
7410 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7411   ApiTestFuzzer::Fuzz();
7412   LocalContext context;
7413   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7414   CompileRun(
7415     "o1.__proto__ = { };"
7416     "var o2 = { __proto__: o1 };"
7417     "var o3 = { __proto__: o2 };"
7418     "var o4 = { __proto__: o3 };"
7419     "for (var i = 0; i < 10; i++) o4.p4;"
7420     "for (var i = 0; i < 10; i++) o3.p3;"
7421     "for (var i = 0; i < 10; i++) o2.p2;"
7422     "for (var i = 0; i < 10; i++) o1.p1;");
7423 }
7424
7425
7426 static void PGetter2(Local<String> name,
7427                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7428   ApiTestFuzzer::Fuzz();
7429   p_getter_count2++;
7430   v8::Handle<v8::Object> global =
7431       info.GetIsolate()->GetCurrentContext()->Global();
7432   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7433   if (name->Equals(v8_str("p1"))) {
7434     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7435   } else if (name->Equals(v8_str("p2"))) {
7436     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7437   } else if (name->Equals(v8_str("p3"))) {
7438     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7439   } else if (name->Equals(v8_str("p4"))) {
7440     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7441   }
7442 }
7443
7444
7445 THREADED_TEST(GetterHolders) {
7446   v8::Isolate* isolate = CcTest::isolate();
7447   v8::HandleScope scope(isolate);
7448   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7449   obj->SetAccessor(v8_str("p1"), PGetter);
7450   obj->SetAccessor(v8_str("p2"), PGetter);
7451   obj->SetAccessor(v8_str("p3"), PGetter);
7452   obj->SetAccessor(v8_str("p4"), PGetter);
7453   p_getter_count = 0;
7454   RunHolderTest(obj);
7455   CHECK_EQ(40, p_getter_count);
7456 }
7457
7458
7459 THREADED_TEST(PreInterceptorHolders) {
7460   v8::Isolate* isolate = CcTest::isolate();
7461   v8::HandleScope scope(isolate);
7462   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7463   obj->SetNamedPropertyHandler(PGetter2);
7464   p_getter_count2 = 0;
7465   RunHolderTest(obj);
7466   CHECK_EQ(40, p_getter_count2);
7467 }
7468
7469
7470 THREADED_TEST(ObjectInstantiation) {
7471   v8::Isolate* isolate = CcTest::isolate();
7472   v8::HandleScope scope(isolate);
7473   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7474   templ->SetAccessor(v8_str("t"), PGetter2);
7475   LocalContext context;
7476   context->Global()->Set(v8_str("o"), templ->NewInstance());
7477   for (int i = 0; i < 100; i++) {
7478     v8::HandleScope inner_scope(CcTest::isolate());
7479     v8::Handle<v8::Object> obj = templ->NewInstance();
7480     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7481     context->Global()->Set(v8_str("o2"), obj);
7482     v8::Handle<Value> value =
7483         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7484     CHECK_EQ(v8::True(isolate), value);
7485     context->Global()->Set(v8_str("o"), obj);
7486   }
7487 }
7488
7489
7490 static int StrCmp16(uint16_t* a, uint16_t* b) {
7491   while (true) {
7492     if (*a == 0 && *b == 0) return 0;
7493     if (*a != *b) return 0 + *a - *b;
7494     a++;
7495     b++;
7496   }
7497 }
7498
7499
7500 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7501   while (true) {
7502     if (n-- == 0) return 0;
7503     if (*a == 0 && *b == 0) return 0;
7504     if (*a != *b) return 0 + *a - *b;
7505     a++;
7506     b++;
7507   }
7508 }
7509
7510
7511 int GetUtf8Length(Handle<String> str) {
7512   int len = str->Utf8Length();
7513   if (len < 0) {
7514     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7515     i::FlattenString(istr);
7516     len = str->Utf8Length();
7517   }
7518   return len;
7519 }
7520
7521
7522 THREADED_TEST(StringWrite) {
7523   LocalContext context;
7524   v8::HandleScope scope(context->GetIsolate());
7525   v8::Handle<String> str = v8_str("abcde");
7526   // abc<Icelandic eth><Unicode snowman>.
7527   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7528   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7529       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7530   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7531   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7532   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7533       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7534   // single lead surrogate
7535   uint16_t lead[1] = { 0xd800 };
7536   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7537       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7538   // single trail surrogate
7539   uint16_t trail[1] = { 0xdc00 };
7540   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7541       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7542   // surrogate pair
7543   uint16_t pair[2] = { 0xd800,  0xdc00 };
7544   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7545       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7546   const int kStride = 4;  // Must match stride in for loops in JS below.
7547   CompileRun(
7548       "var left = '';"
7549       "for (var i = 0; i < 0xd800; i += 4) {"
7550       "  left = left + String.fromCharCode(i);"
7551       "}");
7552   CompileRun(
7553       "var right = '';"
7554       "for (var i = 0; i < 0xd800; i += 4) {"
7555       "  right = String.fromCharCode(i) + right;"
7556       "}");
7557   v8::Handle<v8::Object> global = context->Global();
7558   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7559   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7560
7561   CHECK_EQ(5, str2->Length());
7562   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7563   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7564
7565   char buf[100];
7566   char utf8buf[0xd800 * 3];
7567   uint16_t wbuf[100];
7568   int len;
7569   int charlen;
7570
7571   memset(utf8buf, 0x1, 1000);
7572   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7573   CHECK_EQ(9, len);
7574   CHECK_EQ(5, charlen);
7575   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7576
7577   memset(utf8buf, 0x1, 1000);
7578   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7579   CHECK_EQ(8, len);
7580   CHECK_EQ(5, charlen);
7581   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7582
7583   memset(utf8buf, 0x1, 1000);
7584   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7585   CHECK_EQ(5, len);
7586   CHECK_EQ(4, charlen);
7587   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7588
7589   memset(utf8buf, 0x1, 1000);
7590   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7591   CHECK_EQ(5, len);
7592   CHECK_EQ(4, charlen);
7593   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7594
7595   memset(utf8buf, 0x1, 1000);
7596   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7597   CHECK_EQ(5, len);
7598   CHECK_EQ(4, charlen);
7599   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7600
7601   memset(utf8buf, 0x1, 1000);
7602   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7603   CHECK_EQ(3, len);
7604   CHECK_EQ(3, charlen);
7605   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7606
7607   memset(utf8buf, 0x1, 1000);
7608   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7609   CHECK_EQ(3, len);
7610   CHECK_EQ(3, charlen);
7611   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7612
7613   memset(utf8buf, 0x1, 1000);
7614   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7615   CHECK_EQ(2, len);
7616   CHECK_EQ(2, charlen);
7617   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7618
7619   // allow orphan surrogates by default
7620   memset(utf8buf, 0x1, 1000);
7621   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7622   CHECK_EQ(13, len);
7623   CHECK_EQ(8, charlen);
7624   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7625
7626   // replace orphan surrogates with unicode replacement character
7627   memset(utf8buf, 0x1, 1000);
7628   len = orphans_str->WriteUtf8(utf8buf,
7629                                sizeof(utf8buf),
7630                                &charlen,
7631                                String::REPLACE_INVALID_UTF8);
7632   CHECK_EQ(13, len);
7633   CHECK_EQ(8, charlen);
7634   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7635
7636   // replace single lead surrogate with unicode replacement character
7637   memset(utf8buf, 0x1, 1000);
7638   len = lead_str->WriteUtf8(utf8buf,
7639                             sizeof(utf8buf),
7640                             &charlen,
7641                             String::REPLACE_INVALID_UTF8);
7642   CHECK_EQ(4, len);
7643   CHECK_EQ(1, charlen);
7644   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7645
7646   // replace single trail surrogate with unicode replacement character
7647   memset(utf8buf, 0x1, 1000);
7648   len = trail_str->WriteUtf8(utf8buf,
7649                              sizeof(utf8buf),
7650                              &charlen,
7651                              String::REPLACE_INVALID_UTF8);
7652   CHECK_EQ(4, len);
7653   CHECK_EQ(1, charlen);
7654   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7655
7656   // do not replace / write anything if surrogate pair does not fit the buffer
7657   // space
7658   memset(utf8buf, 0x1, 1000);
7659   len = pair_str->WriteUtf8(utf8buf,
7660                              3,
7661                              &charlen,
7662                              String::REPLACE_INVALID_UTF8);
7663   CHECK_EQ(0, len);
7664   CHECK_EQ(0, charlen);
7665
7666   memset(utf8buf, 0x1, sizeof(utf8buf));
7667   len = GetUtf8Length(left_tree);
7668   int utf8_expected =
7669       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7670   CHECK_EQ(utf8_expected, len);
7671   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7672   CHECK_EQ(utf8_expected, len);
7673   CHECK_EQ(0xd800 / kStride, charlen);
7674   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7675   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7676   CHECK_EQ(0xc0 - kStride,
7677            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7678   CHECK_EQ(1, utf8buf[utf8_expected]);
7679
7680   memset(utf8buf, 0x1, sizeof(utf8buf));
7681   len = GetUtf8Length(right_tree);
7682   CHECK_EQ(utf8_expected, len);
7683   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7684   CHECK_EQ(utf8_expected, len);
7685   CHECK_EQ(0xd800 / kStride, charlen);
7686   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7687   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7688   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7689   CHECK_EQ(1, utf8buf[utf8_expected]);
7690
7691   memset(buf, 0x1, sizeof(buf));
7692   memset(wbuf, 0x1, sizeof(wbuf));
7693   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7694   CHECK_EQ(5, len);
7695   len = str->Write(wbuf);
7696   CHECK_EQ(5, len);
7697   CHECK_EQ(0, strcmp("abcde", buf));
7698   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7699   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7700
7701   memset(buf, 0x1, sizeof(buf));
7702   memset(wbuf, 0x1, sizeof(wbuf));
7703   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7704   CHECK_EQ(4, len);
7705   len = str->Write(wbuf, 0, 4);
7706   CHECK_EQ(4, len);
7707   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7708   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7709   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7710
7711   memset(buf, 0x1, sizeof(buf));
7712   memset(wbuf, 0x1, sizeof(wbuf));
7713   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7714   CHECK_EQ(5, len);
7715   len = str->Write(wbuf, 0, 5);
7716   CHECK_EQ(5, len);
7717   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7718   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7719   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7720
7721   memset(buf, 0x1, sizeof(buf));
7722   memset(wbuf, 0x1, sizeof(wbuf));
7723   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7724   CHECK_EQ(5, len);
7725   len = str->Write(wbuf, 0, 6);
7726   CHECK_EQ(5, len);
7727   CHECK_EQ(0, strcmp("abcde", buf));
7728   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7729   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7730
7731   memset(buf, 0x1, sizeof(buf));
7732   memset(wbuf, 0x1, sizeof(wbuf));
7733   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7734   CHECK_EQ(1, len);
7735   len = str->Write(wbuf, 4, -1);
7736   CHECK_EQ(1, len);
7737   CHECK_EQ(0, strcmp("e", buf));
7738   uint16_t answer5[] = {'e', '\0'};
7739   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7740
7741   memset(buf, 0x1, sizeof(buf));
7742   memset(wbuf, 0x1, sizeof(wbuf));
7743   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7744   CHECK_EQ(1, len);
7745   len = str->Write(wbuf, 4, 6);
7746   CHECK_EQ(1, len);
7747   CHECK_EQ(0, strcmp("e", buf));
7748   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7749
7750   memset(buf, 0x1, sizeof(buf));
7751   memset(wbuf, 0x1, sizeof(wbuf));
7752   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7753   CHECK_EQ(1, len);
7754   len = str->Write(wbuf, 4, 1);
7755   CHECK_EQ(1, len);
7756   CHECK_EQ(0, strncmp("e\1", buf, 2));
7757   uint16_t answer6[] = {'e', 0x101};
7758   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7759
7760   memset(buf, 0x1, sizeof(buf));
7761   memset(wbuf, 0x1, sizeof(wbuf));
7762   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7763   CHECK_EQ(1, len);
7764   len = str->Write(wbuf, 3, 1);
7765   CHECK_EQ(1, len);
7766   CHECK_EQ(0, strncmp("d\1", buf, 2));
7767   uint16_t answer7[] = {'d', 0x101};
7768   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7769
7770   memset(wbuf, 0x1, sizeof(wbuf));
7771   wbuf[5] = 'X';
7772   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7773   CHECK_EQ(5, len);
7774   CHECK_EQ('X', wbuf[5]);
7775   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7776   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7777   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7778   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7779   wbuf[5] = '\0';
7780   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7781
7782   memset(buf, 0x1, sizeof(buf));
7783   buf[5] = 'X';
7784   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7785                           0,
7786                           6,
7787                           String::NO_NULL_TERMINATION);
7788   CHECK_EQ(5, len);
7789   CHECK_EQ('X', buf[5]);
7790   CHECK_EQ(0, strncmp("abcde", buf, 5));
7791   CHECK_NE(0, strcmp("abcde", buf));
7792   buf[5] = '\0';
7793   CHECK_EQ(0, strcmp("abcde", buf));
7794
7795   memset(utf8buf, 0x1, sizeof(utf8buf));
7796   utf8buf[8] = 'X';
7797   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7798                         String::NO_NULL_TERMINATION);
7799   CHECK_EQ(8, len);
7800   CHECK_EQ('X', utf8buf[8]);
7801   CHECK_EQ(5, charlen);
7802   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7803   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7804   utf8buf[8] = '\0';
7805   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7806
7807   memset(utf8buf, 0x1, sizeof(utf8buf));
7808   utf8buf[5] = 'X';
7809   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7810                         String::NO_NULL_TERMINATION);
7811   CHECK_EQ(5, len);
7812   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7813   CHECK_EQ(5, charlen);
7814   utf8buf[5] = '\0';
7815   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7816
7817   memset(buf, 0x1, sizeof(buf));
7818   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7819   CHECK_EQ(7, len);
7820   CHECK_EQ(0, strcmp("abc", buf));
7821   CHECK_EQ(0, buf[3]);
7822   CHECK_EQ(0, strcmp("def", buf + 4));
7823
7824   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7825   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7826   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7827 }
7828
7829
7830 static void Utf16Helper(
7831     LocalContext& context,
7832     const char* name,
7833     const char* lengths_name,
7834     int len) {
7835   Local<v8::Array> a =
7836       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7837   Local<v8::Array> alens =
7838       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7839   for (int i = 0; i < len; i++) {
7840     Local<v8::String> string =
7841       Local<v8::String>::Cast(a->Get(i));
7842     Local<v8::Number> expected_len =
7843       Local<v8::Number>::Cast(alens->Get(i));
7844     int length = GetUtf8Length(string);
7845     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7846   }
7847 }
7848
7849
7850 static uint16_t StringGet(Handle<String> str, int index) {
7851   i::Handle<i::String> istring =
7852       v8::Utils::OpenHandle(String::Cast(*str));
7853   return istring->Get(index);
7854 }
7855
7856
7857 static void WriteUtf8Helper(
7858     LocalContext& context,
7859     const char* name,
7860     const char* lengths_name,
7861     int len) {
7862   Local<v8::Array> b =
7863       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7864   Local<v8::Array> alens =
7865       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7866   char buffer[1000];
7867   char buffer2[1000];
7868   for (int i = 0; i < len; i++) {
7869     Local<v8::String> string =
7870       Local<v8::String>::Cast(b->Get(i));
7871     Local<v8::Number> expected_len =
7872       Local<v8::Number>::Cast(alens->Get(i));
7873     int utf8_length = static_cast<int>(expected_len->Value());
7874     for (int j = utf8_length + 1; j >= 0; j--) {
7875       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7876       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7877       int nchars;
7878       int utf8_written =
7879           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7880       int utf8_written2 =
7881           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7882       CHECK_GE(utf8_length + 1, utf8_written);
7883       CHECK_GE(utf8_length, utf8_written2);
7884       for (int k = 0; k < utf8_written2; k++) {
7885         CHECK_EQ(buffer[k], buffer2[k]);
7886       }
7887       CHECK(nchars * 3 >= utf8_written - 1);
7888       CHECK(nchars <= utf8_written);
7889       if (j == utf8_length + 1) {
7890         CHECK_EQ(utf8_written2, utf8_length);
7891         CHECK_EQ(utf8_written2 + 1, utf8_written);
7892       }
7893       CHECK_EQ(buffer[utf8_written], 42);
7894       if (j > utf8_length) {
7895         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7896         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7897         Handle<String> roundtrip = v8_str(buffer);
7898         CHECK(roundtrip->Equals(string));
7899       } else {
7900         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7901       }
7902       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7903       if (nchars >= 2) {
7904         uint16_t trail = StringGet(string, nchars - 1);
7905         uint16_t lead = StringGet(string, nchars - 2);
7906         if (((lead & 0xfc00) == 0xd800) &&
7907             ((trail & 0xfc00) == 0xdc00)) {
7908           unsigned char u1 = buffer2[utf8_written2 - 4];
7909           unsigned char u2 = buffer2[utf8_written2 - 3];
7910           unsigned char u3 = buffer2[utf8_written2 - 2];
7911           unsigned char u4 = buffer2[utf8_written2 - 1];
7912           CHECK_EQ((u1 & 0xf8), 0xf0);
7913           CHECK_EQ((u2 & 0xc0), 0x80);
7914           CHECK_EQ((u3 & 0xc0), 0x80);
7915           CHECK_EQ((u4 & 0xc0), 0x80);
7916           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7917           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7918           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7919           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7920           CHECK_EQ((u1 & 0x3), c >> 18);
7921         }
7922       }
7923     }
7924   }
7925 }
7926
7927
7928 THREADED_TEST(Utf16) {
7929   LocalContext context;
7930   v8::HandleScope scope(context->GetIsolate());
7931   CompileRun(
7932       "var pad = '01234567890123456789';"
7933       "var p = [];"
7934       "var plens = [20, 3, 3];"
7935       "p.push('01234567890123456789');"
7936       "var lead = 0xd800;"
7937       "var trail = 0xdc00;"
7938       "p.push(String.fromCharCode(0xd800));"
7939       "p.push(String.fromCharCode(0xdc00));"
7940       "var a = [];"
7941       "var b = [];"
7942       "var c = [];"
7943       "var alens = [];"
7944       "for (var i = 0; i < 3; i++) {"
7945       "  p[1] = String.fromCharCode(lead++);"
7946       "  for (var j = 0; j < 3; j++) {"
7947       "    p[2] = String.fromCharCode(trail++);"
7948       "    a.push(p[i] + p[j]);"
7949       "    b.push(p[i] + p[j]);"
7950       "    c.push(p[i] + p[j]);"
7951       "    alens.push(plens[i] + plens[j]);"
7952       "  }"
7953       "}"
7954       "alens[5] -= 2;"  // Here the surrogate pairs match up.
7955       "var a2 = [];"
7956       "var b2 = [];"
7957       "var c2 = [];"
7958       "var a2lens = [];"
7959       "for (var m = 0; m < 9; m++) {"
7960       "  for (var n = 0; n < 9; n++) {"
7961       "    a2.push(a[m] + a[n]);"
7962       "    b2.push(b[m] + b[n]);"
7963       "    var newc = 'x' + c[m] + c[n] + 'y';"
7964       "    c2.push(newc.substring(1, newc.length - 1));"
7965       "    var utf = alens[m] + alens[n];"  // And here.
7966            // The 'n's that start with 0xdc.. are 6-8
7967            // The 'm's that end with 0xd8.. are 1, 4 and 7
7968       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
7969       "    a2lens.push(utf);"
7970       "  }"
7971       "}");
7972   Utf16Helper(context, "a", "alens", 9);
7973   Utf16Helper(context, "a2", "a2lens", 81);
7974   WriteUtf8Helper(context, "b", "alens", 9);
7975   WriteUtf8Helper(context, "b2", "a2lens", 81);
7976   WriteUtf8Helper(context, "c2", "a2lens", 81);
7977 }
7978
7979
7980 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7981   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7982   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7983   return *is1 == *is2;
7984 }
7985
7986 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
7987                              const char* b) {
7988   Handle<String> symbol1 =
7989       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
7990   Handle<String> symbol2 =
7991       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
7992   CHECK(SameSymbol(symbol1, symbol2));
7993 }
7994
7995
7996 THREADED_TEST(Utf16Symbol) {
7997   LocalContext context;
7998   v8::HandleScope scope(context->GetIsolate());
7999
8000   Handle<String> symbol1 = v8::String::NewFromUtf8(
8001       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8002   Handle<String> symbol2 = v8::String::NewFromUtf8(
8003       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8004   CHECK(SameSymbol(symbol1, symbol2));
8005
8006   SameSymbolHelper(context->GetIsolate(),
8007                    "\360\220\220\205",  // 4 byte encoding.
8008                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8009   SameSymbolHelper(context->GetIsolate(),
8010                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8011                    "\360\220\220\206");  // 4 byte encoding.
8012   SameSymbolHelper(context->GetIsolate(),
8013                    "x\360\220\220\205",  // 4 byte encoding.
8014                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8015   SameSymbolHelper(context->GetIsolate(),
8016                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8017                    "x\360\220\220\206");  // 4 byte encoding.
8018   CompileRun(
8019       "var sym0 = 'benedictus';"
8020       "var sym0b = 'S\303\270ren';"
8021       "var sym1 = '\355\240\201\355\260\207';"
8022       "var sym2 = '\360\220\220\210';"
8023       "var sym3 = 'x\355\240\201\355\260\207';"
8024       "var sym4 = 'x\360\220\220\210';"
8025       "if (sym1.length != 2) throw sym1;"
8026       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8027       "if (sym2.length != 2) throw sym2;"
8028       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8029       "if (sym3.length != 3) throw sym3;"
8030       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8031       "if (sym4.length != 3) throw sym4;"
8032       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8033   Handle<String> sym0 = v8::String::NewFromUtf8(
8034       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8035   Handle<String> sym0b = v8::String::NewFromUtf8(
8036       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8037   Handle<String> sym1 =
8038       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8039                               v8::String::kInternalizedString);
8040   Handle<String> sym2 =
8041       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8042                               v8::String::kInternalizedString);
8043   Handle<String> sym3 = v8::String::NewFromUtf8(
8044       context->GetIsolate(), "x\355\240\201\355\260\207",
8045       v8::String::kInternalizedString);
8046   Handle<String> sym4 =
8047       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8048                               v8::String::kInternalizedString);
8049   v8::Local<v8::Object> global = context->Global();
8050   Local<Value> s0 = global->Get(v8_str("sym0"));
8051   Local<Value> s0b = global->Get(v8_str("sym0b"));
8052   Local<Value> s1 = global->Get(v8_str("sym1"));
8053   Local<Value> s2 = global->Get(v8_str("sym2"));
8054   Local<Value> s3 = global->Get(v8_str("sym3"));
8055   Local<Value> s4 = global->Get(v8_str("sym4"));
8056   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8057   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8058   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8059   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8060   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8061   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8062 }
8063
8064
8065 THREADED_TEST(ToArrayIndex) {
8066   LocalContext context;
8067   v8::Isolate* isolate = context->GetIsolate();
8068   v8::HandleScope scope(isolate);
8069
8070   v8::Handle<String> str = v8_str("42");
8071   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8072   CHECK(!index.IsEmpty());
8073   CHECK_EQ(42.0, index->Uint32Value());
8074   str = v8_str("42asdf");
8075   index = str->ToArrayIndex();
8076   CHECK(index.IsEmpty());
8077   str = v8_str("-42");
8078   index = str->ToArrayIndex();
8079   CHECK(index.IsEmpty());
8080   str = v8_str("4294967295");
8081   index = str->ToArrayIndex();
8082   CHECK(!index.IsEmpty());
8083   CHECK_EQ(4294967295.0, index->Uint32Value());
8084   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8085   index = num->ToArrayIndex();
8086   CHECK(!index.IsEmpty());
8087   CHECK_EQ(1.0, index->Uint32Value());
8088   num = v8::Number::New(isolate, -1);
8089   index = num->ToArrayIndex();
8090   CHECK(index.IsEmpty());
8091   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8092   index = obj->ToArrayIndex();
8093   CHECK(index.IsEmpty());
8094 }
8095
8096
8097 THREADED_TEST(ErrorConstruction) {
8098   LocalContext context;
8099   v8::HandleScope scope(context->GetIsolate());
8100
8101   v8::Handle<String> foo = v8_str("foo");
8102   v8::Handle<String> message = v8_str("message");
8103   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8104   CHECK(range_error->IsObject());
8105   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8106   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8107   CHECK(reference_error->IsObject());
8108   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8109   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8110   CHECK(syntax_error->IsObject());
8111   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8112   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8113   CHECK(type_error->IsObject());
8114   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8115   v8::Handle<Value> error = v8::Exception::Error(foo);
8116   CHECK(error->IsObject());
8117   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8118 }
8119
8120
8121 static void YGetter(Local<String> name,
8122                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8123   ApiTestFuzzer::Fuzz();
8124   info.GetReturnValue().Set(v8_num(10));
8125 }
8126
8127
8128 static void YSetter(Local<String> name,
8129                     Local<Value> value,
8130                     const v8::PropertyCallbackInfo<void>& info) {
8131   if (info.This()->Has(name)) {
8132     info.This()->Delete(name);
8133   }
8134   info.This()->Set(name, value);
8135 }
8136
8137
8138 THREADED_TEST(DeleteAccessor) {
8139   v8::Isolate* isolate = CcTest::isolate();
8140   v8::HandleScope scope(isolate);
8141   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8142   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8143   LocalContext context;
8144   v8::Handle<v8::Object> holder = obj->NewInstance();
8145   context->Global()->Set(v8_str("holder"), holder);
8146   v8::Handle<Value> result = CompileRun(
8147       "holder.y = 11; holder.y = 12; holder.y");
8148   CHECK_EQ(12, result->Uint32Value());
8149 }
8150
8151
8152 THREADED_TEST(TypeSwitch) {
8153   v8::Isolate* isolate = CcTest::isolate();
8154   v8::HandleScope scope(isolate);
8155   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8156   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8157   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8158   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8159   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8160   LocalContext context;
8161   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8162   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8163   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8164   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8165   for (int i = 0; i < 10; i++) {
8166     CHECK_EQ(0, type_switch->match(obj0));
8167     CHECK_EQ(1, type_switch->match(obj1));
8168     CHECK_EQ(2, type_switch->match(obj2));
8169     CHECK_EQ(3, type_switch->match(obj3));
8170     CHECK_EQ(3, type_switch->match(obj3));
8171     CHECK_EQ(2, type_switch->match(obj2));
8172     CHECK_EQ(1, type_switch->match(obj1));
8173     CHECK_EQ(0, type_switch->match(obj0));
8174   }
8175 }
8176
8177
8178 // For use within the TestSecurityHandler() test.
8179 static bool g_security_callback_result = false;
8180 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8181                                       Local<Value> name,
8182                                       v8::AccessType type,
8183                                       Local<Value> data) {
8184   // Always allow read access.
8185   if (type == v8::ACCESS_GET)
8186     return true;
8187
8188   // Sometimes allow other access.
8189   return g_security_callback_result;
8190 }
8191
8192
8193 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8194                                         uint32_t key,
8195                                         v8::AccessType type,
8196                                         Local<Value> data) {
8197   // Always allow read access.
8198   if (type == v8::ACCESS_GET)
8199     return true;
8200
8201   // Sometimes allow other access.
8202   return g_security_callback_result;
8203 }
8204
8205
8206 static int trouble_nesting = 0;
8207 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8208   ApiTestFuzzer::Fuzz();
8209   trouble_nesting++;
8210
8211   // Call a JS function that throws an uncaught exception.
8212   Local<v8::Object> arg_this =
8213       args.GetIsolate()->GetCurrentContext()->Global();
8214   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8215     arg_this->Get(v8_str("trouble_callee")) :
8216     arg_this->Get(v8_str("trouble_caller"));
8217   CHECK(trouble_callee->IsFunction());
8218   args.GetReturnValue().Set(
8219       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8220 }
8221
8222
8223 static int report_count = 0;
8224 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8225                                              v8::Handle<Value>) {
8226   report_count++;
8227 }
8228
8229
8230 // Counts uncaught exceptions, but other tests running in parallel
8231 // also have uncaught exceptions.
8232 TEST(ApiUncaughtException) {
8233   report_count = 0;
8234   LocalContext env;
8235   v8::Isolate* isolate = env->GetIsolate();
8236   v8::HandleScope scope(isolate);
8237   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8238
8239   Local<v8::FunctionTemplate> fun =
8240       v8::FunctionTemplate::New(isolate, TroubleCallback);
8241   v8::Local<v8::Object> global = env->Global();
8242   global->Set(v8_str("trouble"), fun->GetFunction());
8243
8244   Script::Compile(v8_str("function trouble_callee() {"
8245                          "  var x = null;"
8246                          "  return x.foo;"
8247                          "};"
8248                          "function trouble_caller() {"
8249                          "  trouble();"
8250                          "};"))->Run();
8251   Local<Value> trouble = global->Get(v8_str("trouble"));
8252   CHECK(trouble->IsFunction());
8253   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8254   CHECK(trouble_callee->IsFunction());
8255   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8256   CHECK(trouble_caller->IsFunction());
8257   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8258   CHECK_EQ(1, report_count);
8259   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8260 }
8261
8262 static const char* script_resource_name = "ExceptionInNativeScript.js";
8263 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8264                                                 v8::Handle<Value>) {
8265   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8266   CHECK(!name_val.IsEmpty() && name_val->IsString());
8267   v8::String::Utf8Value name(message->GetScriptResourceName());
8268   CHECK_EQ(script_resource_name, *name);
8269   CHECK_EQ(3, message->GetLineNumber());
8270   v8::String::Utf8Value source_line(message->GetSourceLine());
8271   CHECK_EQ("  new o.foo();", *source_line);
8272 }
8273
8274
8275 TEST(ExceptionInNativeScript) {
8276   LocalContext env;
8277   v8::Isolate* isolate = env->GetIsolate();
8278   v8::HandleScope scope(isolate);
8279   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8280
8281   Local<v8::FunctionTemplate> fun =
8282       v8::FunctionTemplate::New(isolate, TroubleCallback);
8283   v8::Local<v8::Object> global = env->Global();
8284   global->Set(v8_str("trouble"), fun->GetFunction());
8285
8286   Script::Compile(
8287       v8_str(
8288           "function trouble() {\n"
8289           "  var o = {};\n"
8290           "  new o.foo();\n"
8291           "};"),
8292       v8::String::NewFromUtf8(isolate, script_resource_name))->Run();
8293   Local<Value> trouble = global->Get(v8_str("trouble"));
8294   CHECK(trouble->IsFunction());
8295   Function::Cast(*trouble)->Call(global, 0, NULL);
8296   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8297 }
8298
8299
8300 TEST(CompilationErrorUsingTryCatchHandler) {
8301   LocalContext env;
8302   v8::HandleScope scope(env->GetIsolate());
8303   v8::TryCatch try_catch;
8304   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
8305   CHECK_NE(NULL, *try_catch.Exception());
8306   CHECK(try_catch.HasCaught());
8307 }
8308
8309
8310 TEST(TryCatchFinallyUsingTryCatchHandler) {
8311   LocalContext env;
8312   v8::HandleScope scope(env->GetIsolate());
8313   v8::TryCatch try_catch;
8314   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
8315   CHECK(!try_catch.HasCaught());
8316   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
8317   CHECK(try_catch.HasCaught());
8318   try_catch.Reset();
8319   Script::Compile(v8_str("(function() {"
8320                          "try { throw ''; } finally { return; }"
8321                          "})()"))->Run();
8322   CHECK(!try_catch.HasCaught());
8323   Script::Compile(v8_str("(function()"
8324                          "  { try { throw ''; } finally { throw 0; }"
8325                          "})()"))->Run();
8326   CHECK(try_catch.HasCaught());
8327 }
8328
8329
8330 // SecurityHandler can't be run twice
8331 TEST(SecurityHandler) {
8332   v8::Isolate* isolate = CcTest::isolate();
8333   v8::HandleScope scope0(isolate);
8334   v8::Handle<v8::ObjectTemplate> global_template =
8335       v8::ObjectTemplate::New(isolate);
8336   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8337                                            IndexedSecurityTestCallback);
8338   // Create an environment
8339   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8340   context0->Enter();
8341
8342   v8::Handle<v8::Object> global0 = context0->Global();
8343   v8::Handle<Script> script0 = v8_compile("foo = 111");
8344   script0->Run();
8345   global0->Set(v8_str("0"), v8_num(999));
8346   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8347   CHECK_EQ(111, foo0->Int32Value());
8348   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8349   CHECK_EQ(999, z0->Int32Value());
8350
8351   // Create another environment, should fail security checks.
8352   v8::HandleScope scope1(isolate);
8353
8354   v8::Handle<Context> context1 =
8355     Context::New(isolate, NULL, global_template);
8356   context1->Enter();
8357
8358   v8::Handle<v8::Object> global1 = context1->Global();
8359   global1->Set(v8_str("othercontext"), global0);
8360   // This set will fail the security check.
8361   v8::Handle<Script> script1 =
8362     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8363   script1->Run();
8364   // This read will pass the security check.
8365   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8366   CHECK_EQ(111, foo1->Int32Value());
8367   // This read will pass the security check.
8368   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8369   CHECK_EQ(999, z1->Int32Value());
8370
8371   // Create another environment, should pass security checks.
8372   { g_security_callback_result = true;  // allow security handler to pass.
8373     v8::HandleScope scope2(isolate);
8374     LocalContext context2;
8375     v8::Handle<v8::Object> global2 = context2->Global();
8376     global2->Set(v8_str("othercontext"), global0);
8377     v8::Handle<Script> script2 =
8378         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8379     script2->Run();
8380     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8381     CHECK_EQ(333, foo2->Int32Value());
8382     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8383     CHECK_EQ(888, z2->Int32Value());
8384   }
8385
8386   context1->Exit();
8387   context0->Exit();
8388 }
8389
8390
8391 THREADED_TEST(SecurityChecks) {
8392   LocalContext env1;
8393   v8::HandleScope handle_scope(env1->GetIsolate());
8394   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8395
8396   Local<Value> foo = v8_str("foo");
8397   Local<Value> bar = v8_str("bar");
8398
8399   // Set to the same domain.
8400   env1->SetSecurityToken(foo);
8401
8402   // Create a function in env1.
8403   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
8404   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8405   CHECK(spy->IsFunction());
8406
8407   // Create another function accessing global objects.
8408   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
8409   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8410   CHECK(spy2->IsFunction());
8411
8412   // Switch to env2 in the same domain and invoke spy on env2.
8413   {
8414     env2->SetSecurityToken(foo);
8415     // Enter env2
8416     Context::Scope scope_env2(env2);
8417     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8418     CHECK(result->IsFunction());
8419   }
8420
8421   {
8422     env2->SetSecurityToken(bar);
8423     Context::Scope scope_env2(env2);
8424
8425     // Call cross_domain_call, it should throw an exception
8426     v8::TryCatch try_catch;
8427     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8428     CHECK(try_catch.HasCaught());
8429   }
8430 }
8431
8432
8433 // Regression test case for issue 1183439.
8434 THREADED_TEST(SecurityChecksForPrototypeChain) {
8435   LocalContext current;
8436   v8::HandleScope scope(current->GetIsolate());
8437   v8::Handle<Context> other = Context::New(current->GetIsolate());
8438
8439   // Change context to be able to get to the Object function in the
8440   // other context without hitting the security checks.
8441   v8::Local<Value> other_object;
8442   { Context::Scope scope(other);
8443     other_object = other->Global()->Get(v8_str("Object"));
8444     other->Global()->Set(v8_num(42), v8_num(87));
8445   }
8446
8447   current->Global()->Set(v8_str("other"), other->Global());
8448   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8449
8450   // Make sure the security check fails here and we get an undefined
8451   // result instead of getting the Object function. Repeat in a loop
8452   // to make sure to exercise the IC code.
8453   v8::Local<Script> access_other0 = v8_compile("other.Object");
8454   v8::Local<Script> access_other1 = v8_compile("other[42]");
8455   for (int i = 0; i < 5; i++) {
8456     CHECK(!access_other0->Run()->Equals(other_object));
8457     CHECK(access_other0->Run()->IsUndefined());
8458     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8459     CHECK(access_other1->Run()->IsUndefined());
8460   }
8461
8462   // Create an object that has 'other' in its prototype chain and make
8463   // sure we cannot access the Object function indirectly through
8464   // that. Repeat in a loop to make sure to exercise the IC code.
8465   v8_compile("function F() { };"
8466              "F.prototype = other;"
8467              "var f = new F();")->Run();
8468   v8::Local<Script> access_f0 = v8_compile("f.Object");
8469   v8::Local<Script> access_f1 = v8_compile("f[42]");
8470   for (int j = 0; j < 5; j++) {
8471     CHECK(!access_f0->Run()->Equals(other_object));
8472     CHECK(access_f0->Run()->IsUndefined());
8473     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8474     CHECK(access_f1->Run()->IsUndefined());
8475   }
8476
8477   // Now it gets hairy: Set the prototype for the other global object
8478   // to be the current global object. The prototype chain for 'f' now
8479   // goes through 'other' but ends up in the current global object.
8480   { Context::Scope scope(other);
8481     other->Global()->Set(v8_str("__proto__"), current->Global());
8482   }
8483   // Set a named and an index property on the current global
8484   // object. To force the lookup to go through the other global object,
8485   // the properties must not exist in the other global object.
8486   current->Global()->Set(v8_str("foo"), v8_num(100));
8487   current->Global()->Set(v8_num(99), v8_num(101));
8488   // Try to read the properties from f and make sure that the access
8489   // gets stopped by the security checks on the other global object.
8490   Local<Script> access_f2 = v8_compile("f.foo");
8491   Local<Script> access_f3 = v8_compile("f[99]");
8492   for (int k = 0; k < 5; k++) {
8493     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8494     CHECK(access_f2->Run()->IsUndefined());
8495     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8496     CHECK(access_f3->Run()->IsUndefined());
8497   }
8498 }
8499
8500
8501 THREADED_TEST(CrossDomainDelete) {
8502   LocalContext env1;
8503   v8::HandleScope handle_scope(env1->GetIsolate());
8504   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8505
8506   Local<Value> foo = v8_str("foo");
8507   Local<Value> bar = v8_str("bar");
8508
8509   // Set to the same domain.
8510   env1->SetSecurityToken(foo);
8511   env2->SetSecurityToken(foo);
8512
8513   env1->Global()->Set(v8_str("prop"), v8_num(3));
8514   env2->Global()->Set(v8_str("env1"), env1->Global());
8515
8516   // Change env2 to a different domain and delete env1.prop.
8517   env2->SetSecurityToken(bar);
8518   {
8519     Context::Scope scope_env2(env2);
8520     Local<Value> result =
8521         Script::Compile(v8_str("delete env1.prop"))->Run();
8522     CHECK(result->IsFalse());
8523   }
8524
8525   // Check that env1.prop still exists.
8526   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8527   CHECK(v->IsNumber());
8528   CHECK_EQ(3, v->Int32Value());
8529 }
8530
8531
8532 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8533   LocalContext env1;
8534   v8::HandleScope handle_scope(env1->GetIsolate());
8535   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8536
8537   Local<Value> foo = v8_str("foo");
8538   Local<Value> bar = v8_str("bar");
8539
8540   // Set to the same domain.
8541   env1->SetSecurityToken(foo);
8542   env2->SetSecurityToken(foo);
8543
8544   env1->Global()->Set(v8_str("prop"), v8_num(3));
8545   env2->Global()->Set(v8_str("env1"), env1->Global());
8546
8547   // env1.prop is enumerable in env2.
8548   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8549   {
8550     Context::Scope scope_env2(env2);
8551     Local<Value> result = Script::Compile(test)->Run();
8552     CHECK(result->IsTrue());
8553   }
8554
8555   // Change env2 to a different domain and test again.
8556   env2->SetSecurityToken(bar);
8557   {
8558     Context::Scope scope_env2(env2);
8559     Local<Value> result = Script::Compile(test)->Run();
8560     CHECK(result->IsFalse());
8561   }
8562 }
8563
8564
8565 THREADED_TEST(CrossDomainForIn) {
8566   LocalContext env1;
8567   v8::HandleScope handle_scope(env1->GetIsolate());
8568   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8569
8570   Local<Value> foo = v8_str("foo");
8571   Local<Value> bar = v8_str("bar");
8572
8573   // Set to the same domain.
8574   env1->SetSecurityToken(foo);
8575   env2->SetSecurityToken(foo);
8576
8577   env1->Global()->Set(v8_str("prop"), v8_num(3));
8578   env2->Global()->Set(v8_str("env1"), env1->Global());
8579
8580   // Change env2 to a different domain and set env1's global object
8581   // as the __proto__ of an object in env2 and enumerate properties
8582   // in for-in. It shouldn't enumerate properties on env1's global
8583   // object.
8584   env2->SetSecurityToken(bar);
8585   {
8586     Context::Scope scope_env2(env2);
8587     Local<Value> result =
8588         CompileRun("(function(){var obj = {'__proto__':env1};"
8589                    "for (var p in obj)"
8590                    "   if (p == 'prop') return false;"
8591                    "return true;})()");
8592     CHECK(result->IsTrue());
8593   }
8594 }
8595
8596
8597 TEST(ContextDetachGlobal) {
8598   LocalContext env1;
8599   v8::HandleScope handle_scope(env1->GetIsolate());
8600   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8601
8602   Local<v8::Object> global1 = env1->Global();
8603
8604   Local<Value> foo = v8_str("foo");
8605
8606   // Set to the same domain.
8607   env1->SetSecurityToken(foo);
8608   env2->SetSecurityToken(foo);
8609
8610   // Enter env2
8611   env2->Enter();
8612
8613   // Create a function in env2 and add a reference to it in env1.
8614   Local<v8::Object> global2 = env2->Global();
8615   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8616   CompileRun("function getProp() {return prop;}");
8617
8618   env1->Global()->Set(v8_str("getProp"),
8619                       global2->Get(v8_str("getProp")));
8620
8621   // Detach env2's global, and reuse the global object of env2
8622   env2->Exit();
8623   env2->DetachGlobal();
8624
8625   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8626                                           0,
8627                                           v8::Handle<v8::ObjectTemplate>(),
8628                                           global2);
8629   env3->SetSecurityToken(v8_str("bar"));
8630   env3->Enter();
8631
8632   Local<v8::Object> global3 = env3->Global();
8633   CHECK_EQ(global2, global3);
8634   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8635   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8636   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8637   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8638   env3->Exit();
8639
8640   // Call getProp in env1, and it should return the value 1
8641   {
8642     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8643     CHECK(get_prop->IsFunction());
8644     v8::TryCatch try_catch;
8645     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8646     CHECK(!try_catch.HasCaught());
8647     CHECK_EQ(1, r->Int32Value());
8648   }
8649
8650   // Check that env3 is not accessible from env1
8651   {
8652     Local<Value> r = global3->Get(v8_str("prop2"));
8653     CHECK(r->IsUndefined());
8654   }
8655 }
8656
8657
8658 TEST(DetachGlobal) {
8659   LocalContext env1;
8660   v8::HandleScope scope(env1->GetIsolate());
8661
8662   // Create second environment.
8663   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8664
8665   Local<Value> foo = v8_str("foo");
8666
8667   // Set same security token for env1 and env2.
8668   env1->SetSecurityToken(foo);
8669   env2->SetSecurityToken(foo);
8670
8671   // Create a property on the global object in env2.
8672   {
8673     v8::Context::Scope scope(env2);
8674     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8675   }
8676
8677   // Create a reference to env2 global from env1 global.
8678   env1->Global()->Set(v8_str("other"), env2->Global());
8679
8680   // Check that we have access to other.p in env2 from env1.
8681   Local<Value> result = CompileRun("other.p");
8682   CHECK(result->IsInt32());
8683   CHECK_EQ(42, result->Int32Value());
8684
8685   // Hold on to global from env2 and detach global from env2.
8686   Local<v8::Object> global2 = env2->Global();
8687   env2->DetachGlobal();
8688
8689   // Check that the global has been detached. No other.p property can
8690   // be found.
8691   result = CompileRun("other.p");
8692   CHECK(result->IsUndefined());
8693
8694   // Reuse global2 for env3.
8695   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8696                                           0,
8697                                           v8::Handle<v8::ObjectTemplate>(),
8698                                           global2);
8699   CHECK_EQ(global2, env3->Global());
8700
8701   // Start by using the same security token for env3 as for env1 and env2.
8702   env3->SetSecurityToken(foo);
8703
8704   // Create a property on the global object in env3.
8705   {
8706     v8::Context::Scope scope(env3);
8707     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8708   }
8709
8710   // Check that other.p is now the property in env3 and that we have access.
8711   result = CompileRun("other.p");
8712   CHECK(result->IsInt32());
8713   CHECK_EQ(24, result->Int32Value());
8714
8715   // Change security token for env3 to something different from env1 and env2.
8716   env3->SetSecurityToken(v8_str("bar"));
8717
8718   // Check that we do not have access to other.p in env1. |other| is now
8719   // the global object for env3 which has a different security token,
8720   // so access should be blocked.
8721   result = CompileRun("other.p");
8722   CHECK(result->IsUndefined());
8723 }
8724
8725
8726 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8727   info.GetReturnValue().Set(
8728       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8729 }
8730
8731
8732 TEST(DetachedAccesses) {
8733   LocalContext env1;
8734   v8::HandleScope scope(env1->GetIsolate());
8735
8736   // Create second environment.
8737   Local<ObjectTemplate> inner_global_template =
8738       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8739   inner_global_template ->SetAccessorProperty(
8740       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8741   v8::Local<Context> env2 =
8742       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8743
8744   Local<Value> foo = v8_str("foo");
8745
8746   // Set same security token for env1 and env2.
8747   env1->SetSecurityToken(foo);
8748   env2->SetSecurityToken(foo);
8749
8750   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8751
8752   {
8753     v8::Context::Scope scope(env2);
8754     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8755     CompileRun(
8756         "function bound_x() { return x; }"
8757         "function get_x()   { return this.x; }"
8758         "function get_x_w() { return (function() {return this.x;})(); }");
8759     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8760     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8761     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8762     env1->Global()->Set(
8763         v8_str("this_x"),
8764         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8765   }
8766
8767   Local<Object> env2_global = env2->Global();
8768   env2_global->TurnOnAccessCheck();
8769   env2->DetachGlobal();
8770
8771   Local<Value> result;
8772   result = CompileRun("bound_x()");
8773   CHECK_EQ(v8_str("env2_x"), result);
8774   result = CompileRun("get_x()");
8775   CHECK(result->IsUndefined());
8776   result = CompileRun("get_x_w()");
8777   CHECK(result->IsUndefined());
8778   result = CompileRun("this_x()");
8779   CHECK_EQ(v8_str("env2_x"), result);
8780
8781   // Reattach env2's proxy
8782   env2 = Context::New(env1->GetIsolate(),
8783                       0,
8784                       v8::Handle<v8::ObjectTemplate>(),
8785                       env2_global);
8786   env2->SetSecurityToken(foo);
8787   {
8788     v8::Context::Scope scope(env2);
8789     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8790     env2->Global()->Set(v8_str("env1"), env1->Global());
8791     result = CompileRun(
8792         "results = [];"
8793         "for (var i = 0; i < 4; i++ ) {"
8794         "  results.push(env1.bound_x());"
8795         "  results.push(env1.get_x());"
8796         "  results.push(env1.get_x_w());"
8797         "  results.push(env1.this_x());"
8798         "}"
8799         "results");
8800     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8801     CHECK_EQ(16, results->Length());
8802     for (int i = 0; i < 16; i += 4) {
8803       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8804       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8805       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8806       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8807     }
8808   }
8809
8810   result = CompileRun(
8811       "results = [];"
8812       "for (var i = 0; i < 4; i++ ) {"
8813       "  results.push(bound_x());"
8814       "  results.push(get_x());"
8815       "  results.push(get_x_w());"
8816       "  results.push(this_x());"
8817       "}"
8818       "results");
8819   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8820   CHECK_EQ(16, results->Length());
8821   for (int i = 0; i < 16; i += 4) {
8822     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8823     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8824     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8825     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8826   }
8827
8828   result = CompileRun(
8829       "results = [];"
8830       "for (var i = 0; i < 4; i++ ) {"
8831       "  results.push(this.bound_x());"
8832       "  results.push(this.get_x());"
8833       "  results.push(this.get_x_w());"
8834       "  results.push(this.this_x());"
8835       "}"
8836       "results");
8837   results = Local<v8::Array>::Cast(result);
8838   CHECK_EQ(16, results->Length());
8839   for (int i = 0; i < 16; i += 4) {
8840     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8841     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8842     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8843     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8844   }
8845 }
8846
8847
8848 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8849 static bool NamedAccessBlocker(Local<v8::Object> global,
8850                                Local<Value> name,
8851                                v8::AccessType type,
8852                                Local<Value> data) {
8853   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8854       allowed_access_type[type];
8855 }
8856
8857
8858 static bool IndexedAccessBlocker(Local<v8::Object> global,
8859                                  uint32_t key,
8860                                  v8::AccessType type,
8861                                  Local<Value> data) {
8862   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8863       allowed_access_type[type];
8864 }
8865
8866
8867 static int g_echo_value_1 = -1;
8868 static int g_echo_value_2 = -1;
8869
8870
8871 static void EchoGetter(
8872     Local<String> name,
8873     const v8::PropertyCallbackInfo<v8::Value>& info) {
8874   info.GetReturnValue().Set(v8_num(g_echo_value_1));
8875 }
8876
8877
8878 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8879   info.GetReturnValue().Set(v8_num(g_echo_value_2));
8880 }
8881
8882
8883 static void EchoSetter(Local<String> name,
8884                        Local<Value> value,
8885                        const v8::PropertyCallbackInfo<void>&) {
8886   if (value->IsNumber())
8887     g_echo_value_1 = value->Int32Value();
8888 }
8889
8890
8891 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8892   v8::Handle<v8::Value> value = info[0];
8893   if (value->IsNumber())
8894     g_echo_value_2 = value->Int32Value();
8895 }
8896
8897
8898 static void UnreachableGetter(
8899     Local<String> name,
8900     const v8::PropertyCallbackInfo<v8::Value>& info) {
8901   CHECK(false);  // This function should not be called..
8902 }
8903
8904
8905 static void UnreachableSetter(Local<String>,
8906                               Local<Value>,
8907                               const v8::PropertyCallbackInfo<void>&) {
8908   CHECK(false);  // This function should nto be called.
8909 }
8910
8911
8912 static void UnreachableFunction(
8913     const v8::FunctionCallbackInfo<v8::Value>& info) {
8914   CHECK(false);  // This function should not be called..
8915 }
8916
8917
8918 TEST(AccessControl) {
8919   v8::Isolate* isolate = CcTest::isolate();
8920   v8::HandleScope handle_scope(isolate);
8921   v8::Handle<v8::ObjectTemplate> global_template =
8922       v8::ObjectTemplate::New(isolate);
8923
8924   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8925                                            IndexedAccessBlocker);
8926
8927   // Add an accessor accessible by cross-domain JS code.
8928   global_template->SetAccessor(
8929       v8_str("accessible_prop"),
8930       EchoGetter, EchoSetter,
8931       v8::Handle<Value>(),
8932       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8933
8934
8935   global_template->SetAccessorProperty(
8936       v8_str("accessible_js_prop"),
8937       v8::FunctionTemplate::New(isolate, EchoGetter),
8938       v8::FunctionTemplate::New(isolate, EchoSetter),
8939       v8::None,
8940       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8941
8942   // Add an accessor that is not accessible by cross-domain JS code.
8943   global_template->SetAccessor(v8_str("blocked_prop"),
8944                                UnreachableGetter, UnreachableSetter,
8945                                v8::Handle<Value>(),
8946                                v8::DEFAULT);
8947
8948   global_template->SetAccessorProperty(
8949       v8_str("blocked_js_prop"),
8950       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8951       v8::FunctionTemplate::New(isolate, UnreachableFunction),
8952       v8::None,
8953       v8::DEFAULT);
8954
8955   // Create an environment
8956   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8957   context0->Enter();
8958
8959   v8::Handle<v8::Object> global0 = context0->Global();
8960
8961   // Define a property with JS getter and setter.
8962   CompileRun(
8963       "function getter() { return 'getter'; };\n"
8964       "function setter() { return 'setter'; }\n"
8965       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8966
8967   Local<Value> getter = global0->Get(v8_str("getter"));
8968   Local<Value> setter = global0->Get(v8_str("setter"));
8969
8970   // And define normal element.
8971   global0->Set(239, v8_str("239"));
8972
8973   // Define an element with JS getter and setter.
8974   CompileRun(
8975       "function el_getter() { return 'el_getter'; };\n"
8976       "function el_setter() { return 'el_setter'; };\n"
8977       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8978
8979   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8980   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8981
8982   v8::HandleScope scope1(isolate);
8983
8984   v8::Local<Context> context1 = Context::New(isolate);
8985   context1->Enter();
8986
8987   v8::Handle<v8::Object> global1 = context1->Global();
8988   global1->Set(v8_str("other"), global0);
8989
8990   // Access blocked property.
8991   CompileRun("other.blocked_prop = 1");
8992
8993   ExpectUndefined("other.blocked_prop");
8994   ExpectUndefined(
8995       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8996   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8997
8998   // Enable ACCESS_HAS
8999   allowed_access_type[v8::ACCESS_HAS] = true;
9000   ExpectUndefined("other.blocked_prop");
9001   // ... and now we can get the descriptor...
9002   ExpectUndefined(
9003       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9004   // ... and enumerate the property.
9005   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9006   allowed_access_type[v8::ACCESS_HAS] = false;
9007
9008   // Access blocked element.
9009   CompileRun("other[239] = 1");
9010
9011   ExpectUndefined("other[239]");
9012   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9013   ExpectFalse("propertyIsEnumerable.call(other, '239')");
9014
9015   // Enable ACCESS_HAS
9016   allowed_access_type[v8::ACCESS_HAS] = true;
9017   ExpectUndefined("other[239]");
9018   // ... and now we can get the descriptor...
9019   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9020   // ... and enumerate the property.
9021   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9022   allowed_access_type[v8::ACCESS_HAS] = false;
9023
9024   // Access a property with JS accessor.
9025   CompileRun("other.js_accessor_p = 2");
9026
9027   ExpectUndefined("other.js_accessor_p");
9028   ExpectUndefined(
9029       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9030
9031   // Enable ACCESS_HAS.
9032   allowed_access_type[v8::ACCESS_HAS] = true;
9033   ExpectUndefined("other.js_accessor_p");
9034   ExpectUndefined(
9035       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9036   ExpectUndefined(
9037       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9038   ExpectUndefined(
9039       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9040   allowed_access_type[v8::ACCESS_HAS] = false;
9041
9042   // Enable both ACCESS_HAS and ACCESS_GET.
9043   allowed_access_type[v8::ACCESS_HAS] = true;
9044   allowed_access_type[v8::ACCESS_GET] = true;
9045
9046   ExpectString("other.js_accessor_p", "getter");
9047   ExpectObject(
9048       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9049   ExpectUndefined(
9050       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9051   ExpectUndefined(
9052       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9053
9054   allowed_access_type[v8::ACCESS_GET] = false;
9055   allowed_access_type[v8::ACCESS_HAS] = false;
9056
9057   // Enable both ACCESS_HAS and ACCESS_SET.
9058   allowed_access_type[v8::ACCESS_HAS] = true;
9059   allowed_access_type[v8::ACCESS_SET] = true;
9060
9061   ExpectUndefined("other.js_accessor_p");
9062   ExpectUndefined(
9063       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9064   ExpectObject(
9065       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9066   ExpectUndefined(
9067       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9068
9069   allowed_access_type[v8::ACCESS_SET] = false;
9070   allowed_access_type[v8::ACCESS_HAS] = false;
9071
9072   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9073   allowed_access_type[v8::ACCESS_HAS] = true;
9074   allowed_access_type[v8::ACCESS_GET] = true;
9075   allowed_access_type[v8::ACCESS_SET] = true;
9076
9077   ExpectString("other.js_accessor_p", "getter");
9078   ExpectObject(
9079       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9080   ExpectObject(
9081       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9082   ExpectUndefined(
9083       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9084
9085   allowed_access_type[v8::ACCESS_SET] = false;
9086   allowed_access_type[v8::ACCESS_GET] = false;
9087   allowed_access_type[v8::ACCESS_HAS] = false;
9088
9089   // Access an element with JS accessor.
9090   CompileRun("other[42] = 2");
9091
9092   ExpectUndefined("other[42]");
9093   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9094
9095   // Enable ACCESS_HAS.
9096   allowed_access_type[v8::ACCESS_HAS] = true;
9097   ExpectUndefined("other[42]");
9098   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9099   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9100   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9101   allowed_access_type[v8::ACCESS_HAS] = false;
9102
9103   // Enable both ACCESS_HAS and ACCESS_GET.
9104   allowed_access_type[v8::ACCESS_HAS] = true;
9105   allowed_access_type[v8::ACCESS_GET] = true;
9106
9107   ExpectString("other[42]", "el_getter");
9108   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9109   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9110   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9111
9112   allowed_access_type[v8::ACCESS_GET] = false;
9113   allowed_access_type[v8::ACCESS_HAS] = false;
9114
9115   // Enable both ACCESS_HAS and ACCESS_SET.
9116   allowed_access_type[v8::ACCESS_HAS] = true;
9117   allowed_access_type[v8::ACCESS_SET] = true;
9118
9119   ExpectUndefined("other[42]");
9120   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9121   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9122   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9123
9124   allowed_access_type[v8::ACCESS_SET] = false;
9125   allowed_access_type[v8::ACCESS_HAS] = false;
9126
9127   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9128   allowed_access_type[v8::ACCESS_HAS] = true;
9129   allowed_access_type[v8::ACCESS_GET] = true;
9130   allowed_access_type[v8::ACCESS_SET] = true;
9131
9132   ExpectString("other[42]", "el_getter");
9133   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9134   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9135   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9136
9137   allowed_access_type[v8::ACCESS_SET] = false;
9138   allowed_access_type[v8::ACCESS_GET] = false;
9139   allowed_access_type[v8::ACCESS_HAS] = false;
9140
9141   v8::Handle<Value> value;
9142
9143   // Access accessible property
9144   value = CompileRun("other.accessible_prop = 3");
9145   CHECK(value->IsNumber());
9146   CHECK_EQ(3, value->Int32Value());
9147   CHECK_EQ(3, g_echo_value_1);
9148
9149   // Access accessible js property
9150   value = CompileRun("other.accessible_js_prop = 3");
9151   CHECK(value->IsNumber());
9152   CHECK_EQ(3, value->Int32Value());
9153   CHECK_EQ(3, g_echo_value_2);
9154
9155   value = CompileRun("other.accessible_prop");
9156   CHECK(value->IsNumber());
9157   CHECK_EQ(3, value->Int32Value());
9158
9159   value = CompileRun("other.accessible_js_prop");
9160   CHECK(value->IsNumber());
9161   CHECK_EQ(3, value->Int32Value());
9162
9163   value = CompileRun(
9164       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9165   CHECK(value->IsNumber());
9166   CHECK_EQ(3, value->Int32Value());
9167
9168   value = CompileRun(
9169       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9170   CHECK(value->IsNumber());
9171   CHECK_EQ(3, value->Int32Value());
9172
9173   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9174   CHECK(value->IsTrue());
9175
9176   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9177   CHECK(value->IsTrue());
9178
9179   // Enumeration doesn't enumerate accessors from inaccessible objects in
9180   // the prototype chain even if the accessors are in themselves accessible.
9181   value =
9182       CompileRun("(function(){var obj = {'__proto__':other};"
9183                  "for (var p in obj)"
9184                  "   if (p == 'accessible_prop' ||"
9185                  "       p == 'accessible_js_prop' ||"
9186                  "       p == 'blocked_js_prop' ||"
9187                  "       p == 'blocked_js_prop') {"
9188                  "     return false;"
9189                  "   }"
9190                  "return true;})()");
9191   CHECK(value->IsTrue());
9192
9193   context1->Exit();
9194   context0->Exit();
9195 }
9196
9197
9198 TEST(AccessControlES5) {
9199   v8::Isolate* isolate = CcTest::isolate();
9200   v8::HandleScope handle_scope(isolate);
9201   v8::Handle<v8::ObjectTemplate> global_template =
9202       v8::ObjectTemplate::New(isolate);
9203
9204   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9205                                            IndexedAccessBlocker);
9206
9207   // Add accessible accessor.
9208   global_template->SetAccessor(
9209       v8_str("accessible_prop"),
9210       EchoGetter, EchoSetter,
9211       v8::Handle<Value>(),
9212       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9213
9214
9215   // Add an accessor that is not accessible by cross-domain JS code.
9216   global_template->SetAccessor(v8_str("blocked_prop"),
9217                                UnreachableGetter, UnreachableSetter,
9218                                v8::Handle<Value>(),
9219                                v8::DEFAULT);
9220
9221   // Create an environment
9222   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9223   context0->Enter();
9224
9225   v8::Handle<v8::Object> global0 = context0->Global();
9226
9227   v8::Local<Context> context1 = Context::New(isolate);
9228   context1->Enter();
9229   v8::Handle<v8::Object> global1 = context1->Global();
9230   global1->Set(v8_str("other"), global0);
9231
9232   // Regression test for issue 1154.
9233   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9234
9235   ExpectUndefined("other.blocked_prop");
9236
9237   // Regression test for issue 1027.
9238   CompileRun("Object.defineProperty(\n"
9239              "  other, 'blocked_prop', {configurable: false})");
9240   ExpectUndefined("other.blocked_prop");
9241   ExpectUndefined(
9242       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9243
9244   // Regression test for issue 1171.
9245   ExpectTrue("Object.isExtensible(other)");
9246   CompileRun("Object.preventExtensions(other)");
9247   ExpectTrue("Object.isExtensible(other)");
9248
9249   // Object.seal and Object.freeze.
9250   CompileRun("Object.freeze(other)");
9251   ExpectTrue("Object.isExtensible(other)");
9252
9253   CompileRun("Object.seal(other)");
9254   ExpectTrue("Object.isExtensible(other)");
9255
9256   // Regression test for issue 1250.
9257   // Make sure that we can set the accessible accessors value using normal
9258   // assignment.
9259   CompileRun("other.accessible_prop = 42");
9260   CHECK_EQ(42, g_echo_value_1);
9261
9262   v8::Handle<Value> value;
9263   // We follow Safari in ignoring assignments to host object accessors.
9264   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9265   value = CompileRun("other.accessible_prop == 42");
9266   CHECK(value->IsTrue());
9267 }
9268
9269
9270 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9271                                             Local<Value> name,
9272                                             v8::AccessType type,
9273                                             Local<Value> data) {
9274   return false;
9275 }
9276
9277
9278 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9279                                               uint32_t key,
9280                                               v8::AccessType type,
9281                                               Local<Value> data) {
9282   return false;
9283 }
9284
9285
9286 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9287   v8::Isolate* isolate = CcTest::isolate();
9288   v8::HandleScope handle_scope(isolate);
9289   v8::Handle<v8::ObjectTemplate> obj_template =
9290       v8::ObjectTemplate::New(isolate);
9291
9292   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9293   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9294                                         GetOwnPropertyNamesIndexedBlocker);
9295
9296   // Create an environment
9297   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9298   context0->Enter();
9299
9300   v8::Handle<v8::Object> global0 = context0->Global();
9301
9302   v8::HandleScope scope1(CcTest::isolate());
9303
9304   v8::Local<Context> context1 = Context::New(isolate);
9305   context1->Enter();
9306
9307   v8::Handle<v8::Object> global1 = context1->Global();
9308   global1->Set(v8_str("other"), global0);
9309   global1->Set(v8_str("object"), obj_template->NewInstance());
9310
9311   v8::Handle<Value> value;
9312
9313   // Attempt to get the property names of the other global object and
9314   // of an object that requires access checks.  Accessing the other
9315   // global object should be blocked by access checks on the global
9316   // proxy object.  Accessing the object that requires access checks
9317   // is blocked by the access checks on the object itself.
9318   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9319   CHECK(value->IsTrue());
9320
9321   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9322   CHECK(value->IsTrue());
9323
9324   context1->Exit();
9325   context0->Exit();
9326 }
9327
9328
9329 static void IndexedPropertyEnumerator(
9330     const v8::PropertyCallbackInfo<v8::Array>& info) {
9331   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9332   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9333   result->Set(1, v8::Object::New(info.GetIsolate()));
9334   info.GetReturnValue().Set(result);
9335 }
9336
9337
9338 static void NamedPropertyEnumerator(
9339     const v8::PropertyCallbackInfo<v8::Array>& info) {
9340   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9341   result->Set(0, v8_str("x"));
9342   result->Set(1, v8::Object::New(info.GetIsolate()));
9343   info.GetReturnValue().Set(result);
9344 }
9345
9346
9347 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9348   v8::Isolate* isolate = CcTest::isolate();
9349   v8::HandleScope handle_scope(isolate);
9350   v8::Handle<v8::ObjectTemplate> obj_template =
9351       v8::ObjectTemplate::New(isolate);
9352
9353   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9354   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9355   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9356                                           IndexedPropertyEnumerator);
9357   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9358                                         NamedPropertyEnumerator);
9359
9360   LocalContext context;
9361   v8::Handle<v8::Object> global = context->Global();
9362   global->Set(v8_str("object"), obj_template->NewInstance());
9363
9364   v8::Handle<v8::Value> result =
9365       CompileRun("Object.getOwnPropertyNames(object)");
9366   CHECK(result->IsArray());
9367   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9368   CHECK_EQ(3, result_array->Length());
9369   CHECK(result_array->Get(0)->IsString());
9370   CHECK(result_array->Get(1)->IsString());
9371   CHECK(result_array->Get(2)->IsString());
9372   CHECK_EQ(v8_str("7"), result_array->Get(0));
9373   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9374   CHECK_EQ(v8_str("x"), result_array->Get(2));
9375 }
9376
9377
9378 static void ConstTenGetter(Local<String> name,
9379                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9380   info.GetReturnValue().Set(v8_num(10));
9381 }
9382
9383
9384 THREADED_TEST(CrossDomainAccessors) {
9385   v8::Isolate* isolate = CcTest::isolate();
9386   v8::HandleScope handle_scope(isolate);
9387
9388   v8::Handle<v8::FunctionTemplate> func_template =
9389       v8::FunctionTemplate::New(isolate);
9390
9391   v8::Handle<v8::ObjectTemplate> global_template =
9392       func_template->InstanceTemplate();
9393
9394   v8::Handle<v8::ObjectTemplate> proto_template =
9395       func_template->PrototypeTemplate();
9396
9397   // Add an accessor to proto that's accessible by cross-domain JS code.
9398   proto_template->SetAccessor(v8_str("accessible"),
9399                               ConstTenGetter, 0,
9400                               v8::Handle<Value>(),
9401                               v8::ALL_CAN_READ);
9402
9403   // Add an accessor that is not accessible by cross-domain JS code.
9404   global_template->SetAccessor(v8_str("unreachable"),
9405                                UnreachableGetter, 0,
9406                                v8::Handle<Value>(),
9407                                v8::DEFAULT);
9408
9409   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9410   context0->Enter();
9411
9412   Local<v8::Object> global = context0->Global();
9413   // Add a normal property that shadows 'accessible'
9414   global->Set(v8_str("accessible"), v8_num(11));
9415
9416   // Enter a new context.
9417   v8::HandleScope scope1(CcTest::isolate());
9418   v8::Local<Context> context1 = Context::New(isolate);
9419   context1->Enter();
9420
9421   v8::Handle<v8::Object> global1 = context1->Global();
9422   global1->Set(v8_str("other"), global);
9423
9424   // Should return 10, instead of 11
9425   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9426   CHECK(value->IsNumber());
9427   CHECK_EQ(10, value->Int32Value());
9428
9429   value = v8_compile("other.unreachable")->Run();
9430   CHECK(value->IsUndefined());
9431
9432   context1->Exit();
9433   context0->Exit();
9434 }
9435
9436
9437 static int named_access_count = 0;
9438 static int indexed_access_count = 0;
9439
9440 static bool NamedAccessCounter(Local<v8::Object> global,
9441                                Local<Value> name,
9442                                v8::AccessType type,
9443                                Local<Value> data) {
9444   named_access_count++;
9445   return true;
9446 }
9447
9448
9449 static bool IndexedAccessCounter(Local<v8::Object> global,
9450                                  uint32_t key,
9451                                  v8::AccessType type,
9452                                  Local<Value> data) {
9453   indexed_access_count++;
9454   return true;
9455 }
9456
9457
9458 // This one is too easily disturbed by other tests.
9459 TEST(AccessControlIC) {
9460   named_access_count = 0;
9461   indexed_access_count = 0;
9462
9463   v8::Isolate* isolate = CcTest::isolate();
9464   v8::HandleScope handle_scope(isolate);
9465
9466   // Create an environment.
9467   v8::Local<Context> context0 = Context::New(isolate);
9468   context0->Enter();
9469
9470   // Create an object that requires access-check functions to be
9471   // called for cross-domain access.
9472   v8::Handle<v8::ObjectTemplate> object_template =
9473       v8::ObjectTemplate::New(isolate);
9474   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9475                                            IndexedAccessCounter);
9476   Local<v8::Object> object = object_template->NewInstance();
9477
9478   v8::HandleScope scope1(isolate);
9479
9480   // Create another environment.
9481   v8::Local<Context> context1 = Context::New(isolate);
9482   context1->Enter();
9483
9484   // Make easy access to the object from the other environment.
9485   v8::Handle<v8::Object> global1 = context1->Global();
9486   global1->Set(v8_str("obj"), object);
9487
9488   v8::Handle<Value> value;
9489
9490   // Check that the named access-control function is called every time.
9491   CompileRun("function testProp(obj) {"
9492              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9493              "  for (var j = 0; j < 10; j++) obj.prop;"
9494              "  return obj.prop"
9495              "}");
9496   value = CompileRun("testProp(obj)");
9497   CHECK(value->IsNumber());
9498   CHECK_EQ(1, value->Int32Value());
9499   CHECK_EQ(21, named_access_count);
9500
9501   // Check that the named access-control function is called every time.
9502   CompileRun("var p = 'prop';"
9503              "function testKeyed(obj) {"
9504              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9505              "  for (var j = 0; j < 10; j++) obj[p];"
9506              "  return obj[p];"
9507              "}");
9508   // Use obj which requires access checks.  No inline caching is used
9509   // in that case.
9510   value = CompileRun("testKeyed(obj)");
9511   CHECK(value->IsNumber());
9512   CHECK_EQ(1, value->Int32Value());
9513   CHECK_EQ(42, named_access_count);
9514   // Force the inline caches into generic state and try again.
9515   CompileRun("testKeyed({ a: 0 })");
9516   CompileRun("testKeyed({ b: 0 })");
9517   value = CompileRun("testKeyed(obj)");
9518   CHECK(value->IsNumber());
9519   CHECK_EQ(1, value->Int32Value());
9520   CHECK_EQ(63, named_access_count);
9521
9522   // Check that the indexed access-control function is called every time.
9523   CompileRun("function testIndexed(obj) {"
9524              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9525              "  for (var j = 0; j < 10; j++) obj[0];"
9526              "  return obj[0]"
9527              "}");
9528   value = CompileRun("testIndexed(obj)");
9529   CHECK(value->IsNumber());
9530   CHECK_EQ(1, value->Int32Value());
9531   CHECK_EQ(21, indexed_access_count);
9532   // Force the inline caches into generic state.
9533   CompileRun("testIndexed(new Array(1))");
9534   // Test that the indexed access check is called.
9535   value = CompileRun("testIndexed(obj)");
9536   CHECK(value->IsNumber());
9537   CHECK_EQ(1, value->Int32Value());
9538   CHECK_EQ(42, indexed_access_count);
9539
9540   // Check that the named access check is called when invoking
9541   // functions on an object that requires access checks.
9542   CompileRun("obj.f = function() {}");
9543   CompileRun("function testCallNormal(obj) {"
9544              "  for (var i = 0; i < 10; i++) obj.f();"
9545              "}");
9546   CompileRun("testCallNormal(obj)");
9547   CHECK_EQ(74, named_access_count);
9548
9549   // Force obj into slow case.
9550   value = CompileRun("delete obj.prop");
9551   CHECK(value->BooleanValue());
9552   // Force inline caches into dictionary probing mode.
9553   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9554   // Test that the named access check is called.
9555   value = CompileRun("testProp(obj);");
9556   CHECK(value->IsNumber());
9557   CHECK_EQ(1, value->Int32Value());
9558   CHECK_EQ(96, named_access_count);
9559
9560   // Force the call inline cache into dictionary probing mode.
9561   CompileRun("o.f = function() {}; testCallNormal(o)");
9562   // Test that the named access check is still called for each
9563   // invocation of the function.
9564   value = CompileRun("testCallNormal(obj)");
9565   CHECK_EQ(106, named_access_count);
9566
9567   context1->Exit();
9568   context0->Exit();
9569 }
9570
9571
9572 static bool NamedAccessFlatten(Local<v8::Object> global,
9573                                Local<Value> name,
9574                                v8::AccessType type,
9575                                Local<Value> data) {
9576   char buf[100];
9577   int len;
9578
9579   CHECK(name->IsString());
9580
9581   memset(buf, 0x1, sizeof(buf));
9582   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9583   CHECK_EQ(4, len);
9584
9585   uint16_t buf2[100];
9586
9587   memset(buf, 0x1, sizeof(buf));
9588   len = name.As<String>()->Write(buf2);
9589   CHECK_EQ(4, len);
9590
9591   return true;
9592 }
9593
9594
9595 static bool IndexedAccessFlatten(Local<v8::Object> global,
9596                                  uint32_t key,
9597                                  v8::AccessType type,
9598                                  Local<Value> data) {
9599   return true;
9600 }
9601
9602
9603 // Regression test.  In access checks, operations that may cause
9604 // garbage collection are not allowed.  It used to be the case that
9605 // using the Write operation on a string could cause a garbage
9606 // collection due to flattening of the string.  This is no longer the
9607 // case.
9608 THREADED_TEST(AccessControlFlatten) {
9609   named_access_count = 0;
9610   indexed_access_count = 0;
9611
9612   v8::Isolate* isolate = CcTest::isolate();
9613   v8::HandleScope handle_scope(isolate);
9614
9615   // Create an environment.
9616   v8::Local<Context> context0 = Context::New(isolate);
9617   context0->Enter();
9618
9619   // Create an object that requires access-check functions to be
9620   // called for cross-domain access.
9621   v8::Handle<v8::ObjectTemplate> object_template =
9622       v8::ObjectTemplate::New(isolate);
9623   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9624                                            IndexedAccessFlatten);
9625   Local<v8::Object> object = object_template->NewInstance();
9626
9627   v8::HandleScope scope1(isolate);
9628
9629   // Create another environment.
9630   v8::Local<Context> context1 = Context::New(isolate);
9631   context1->Enter();
9632
9633   // Make easy access to the object from the other environment.
9634   v8::Handle<v8::Object> global1 = context1->Global();
9635   global1->Set(v8_str("obj"), object);
9636
9637   v8::Handle<Value> value;
9638
9639   value = v8_compile("var p = 'as' + 'df';")->Run();
9640   value = v8_compile("obj[p];")->Run();
9641
9642   context1->Exit();
9643   context0->Exit();
9644 }
9645
9646
9647 static void AccessControlNamedGetter(
9648     Local<String>,
9649     const v8::PropertyCallbackInfo<v8::Value>& info) {
9650   info.GetReturnValue().Set(42);
9651 }
9652
9653
9654 static void AccessControlNamedSetter(
9655     Local<String>,
9656     Local<Value> value,
9657     const v8::PropertyCallbackInfo<v8::Value>& info) {
9658   info.GetReturnValue().Set(value);
9659 }
9660
9661
9662 static void AccessControlIndexedGetter(
9663       uint32_t index,
9664       const v8::PropertyCallbackInfo<v8::Value>& info) {
9665   info.GetReturnValue().Set(v8_num(42));
9666 }
9667
9668
9669 static void AccessControlIndexedSetter(
9670     uint32_t,
9671     Local<Value> value,
9672     const v8::PropertyCallbackInfo<v8::Value>& info) {
9673   info.GetReturnValue().Set(value);
9674 }
9675
9676
9677 THREADED_TEST(AccessControlInterceptorIC) {
9678   named_access_count = 0;
9679   indexed_access_count = 0;
9680
9681   v8::Isolate* isolate = CcTest::isolate();
9682   v8::HandleScope handle_scope(isolate);
9683
9684   // Create an environment.
9685   v8::Local<Context> context0 = Context::New(isolate);
9686   context0->Enter();
9687
9688   // Create an object that requires access-check functions to be
9689   // called for cross-domain access.  The object also has interceptors
9690   // interceptor.
9691   v8::Handle<v8::ObjectTemplate> object_template =
9692       v8::ObjectTemplate::New(isolate);
9693   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9694                                            IndexedAccessCounter);
9695   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9696                                            AccessControlNamedSetter);
9697   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9698                                              AccessControlIndexedSetter);
9699   Local<v8::Object> object = object_template->NewInstance();
9700
9701   v8::HandleScope scope1(isolate);
9702
9703   // Create another environment.
9704   v8::Local<Context> context1 = Context::New(isolate);
9705   context1->Enter();
9706
9707   // Make easy access to the object from the other environment.
9708   v8::Handle<v8::Object> global1 = context1->Global();
9709   global1->Set(v8_str("obj"), object);
9710
9711   v8::Handle<Value> value;
9712
9713   // Check that the named access-control function is called every time
9714   // eventhough there is an interceptor on the object.
9715   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9716   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9717                      "obj.x")->Run();
9718   CHECK(value->IsNumber());
9719   CHECK_EQ(42, value->Int32Value());
9720   CHECK_EQ(21, named_access_count);
9721
9722   value = v8_compile("var p = 'x';")->Run();
9723   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9724   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9725                      "obj[p]")->Run();
9726   CHECK(value->IsNumber());
9727   CHECK_EQ(42, value->Int32Value());
9728   CHECK_EQ(42, named_access_count);
9729
9730   // Check that the indexed access-control function is called every
9731   // time eventhough there is an interceptor on the object.
9732   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9733   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9734                      "obj[0]")->Run();
9735   CHECK(value->IsNumber());
9736   CHECK_EQ(42, value->Int32Value());
9737   CHECK_EQ(21, indexed_access_count);
9738
9739   context1->Exit();
9740   context0->Exit();
9741 }
9742
9743
9744 THREADED_TEST(Version) {
9745   v8::V8::GetVersion();
9746 }
9747
9748
9749 static void InstanceFunctionCallback(
9750     const v8::FunctionCallbackInfo<v8::Value>& args) {
9751   ApiTestFuzzer::Fuzz();
9752   args.GetReturnValue().Set(v8_num(12));
9753 }
9754
9755
9756 THREADED_TEST(InstanceProperties) {
9757   LocalContext context;
9758   v8::Isolate* isolate = context->GetIsolate();
9759   v8::HandleScope handle_scope(isolate);
9760
9761   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9762   Local<ObjectTemplate> instance = t->InstanceTemplate();
9763
9764   instance->Set(v8_str("x"), v8_num(42));
9765   instance->Set(v8_str("f"),
9766                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9767
9768   Local<Value> o = t->GetFunction()->NewInstance();
9769
9770   context->Global()->Set(v8_str("i"), o);
9771   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9772   CHECK_EQ(42, value->Int32Value());
9773
9774   value = Script::Compile(v8_str("i.f()"))->Run();
9775   CHECK_EQ(12, value->Int32Value());
9776 }
9777
9778
9779 static void GlobalObjectInstancePropertiesGet(
9780     Local<String> key,
9781     const v8::PropertyCallbackInfo<v8::Value>&) {
9782   ApiTestFuzzer::Fuzz();
9783 }
9784
9785
9786 THREADED_TEST(GlobalObjectInstanceProperties) {
9787   v8::Isolate* isolate = CcTest::isolate();
9788   v8::HandleScope handle_scope(isolate);
9789
9790   Local<Value> global_object;
9791
9792   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9793   t->InstanceTemplate()->SetNamedPropertyHandler(
9794       GlobalObjectInstancePropertiesGet);
9795   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9796   instance_template->Set(v8_str("x"), v8_num(42));
9797   instance_template->Set(v8_str("f"),
9798                          v8::FunctionTemplate::New(isolate,
9799                                                    InstanceFunctionCallback));
9800
9801   // The script to check how Crankshaft compiles missing global function
9802   // invocations.  function g is not defined and should throw on call.
9803   const char* script =
9804       "function wrapper(call) {"
9805       "  var x = 0, y = 1;"
9806       "  for (var i = 0; i < 1000; i++) {"
9807       "    x += i * 100;"
9808       "    y += i * 100;"
9809       "  }"
9810       "  if (call) g();"
9811       "}"
9812       "for (var i = 0; i < 17; i++) wrapper(false);"
9813       "var thrown = 0;"
9814       "try { wrapper(true); } catch (e) { thrown = 1; };"
9815       "thrown";
9816
9817   {
9818     LocalContext env(NULL, instance_template);
9819     // Hold on to the global object so it can be used again in another
9820     // environment initialization.
9821     global_object = env->Global();
9822
9823     Local<Value> value = Script::Compile(v8_str("x"))->Run();
9824     CHECK_EQ(42, value->Int32Value());
9825     value = Script::Compile(v8_str("f()"))->Run();
9826     CHECK_EQ(12, value->Int32Value());
9827     value = Script::Compile(v8_str(script))->Run();
9828     CHECK_EQ(1, value->Int32Value());
9829   }
9830
9831   {
9832     // Create new environment reusing the global object.
9833     LocalContext env(NULL, instance_template, global_object);
9834     Local<Value> value = Script::Compile(v8_str("x"))->Run();
9835     CHECK_EQ(42, value->Int32Value());
9836     value = Script::Compile(v8_str("f()"))->Run();
9837     CHECK_EQ(12, value->Int32Value());
9838     value = Script::Compile(v8_str(script))->Run();
9839     CHECK_EQ(1, value->Int32Value());
9840   }
9841 }
9842
9843
9844 THREADED_TEST(CallKnownGlobalReceiver) {
9845   v8::Isolate* isolate = CcTest::isolate();
9846   v8::HandleScope handle_scope(isolate);
9847
9848   Local<Value> global_object;
9849
9850   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9851   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9852
9853   // The script to check that we leave global object not
9854   // global object proxy on stack when we deoptimize from inside
9855   // arguments evaluation.
9856   // To provoke error we need to both force deoptimization
9857   // from arguments evaluation and to force CallIC to take
9858   // CallIC_Miss code path that can't cope with global proxy.
9859   const char* script =
9860       "function bar(x, y) { try { } finally { } }"
9861       "function baz(x) { try { } finally { } }"
9862       "function bom(x) { try { } finally { } }"
9863       "function foo(x) { bar([x], bom(2)); }"
9864       "for (var i = 0; i < 10000; i++) foo(1);"
9865       "foo";
9866
9867   Local<Value> foo;
9868   {
9869     LocalContext env(NULL, instance_template);
9870     // Hold on to the global object so it can be used again in another
9871     // environment initialization.
9872     global_object = env->Global();
9873     foo = Script::Compile(v8_str(script))->Run();
9874   }
9875
9876   {
9877     // Create new environment reusing the global object.
9878     LocalContext env(NULL, instance_template, global_object);
9879     env->Global()->Set(v8_str("foo"), foo);
9880     Script::Compile(v8_str("foo()"))->Run();
9881   }
9882 }
9883
9884
9885 static void ShadowFunctionCallback(
9886     const v8::FunctionCallbackInfo<v8::Value>& args) {
9887   ApiTestFuzzer::Fuzz();
9888   args.GetReturnValue().Set(v8_num(42));
9889 }
9890
9891
9892 static int shadow_y;
9893 static int shadow_y_setter_call_count;
9894 static int shadow_y_getter_call_count;
9895
9896
9897 static void ShadowYSetter(Local<String>,
9898                           Local<Value>,
9899                           const v8::PropertyCallbackInfo<void>&) {
9900   shadow_y_setter_call_count++;
9901   shadow_y = 42;
9902 }
9903
9904
9905 static void ShadowYGetter(Local<String> name,
9906                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9907   ApiTestFuzzer::Fuzz();
9908   shadow_y_getter_call_count++;
9909   info.GetReturnValue().Set(v8_num(shadow_y));
9910 }
9911
9912
9913 static void ShadowIndexedGet(uint32_t index,
9914                              const v8::PropertyCallbackInfo<v8::Value>&) {
9915 }
9916
9917
9918 static void ShadowNamedGet(Local<String> key,
9919                            const v8::PropertyCallbackInfo<v8::Value>&) {
9920 }
9921
9922
9923 THREADED_TEST(ShadowObject) {
9924   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9925   v8::Isolate* isolate = CcTest::isolate();
9926   v8::HandleScope handle_scope(isolate);
9927
9928   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9929   LocalContext context(NULL, global_template);
9930
9931   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9932   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9933   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9934   Local<ObjectTemplate> proto = t->PrototypeTemplate();
9935   Local<ObjectTemplate> instance = t->InstanceTemplate();
9936
9937   proto->Set(v8_str("f"),
9938              v8::FunctionTemplate::New(isolate,
9939                                        ShadowFunctionCallback,
9940                                        Local<Value>()));
9941   proto->Set(v8_str("x"), v8_num(12));
9942
9943   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9944
9945   Local<Value> o = t->GetFunction()->NewInstance();
9946   context->Global()->Set(v8_str("__proto__"), o);
9947
9948   Local<Value> value =
9949       Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9950   CHECK(value->IsBoolean());
9951   CHECK(!value->BooleanValue());
9952
9953   value = Script::Compile(v8_str("x"))->Run();
9954   CHECK_EQ(12, value->Int32Value());
9955
9956   value = Script::Compile(v8_str("f()"))->Run();
9957   CHECK_EQ(42, value->Int32Value());
9958
9959   Script::Compile(v8_str("y = 43"))->Run();
9960   CHECK_EQ(1, shadow_y_setter_call_count);
9961   value = Script::Compile(v8_str("y"))->Run();
9962   CHECK_EQ(1, shadow_y_getter_call_count);
9963   CHECK_EQ(42, value->Int32Value());
9964 }
9965
9966
9967 THREADED_TEST(HiddenPrototype) {
9968   LocalContext context;
9969   v8::Isolate* isolate = context->GetIsolate();
9970   v8::HandleScope handle_scope(isolate);
9971
9972   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9973   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9974   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9975   t1->SetHiddenPrototype(true);
9976   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9977   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9978   t2->SetHiddenPrototype(true);
9979   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9980   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9981   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9982
9983   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9984   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9985   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9986   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9987
9988   // Setting the prototype on an object skips hidden prototypes.
9989   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9990   o0->Set(v8_str("__proto__"), o1);
9991   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9992   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9993   o0->Set(v8_str("__proto__"), o2);
9994   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9995   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9996   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9997   o0->Set(v8_str("__proto__"), o3);
9998   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9999   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10000   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10001   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10002
10003   // Getting the prototype of o0 should get the first visible one
10004   // which is o3.  Therefore, z should not be defined on the prototype
10005   // object.
10006   Local<Value> proto = o0->Get(v8_str("__proto__"));
10007   CHECK(proto->IsObject());
10008   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10009 }
10010
10011
10012 THREADED_TEST(HiddenPrototypeSet) {
10013   LocalContext context;
10014   v8::Isolate* isolate = context->GetIsolate();
10015   v8::HandleScope handle_scope(isolate);
10016
10017   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10018   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10019   ht->SetHiddenPrototype(true);
10020   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10021   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10022
10023   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10024   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10025   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10026   o->Set(v8_str("__proto__"), h);
10027   h->Set(v8_str("__proto__"), p);
10028
10029   // Setting a property that exists on the hidden prototype goes there.
10030   o->Set(v8_str("x"), v8_num(7));
10031   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10032   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10033   CHECK(p->Get(v8_str("x"))->IsUndefined());
10034
10035   // Setting a new property should not be forwarded to the hidden prototype.
10036   o->Set(v8_str("y"), v8_num(6));
10037   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10038   CHECK(h->Get(v8_str("y"))->IsUndefined());
10039   CHECK(p->Get(v8_str("y"))->IsUndefined());
10040
10041   // Setting a property that only exists on a prototype of the hidden prototype
10042   // is treated normally again.
10043   p->Set(v8_str("z"), v8_num(8));
10044   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10045   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10046   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10047   o->Set(v8_str("z"), v8_num(9));
10048   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10049   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10050   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10051 }
10052
10053
10054 // Regression test for issue 2457.
10055 THREADED_TEST(HiddenPrototypeIdentityHash) {
10056   LocalContext context;
10057   v8::HandleScope handle_scope(context->GetIsolate());
10058
10059   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10060   t->SetHiddenPrototype(true);
10061   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10062   Handle<Object> p = t->GetFunction()->NewInstance();
10063   Handle<Object> o = Object::New(context->GetIsolate());
10064   o->SetPrototype(p);
10065
10066   int hash = o->GetIdentityHash();
10067   USE(hash);
10068   o->Set(v8_str("foo"), v8_num(42));
10069   ASSERT_EQ(hash, o->GetIdentityHash());
10070 }
10071
10072
10073 THREADED_TEST(SetPrototype) {
10074   LocalContext context;
10075   v8::Isolate* isolate = context->GetIsolate();
10076   v8::HandleScope handle_scope(isolate);
10077
10078   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10079   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10080   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10081   t1->SetHiddenPrototype(true);
10082   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10083   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10084   t2->SetHiddenPrototype(true);
10085   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10086   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10087   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10088
10089   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10090   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10091   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10092   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10093
10094   // Setting the prototype on an object does not skip hidden prototypes.
10095   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10096   CHECK(o0->SetPrototype(o1));
10097   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10098   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10099   CHECK(o1->SetPrototype(o2));
10100   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10101   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10102   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10103   CHECK(o2->SetPrototype(o3));
10104   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10105   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10106   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10107   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10108
10109   // Getting the prototype of o0 should get the first visible one
10110   // which is o3.  Therefore, z should not be defined on the prototype
10111   // object.
10112   Local<Value> proto = o0->Get(v8_str("__proto__"));
10113   CHECK(proto->IsObject());
10114   CHECK_EQ(proto.As<v8::Object>(), o3);
10115
10116   // However, Object::GetPrototype ignores hidden prototype.
10117   Local<Value> proto0 = o0->GetPrototype();
10118   CHECK(proto0->IsObject());
10119   CHECK_EQ(proto0.As<v8::Object>(), o1);
10120
10121   Local<Value> proto1 = o1->GetPrototype();
10122   CHECK(proto1->IsObject());
10123   CHECK_EQ(proto1.As<v8::Object>(), o2);
10124
10125   Local<Value> proto2 = o2->GetPrototype();
10126   CHECK(proto2->IsObject());
10127   CHECK_EQ(proto2.As<v8::Object>(), o3);
10128 }
10129
10130
10131 // Getting property names of an object with a prototype chain that
10132 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10133 // crash the runtime.
10134 THREADED_TEST(Regress91517) {
10135   i::FLAG_allow_natives_syntax = true;
10136   LocalContext context;
10137   v8::Isolate* isolate = context->GetIsolate();
10138   v8::HandleScope handle_scope(isolate);
10139
10140   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10141   t1->SetHiddenPrototype(true);
10142   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10143   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10144   t2->SetHiddenPrototype(true);
10145   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10146   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10147   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10148   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10149   t3->SetHiddenPrototype(true);
10150   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10151   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10152   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10153
10154   // Force dictionary-based properties.
10155   i::ScopedVector<char> name_buf(1024);
10156   for (int i = 1; i <= 1000; i++) {
10157     i::OS::SNPrintF(name_buf, "sdf%d", i);
10158     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10159   }
10160
10161   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10162   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10163   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10164   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10165
10166   // Create prototype chain of hidden prototypes.
10167   CHECK(o4->SetPrototype(o3));
10168   CHECK(o3->SetPrototype(o2));
10169   CHECK(o2->SetPrototype(o1));
10170
10171   // Call the runtime version of GetLocalPropertyNames() on the natively
10172   // created object through JavaScript.
10173   context->Global()->Set(v8_str("obj"), o4);
10174   // PROPERTY_ATTRIBUTES_NONE = 0
10175   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10176
10177   ExpectInt32("names.length", 1006);
10178   ExpectTrue("names.indexOf(\"baz\") >= 0");
10179   ExpectTrue("names.indexOf(\"boo\") >= 0");
10180   ExpectTrue("names.indexOf(\"foo\") >= 0");
10181   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10182   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10183   ExpectFalse("names[1005] == undefined");
10184 }
10185
10186
10187 // Getting property names of an object with a hidden and inherited
10188 // prototype should not duplicate the accessor properties inherited.
10189 THREADED_TEST(Regress269562) {
10190   i::FLAG_allow_natives_syntax = true;
10191   LocalContext context;
10192   v8::HandleScope handle_scope(context->GetIsolate());
10193
10194   Local<v8::FunctionTemplate> t1 =
10195       v8::FunctionTemplate::New(context->GetIsolate());
10196   t1->SetHiddenPrototype(true);
10197
10198   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10199   i1->SetAccessor(v8_str("foo"),
10200                   SimpleAccessorGetter, SimpleAccessorSetter);
10201   i1->SetAccessor(v8_str("bar"),
10202                   SimpleAccessorGetter, SimpleAccessorSetter);
10203   i1->SetAccessor(v8_str("baz"),
10204                   SimpleAccessorGetter, SimpleAccessorSetter);
10205   i1->Set(v8_str("n1"), v8_num(1));
10206   i1->Set(v8_str("n2"), v8_num(2));
10207
10208   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10209   Local<v8::FunctionTemplate> t2 =
10210       v8::FunctionTemplate::New(context->GetIsolate());
10211   t2->SetHiddenPrototype(true);
10212
10213   // Inherit from t1 and mark prototype as hidden.
10214   t2->Inherit(t1);
10215   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10216
10217   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10218   CHECK(o2->SetPrototype(o1));
10219
10220   v8::Local<v8::Symbol> sym = v8::Symbol::New(context->GetIsolate(), "s1");
10221   o1->Set(sym, v8_num(3));
10222   o1->SetHiddenValue(v8_str("h1"),
10223                      v8::Integer::New(context->GetIsolate(), 2013));
10224
10225   // Call the runtime version of GetLocalPropertyNames() on
10226   // the natively created object through JavaScript.
10227   context->Global()->Set(v8_str("obj"), o2);
10228   context->Global()->Set(v8_str("sym"), sym);
10229   // PROPERTY_ATTRIBUTES_NONE = 0
10230   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10231
10232   ExpectInt32("names.length", 7);
10233   ExpectTrue("names.indexOf(\"foo\") >= 0");
10234   ExpectTrue("names.indexOf(\"bar\") >= 0");
10235   ExpectTrue("names.indexOf(\"baz\") >= 0");
10236   ExpectTrue("names.indexOf(\"n1\") >= 0");
10237   ExpectTrue("names.indexOf(\"n2\") >= 0");
10238   ExpectTrue("names.indexOf(sym) >= 0");
10239   ExpectTrue("names.indexOf(\"mine\") >= 0");
10240 }
10241
10242
10243 THREADED_TEST(FunctionReadOnlyPrototype) {
10244   LocalContext context;
10245   v8::Isolate* isolate = context->GetIsolate();
10246   v8::HandleScope handle_scope(isolate);
10247
10248   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10249   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10250   t1->ReadOnlyPrototype();
10251   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10252   // Configured value of ReadOnly flag.
10253   CHECK(CompileRun(
10254       "(function() {"
10255       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10256       "  return (descriptor['writable'] == false);"
10257       "})()")->BooleanValue());
10258   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10259   CHECK_EQ(42,
10260            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10261
10262   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10263   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10264   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10265   // Default value of ReadOnly flag.
10266   CHECK(CompileRun(
10267       "(function() {"
10268       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10269       "  return (descriptor['writable'] == true);"
10270       "})()")->BooleanValue());
10271   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10272 }
10273
10274
10275 THREADED_TEST(SetPrototypeThrows) {
10276   LocalContext context;
10277   v8::Isolate* isolate = context->GetIsolate();
10278   v8::HandleScope handle_scope(isolate);
10279
10280   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10281
10282   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10283   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10284
10285   CHECK(o0->SetPrototype(o1));
10286   // If setting the prototype leads to the cycle, SetPrototype should
10287   // return false and keep VM in sane state.
10288   v8::TryCatch try_catch;
10289   CHECK(!o1->SetPrototype(o0));
10290   CHECK(!try_catch.HasCaught());
10291   ASSERT(!CcTest::i_isolate()->has_pending_exception());
10292
10293   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10294 }
10295
10296
10297 THREADED_TEST(FunctionRemovePrototype) {
10298   LocalContext context;
10299   v8::Isolate* isolate = context->GetIsolate();
10300   v8::HandleScope handle_scope(isolate);
10301
10302   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10303   t1->RemovePrototype();
10304   Local<v8::Function> fun = t1->GetFunction();
10305   context->Global()->Set(v8_str("fun"), fun);
10306   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10307
10308   v8::TryCatch try_catch;
10309   CompileRun("new fun()");
10310   CHECK(try_catch.HasCaught());
10311
10312   try_catch.Reset();
10313   fun->NewInstance();
10314   CHECK(try_catch.HasCaught());
10315 }
10316
10317
10318 THREADED_TEST(GetterSetterExceptions) {
10319   LocalContext context;
10320   v8::Isolate* isolate = context->GetIsolate();
10321   v8::HandleScope handle_scope(isolate);
10322   CompileRun(
10323     "function Foo() { };"
10324     "function Throw() { throw 5; };"
10325     "var x = { };"
10326     "x.__defineSetter__('set', Throw);"
10327     "x.__defineGetter__('get', Throw);");
10328   Local<v8::Object> x =
10329       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10330   v8::TryCatch try_catch;
10331   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10332   x->Get(v8_str("get"));
10333   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10334   x->Get(v8_str("get"));
10335   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10336   x->Get(v8_str("get"));
10337   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10338   x->Get(v8_str("get"));
10339 }
10340
10341
10342 THREADED_TEST(Constructor) {
10343   LocalContext context;
10344   v8::Isolate* isolate = context->GetIsolate();
10345   v8::HandleScope handle_scope(isolate);
10346   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10347   templ->SetClassName(v8_str("Fun"));
10348   Local<Function> cons = templ->GetFunction();
10349   context->Global()->Set(v8_str("Fun"), cons);
10350   Local<v8::Object> inst = cons->NewInstance();
10351   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10352   CHECK(obj->IsJSObject());
10353   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10354   CHECK(value->BooleanValue());
10355 }
10356
10357
10358 static void ConstructorCallback(
10359     const v8::FunctionCallbackInfo<v8::Value>& args) {
10360   ApiTestFuzzer::Fuzz();
10361   Local<Object> This;
10362
10363   if (args.IsConstructCall()) {
10364     Local<Object> Holder = args.Holder();
10365     This = Object::New(args.GetIsolate());
10366     Local<Value> proto = Holder->GetPrototype();
10367     if (proto->IsObject()) {
10368       This->SetPrototype(proto);
10369     }
10370   } else {
10371     This = args.This();
10372   }
10373
10374   This->Set(v8_str("a"), args[0]);
10375   args.GetReturnValue().Set(This);
10376 }
10377
10378
10379 static void FakeConstructorCallback(
10380     const v8::FunctionCallbackInfo<v8::Value>& args) {
10381   ApiTestFuzzer::Fuzz();
10382   args.GetReturnValue().Set(args[0]);
10383 }
10384
10385
10386 THREADED_TEST(ConstructorForObject) {
10387   LocalContext context;
10388   v8::Isolate* isolate = context->GetIsolate();
10389   v8::HandleScope handle_scope(isolate);
10390
10391   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10392     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10393     Local<Object> instance = instance_template->NewInstance();
10394     context->Global()->Set(v8_str("obj"), instance);
10395     v8::TryCatch try_catch;
10396     Local<Value> value;
10397     CHECK(!try_catch.HasCaught());
10398
10399     // Call the Object's constructor with a 32-bit signed integer.
10400     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10401     CHECK(!try_catch.HasCaught());
10402     CHECK(value->IsInt32());
10403     CHECK_EQ(28, value->Int32Value());
10404
10405     Local<Value> args1[] = { v8_num(28) };
10406     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10407     CHECK(value_obj1->IsObject());
10408     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10409     value = object1->Get(v8_str("a"));
10410     CHECK(value->IsInt32());
10411     CHECK(!try_catch.HasCaught());
10412     CHECK_EQ(28, value->Int32Value());
10413
10414     // Call the Object's constructor with a String.
10415     value = CompileRun(
10416         "(function() { var o = new obj('tipli'); return o.a; })()");
10417     CHECK(!try_catch.HasCaught());
10418     CHECK(value->IsString());
10419     String::Utf8Value string_value1(value->ToString());
10420     CHECK_EQ("tipli", *string_value1);
10421
10422     Local<Value> args2[] = { v8_str("tipli") };
10423     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10424     CHECK(value_obj2->IsObject());
10425     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10426     value = object2->Get(v8_str("a"));
10427     CHECK(!try_catch.HasCaught());
10428     CHECK(value->IsString());
10429     String::Utf8Value string_value2(value->ToString());
10430     CHECK_EQ("tipli", *string_value2);
10431
10432     // Call the Object's constructor with a Boolean.
10433     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10434     CHECK(!try_catch.HasCaught());
10435     CHECK(value->IsBoolean());
10436     CHECK_EQ(true, value->BooleanValue());
10437
10438     Handle<Value> args3[] = { v8::True(isolate) };
10439     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10440     CHECK(value_obj3->IsObject());
10441     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10442     value = object3->Get(v8_str("a"));
10443     CHECK(!try_catch.HasCaught());
10444     CHECK(value->IsBoolean());
10445     CHECK_EQ(true, value->BooleanValue());
10446
10447     // Call the Object's constructor with undefined.
10448     Handle<Value> args4[] = { v8::Undefined(isolate) };
10449     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10450     CHECK(value_obj4->IsObject());
10451     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10452     value = object4->Get(v8_str("a"));
10453     CHECK(!try_catch.HasCaught());
10454     CHECK(value->IsUndefined());
10455
10456     // Call the Object's constructor with null.
10457     Handle<Value> args5[] = { v8::Null(isolate) };
10458     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10459     CHECK(value_obj5->IsObject());
10460     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10461     value = object5->Get(v8_str("a"));
10462     CHECK(!try_catch.HasCaught());
10463     CHECK(value->IsNull());
10464   }
10465
10466   // Check exception handling when there is no constructor set for the Object.
10467   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10468     Local<Object> instance = instance_template->NewInstance();
10469     context->Global()->Set(v8_str("obj2"), instance);
10470     v8::TryCatch try_catch;
10471     Local<Value> value;
10472     CHECK(!try_catch.HasCaught());
10473
10474     value = CompileRun("new obj2(28)");
10475     CHECK(try_catch.HasCaught());
10476     String::Utf8Value exception_value1(try_catch.Exception());
10477     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10478     try_catch.Reset();
10479
10480     Local<Value> args[] = { v8_num(29) };
10481     value = instance->CallAsConstructor(1, args);
10482     CHECK(try_catch.HasCaught());
10483     String::Utf8Value exception_value2(try_catch.Exception());
10484     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10485     try_catch.Reset();
10486   }
10487
10488   // Check the case when constructor throws exception.
10489   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10490     instance_template->SetCallAsFunctionHandler(ThrowValue);
10491     Local<Object> instance = instance_template->NewInstance();
10492     context->Global()->Set(v8_str("obj3"), instance);
10493     v8::TryCatch try_catch;
10494     Local<Value> value;
10495     CHECK(!try_catch.HasCaught());
10496
10497     value = CompileRun("new obj3(22)");
10498     CHECK(try_catch.HasCaught());
10499     String::Utf8Value exception_value1(try_catch.Exception());
10500     CHECK_EQ("22", *exception_value1);
10501     try_catch.Reset();
10502
10503     Local<Value> args[] = { v8_num(23) };
10504     value = instance->CallAsConstructor(1, args);
10505     CHECK(try_catch.HasCaught());
10506     String::Utf8Value exception_value2(try_catch.Exception());
10507     CHECK_EQ("23", *exception_value2);
10508     try_catch.Reset();
10509   }
10510
10511   // Check whether constructor returns with an object or non-object.
10512   { Local<FunctionTemplate> function_template =
10513         FunctionTemplate::New(isolate, FakeConstructorCallback);
10514     Local<Function> function = function_template->GetFunction();
10515     Local<Object> instance1 = function;
10516     context->Global()->Set(v8_str("obj4"), instance1);
10517     v8::TryCatch try_catch;
10518     Local<Value> value;
10519     CHECK(!try_catch.HasCaught());
10520
10521     CHECK(instance1->IsObject());
10522     CHECK(instance1->IsFunction());
10523
10524     value = CompileRun("new obj4(28)");
10525     CHECK(!try_catch.HasCaught());
10526     CHECK(value->IsObject());
10527
10528     Local<Value> args1[] = { v8_num(28) };
10529     value = instance1->CallAsConstructor(1, args1);
10530     CHECK(!try_catch.HasCaught());
10531     CHECK(value->IsObject());
10532
10533     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10534     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10535     Local<Object> instance2 = instance_template->NewInstance();
10536     context->Global()->Set(v8_str("obj5"), instance2);
10537     CHECK(!try_catch.HasCaught());
10538
10539     CHECK(instance2->IsObject());
10540     CHECK(!instance2->IsFunction());
10541
10542     value = CompileRun("new obj5(28)");
10543     CHECK(!try_catch.HasCaught());
10544     CHECK(!value->IsObject());
10545
10546     Local<Value> args2[] = { v8_num(28) };
10547     value = instance2->CallAsConstructor(1, args2);
10548     CHECK(!try_catch.HasCaught());
10549     CHECK(!value->IsObject());
10550   }
10551 }
10552
10553
10554 THREADED_TEST(FunctionDescriptorException) {
10555   LocalContext context;
10556   v8::Isolate* isolate = context->GetIsolate();
10557   v8::HandleScope handle_scope(isolate);
10558   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10559   templ->SetClassName(v8_str("Fun"));
10560   Local<Function> cons = templ->GetFunction();
10561   context->Global()->Set(v8_str("Fun"), cons);
10562   Local<Value> value = CompileRun(
10563     "function test() {"
10564     "  try {"
10565     "    (new Fun()).blah()"
10566     "  } catch (e) {"
10567     "    var str = String(e);"
10568     // "    if (str.indexOf('TypeError') == -1) return 1;"
10569     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10570     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10571     "    return 0;"
10572     "  }"
10573     "  return 4;"
10574     "}"
10575     "test();");
10576   CHECK_EQ(0, value->Int32Value());
10577 }
10578
10579
10580 THREADED_TEST(EvalAliasedDynamic) {
10581   LocalContext current;
10582   v8::HandleScope scope(current->GetIsolate());
10583
10584   // Tests where aliased eval can only be resolved dynamically.
10585   Local<Script> script =
10586       Script::Compile(v8_str("function f(x) { "
10587                              "  var foo = 2;"
10588                              "  with (x) { return eval('foo'); }"
10589                              "}"
10590                              "foo = 0;"
10591                              "result1 = f(new Object());"
10592                              "result2 = f(this);"
10593                              "var x = new Object();"
10594                              "x.eval = function(x) { return 1; };"
10595                              "result3 = f(x);"));
10596   script->Run();
10597   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10598   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10599   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10600
10601   v8::TryCatch try_catch;
10602   script =
10603     Script::Compile(v8_str("function f(x) { "
10604                            "  var bar = 2;"
10605                            "  with (x) { return eval('bar'); }"
10606                            "}"
10607                            "result4 = f(this)"));
10608   script->Run();
10609   CHECK(!try_catch.HasCaught());
10610   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10611
10612   try_catch.Reset();
10613 }
10614
10615
10616 THREADED_TEST(CrossEval) {
10617   v8::HandleScope scope(CcTest::isolate());
10618   LocalContext other;
10619   LocalContext current;
10620
10621   Local<String> token = v8_str("<security token>");
10622   other->SetSecurityToken(token);
10623   current->SetSecurityToken(token);
10624
10625   // Set up reference from current to other.
10626   current->Global()->Set(v8_str("other"), other->Global());
10627
10628   // Check that new variables are introduced in other context.
10629   Local<Script> script =
10630       Script::Compile(v8_str("other.eval('var foo = 1234')"));
10631   script->Run();
10632   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10633   CHECK_EQ(1234, foo->Int32Value());
10634   CHECK(!current->Global()->Has(v8_str("foo")));
10635
10636   // Check that writing to non-existing properties introduces them in
10637   // the other context.
10638   script =
10639       Script::Compile(v8_str("other.eval('na = 1234')"));
10640   script->Run();
10641   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10642   CHECK(!current->Global()->Has(v8_str("na")));
10643
10644   // Check that global variables in current context are not visible in other
10645   // context.
10646   v8::TryCatch try_catch;
10647   script =
10648       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10649   Local<Value> result = script->Run();
10650   CHECK(try_catch.HasCaught());
10651   try_catch.Reset();
10652
10653   // Check that local variables in current context are not visible in other
10654   // context.
10655   script =
10656       Script::Compile(v8_str("(function() { "
10657                              "  var baz = 87;"
10658                              "  return other.eval('baz');"
10659                              "})();"));
10660   result = script->Run();
10661   CHECK(try_catch.HasCaught());
10662   try_catch.Reset();
10663
10664   // Check that global variables in the other environment are visible
10665   // when evaluting code.
10666   other->Global()->Set(v8_str("bis"), v8_num(1234));
10667   script = Script::Compile(v8_str("other.eval('bis')"));
10668   CHECK_EQ(1234, script->Run()->Int32Value());
10669   CHECK(!try_catch.HasCaught());
10670
10671   // Check that the 'this' pointer points to the global object evaluating
10672   // code.
10673   other->Global()->Set(v8_str("t"), other->Global());
10674   script = Script::Compile(v8_str("other.eval('this == t')"));
10675   result = script->Run();
10676   CHECK(result->IsTrue());
10677   CHECK(!try_catch.HasCaught());
10678
10679   // Check that variables introduced in with-statement are not visible in
10680   // other context.
10681   script =
10682       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10683   result = script->Run();
10684   CHECK(try_catch.HasCaught());
10685   try_catch.Reset();
10686
10687   // Check that you cannot use 'eval.call' with another object than the
10688   // current global object.
10689   script =
10690       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10691   result = script->Run();
10692   CHECK(try_catch.HasCaught());
10693 }
10694
10695
10696 // Test that calling eval in a context which has been detached from
10697 // its global throws an exception.  This behavior is consistent with
10698 // other JavaScript implementations.
10699 THREADED_TEST(EvalInDetachedGlobal) {
10700   v8::Isolate* isolate = CcTest::isolate();
10701   v8::HandleScope scope(isolate);
10702
10703   v8::Local<Context> context0 = Context::New(isolate);
10704   v8::Local<Context> context1 = Context::New(isolate);
10705
10706   // Set up function in context0 that uses eval from context0.
10707   context0->Enter();
10708   v8::Handle<v8::Value> fun =
10709       CompileRun("var x = 42;"
10710                  "(function() {"
10711                  "  var e = eval;"
10712                  "  return function(s) { return e(s); }"
10713                  "})()");
10714   context0->Exit();
10715
10716   // Put the function into context1 and call it before and after
10717   // detaching the global.  Before detaching, the call succeeds and
10718   // after detaching and exception is thrown.
10719   context1->Enter();
10720   context1->Global()->Set(v8_str("fun"), fun);
10721   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10722   CHECK_EQ(42, x_value->Int32Value());
10723   context0->DetachGlobal();
10724   v8::TryCatch catcher;
10725   x_value = CompileRun("fun('x')");
10726   CHECK(x_value.IsEmpty());
10727   CHECK(catcher.HasCaught());
10728   context1->Exit();
10729 }
10730
10731
10732 THREADED_TEST(CrossLazyLoad) {
10733   v8::HandleScope scope(CcTest::isolate());
10734   LocalContext other;
10735   LocalContext current;
10736
10737   Local<String> token = v8_str("<security token>");
10738   other->SetSecurityToken(token);
10739   current->SetSecurityToken(token);
10740
10741   // Set up reference from current to other.
10742   current->Global()->Set(v8_str("other"), other->Global());
10743
10744   // Trigger lazy loading in other context.
10745   Local<Script> script =
10746       Script::Compile(v8_str("other.eval('new Date(42)')"));
10747   Local<Value> value = script->Run();
10748   CHECK_EQ(42.0, value->NumberValue());
10749 }
10750
10751
10752 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10753   ApiTestFuzzer::Fuzz();
10754   if (args.IsConstructCall()) {
10755     if (args[0]->IsInt32()) {
10756       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10757       return;
10758     }
10759   }
10760
10761   args.GetReturnValue().Set(args[0]);
10762 }
10763
10764
10765 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10766   args.GetReturnValue().Set(args.This());
10767 }
10768
10769
10770 // Test that a call handler can be set for objects which will allow
10771 // non-function objects created through the API to be called as
10772 // functions.
10773 THREADED_TEST(CallAsFunction) {
10774   LocalContext context;
10775   v8::Isolate* isolate = context->GetIsolate();
10776   v8::HandleScope scope(isolate);
10777
10778   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10779     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10780     instance_template->SetCallAsFunctionHandler(call_as_function);
10781     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10782     context->Global()->Set(v8_str("obj"), instance);
10783     v8::TryCatch try_catch;
10784     Local<Value> value;
10785     CHECK(!try_catch.HasCaught());
10786
10787     value = CompileRun("obj(42)");
10788     CHECK(!try_catch.HasCaught());
10789     CHECK_EQ(42, value->Int32Value());
10790
10791     value = CompileRun("(function(o){return o(49)})(obj)");
10792     CHECK(!try_catch.HasCaught());
10793     CHECK_EQ(49, value->Int32Value());
10794
10795     // test special case of call as function
10796     value = CompileRun("[obj]['0'](45)");
10797     CHECK(!try_catch.HasCaught());
10798     CHECK_EQ(45, value->Int32Value());
10799
10800     value = CompileRun("obj.call = Function.prototype.call;"
10801                        "obj.call(null, 87)");
10802     CHECK(!try_catch.HasCaught());
10803     CHECK_EQ(87, value->Int32Value());
10804
10805     // Regression tests for bug #1116356: Calling call through call/apply
10806     // must work for non-function receivers.
10807     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10808     value = CompileRun(apply_99);
10809     CHECK(!try_catch.HasCaught());
10810     CHECK_EQ(99, value->Int32Value());
10811
10812     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10813     value = CompileRun(call_17);
10814     CHECK(!try_catch.HasCaught());
10815     CHECK_EQ(17, value->Int32Value());
10816
10817     // Check that the call-as-function handler can be called through
10818     // new.
10819     value = CompileRun("new obj(43)");
10820     CHECK(!try_catch.HasCaught());
10821     CHECK_EQ(-43, value->Int32Value());
10822
10823     // Check that the call-as-function handler can be called through
10824     // the API.
10825     v8::Handle<Value> args[] = { v8_num(28) };
10826     value = instance->CallAsFunction(instance, 1, args);
10827     CHECK(!try_catch.HasCaught());
10828     CHECK_EQ(28, value->Int32Value());
10829   }
10830
10831   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10832     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10833     USE(instance_template);
10834     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10835     context->Global()->Set(v8_str("obj2"), instance);
10836     v8::TryCatch try_catch;
10837     Local<Value> value;
10838     CHECK(!try_catch.HasCaught());
10839
10840     // Call an object without call-as-function handler through the JS
10841     value = CompileRun("obj2(28)");
10842     CHECK(value.IsEmpty());
10843     CHECK(try_catch.HasCaught());
10844     String::Utf8Value exception_value1(try_catch.Exception());
10845     // TODO(verwaest): Better message
10846     CHECK_EQ("TypeError: object is not a function",
10847              *exception_value1);
10848     try_catch.Reset();
10849
10850     // Call an object without call-as-function handler through the API
10851     value = CompileRun("obj2(28)");
10852     v8::Handle<Value> args[] = { v8_num(28) };
10853     value = instance->CallAsFunction(instance, 1, args);
10854     CHECK(value.IsEmpty());
10855     CHECK(try_catch.HasCaught());
10856     String::Utf8Value exception_value2(try_catch.Exception());
10857     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10858     try_catch.Reset();
10859   }
10860
10861   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10862     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10863     instance_template->SetCallAsFunctionHandler(ThrowValue);
10864     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10865     context->Global()->Set(v8_str("obj3"), instance);
10866     v8::TryCatch try_catch;
10867     Local<Value> value;
10868     CHECK(!try_catch.HasCaught());
10869
10870     // Catch the exception which is thrown by call-as-function handler
10871     value = CompileRun("obj3(22)");
10872     CHECK(try_catch.HasCaught());
10873     String::Utf8Value exception_value1(try_catch.Exception());
10874     CHECK_EQ("22", *exception_value1);
10875     try_catch.Reset();
10876
10877     v8::Handle<Value> args[] = { v8_num(23) };
10878     value = instance->CallAsFunction(instance, 1, args);
10879     CHECK(try_catch.HasCaught());
10880     String::Utf8Value exception_value2(try_catch.Exception());
10881     CHECK_EQ("23", *exception_value2);
10882     try_catch.Reset();
10883   }
10884
10885   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10886     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10887     instance_template->SetCallAsFunctionHandler(ReturnThis);
10888     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10889
10890     Local<v8::Value> a1 =
10891         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10892     CHECK(a1->StrictEquals(instance));
10893     Local<v8::Value> a2 =
10894         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10895     CHECK(a2->StrictEquals(instance));
10896     Local<v8::Value> a3 =
10897         instance->CallAsFunction(v8_num(42), 0, NULL);
10898     CHECK(a3->StrictEquals(instance));
10899     Local<v8::Value> a4 =
10900         instance->CallAsFunction(v8_str("hello"), 0, NULL);
10901     CHECK(a4->StrictEquals(instance));
10902     Local<v8::Value> a5 =
10903         instance->CallAsFunction(v8::True(isolate), 0, NULL);
10904     CHECK(a5->StrictEquals(instance));
10905   }
10906
10907   { CompileRun(
10908       "function ReturnThisSloppy() {"
10909       "  return this;"
10910       "}"
10911       "function ReturnThisStrict() {"
10912       "  'use strict';"
10913       "  return this;"
10914       "}");
10915     Local<Function> ReturnThisSloppy =
10916         Local<Function>::Cast(
10917             context->Global()->Get(v8_str("ReturnThisSloppy")));
10918     Local<Function> ReturnThisStrict =
10919         Local<Function>::Cast(
10920             context->Global()->Get(v8_str("ReturnThisStrict")));
10921
10922     Local<v8::Value> a1 =
10923         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10924     CHECK(a1->StrictEquals(context->Global()));
10925     Local<v8::Value> a2 =
10926         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10927     CHECK(a2->StrictEquals(context->Global()));
10928     Local<v8::Value> a3 =
10929         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10930     CHECK(a3->IsNumberObject());
10931     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10932     Local<v8::Value> a4 =
10933         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10934     CHECK(a4->IsStringObject());
10935     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10936     Local<v8::Value> a5 =
10937         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10938     CHECK(a5->IsBooleanObject());
10939     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10940
10941     Local<v8::Value> a6 =
10942         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10943     CHECK(a6->IsUndefined());
10944     Local<v8::Value> a7 =
10945         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10946     CHECK(a7->IsNull());
10947     Local<v8::Value> a8 =
10948         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10949     CHECK(a8->StrictEquals(v8_num(42)));
10950     Local<v8::Value> a9 =
10951         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10952     CHECK(a9->StrictEquals(v8_str("hello")));
10953     Local<v8::Value> a10 =
10954         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10955     CHECK(a10->StrictEquals(v8::True(isolate)));
10956   }
10957 }
10958
10959
10960 // Check whether a non-function object is callable.
10961 THREADED_TEST(CallableObject) {
10962   LocalContext context;
10963   v8::Isolate* isolate = context->GetIsolate();
10964   v8::HandleScope scope(isolate);
10965
10966   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10967     instance_template->SetCallAsFunctionHandler(call_as_function);
10968     Local<Object> instance = instance_template->NewInstance();
10969     v8::TryCatch try_catch;
10970
10971     CHECK(instance->IsCallable());
10972     CHECK(!try_catch.HasCaught());
10973   }
10974
10975   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10976     Local<Object> instance = instance_template->NewInstance();
10977     v8::TryCatch try_catch;
10978
10979     CHECK(!instance->IsCallable());
10980     CHECK(!try_catch.HasCaught());
10981   }
10982
10983   { Local<FunctionTemplate> function_template =
10984         FunctionTemplate::New(isolate, call_as_function);
10985     Local<Function> function = function_template->GetFunction();
10986     Local<Object> instance = function;
10987     v8::TryCatch try_catch;
10988
10989     CHECK(instance->IsCallable());
10990     CHECK(!try_catch.HasCaught());
10991   }
10992
10993   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10994     Local<Function> function = function_template->GetFunction();
10995     Local<Object> instance = function;
10996     v8::TryCatch try_catch;
10997
10998     CHECK(instance->IsCallable());
10999     CHECK(!try_catch.HasCaught());
11000   }
11001 }
11002
11003
11004 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11005   v8::HandleScope scope(isolate);
11006   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11007   for (int i = 0; i < iterations; i++) {
11008     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11009   }
11010   return Recurse(isolate, depth - 1, iterations);
11011 }
11012
11013
11014 THREADED_TEST(HandleIteration) {
11015   static const int kIterations = 500;
11016   static const int kNesting = 200;
11017   LocalContext context;
11018   v8::Isolate* isolate = context->GetIsolate();
11019   v8::HandleScope scope0(isolate);
11020   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11021   {
11022     v8::HandleScope scope1(isolate);
11023     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11024     for (int i = 0; i < kIterations; i++) {
11025       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11026       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11027     }
11028
11029     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11030     {
11031       v8::HandleScope scope2(CcTest::isolate());
11032       for (int j = 0; j < kIterations; j++) {
11033         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11034         CHECK_EQ(j + 1 + kIterations,
11035                  v8::HandleScope::NumberOfHandles(isolate));
11036       }
11037     }
11038     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11039   }
11040   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11041   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11042 }
11043
11044
11045 static void InterceptorHasOwnPropertyGetter(
11046     Local<String> name,
11047     const v8::PropertyCallbackInfo<v8::Value>& info) {
11048   ApiTestFuzzer::Fuzz();
11049 }
11050
11051
11052 THREADED_TEST(InterceptorHasOwnProperty) {
11053   LocalContext context;
11054   v8::Isolate* isolate = context->GetIsolate();
11055   v8::HandleScope scope(isolate);
11056   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11057   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11058   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11059   Local<Function> function = fun_templ->GetFunction();
11060   context->Global()->Set(v8_str("constructor"), function);
11061   v8::Handle<Value> value = CompileRun(
11062       "var o = new constructor();"
11063       "o.hasOwnProperty('ostehaps');");
11064   CHECK_EQ(false, value->BooleanValue());
11065   value = CompileRun(
11066       "o.ostehaps = 42;"
11067       "o.hasOwnProperty('ostehaps');");
11068   CHECK_EQ(true, value->BooleanValue());
11069   value = CompileRun(
11070       "var p = new constructor();"
11071       "p.hasOwnProperty('ostehaps');");
11072   CHECK_EQ(false, value->BooleanValue());
11073 }
11074
11075
11076 static void InterceptorHasOwnPropertyGetterGC(
11077     Local<String> name,
11078     const v8::PropertyCallbackInfo<v8::Value>& info) {
11079   ApiTestFuzzer::Fuzz();
11080   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11081 }
11082
11083
11084 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11085   LocalContext context;
11086   v8::Isolate* isolate = context->GetIsolate();
11087   v8::HandleScope scope(isolate);
11088   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11089   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11090   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11091   Local<Function> function = fun_templ->GetFunction();
11092   context->Global()->Set(v8_str("constructor"), function);
11093   // Let's first make some stuff so we can be sure to get a good GC.
11094   CompileRun(
11095       "function makestr(size) {"
11096       "  switch (size) {"
11097       "    case 1: return 'f';"
11098       "    case 2: return 'fo';"
11099       "    case 3: return 'foo';"
11100       "  }"
11101       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11102       "}"
11103       "var x = makestr(12345);"
11104       "x = makestr(31415);"
11105       "x = makestr(23456);");
11106   v8::Handle<Value> value = CompileRun(
11107       "var o = new constructor();"
11108       "o.__proto__ = new String(x);"
11109       "o.hasOwnProperty('ostehaps');");
11110   CHECK_EQ(false, value->BooleanValue());
11111 }
11112
11113
11114 typedef void (*NamedPropertyGetter)(
11115     Local<String> property,
11116     const v8::PropertyCallbackInfo<v8::Value>& info);
11117
11118
11119 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11120                                    const char* source,
11121                                    int expected) {
11122   v8::Isolate* isolate = CcTest::isolate();
11123   v8::HandleScope scope(isolate);
11124   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11125   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11126   LocalContext context;
11127   context->Global()->Set(v8_str("o"), templ->NewInstance());
11128   v8::Handle<Value> value = CompileRun(source);
11129   CHECK_EQ(expected, value->Int32Value());
11130 }
11131
11132
11133 static void InterceptorLoadICGetter(
11134     Local<String> name,
11135     const v8::PropertyCallbackInfo<v8::Value>& info) {
11136   ApiTestFuzzer::Fuzz();
11137   v8::Isolate* isolate = CcTest::isolate();
11138   CHECK_EQ(isolate, info.GetIsolate());
11139   CHECK_EQ(v8_str("data"), info.Data());
11140   CHECK_EQ(v8_str("x"), name);
11141   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11142 }
11143
11144
11145 // This test should hit the load IC for the interceptor case.
11146 THREADED_TEST(InterceptorLoadIC) {
11147   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11148     "var result = 0;"
11149     "for (var i = 0; i < 1000; i++) {"
11150     "  result = o.x;"
11151     "}",
11152     42);
11153 }
11154
11155
11156 // Below go several tests which verify that JITing for various
11157 // configurations of interceptor and explicit fields works fine
11158 // (those cases are special cased to get better performance).
11159
11160 static void InterceptorLoadXICGetter(
11161     Local<String> name,
11162     const v8::PropertyCallbackInfo<v8::Value>& info) {
11163   ApiTestFuzzer::Fuzz();
11164   info.GetReturnValue().Set(
11165       v8_str("x")->Equals(name) ?
11166           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11167           v8::Handle<v8::Value>());
11168 }
11169
11170
11171 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11172   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11173     "var result = 0;"
11174     "o.y = 239;"
11175     "for (var i = 0; i < 1000; i++) {"
11176     "  result = o.y;"
11177     "}",
11178     239);
11179 }
11180
11181
11182 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11183   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11184     "var result = 0;"
11185     "o.__proto__ = { 'y': 239 };"
11186     "for (var i = 0; i < 1000; i++) {"
11187     "  result = o.y + o.x;"
11188     "}",
11189     239 + 42);
11190 }
11191
11192
11193 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11194   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11195     "var result = 0;"
11196     "o.__proto__.y = 239;"
11197     "for (var i = 0; i < 1000; i++) {"
11198     "  result = o.y + o.x;"
11199     "}",
11200     239 + 42);
11201 }
11202
11203
11204 THREADED_TEST(InterceptorLoadICUndefined) {
11205   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11206     "var result = 0;"
11207     "for (var i = 0; i < 1000; i++) {"
11208     "  result = (o.y == undefined) ? 239 : 42;"
11209     "}",
11210     239);
11211 }
11212
11213
11214 THREADED_TEST(InterceptorLoadICWithOverride) {
11215   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11216     "fst = new Object();  fst.__proto__ = o;"
11217     "snd = new Object();  snd.__proto__ = fst;"
11218     "var result1 = 0;"
11219     "for (var i = 0; i < 1000;  i++) {"
11220     "  result1 = snd.x;"
11221     "}"
11222     "fst.x = 239;"
11223     "var result = 0;"
11224     "for (var i = 0; i < 1000; i++) {"
11225     "  result = snd.x;"
11226     "}"
11227     "result + result1",
11228     239 + 42);
11229 }
11230
11231
11232 // Test the case when we stored field into
11233 // a stub, but interceptor produced value on its own.
11234 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11235   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11236     "proto = new Object();"
11237     "o.__proto__ = proto;"
11238     "proto.x = 239;"
11239     "for (var i = 0; i < 1000; i++) {"
11240     "  o.x;"
11241     // Now it should be ICed and keep a reference to x defined on proto
11242     "}"
11243     "var result = 0;"
11244     "for (var i = 0; i < 1000; i++) {"
11245     "  result += o.x;"
11246     "}"
11247     "result;",
11248     42 * 1000);
11249 }
11250
11251
11252 // Test the case when we stored field into
11253 // a stub, but it got invalidated later on.
11254 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11255   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11256     "proto1 = new Object();"
11257     "proto2 = new Object();"
11258     "o.__proto__ = proto1;"
11259     "proto1.__proto__ = proto2;"
11260     "proto2.y = 239;"
11261     "for (var i = 0; i < 1000; i++) {"
11262     "  o.y;"
11263     // Now it should be ICed and keep a reference to y defined on proto2
11264     "}"
11265     "proto1.y = 42;"
11266     "var result = 0;"
11267     "for (var i = 0; i < 1000; i++) {"
11268     "  result += o.y;"
11269     "}"
11270     "result;",
11271     42 * 1000);
11272 }
11273
11274
11275 static int interceptor_load_not_handled_calls = 0;
11276 static void InterceptorLoadNotHandled(
11277     Local<String> name,
11278     const v8::PropertyCallbackInfo<v8::Value>& info) {
11279   ++interceptor_load_not_handled_calls;
11280 }
11281
11282
11283 // Test how post-interceptor lookups are done in the non-cacheable
11284 // case: the interceptor should not be invoked during this lookup.
11285 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11286   interceptor_load_not_handled_calls = 0;
11287   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11288     "receiver = new Object();"
11289     "receiver.__proto__ = o;"
11290     "proto = new Object();"
11291     "/* Make proto a slow-case object. */"
11292     "for (var i = 0; i < 1000; i++) {"
11293     "  proto[\"xxxxxxxx\" + i] = [];"
11294     "}"
11295     "proto.x = 17;"
11296     "o.__proto__ = proto;"
11297     "var result = 0;"
11298     "for (var i = 0; i < 1000; i++) {"
11299     "  result += receiver.x;"
11300     "}"
11301     "result;",
11302     17 * 1000);
11303   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11304 }
11305
11306
11307 // Test the case when we stored field into
11308 // a stub, but it got invalidated later on due to override on
11309 // global object which is between interceptor and fields' holders.
11310 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11311   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11312     "o.__proto__ = this;"  // set a global to be a proto of o.
11313     "this.__proto__.y = 239;"
11314     "for (var i = 0; i < 10; i++) {"
11315     "  if (o.y != 239) throw 'oops: ' + o.y;"
11316     // Now it should be ICed and keep a reference to y defined on field_holder.
11317     "}"
11318     "this.y = 42;"  // Assign on a global.
11319     "var result = 0;"
11320     "for (var i = 0; i < 10; i++) {"
11321     "  result += o.y;"
11322     "}"
11323     "result;",
11324     42 * 10);
11325 }
11326
11327
11328 static void SetOnThis(Local<String> name,
11329                       Local<Value> value,
11330                       const v8::PropertyCallbackInfo<void>& info) {
11331   info.This()->ForceSet(name, value);
11332 }
11333
11334
11335 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11336   v8::Isolate* isolate = CcTest::isolate();
11337   v8::HandleScope scope(isolate);
11338   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11339   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11340   templ->SetAccessor(v8_str("y"), Return239Callback);
11341   LocalContext context;
11342   context->Global()->Set(v8_str("o"), templ->NewInstance());
11343
11344   // Check the case when receiver and interceptor's holder
11345   // are the same objects.
11346   v8::Handle<Value> value = CompileRun(
11347       "var result = 0;"
11348       "for (var i = 0; i < 7; i++) {"
11349       "  result = o.y;"
11350       "}");
11351   CHECK_EQ(239, value->Int32Value());
11352
11353   // Check the case when interceptor's holder is in proto chain
11354   // of receiver.
11355   value = CompileRun(
11356       "r = { __proto__: o };"
11357       "var result = 0;"
11358       "for (var i = 0; i < 7; i++) {"
11359       "  result = r.y;"
11360       "}");
11361   CHECK_EQ(239, value->Int32Value());
11362 }
11363
11364
11365 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11366   v8::Isolate* isolate = CcTest::isolate();
11367   v8::HandleScope scope(isolate);
11368   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11369   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11370   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11371   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11372
11373   LocalContext context;
11374   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11375   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11376
11377   // Check the case when receiver and interceptor's holder
11378   // are the same objects.
11379   v8::Handle<Value> value = CompileRun(
11380       "o.__proto__ = p;"
11381       "var result = 0;"
11382       "for (var i = 0; i < 7; i++) {"
11383       "  result = o.x + o.y;"
11384       "}");
11385   CHECK_EQ(239 + 42, value->Int32Value());
11386
11387   // Check the case when interceptor's holder is in proto chain
11388   // of receiver.
11389   value = CompileRun(
11390       "r = { __proto__: o };"
11391       "var result = 0;"
11392       "for (var i = 0; i < 7; i++) {"
11393       "  result = r.x + r.y;"
11394       "}");
11395   CHECK_EQ(239 + 42, value->Int32Value());
11396 }
11397
11398
11399 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11400   v8::Isolate* isolate = CcTest::isolate();
11401   v8::HandleScope scope(isolate);
11402   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11403   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11404   templ->SetAccessor(v8_str("y"), Return239Callback);
11405
11406   LocalContext context;
11407   context->Global()->Set(v8_str("o"), templ->NewInstance());
11408
11409   v8::Handle<Value> value = CompileRun(
11410     "fst = new Object();  fst.__proto__ = o;"
11411     "snd = new Object();  snd.__proto__ = fst;"
11412     "var result1 = 0;"
11413     "for (var i = 0; i < 7;  i++) {"
11414     "  result1 = snd.x;"
11415     "}"
11416     "fst.x = 239;"
11417     "var result = 0;"
11418     "for (var i = 0; i < 7; i++) {"
11419     "  result = snd.x;"
11420     "}"
11421     "result + result1");
11422   CHECK_EQ(239 + 42, value->Int32Value());
11423 }
11424
11425
11426 // Test the case when we stored callback into
11427 // a stub, but interceptor produced value on its own.
11428 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11429   v8::Isolate* isolate = CcTest::isolate();
11430   v8::HandleScope scope(isolate);
11431   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11432   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11433   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11434   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11435
11436   LocalContext context;
11437   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11438   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11439
11440   v8::Handle<Value> value = CompileRun(
11441     "o.__proto__ = p;"
11442     "for (var i = 0; i < 7; i++) {"
11443     "  o.x;"
11444     // Now it should be ICed and keep a reference to x defined on p
11445     "}"
11446     "var result = 0;"
11447     "for (var i = 0; i < 7; i++) {"
11448     "  result += o.x;"
11449     "}"
11450     "result");
11451   CHECK_EQ(42 * 7, value->Int32Value());
11452 }
11453
11454
11455 // Test the case when we stored callback into
11456 // a stub, but it got invalidated later on.
11457 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11458   v8::Isolate* isolate = CcTest::isolate();
11459   v8::HandleScope scope(isolate);
11460   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11461   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11462   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11463   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11464
11465   LocalContext context;
11466   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11467   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11468
11469   v8::Handle<Value> value = CompileRun(
11470     "inbetween = new Object();"
11471     "o.__proto__ = inbetween;"
11472     "inbetween.__proto__ = p;"
11473     "for (var i = 0; i < 10; i++) {"
11474     "  o.y;"
11475     // Now it should be ICed and keep a reference to y defined on p
11476     "}"
11477     "inbetween.y = 42;"
11478     "var result = 0;"
11479     "for (var i = 0; i < 10; i++) {"
11480     "  result += o.y;"
11481     "}"
11482     "result");
11483   CHECK_EQ(42 * 10, value->Int32Value());
11484 }
11485
11486
11487 // Test the case when we stored callback into
11488 // a stub, but it got invalidated later on due to override on
11489 // global object which is between interceptor and callbacks' holders.
11490 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11491   v8::Isolate* isolate = CcTest::isolate();
11492   v8::HandleScope scope(isolate);
11493   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11494   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11495   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11496   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11497
11498   LocalContext context;
11499   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11500   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11501
11502   v8::Handle<Value> value = CompileRun(
11503     "o.__proto__ = this;"
11504     "this.__proto__ = p;"
11505     "for (var i = 0; i < 10; i++) {"
11506     "  if (o.y != 239) throw 'oops: ' + o.y;"
11507     // Now it should be ICed and keep a reference to y defined on p
11508     "}"
11509     "this.y = 42;"
11510     "var result = 0;"
11511     "for (var i = 0; i < 10; i++) {"
11512     "  result += o.y;"
11513     "}"
11514     "result");
11515   CHECK_EQ(42 * 10, value->Int32Value());
11516 }
11517
11518
11519 static void InterceptorLoadICGetter0(
11520     Local<String> name,
11521     const v8::PropertyCallbackInfo<v8::Value>& info) {
11522   ApiTestFuzzer::Fuzz();
11523   CHECK(v8_str("x")->Equals(name));
11524   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11525 }
11526
11527
11528 THREADED_TEST(InterceptorReturningZero) {
11529   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11530      "o.x == undefined ? 1 : 0",
11531      0);
11532 }
11533
11534
11535 static void InterceptorStoreICSetter(
11536     Local<String> key,
11537     Local<Value> value,
11538     const v8::PropertyCallbackInfo<v8::Value>& info) {
11539   CHECK(v8_str("x")->Equals(key));
11540   CHECK_EQ(42, value->Int32Value());
11541   info.GetReturnValue().Set(value);
11542 }
11543
11544
11545 // This test should hit the store IC for the interceptor case.
11546 THREADED_TEST(InterceptorStoreIC) {
11547   v8::Isolate* isolate = CcTest::isolate();
11548   v8::HandleScope scope(isolate);
11549   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11550   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11551                                  InterceptorStoreICSetter,
11552                                  0, 0, 0, v8_str("data"));
11553   LocalContext context;
11554   context->Global()->Set(v8_str("o"), templ->NewInstance());
11555   CompileRun(
11556       "for (var i = 0; i < 1000; i++) {"
11557       "  o.x = 42;"
11558       "}");
11559 }
11560
11561
11562 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11563   v8::Isolate* isolate = CcTest::isolate();
11564   v8::HandleScope scope(isolate);
11565   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11566   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11567   LocalContext context;
11568   context->Global()->Set(v8_str("o"), templ->NewInstance());
11569   v8::Handle<Value> value = CompileRun(
11570     "for (var i = 0; i < 1000; i++) {"
11571     "  o.y = 239;"
11572     "}"
11573     "42 + o.y");
11574   CHECK_EQ(239 + 42, value->Int32Value());
11575 }
11576
11577
11578
11579
11580 v8::Handle<Value> call_ic_function;
11581 v8::Handle<Value> call_ic_function2;
11582 v8::Handle<Value> call_ic_function3;
11583
11584 static void InterceptorCallICGetter(
11585     Local<String> name,
11586     const v8::PropertyCallbackInfo<v8::Value>& info) {
11587   ApiTestFuzzer::Fuzz();
11588   CHECK(v8_str("x")->Equals(name));
11589   info.GetReturnValue().Set(call_ic_function);
11590 }
11591
11592
11593 // This test should hit the call IC for the interceptor case.
11594 THREADED_TEST(InterceptorCallIC) {
11595   v8::Isolate* isolate = CcTest::isolate();
11596   v8::HandleScope scope(isolate);
11597   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11598   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11599   LocalContext context;
11600   context->Global()->Set(v8_str("o"), templ->NewInstance());
11601   call_ic_function =
11602       v8_compile("function f(x) { return x + 1; }; f")->Run();
11603   v8::Handle<Value> value = CompileRun(
11604     "var result = 0;"
11605     "for (var i = 0; i < 1000; i++) {"
11606     "  result = o.x(41);"
11607     "}");
11608   CHECK_EQ(42, value->Int32Value());
11609 }
11610
11611
11612 // This test checks that if interceptor doesn't provide
11613 // a value, we can fetch regular value.
11614 THREADED_TEST(InterceptorCallICSeesOthers) {
11615   v8::Isolate* isolate = CcTest::isolate();
11616   v8::HandleScope scope(isolate);
11617   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11618   templ->SetNamedPropertyHandler(NoBlockGetterX);
11619   LocalContext context;
11620   context->Global()->Set(v8_str("o"), templ->NewInstance());
11621   v8::Handle<Value> value = CompileRun(
11622     "o.x = function f(x) { return x + 1; };"
11623     "var result = 0;"
11624     "for (var i = 0; i < 7; i++) {"
11625     "  result = o.x(41);"
11626     "}");
11627   CHECK_EQ(42, value->Int32Value());
11628 }
11629
11630
11631 static v8::Handle<Value> call_ic_function4;
11632 static void InterceptorCallICGetter4(
11633     Local<String> name,
11634     const v8::PropertyCallbackInfo<v8::Value>& info) {
11635   ApiTestFuzzer::Fuzz();
11636   CHECK(v8_str("x")->Equals(name));
11637   info.GetReturnValue().Set(call_ic_function4);
11638 }
11639
11640
11641 // This test checks that if interceptor provides a function,
11642 // even if we cached shadowed variant, interceptor's function
11643 // is invoked
11644 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11645   v8::Isolate* isolate = CcTest::isolate();
11646   v8::HandleScope scope(isolate);
11647   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11648   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11649   LocalContext context;
11650   context->Global()->Set(v8_str("o"), templ->NewInstance());
11651   call_ic_function4 =
11652       v8_compile("function f(x) { return x - 1; }; f")->Run();
11653   v8::Handle<Value> value = CompileRun(
11654     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11655     "var result = 0;"
11656     "for (var i = 0; i < 1000; i++) {"
11657     "  result = o.x(42);"
11658     "}");
11659   CHECK_EQ(41, value->Int32Value());
11660 }
11661
11662
11663 // Test the case when we stored cacheable lookup into
11664 // a stub, but it got invalidated later on
11665 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11666   v8::Isolate* isolate = CcTest::isolate();
11667   v8::HandleScope scope(isolate);
11668   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11669   templ->SetNamedPropertyHandler(NoBlockGetterX);
11670   LocalContext context;
11671   context->Global()->Set(v8_str("o"), templ->NewInstance());
11672   v8::Handle<Value> value = CompileRun(
11673     "proto1 = new Object();"
11674     "proto2 = new Object();"
11675     "o.__proto__ = proto1;"
11676     "proto1.__proto__ = proto2;"
11677     "proto2.y = function(x) { return x + 1; };"
11678     // Invoke it many times to compile a stub
11679     "for (var i = 0; i < 7; i++) {"
11680     "  o.y(42);"
11681     "}"
11682     "proto1.y = function(x) { return x - 1; };"
11683     "var result = 0;"
11684     "for (var i = 0; i < 7; i++) {"
11685     "  result += o.y(42);"
11686     "}");
11687   CHECK_EQ(41 * 7, value->Int32Value());
11688 }
11689
11690
11691 // This test checks that if interceptor doesn't provide a function,
11692 // cached constant function is used
11693 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11694   v8::Isolate* isolate = CcTest::isolate();
11695   v8::HandleScope scope(isolate);
11696   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11697   templ->SetNamedPropertyHandler(NoBlockGetterX);
11698   LocalContext context;
11699   context->Global()->Set(v8_str("o"), templ->NewInstance());
11700   v8::Handle<Value> value = CompileRun(
11701     "function inc(x) { return x + 1; };"
11702     "inc(1);"
11703     "o.x = inc;"
11704     "var result = 0;"
11705     "for (var i = 0; i < 1000; i++) {"
11706     "  result = o.x(42);"
11707     "}");
11708   CHECK_EQ(43, value->Int32Value());
11709 }
11710
11711
11712 static v8::Handle<Value> call_ic_function5;
11713 static void InterceptorCallICGetter5(
11714     Local<String> name,
11715     const v8::PropertyCallbackInfo<v8::Value>& info) {
11716   ApiTestFuzzer::Fuzz();
11717   if (v8_str("x")->Equals(name))
11718     info.GetReturnValue().Set(call_ic_function5);
11719 }
11720
11721
11722 // This test checks that if interceptor provides a function,
11723 // even if we cached constant function, interceptor's function
11724 // is invoked
11725 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11726   v8::Isolate* isolate = CcTest::isolate();
11727   v8::HandleScope scope(isolate);
11728   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11729   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11730   LocalContext context;
11731   context->Global()->Set(v8_str("o"), templ->NewInstance());
11732   call_ic_function5 =
11733       v8_compile("function f(x) { return x - 1; }; f")->Run();
11734   v8::Handle<Value> value = CompileRun(
11735     "function inc(x) { return x + 1; };"
11736     "inc(1);"
11737     "o.x = inc;"
11738     "var result = 0;"
11739     "for (var i = 0; i < 1000; i++) {"
11740     "  result = o.x(42);"
11741     "}");
11742   CHECK_EQ(41, value->Int32Value());
11743 }
11744
11745
11746 static v8::Handle<Value> call_ic_function6;
11747 static void InterceptorCallICGetter6(
11748     Local<String> name,
11749     const v8::PropertyCallbackInfo<v8::Value>& info) {
11750   ApiTestFuzzer::Fuzz();
11751   if (v8_str("x")->Equals(name))
11752     info.GetReturnValue().Set(call_ic_function6);
11753 }
11754
11755
11756 // Same test as above, except the code is wrapped in a function
11757 // to test the optimized compiler.
11758 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11759   i::FLAG_allow_natives_syntax = true;
11760   v8::Isolate* isolate = CcTest::isolate();
11761   v8::HandleScope scope(isolate);
11762   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11763   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11764   LocalContext context;
11765   context->Global()->Set(v8_str("o"), templ->NewInstance());
11766   call_ic_function6 =
11767       v8_compile("function f(x) { return x - 1; }; f")->Run();
11768   v8::Handle<Value> value = CompileRun(
11769     "function inc(x) { return x + 1; };"
11770     "inc(1);"
11771     "o.x = inc;"
11772     "function test() {"
11773     "  var result = 0;"
11774     "  for (var i = 0; i < 1000; i++) {"
11775     "    result = o.x(42);"
11776     "  }"
11777     "  return result;"
11778     "};"
11779     "test();"
11780     "test();"
11781     "test();"
11782     "%OptimizeFunctionOnNextCall(test);"
11783     "test()");
11784   CHECK_EQ(41, value->Int32Value());
11785 }
11786
11787
11788 // Test the case when we stored constant function into
11789 // a stub, but it got invalidated later on
11790 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11791   v8::Isolate* isolate = CcTest::isolate();
11792   v8::HandleScope scope(isolate);
11793   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11794   templ->SetNamedPropertyHandler(NoBlockGetterX);
11795   LocalContext context;
11796   context->Global()->Set(v8_str("o"), templ->NewInstance());
11797   v8::Handle<Value> value = CompileRun(
11798     "function inc(x) { return x + 1; };"
11799     "inc(1);"
11800     "proto1 = new Object();"
11801     "proto2 = new Object();"
11802     "o.__proto__ = proto1;"
11803     "proto1.__proto__ = proto2;"
11804     "proto2.y = inc;"
11805     // Invoke it many times to compile a stub
11806     "for (var i = 0; i < 7; i++) {"
11807     "  o.y(42);"
11808     "}"
11809     "proto1.y = function(x) { return x - 1; };"
11810     "var result = 0;"
11811     "for (var i = 0; i < 7; i++) {"
11812     "  result += o.y(42);"
11813     "}");
11814   CHECK_EQ(41 * 7, value->Int32Value());
11815 }
11816
11817
11818 // Test the case when we stored constant function into
11819 // a stub, but it got invalidated later on due to override on
11820 // global object which is between interceptor and constant function' holders.
11821 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11822   v8::Isolate* isolate = CcTest::isolate();
11823   v8::HandleScope scope(isolate);
11824   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11825   templ->SetNamedPropertyHandler(NoBlockGetterX);
11826   LocalContext context;
11827   context->Global()->Set(v8_str("o"), templ->NewInstance());
11828   v8::Handle<Value> value = CompileRun(
11829     "function inc(x) { return x + 1; };"
11830     "inc(1);"
11831     "o.__proto__ = this;"
11832     "this.__proto__.y = inc;"
11833     // Invoke it many times to compile a stub
11834     "for (var i = 0; i < 7; i++) {"
11835     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11836     "}"
11837     "this.y = function(x) { return x - 1; };"
11838     "var result = 0;"
11839     "for (var i = 0; i < 7; i++) {"
11840     "  result += o.y(42);"
11841     "}");
11842   CHECK_EQ(41 * 7, value->Int32Value());
11843 }
11844
11845
11846 // Test the case when actual function to call sits on global object.
11847 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11848   v8::Isolate* isolate = CcTest::isolate();
11849   v8::HandleScope scope(isolate);
11850   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11851   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11852
11853   LocalContext context;
11854   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11855
11856   v8::Handle<Value> value = CompileRun(
11857     "try {"
11858     "  o.__proto__ = this;"
11859     "  for (var i = 0; i < 10; i++) {"
11860     "    var v = o.parseFloat('239');"
11861     "    if (v != 239) throw v;"
11862       // Now it should be ICed and keep a reference to parseFloat.
11863     "  }"
11864     "  var result = 0;"
11865     "  for (var i = 0; i < 10; i++) {"
11866     "    result += o.parseFloat('239');"
11867     "  }"
11868     "  result"
11869     "} catch(e) {"
11870     "  e"
11871     "};");
11872   CHECK_EQ(239 * 10, value->Int32Value());
11873 }
11874
11875 static void InterceptorCallICFastApi(
11876     Local<String> name,
11877     const v8::PropertyCallbackInfo<v8::Value>& info) {
11878   ApiTestFuzzer::Fuzz();
11879   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11880   int* call_count =
11881       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11882   ++(*call_count);
11883   if ((*call_count) % 20 == 0) {
11884     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11885   }
11886 }
11887
11888 static void FastApiCallback_TrivialSignature(
11889     const v8::FunctionCallbackInfo<v8::Value>& args) {
11890   ApiTestFuzzer::Fuzz();
11891   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11892   v8::Isolate* isolate = CcTest::isolate();
11893   CHECK_EQ(isolate, args.GetIsolate());
11894   CHECK_EQ(args.This(), args.Holder());
11895   CHECK(args.Data()->Equals(v8_str("method_data")));
11896   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11897 }
11898
11899 static void FastApiCallback_SimpleSignature(
11900     const v8::FunctionCallbackInfo<v8::Value>& args) {
11901   ApiTestFuzzer::Fuzz();
11902   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11903   v8::Isolate* isolate = CcTest::isolate();
11904   CHECK_EQ(isolate, args.GetIsolate());
11905   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11906   CHECK(args.Data()->Equals(v8_str("method_data")));
11907   // Note, we're using HasRealNamedProperty instead of Has to avoid
11908   // invoking the interceptor again.
11909   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11910   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11911 }
11912
11913
11914 // Helper to maximize the odds of object moving.
11915 static void GenerateSomeGarbage() {
11916   CompileRun(
11917       "var garbage;"
11918       "for (var i = 0; i < 1000; i++) {"
11919       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11920       "}"
11921       "garbage = undefined;");
11922 }
11923
11924
11925 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11926   static int count = 0;
11927   if (count++ % 3 == 0) {
11928     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11929         // This should move the stub
11930     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
11931   }
11932 }
11933
11934
11935 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11936   LocalContext context;
11937   v8::Isolate* isolate = context->GetIsolate();
11938   v8::HandleScope scope(isolate);
11939   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11940       v8::ObjectTemplate::New(isolate);
11941   nativeobject_templ->Set(isolate, "callback",
11942                           v8::FunctionTemplate::New(isolate,
11943                                                     DirectApiCallback));
11944   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11945   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11946   // call the api function multiple times to ensure direct call stub creation.
11947   CompileRun(
11948         "function f() {"
11949         "  for (var i = 1; i <= 30; i++) {"
11950         "    nativeobject.callback();"
11951         "  }"
11952         "}"
11953         "f();");
11954 }
11955
11956
11957 void ThrowingDirectApiCallback(
11958     const v8::FunctionCallbackInfo<v8::Value>& args) {
11959   args.GetIsolate()->ThrowException(v8_str("g"));
11960 }
11961
11962
11963 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11964   LocalContext context;
11965   v8::Isolate* isolate = context->GetIsolate();
11966   v8::HandleScope scope(isolate);
11967   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
11968       v8::ObjectTemplate::New(isolate);
11969   nativeobject_templ->Set(isolate, "callback",
11970                           v8::FunctionTemplate::New(isolate,
11971                                                     ThrowingDirectApiCallback));
11972   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11973   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11974   // call the api function multiple times to ensure direct call stub creation.
11975   v8::Handle<Value> result = CompileRun(
11976       "var result = '';"
11977       "function f() {"
11978       "  for (var i = 1; i <= 5; i++) {"
11979       "    try { nativeobject.callback(); } catch (e) { result += e; }"
11980       "  }"
11981       "}"
11982       "f(); result;");
11983   CHECK_EQ(v8_str("ggggg"), result);
11984 }
11985
11986
11987 static Handle<Value> DoDirectGetter() {
11988   if (++p_getter_count % 3 == 0) {
11989     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11990     GenerateSomeGarbage();
11991   }
11992   return v8_str("Direct Getter Result");
11993 }
11994
11995 static void DirectGetterCallback(
11996     Local<String> name,
11997     const v8::PropertyCallbackInfo<v8::Value>& info) {
11998   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
11999   info.GetReturnValue().Set(DoDirectGetter());
12000 }
12001
12002
12003 template<typename Accessor>
12004 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12005   LocalContext context;
12006   v8::Isolate* isolate = context->GetIsolate();
12007   v8::HandleScope scope(isolate);
12008   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12009   obj->SetAccessor(v8_str("p1"), accessor);
12010   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12011   p_getter_count = 0;
12012   v8::Handle<v8::Value> result = CompileRun(
12013       "function f() {"
12014       "  for (var i = 0; i < 30; i++) o1.p1;"
12015       "  return o1.p1"
12016       "}"
12017       "f();");
12018   CHECK_EQ(v8_str("Direct Getter Result"), result);
12019   CHECK_EQ(31, p_getter_count);
12020 }
12021
12022
12023 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12024   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12025 }
12026
12027
12028 void ThrowingDirectGetterCallback(
12029     Local<String> name,
12030     const v8::PropertyCallbackInfo<v8::Value>& info) {
12031   info.GetIsolate()->ThrowException(v8_str("g"));
12032 }
12033
12034
12035 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12036   LocalContext context;
12037   v8::Isolate* isolate = context->GetIsolate();
12038   v8::HandleScope scope(isolate);
12039   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12040   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12041   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12042   v8::Handle<Value> result = CompileRun(
12043       "var result = '';"
12044       "for (var i = 0; i < 5; i++) {"
12045       "    try { o1.p1; } catch (e) { result += e; }"
12046       "}"
12047       "result;");
12048   CHECK_EQ(v8_str("ggggg"), result);
12049 }
12050
12051
12052 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12053   int interceptor_call_count = 0;
12054   v8::Isolate* isolate = CcTest::isolate();
12055   v8::HandleScope scope(isolate);
12056   v8::Handle<v8::FunctionTemplate> fun_templ =
12057       v8::FunctionTemplate::New(isolate);
12058   v8::Handle<v8::FunctionTemplate> method_templ =
12059       v8::FunctionTemplate::New(isolate,
12060                                 FastApiCallback_TrivialSignature,
12061                                 v8_str("method_data"),
12062                                 v8::Handle<v8::Signature>());
12063   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12064   proto_templ->Set(v8_str("method"), method_templ);
12065   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12066   templ->SetNamedPropertyHandler(
12067       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12068       v8::External::New(isolate, &interceptor_call_count));
12069   LocalContext context;
12070   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12071   GenerateSomeGarbage();
12072   context->Global()->Set(v8_str("o"), fun->NewInstance());
12073   CompileRun(
12074       "var result = 0;"
12075       "for (var i = 0; i < 100; i++) {"
12076       "  result = o.method(41);"
12077       "}");
12078   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12079   CHECK_EQ(100, interceptor_call_count);
12080 }
12081
12082
12083 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12084   int interceptor_call_count = 0;
12085   v8::Isolate* isolate = CcTest::isolate();
12086   v8::HandleScope scope(isolate);
12087   v8::Handle<v8::FunctionTemplate> fun_templ =
12088       v8::FunctionTemplate::New(isolate);
12089   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12090       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12091       v8::Signature::New(isolate, fun_templ));
12092   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12093   proto_templ->Set(v8_str("method"), method_templ);
12094   fun_templ->SetHiddenPrototype(true);
12095   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12096   templ->SetNamedPropertyHandler(
12097       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12098       v8::External::New(isolate, &interceptor_call_count));
12099   LocalContext context;
12100   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12101   GenerateSomeGarbage();
12102   context->Global()->Set(v8_str("o"), fun->NewInstance());
12103   CompileRun(
12104       "o.foo = 17;"
12105       "var receiver = {};"
12106       "receiver.__proto__ = o;"
12107       "var result = 0;"
12108       "for (var i = 0; i < 100; i++) {"
12109       "  result = receiver.method(41);"
12110       "}");
12111   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12112   CHECK_EQ(100, interceptor_call_count);
12113 }
12114
12115
12116 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12117   int interceptor_call_count = 0;
12118   v8::Isolate* isolate = CcTest::isolate();
12119   v8::HandleScope scope(isolate);
12120   v8::Handle<v8::FunctionTemplate> fun_templ =
12121       v8::FunctionTemplate::New(isolate);
12122   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12123       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12124       v8::Signature::New(isolate, fun_templ));
12125   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12126   proto_templ->Set(v8_str("method"), method_templ);
12127   fun_templ->SetHiddenPrototype(true);
12128   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12129   templ->SetNamedPropertyHandler(
12130       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12131       v8::External::New(isolate, &interceptor_call_count));
12132   LocalContext context;
12133   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12134   GenerateSomeGarbage();
12135   context->Global()->Set(v8_str("o"), fun->NewInstance());
12136   CompileRun(
12137       "o.foo = 17;"
12138       "var receiver = {};"
12139       "receiver.__proto__ = o;"
12140       "var result = 0;"
12141       "var saved_result = 0;"
12142       "for (var i = 0; i < 100; i++) {"
12143       "  result = receiver.method(41);"
12144       "  if (i == 50) {"
12145       "    saved_result = result;"
12146       "    receiver = {method: function(x) { return x - 1 }};"
12147       "  }"
12148       "}");
12149   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12150   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12151   CHECK_GE(interceptor_call_count, 50);
12152 }
12153
12154
12155 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12156   int interceptor_call_count = 0;
12157   v8::Isolate* isolate = CcTest::isolate();
12158   v8::HandleScope scope(isolate);
12159   v8::Handle<v8::FunctionTemplate> fun_templ =
12160       v8::FunctionTemplate::New(isolate);
12161   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12162       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12163       v8::Signature::New(isolate, fun_templ));
12164   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12165   proto_templ->Set(v8_str("method"), method_templ);
12166   fun_templ->SetHiddenPrototype(true);
12167   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12168   templ->SetNamedPropertyHandler(
12169       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12170       v8::External::New(isolate, &interceptor_call_count));
12171   LocalContext context;
12172   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12173   GenerateSomeGarbage();
12174   context->Global()->Set(v8_str("o"), fun->NewInstance());
12175   CompileRun(
12176       "o.foo = 17;"
12177       "var receiver = {};"
12178       "receiver.__proto__ = o;"
12179       "var result = 0;"
12180       "var saved_result = 0;"
12181       "for (var i = 0; i < 100; i++) {"
12182       "  result = receiver.method(41);"
12183       "  if (i == 50) {"
12184       "    saved_result = result;"
12185       "    o.method = function(x) { return x - 1 };"
12186       "  }"
12187       "}");
12188   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12189   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12190   CHECK_GE(interceptor_call_count, 50);
12191 }
12192
12193
12194 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12195   int interceptor_call_count = 0;
12196   v8::Isolate* isolate = CcTest::isolate();
12197   v8::HandleScope scope(isolate);
12198   v8::Handle<v8::FunctionTemplate> fun_templ =
12199       v8::FunctionTemplate::New(isolate);
12200   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12201       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12202       v8::Signature::New(isolate, fun_templ));
12203   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12204   proto_templ->Set(v8_str("method"), method_templ);
12205   fun_templ->SetHiddenPrototype(true);
12206   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12207   templ->SetNamedPropertyHandler(
12208       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12209       v8::External::New(isolate, &interceptor_call_count));
12210   LocalContext context;
12211   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12212   GenerateSomeGarbage();
12213   context->Global()->Set(v8_str("o"), fun->NewInstance());
12214   v8::TryCatch try_catch;
12215   CompileRun(
12216       "o.foo = 17;"
12217       "var receiver = {};"
12218       "receiver.__proto__ = o;"
12219       "var result = 0;"
12220       "var saved_result = 0;"
12221       "for (var i = 0; i < 100; i++) {"
12222       "  result = receiver.method(41);"
12223       "  if (i == 50) {"
12224       "    saved_result = result;"
12225       "    receiver = 333;"
12226       "  }"
12227       "}");
12228   CHECK(try_catch.HasCaught());
12229   // TODO(verwaest): Adjust message.
12230   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12231            try_catch.Exception()->ToString());
12232   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12233   CHECK_GE(interceptor_call_count, 50);
12234 }
12235
12236
12237 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12238   int interceptor_call_count = 0;
12239   v8::Isolate* isolate = CcTest::isolate();
12240   v8::HandleScope scope(isolate);
12241   v8::Handle<v8::FunctionTemplate> fun_templ =
12242       v8::FunctionTemplate::New(isolate);
12243   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12244       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12245       v8::Signature::New(isolate, fun_templ));
12246   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12247   proto_templ->Set(v8_str("method"), method_templ);
12248   fun_templ->SetHiddenPrototype(true);
12249   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12250   templ->SetNamedPropertyHandler(
12251       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12252       v8::External::New(isolate, &interceptor_call_count));
12253   LocalContext context;
12254   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12255   GenerateSomeGarbage();
12256   context->Global()->Set(v8_str("o"), fun->NewInstance());
12257   v8::TryCatch try_catch;
12258   CompileRun(
12259       "o.foo = 17;"
12260       "var receiver = {};"
12261       "receiver.__proto__ = o;"
12262       "var result = 0;"
12263       "var saved_result = 0;"
12264       "for (var i = 0; i < 100; i++) {"
12265       "  result = receiver.method(41);"
12266       "  if (i == 50) {"
12267       "    saved_result = result;"
12268       "    receiver = {method: receiver.method};"
12269       "  }"
12270       "}");
12271   CHECK(try_catch.HasCaught());
12272   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12273            try_catch.Exception()->ToString());
12274   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12275   CHECK_GE(interceptor_call_count, 50);
12276 }
12277
12278
12279 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12280   v8::Isolate* isolate = CcTest::isolate();
12281   v8::HandleScope scope(isolate);
12282   v8::Handle<v8::FunctionTemplate> fun_templ =
12283       v8::FunctionTemplate::New(isolate);
12284   v8::Handle<v8::FunctionTemplate> method_templ =
12285       v8::FunctionTemplate::New(isolate,
12286                                 FastApiCallback_TrivialSignature,
12287                                 v8_str("method_data"),
12288                                 v8::Handle<v8::Signature>());
12289   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12290   proto_templ->Set(v8_str("method"), method_templ);
12291   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12292   USE(templ);
12293   LocalContext context;
12294   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12295   GenerateSomeGarbage();
12296   context->Global()->Set(v8_str("o"), fun->NewInstance());
12297   CompileRun(
12298       "var result = 0;"
12299       "for (var i = 0; i < 100; i++) {"
12300       "  result = o.method(41);"
12301       "}");
12302
12303   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12304 }
12305
12306
12307 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12308   v8::Isolate* isolate = CcTest::isolate();
12309   v8::HandleScope scope(isolate);
12310   v8::Handle<v8::FunctionTemplate> fun_templ =
12311       v8::FunctionTemplate::New(isolate);
12312   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12313       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12314       v8::Signature::New(isolate, fun_templ));
12315   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12316   proto_templ->Set(v8_str("method"), method_templ);
12317   fun_templ->SetHiddenPrototype(true);
12318   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12319   CHECK(!templ.IsEmpty());
12320   LocalContext context;
12321   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12322   GenerateSomeGarbage();
12323   context->Global()->Set(v8_str("o"), fun->NewInstance());
12324   CompileRun(
12325       "o.foo = 17;"
12326       "var receiver = {};"
12327       "receiver.__proto__ = o;"
12328       "var result = 0;"
12329       "for (var i = 0; i < 100; i++) {"
12330       "  result = receiver.method(41);"
12331       "}");
12332
12333   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12334 }
12335
12336
12337 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12338   v8::Isolate* isolate = CcTest::isolate();
12339   v8::HandleScope scope(isolate);
12340   v8::Handle<v8::FunctionTemplate> fun_templ =
12341       v8::FunctionTemplate::New(isolate);
12342   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12343       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12344       v8::Signature::New(isolate, fun_templ));
12345   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12346   proto_templ->Set(v8_str("method"), method_templ);
12347   fun_templ->SetHiddenPrototype(true);
12348   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12349   CHECK(!templ.IsEmpty());
12350   LocalContext context;
12351   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12352   GenerateSomeGarbage();
12353   context->Global()->Set(v8_str("o"), fun->NewInstance());
12354   CompileRun(
12355       "o.foo = 17;"
12356       "var receiver = {};"
12357       "receiver.__proto__ = o;"
12358       "var result = 0;"
12359       "var saved_result = 0;"
12360       "for (var i = 0; i < 100; i++) {"
12361       "  result = receiver.method(41);"
12362       "  if (i == 50) {"
12363       "    saved_result = result;"
12364       "    receiver = {method: function(x) { return x - 1 }};"
12365       "  }"
12366       "}");
12367   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12368   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12369 }
12370
12371
12372 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12373   v8::Isolate* isolate = CcTest::isolate();
12374   v8::HandleScope scope(isolate);
12375   v8::Handle<v8::FunctionTemplate> fun_templ =
12376       v8::FunctionTemplate::New(isolate);
12377   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12378       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12379       v8::Signature::New(isolate, fun_templ));
12380   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12381   proto_templ->Set(v8_str("method"), method_templ);
12382   fun_templ->SetHiddenPrototype(true);
12383   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12384   CHECK(!templ.IsEmpty());
12385   LocalContext context;
12386   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12387   GenerateSomeGarbage();
12388   context->Global()->Set(v8_str("o"), fun->NewInstance());
12389   v8::TryCatch try_catch;
12390   CompileRun(
12391       "o.foo = 17;"
12392       "var receiver = {};"
12393       "receiver.__proto__ = o;"
12394       "var result = 0;"
12395       "var saved_result = 0;"
12396       "for (var i = 0; i < 100; i++) {"
12397       "  result = receiver.method(41);"
12398       "  if (i == 50) {"
12399       "    saved_result = result;"
12400       "    receiver = 333;"
12401       "  }"
12402       "}");
12403   CHECK(try_catch.HasCaught());
12404   // TODO(verwaest): Adjust message.
12405   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12406            try_catch.Exception()->ToString());
12407   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12408 }
12409
12410
12411 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12412   v8::Isolate* isolate = CcTest::isolate();
12413   v8::HandleScope scope(isolate);
12414   v8::Handle<v8::FunctionTemplate> fun_templ =
12415       v8::FunctionTemplate::New(isolate);
12416   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12417       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12418       v8::Signature::New(isolate, fun_templ));
12419   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12420   proto_templ->Set(v8_str("method"), method_templ);
12421   fun_templ->SetHiddenPrototype(true);
12422   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12423   CHECK(!templ.IsEmpty());
12424   LocalContext context;
12425   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12426   GenerateSomeGarbage();
12427   context->Global()->Set(v8_str("o"), fun->NewInstance());
12428   v8::TryCatch try_catch;
12429   CompileRun(
12430       "o.foo = 17;"
12431       "var receiver = {};"
12432       "receiver.__proto__ = o;"
12433       "var result = 0;"
12434       "var saved_result = 0;"
12435       "for (var i = 0; i < 100; i++) {"
12436       "  result = receiver.method(41);"
12437       "  if (i == 50) {"
12438       "    saved_result = result;"
12439       "    receiver = Object.create(receiver);"
12440       "  }"
12441       "}");
12442   CHECK(try_catch.HasCaught());
12443   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12444            try_catch.Exception()->ToString());
12445   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12446 }
12447
12448
12449 v8::Handle<Value> keyed_call_ic_function;
12450
12451 static void InterceptorKeyedCallICGetter(
12452     Local<String> name,
12453     const v8::PropertyCallbackInfo<v8::Value>& info) {
12454   ApiTestFuzzer::Fuzz();
12455   if (v8_str("x")->Equals(name)) {
12456     info.GetReturnValue().Set(keyed_call_ic_function);
12457   }
12458 }
12459
12460
12461 // Test the case when we stored cacheable lookup into
12462 // a stub, but the function name changed (to another cacheable function).
12463 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12464   v8::Isolate* isolate = CcTest::isolate();
12465   v8::HandleScope scope(isolate);
12466   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12467   templ->SetNamedPropertyHandler(NoBlockGetterX);
12468   LocalContext context;
12469   context->Global()->Set(v8_str("o"), templ->NewInstance());
12470   CompileRun(
12471     "proto = new Object();"
12472     "proto.y = function(x) { return x + 1; };"
12473     "proto.z = function(x) { return x - 1; };"
12474     "o.__proto__ = proto;"
12475     "var result = 0;"
12476     "var method = 'y';"
12477     "for (var i = 0; i < 10; i++) {"
12478     "  if (i == 5) { method = 'z'; };"
12479     "  result += o[method](41);"
12480     "}");
12481   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12482 }
12483
12484
12485 // Test the case when we stored cacheable lookup into
12486 // a stub, but the function name changed (and the new function is present
12487 // both before and after the interceptor in the prototype chain).
12488 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12489   v8::Isolate* isolate = CcTest::isolate();
12490   v8::HandleScope scope(isolate);
12491   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12492   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12493   LocalContext context;
12494   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12495   keyed_call_ic_function =
12496       v8_compile("function f(x) { return x - 1; }; f")->Run();
12497   CompileRun(
12498     "o = new Object();"
12499     "proto2 = new Object();"
12500     "o.y = function(x) { return x + 1; };"
12501     "proto2.y = function(x) { return x + 2; };"
12502     "o.__proto__ = proto1;"
12503     "proto1.__proto__ = proto2;"
12504     "var result = 0;"
12505     "var method = 'x';"
12506     "for (var i = 0; i < 10; i++) {"
12507     "  if (i == 5) { method = 'y'; };"
12508     "  result += o[method](41);"
12509     "}");
12510   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12511 }
12512
12513
12514 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12515 // on the global object.
12516 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12517   v8::Isolate* isolate = CcTest::isolate();
12518   v8::HandleScope scope(isolate);
12519   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12520   templ->SetNamedPropertyHandler(NoBlockGetterX);
12521   LocalContext context;
12522   context->Global()->Set(v8_str("o"), templ->NewInstance());
12523   CompileRun(
12524     "function inc(x) { return x + 1; };"
12525     "inc(1);"
12526     "function dec(x) { return x - 1; };"
12527     "dec(1);"
12528     "o.__proto__ = this;"
12529     "this.__proto__.x = inc;"
12530     "this.__proto__.y = dec;"
12531     "var result = 0;"
12532     "var method = 'x';"
12533     "for (var i = 0; i < 10; i++) {"
12534     "  if (i == 5) { method = 'y'; };"
12535     "  result += o[method](41);"
12536     "}");
12537   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12538 }
12539
12540
12541 // Test the case when actual function to call sits on global object.
12542 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12543   v8::Isolate* isolate = CcTest::isolate();
12544   v8::HandleScope scope(isolate);
12545   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12546   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12547   LocalContext context;
12548   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12549
12550   CompileRun(
12551     "function len(x) { return x.length; };"
12552     "o.__proto__ = this;"
12553     "var m = 'parseFloat';"
12554     "var result = 0;"
12555     "for (var i = 0; i < 10; i++) {"
12556     "  if (i == 5) {"
12557     "    m = 'len';"
12558     "    saved_result = result;"
12559     "  };"
12560     "  result = o[m]('239');"
12561     "}");
12562   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12563   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12564 }
12565
12566
12567 // Test the map transition before the interceptor.
12568 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12569   v8::Isolate* isolate = CcTest::isolate();
12570   v8::HandleScope scope(isolate);
12571   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12572   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12573   LocalContext context;
12574   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12575
12576   CompileRun(
12577     "var o = new Object();"
12578     "o.__proto__ = proto;"
12579     "o.method = function(x) { return x + 1; };"
12580     "var m = 'method';"
12581     "var result = 0;"
12582     "for (var i = 0; i < 10; i++) {"
12583     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12584     "  result += o[m](41);"
12585     "}");
12586   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12587 }
12588
12589
12590 // Test the map transition after the interceptor.
12591 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12592   v8::Isolate* isolate = CcTest::isolate();
12593   v8::HandleScope scope(isolate);
12594   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12595   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12596   LocalContext context;
12597   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12598
12599   CompileRun(
12600     "var proto = new Object();"
12601     "o.__proto__ = proto;"
12602     "proto.method = function(x) { return x + 1; };"
12603     "var m = 'method';"
12604     "var result = 0;"
12605     "for (var i = 0; i < 10; i++) {"
12606     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12607     "  result += o[m](41);"
12608     "}");
12609   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12610 }
12611
12612
12613 static int interceptor_call_count = 0;
12614
12615 static void InterceptorICRefErrorGetter(
12616     Local<String> name,
12617     const v8::PropertyCallbackInfo<v8::Value>& info) {
12618   ApiTestFuzzer::Fuzz();
12619   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12620     info.GetReturnValue().Set(call_ic_function2);
12621   }
12622 }
12623
12624
12625 // This test should hit load and call ICs for the interceptor case.
12626 // Once in a while, the interceptor will reply that a property was not
12627 // found in which case we should get a reference error.
12628 THREADED_TEST(InterceptorICReferenceErrors) {
12629   v8::Isolate* isolate = CcTest::isolate();
12630   v8::HandleScope scope(isolate);
12631   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12632   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12633   LocalContext context(0, templ, v8::Handle<Value>());
12634   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12635   v8::Handle<Value> value = CompileRun(
12636     "function f() {"
12637     "  for (var i = 0; i < 1000; i++) {"
12638     "    try { x; } catch(e) { return true; }"
12639     "  }"
12640     "  return false;"
12641     "};"
12642     "f();");
12643   CHECK_EQ(true, value->BooleanValue());
12644   interceptor_call_count = 0;
12645   value = CompileRun(
12646     "function g() {"
12647     "  for (var i = 0; i < 1000; i++) {"
12648     "    try { x(42); } catch(e) { return true; }"
12649     "  }"
12650     "  return false;"
12651     "};"
12652     "g();");
12653   CHECK_EQ(true, value->BooleanValue());
12654 }
12655
12656
12657 static int interceptor_ic_exception_get_count = 0;
12658
12659 static void InterceptorICExceptionGetter(
12660     Local<String> name,
12661     const v8::PropertyCallbackInfo<v8::Value>& info) {
12662   ApiTestFuzzer::Fuzz();
12663   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12664     info.GetReturnValue().Set(call_ic_function3);
12665   }
12666   if (interceptor_ic_exception_get_count == 20) {
12667     info.GetIsolate()->ThrowException(v8_num(42));
12668     return;
12669   }
12670 }
12671
12672
12673 // Test interceptor load/call IC where the interceptor throws an
12674 // exception once in a while.
12675 THREADED_TEST(InterceptorICGetterExceptions) {
12676   interceptor_ic_exception_get_count = 0;
12677   v8::Isolate* isolate = CcTest::isolate();
12678   v8::HandleScope scope(isolate);
12679   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12680   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12681   LocalContext context(0, templ, v8::Handle<Value>());
12682   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12683   v8::Handle<Value> value = CompileRun(
12684     "function f() {"
12685     "  for (var i = 0; i < 100; i++) {"
12686     "    try { x; } catch(e) { return true; }"
12687     "  }"
12688     "  return false;"
12689     "};"
12690     "f();");
12691   CHECK_EQ(true, value->BooleanValue());
12692   interceptor_ic_exception_get_count = 0;
12693   value = CompileRun(
12694     "function f() {"
12695     "  for (var i = 0; i < 100; i++) {"
12696     "    try { x(42); } catch(e) { return true; }"
12697     "  }"
12698     "  return false;"
12699     "};"
12700     "f();");
12701   CHECK_EQ(true, value->BooleanValue());
12702 }
12703
12704
12705 static int interceptor_ic_exception_set_count = 0;
12706
12707 static void InterceptorICExceptionSetter(
12708       Local<String> key,
12709       Local<Value> value,
12710       const v8::PropertyCallbackInfo<v8::Value>& info) {
12711   ApiTestFuzzer::Fuzz();
12712   if (++interceptor_ic_exception_set_count > 20) {
12713     info.GetIsolate()->ThrowException(v8_num(42));
12714   }
12715 }
12716
12717
12718 // Test interceptor store IC where the interceptor throws an exception
12719 // once in a while.
12720 THREADED_TEST(InterceptorICSetterExceptions) {
12721   interceptor_ic_exception_set_count = 0;
12722   v8::Isolate* isolate = CcTest::isolate();
12723   v8::HandleScope scope(isolate);
12724   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12725   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12726   LocalContext context(0, templ, v8::Handle<Value>());
12727   v8::Handle<Value> value = CompileRun(
12728     "function f() {"
12729     "  for (var i = 0; i < 100; i++) {"
12730     "    try { x = 42; } catch(e) { return true; }"
12731     "  }"
12732     "  return false;"
12733     "};"
12734     "f();");
12735   CHECK_EQ(true, value->BooleanValue());
12736 }
12737
12738
12739 // Test that we ignore null interceptors.
12740 THREADED_TEST(NullNamedInterceptor) {
12741   v8::Isolate* isolate = CcTest::isolate();
12742   v8::HandleScope scope(isolate);
12743   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12744   templ->SetNamedPropertyHandler(
12745       static_cast<v8::NamedPropertyGetterCallback>(0));
12746   LocalContext context;
12747   templ->Set(CcTest::isolate(), "x", v8_num(42));
12748   v8::Handle<v8::Object> obj = templ->NewInstance();
12749   context->Global()->Set(v8_str("obj"), obj);
12750   v8::Handle<Value> value = CompileRun("obj.x");
12751   CHECK(value->IsInt32());
12752   CHECK_EQ(42, value->Int32Value());
12753 }
12754
12755
12756 // Test that we ignore null interceptors.
12757 THREADED_TEST(NullIndexedInterceptor) {
12758   v8::Isolate* isolate = CcTest::isolate();
12759   v8::HandleScope scope(isolate);
12760   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12761   templ->SetIndexedPropertyHandler(
12762       static_cast<v8::IndexedPropertyGetterCallback>(0));
12763   LocalContext context;
12764   templ->Set(CcTest::isolate(), "42", v8_num(42));
12765   v8::Handle<v8::Object> obj = templ->NewInstance();
12766   context->Global()->Set(v8_str("obj"), obj);
12767   v8::Handle<Value> value = CompileRun("obj[42]");
12768   CHECK(value->IsInt32());
12769   CHECK_EQ(42, value->Int32Value());
12770 }
12771
12772
12773 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12774   v8::Isolate* isolate = CcTest::isolate();
12775   v8::HandleScope scope(isolate);
12776   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12777   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12778   LocalContext env;
12779   env->Global()->Set(v8_str("obj"),
12780                      templ->GetFunction()->NewInstance());
12781   ExpectTrue("obj.x === 42");
12782   ExpectTrue("!obj.propertyIsEnumerable('x')");
12783 }
12784
12785
12786 static void ThrowingGetter(Local<String> name,
12787                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12788   ApiTestFuzzer::Fuzz();
12789   info.GetIsolate()->ThrowException(Handle<Value>());
12790   info.GetReturnValue().SetUndefined();
12791 }
12792
12793
12794 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12795   LocalContext context;
12796   HandleScope scope(context->GetIsolate());
12797
12798   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12799   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12800   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12801
12802   Local<Object> instance = templ->GetFunction()->NewInstance();
12803
12804   Local<Object> another = Object::New(context->GetIsolate());
12805   another->SetPrototype(instance);
12806
12807   Local<Object> with_js_getter = CompileRun(
12808       "o = {};\n"
12809       "o.__defineGetter__('f', function() { throw undefined; });\n"
12810       "o\n").As<Object>();
12811   CHECK(!with_js_getter.IsEmpty());
12812
12813   TryCatch try_catch;
12814
12815   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12816   CHECK(try_catch.HasCaught());
12817   try_catch.Reset();
12818   CHECK(result.IsEmpty());
12819
12820   result = another->GetRealNamedProperty(v8_str("f"));
12821   CHECK(try_catch.HasCaught());
12822   try_catch.Reset();
12823   CHECK(result.IsEmpty());
12824
12825   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12826   CHECK(try_catch.HasCaught());
12827   try_catch.Reset();
12828   CHECK(result.IsEmpty());
12829
12830   result = another->Get(v8_str("f"));
12831   CHECK(try_catch.HasCaught());
12832   try_catch.Reset();
12833   CHECK(result.IsEmpty());
12834
12835   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12836   CHECK(try_catch.HasCaught());
12837   try_catch.Reset();
12838   CHECK(result.IsEmpty());
12839
12840   result = with_js_getter->Get(v8_str("f"));
12841   CHECK(try_catch.HasCaught());
12842   try_catch.Reset();
12843   CHECK(result.IsEmpty());
12844 }
12845
12846
12847 static void ThrowingCallbackWithTryCatch(
12848     const v8::FunctionCallbackInfo<v8::Value>& args) {
12849   TryCatch try_catch;
12850   // Verboseness is important: it triggers message delivery which can call into
12851   // external code.
12852   try_catch.SetVerbose(true);
12853   CompileRun("throw 'from JS';");
12854   CHECK(try_catch.HasCaught());
12855   CHECK(!CcTest::i_isolate()->has_pending_exception());
12856   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12857 }
12858
12859
12860 static int call_depth;
12861
12862
12863 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12864   TryCatch try_catch;
12865 }
12866
12867
12868 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12869   if (--call_depth) CompileRun("throw 'ThrowInJS';");
12870 }
12871
12872
12873 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12874   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12875 }
12876
12877
12878 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12879   Handle<String> errorMessageString = message->Get();
12880   CHECK(!errorMessageString.IsEmpty());
12881   message->GetStackTrace();
12882   message->GetScriptResourceName();
12883 }
12884
12885
12886 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12887   LocalContext context;
12888   v8::Isolate* isolate = context->GetIsolate();
12889   HandleScope scope(isolate);
12890
12891   Local<Function> func =
12892       FunctionTemplate::New(isolate,
12893                             ThrowingCallbackWithTryCatch)->GetFunction();
12894   context->Global()->Set(v8_str("func"), func);
12895
12896   MessageCallback callbacks[] =
12897       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12898   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12899     MessageCallback callback = callbacks[i];
12900     if (callback != NULL) {
12901       V8::AddMessageListener(callback);
12902     }
12903     // Some small number to control number of times message handler should
12904     // throw an exception.
12905     call_depth = 5;
12906     ExpectFalse(
12907         "var thrown = false;\n"
12908         "try { func(); } catch(e) { thrown = true; }\n"
12909         "thrown\n");
12910     if (callback != NULL) {
12911       V8::RemoveMessageListeners(callback);
12912     }
12913   }
12914 }
12915
12916
12917 static void ParentGetter(Local<String> name,
12918                          const v8::PropertyCallbackInfo<v8::Value>& info) {
12919   ApiTestFuzzer::Fuzz();
12920   info.GetReturnValue().Set(v8_num(1));
12921 }
12922
12923
12924 static void ChildGetter(Local<String> name,
12925                         const v8::PropertyCallbackInfo<v8::Value>& info) {
12926   ApiTestFuzzer::Fuzz();
12927   info.GetReturnValue().Set(v8_num(42));
12928 }
12929
12930
12931 THREADED_TEST(Overriding) {
12932   i::FLAG_es5_readonly = true;
12933   LocalContext context;
12934   v8::Isolate* isolate = context->GetIsolate();
12935   v8::HandleScope scope(isolate);
12936
12937   // Parent template.
12938   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
12939   Local<ObjectTemplate> parent_instance_templ =
12940       parent_templ->InstanceTemplate();
12941   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12942
12943   // Template that inherits from the parent template.
12944   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
12945   Local<ObjectTemplate> child_instance_templ =
12946       child_templ->InstanceTemplate();
12947   child_templ->Inherit(parent_templ);
12948   // Override 'f'.  The child version of 'f' should get called for child
12949   // instances.
12950   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12951   // Add 'g' twice.  The 'g' added last should get called for instances.
12952   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12953   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12954
12955   // Add 'h' as an accessor to the proto template with ReadOnly attributes
12956   // so 'h' can be shadowed on the instance object.
12957   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12958   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12959       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12960
12961   // Add 'i' as an accessor to the instance template with ReadOnly attributes
12962   // but the attribute does not have effect because it is duplicated with
12963   // NULL setter.
12964   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12965       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12966
12967
12968
12969   // Instantiate the child template.
12970   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12971
12972   // Check that the child function overrides the parent one.
12973   context->Global()->Set(v8_str("o"), instance);
12974   Local<Value> value = v8_compile("o.f")->Run();
12975   // Check that the 'g' that was added last is hit.
12976   CHECK_EQ(42, value->Int32Value());
12977   value = v8_compile("o.g")->Run();
12978   CHECK_EQ(42, value->Int32Value());
12979
12980   // Check that 'h' cannot be shadowed.
12981   value = v8_compile("o.h = 3; o.h")->Run();
12982   CHECK_EQ(1, value->Int32Value());
12983
12984   // Check that 'i' cannot be shadowed or changed.
12985   value = v8_compile("o.i = 3; o.i")->Run();
12986   CHECK_EQ(42, value->Int32Value());
12987 }
12988
12989
12990 static void IsConstructHandler(
12991     const v8::FunctionCallbackInfo<v8::Value>& args) {
12992   ApiTestFuzzer::Fuzz();
12993   args.GetReturnValue().Set(args.IsConstructCall());
12994 }
12995
12996
12997 THREADED_TEST(IsConstructCall) {
12998   v8::Isolate* isolate = CcTest::isolate();
12999   v8::HandleScope scope(isolate);
13000
13001   // Function template with call handler.
13002   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13003   templ->SetCallHandler(IsConstructHandler);
13004
13005   LocalContext context;
13006
13007   context->Global()->Set(v8_str("f"), templ->GetFunction());
13008   Local<Value> value = v8_compile("f()")->Run();
13009   CHECK(!value->BooleanValue());
13010   value = v8_compile("new f()")->Run();
13011   CHECK(value->BooleanValue());
13012 }
13013
13014
13015 THREADED_TEST(ObjectProtoToString) {
13016   v8::Isolate* isolate = CcTest::isolate();
13017   v8::HandleScope scope(isolate);
13018   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13019   templ->SetClassName(v8_str("MyClass"));
13020
13021   LocalContext context;
13022
13023   Local<String> customized_tostring = v8_str("customized toString");
13024
13025   // Replace Object.prototype.toString
13026   v8_compile("Object.prototype.toString = function() {"
13027                   "  return 'customized toString';"
13028                   "}")->Run();
13029
13030   // Normal ToString call should call replaced Object.prototype.toString
13031   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13032   Local<String> value = instance->ToString();
13033   CHECK(value->IsString() && value->Equals(customized_tostring));
13034
13035   // ObjectProtoToString should not call replace toString function.
13036   value = instance->ObjectProtoToString();
13037   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13038
13039   // Check global
13040   value = context->Global()->ObjectProtoToString();
13041   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13042
13043   // Check ordinary object
13044   Local<Value> object = v8_compile("new Object()")->Run();
13045   value = object.As<v8::Object>()->ObjectProtoToString();
13046   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13047 }
13048
13049
13050 THREADED_TEST(ObjectGetConstructorName) {
13051   LocalContext context;
13052   v8::HandleScope scope(context->GetIsolate());
13053   v8_compile("function Parent() {};"
13054              "function Child() {};"
13055              "Child.prototype = new Parent();"
13056              "var outer = { inner: function() { } };"
13057              "var p = new Parent();"
13058              "var c = new Child();"
13059              "var x = new outer.inner();")->Run();
13060
13061   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13062   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13063       v8_str("Parent")));
13064
13065   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13066   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13067       v8_str("Child")));
13068
13069   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13070   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13071       v8_str("outer.inner")));
13072 }
13073
13074
13075 bool ApiTestFuzzer::fuzzing_ = false;
13076 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13077 int ApiTestFuzzer::active_tests_;
13078 int ApiTestFuzzer::tests_being_run_;
13079 int ApiTestFuzzer::current_;
13080
13081
13082 // We are in a callback and want to switch to another thread (if we
13083 // are currently running the thread fuzzing test).
13084 void ApiTestFuzzer::Fuzz() {
13085   if (!fuzzing_) return;
13086   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13087   test->ContextSwitch();
13088 }
13089
13090
13091 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13092 // not start immediately.
13093 bool ApiTestFuzzer::NextThread() {
13094   int test_position = GetNextTestNumber();
13095   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13096   if (test_position == current_) {
13097     if (kLogThreading)
13098       printf("Stay with %s\n", test_name);
13099     return false;
13100   }
13101   if (kLogThreading) {
13102     printf("Switch from %s to %s\n",
13103            test_name,
13104            RegisterThreadedTest::nth(test_position)->name());
13105   }
13106   current_ = test_position;
13107   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13108   return true;
13109 }
13110
13111
13112 void ApiTestFuzzer::Run() {
13113   // When it is our turn...
13114   gate_.Wait();
13115   {
13116     // ... get the V8 lock and start running the test.
13117     v8::Locker locker(CcTest::isolate());
13118     CallTest();
13119   }
13120   // This test finished.
13121   active_ = false;
13122   active_tests_--;
13123   // If it was the last then signal that fact.
13124   if (active_tests_ == 0) {
13125     all_tests_done_.Signal();
13126   } else {
13127     // Otherwise select a new test and start that.
13128     NextThread();
13129   }
13130 }
13131
13132
13133 static unsigned linear_congruential_generator;
13134
13135
13136 void ApiTestFuzzer::SetUp(PartOfTest part) {
13137   linear_congruential_generator = i::FLAG_testing_prng_seed;
13138   fuzzing_ = true;
13139   int count = RegisterThreadedTest::count();
13140   int start =  count * part / (LAST_PART + 1);
13141   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13142   active_tests_ = tests_being_run_ = end - start + 1;
13143   for (int i = 0; i < tests_being_run_; i++) {
13144     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13145   }
13146   for (int i = 0; i < active_tests_; i++) {
13147     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13148   }
13149 }
13150
13151
13152 static void CallTestNumber(int test_number) {
13153   (RegisterThreadedTest::nth(test_number)->callback())();
13154 }
13155
13156
13157 void ApiTestFuzzer::RunAllTests() {
13158   // Set off the first test.
13159   current_ = -1;
13160   NextThread();
13161   // Wait till they are all done.
13162   all_tests_done_.Wait();
13163 }
13164
13165
13166 int ApiTestFuzzer::GetNextTestNumber() {
13167   int next_test;
13168   do {
13169     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13170     linear_congruential_generator *= 1664525u;
13171     linear_congruential_generator += 1013904223u;
13172   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13173   return next_test;
13174 }
13175
13176
13177 void ApiTestFuzzer::ContextSwitch() {
13178   // If the new thread is the same as the current thread there is nothing to do.
13179   if (NextThread()) {
13180     // Now it can start.
13181     v8::Unlocker unlocker(CcTest::isolate());
13182     // Wait till someone starts us again.
13183     gate_.Wait();
13184     // And we're off.
13185   }
13186 }
13187
13188
13189 void ApiTestFuzzer::TearDown() {
13190   fuzzing_ = false;
13191   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13192     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13193     if (fuzzer != NULL) fuzzer->Join();
13194   }
13195 }
13196
13197
13198 // Lets not be needlessly self-referential.
13199 TEST(Threading1) {
13200   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13201   ApiTestFuzzer::RunAllTests();
13202   ApiTestFuzzer::TearDown();
13203 }
13204
13205
13206 TEST(Threading2) {
13207   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13208   ApiTestFuzzer::RunAllTests();
13209   ApiTestFuzzer::TearDown();
13210 }
13211
13212
13213 TEST(Threading3) {
13214   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13215   ApiTestFuzzer::RunAllTests();
13216   ApiTestFuzzer::TearDown();
13217 }
13218
13219
13220 TEST(Threading4) {
13221   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13222   ApiTestFuzzer::RunAllTests();
13223   ApiTestFuzzer::TearDown();
13224 }
13225
13226
13227 void ApiTestFuzzer::CallTest() {
13228   v8::Isolate::Scope scope(CcTest::isolate());
13229   if (kLogThreading)
13230     printf("Start test %d\n", test_number_);
13231   CallTestNumber(test_number_);
13232   if (kLogThreading)
13233     printf("End test %d\n", test_number_);
13234 }
13235
13236
13237 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13238   v8::Isolate* isolate = args.GetIsolate();
13239   CHECK(v8::Locker::IsLocked(isolate));
13240   ApiTestFuzzer::Fuzz();
13241   v8::Unlocker unlocker(isolate);
13242   const char* code = "throw 7;";
13243   {
13244     v8::Locker nested_locker(isolate);
13245     v8::HandleScope scope(isolate);
13246     v8::Handle<Value> exception;
13247     { v8::TryCatch try_catch;
13248       v8::Handle<Value> value = CompileRun(code);
13249       CHECK(value.IsEmpty());
13250       CHECK(try_catch.HasCaught());
13251       // Make sure to wrap the exception in a new handle because
13252       // the handle returned from the TryCatch is destroyed
13253       // when the TryCatch is destroyed.
13254       exception = Local<Value>::New(isolate, try_catch.Exception());
13255     }
13256     args.GetIsolate()->ThrowException(exception);
13257   }
13258 }
13259
13260
13261 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13262   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13263   ApiTestFuzzer::Fuzz();
13264   v8::Unlocker unlocker(CcTest::isolate());
13265   const char* code = "throw 7;";
13266   {
13267     v8::Locker nested_locker(CcTest::isolate());
13268     v8::HandleScope scope(args.GetIsolate());
13269     v8::Handle<Value> value = CompileRun(code);
13270     CHECK(value.IsEmpty());
13271     args.GetReturnValue().Set(v8_str("foo"));
13272   }
13273 }
13274
13275
13276 // These are locking tests that don't need to be run again
13277 // as part of the locking aggregation tests.
13278 TEST(NestedLockers) {
13279   v8::Isolate* isolate = CcTest::isolate();
13280   v8::Locker locker(isolate);
13281   CHECK(v8::Locker::IsLocked(isolate));
13282   LocalContext env;
13283   v8::HandleScope scope(env->GetIsolate());
13284   Local<v8::FunctionTemplate> fun_templ =
13285       v8::FunctionTemplate::New(isolate, ThrowInJS);
13286   Local<Function> fun = fun_templ->GetFunction();
13287   env->Global()->Set(v8_str("throw_in_js"), fun);
13288   Local<Script> script = v8_compile("(function () {"
13289                                     "  try {"
13290                                     "    throw_in_js();"
13291                                     "    return 42;"
13292                                     "  } catch (e) {"
13293                                     "    return e * 13;"
13294                                     "  }"
13295                                     "})();");
13296   CHECK_EQ(91, script->Run()->Int32Value());
13297 }
13298
13299
13300 // These are locking tests that don't need to be run again
13301 // as part of the locking aggregation tests.
13302 TEST(NestedLockersNoTryCatch) {
13303   v8::Locker locker(CcTest::isolate());
13304   LocalContext env;
13305   v8::HandleScope scope(env->GetIsolate());
13306   Local<v8::FunctionTemplate> fun_templ =
13307       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13308   Local<Function> fun = fun_templ->GetFunction();
13309   env->Global()->Set(v8_str("throw_in_js"), fun);
13310   Local<Script> script = v8_compile("(function () {"
13311                                     "  try {"
13312                                     "    throw_in_js();"
13313                                     "    return 42;"
13314                                     "  } catch (e) {"
13315                                     "    return e * 13;"
13316                                     "  }"
13317                                     "})();");
13318   CHECK_EQ(91, script->Run()->Int32Value());
13319 }
13320
13321
13322 THREADED_TEST(RecursiveLocking) {
13323   v8::Locker locker(CcTest::isolate());
13324   {
13325     v8::Locker locker2(CcTest::isolate());
13326     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13327   }
13328 }
13329
13330
13331 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13332   ApiTestFuzzer::Fuzz();
13333   v8::Unlocker unlocker(CcTest::isolate());
13334 }
13335
13336
13337 THREADED_TEST(LockUnlockLock) {
13338   {
13339     v8::Locker locker(CcTest::isolate());
13340     v8::HandleScope scope(CcTest::isolate());
13341     LocalContext env;
13342     Local<v8::FunctionTemplate> fun_templ =
13343         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13344     Local<Function> fun = fun_templ->GetFunction();
13345     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13346     Local<Script> script = v8_compile("(function () {"
13347                                       "  unlock_for_a_moment();"
13348                                       "  return 42;"
13349                                       "})();");
13350     CHECK_EQ(42, script->Run()->Int32Value());
13351   }
13352   {
13353     v8::Locker locker(CcTest::isolate());
13354     v8::HandleScope scope(CcTest::isolate());
13355     LocalContext env;
13356     Local<v8::FunctionTemplate> fun_templ =
13357         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13358     Local<Function> fun = fun_templ->GetFunction();
13359     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13360     Local<Script> script = v8_compile("(function () {"
13361                                       "  unlock_for_a_moment();"
13362                                       "  return 42;"
13363                                       "})();");
13364     CHECK_EQ(42, script->Run()->Int32Value());
13365   }
13366 }
13367
13368
13369 static int GetGlobalObjectsCount() {
13370   CcTest::heap()->EnsureHeapIsIterable();
13371   int count = 0;
13372   i::HeapIterator it(CcTest::heap());
13373   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13374     if (object->IsJSGlobalObject()) count++;
13375   return count;
13376 }
13377
13378
13379 static void CheckSurvivingGlobalObjectsCount(int expected) {
13380   // We need to collect all garbage twice to be sure that everything
13381   // has been collected.  This is because inline caches are cleared in
13382   // the first garbage collection but some of the maps have already
13383   // been marked at that point.  Therefore some of the maps are not
13384   // collected until the second garbage collection.
13385   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13386   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13387   int count = GetGlobalObjectsCount();
13388 #ifdef DEBUG
13389   if (count != expected) CcTest::heap()->TracePathToGlobal();
13390 #endif
13391   CHECK_EQ(expected, count);
13392 }
13393
13394
13395 TEST(DontLeakGlobalObjects) {
13396   // Regression test for issues 1139850 and 1174891.
13397
13398   i::FLAG_expose_gc = true;
13399   v8::V8::Initialize();
13400
13401   for (int i = 0; i < 5; i++) {
13402     { v8::HandleScope scope(CcTest::isolate());
13403       LocalContext context;
13404     }
13405     v8::V8::ContextDisposedNotification();
13406     CheckSurvivingGlobalObjectsCount(0);
13407
13408     { v8::HandleScope scope(CcTest::isolate());
13409       LocalContext context;
13410       v8_compile("Date")->Run();
13411     }
13412     v8::V8::ContextDisposedNotification();
13413     CheckSurvivingGlobalObjectsCount(0);
13414
13415     { v8::HandleScope scope(CcTest::isolate());
13416       LocalContext context;
13417       v8_compile("/aaa/")->Run();
13418     }
13419     v8::V8::ContextDisposedNotification();
13420     CheckSurvivingGlobalObjectsCount(0);
13421
13422     { v8::HandleScope scope(CcTest::isolate());
13423       const char* extension_list[] = { "v8/gc" };
13424       v8::ExtensionConfiguration extensions(1, extension_list);
13425       LocalContext context(&extensions);
13426       v8_compile("gc();")->Run();
13427     }
13428     v8::V8::ContextDisposedNotification();
13429     CheckSurvivingGlobalObjectsCount(0);
13430   }
13431 }
13432
13433
13434 TEST(CopyablePersistent) {
13435   LocalContext context;
13436   v8::Isolate* isolate = context->GetIsolate();
13437   i::GlobalHandles* globals =
13438       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13439   int initial_handles = globals->global_handles_count();
13440   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13441       CopyableObject;
13442   {
13443     CopyableObject handle1;
13444     {
13445       v8::HandleScope scope(isolate);
13446       handle1.Reset(isolate, v8::Object::New(isolate));
13447     }
13448     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13449     CopyableObject  handle2;
13450     handle2 = handle1;
13451     CHECK(handle1 == handle2);
13452     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13453     CopyableObject handle3(handle2);
13454     CHECK(handle1 == handle3);
13455     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13456   }
13457   // Verify autodispose
13458   CHECK_EQ(initial_handles, globals->global_handles_count());
13459 }
13460
13461
13462 static void WeakApiCallback(
13463     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13464   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13465   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13466   data.GetParameter()->Reset();
13467   delete data.GetParameter();
13468 }
13469
13470
13471 TEST(WeakCallbackApi) {
13472   LocalContext context;
13473   v8::Isolate* isolate = context->GetIsolate();
13474   i::GlobalHandles* globals =
13475       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13476   int initial_handles = globals->global_handles_count();
13477   {
13478     v8::HandleScope scope(isolate);
13479     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13480     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13481     v8::Persistent<v8::Object>* handle =
13482         new v8::Persistent<v8::Object>(isolate, obj);
13483     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13484                                                              WeakApiCallback);
13485   }
13486   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13487       CollectAllGarbage(i::Heap::kNoGCFlags);
13488   // Verify disposed.
13489   CHECK_EQ(initial_handles, globals->global_handles_count());
13490 }
13491
13492
13493 v8::Persistent<v8::Object> some_object;
13494 v8::Persistent<v8::Object> bad_handle;
13495
13496 void NewPersistentHandleCallback(
13497     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13498   v8::HandleScope scope(data.GetIsolate());
13499   bad_handle.Reset(data.GetIsolate(), some_object);
13500   data.GetParameter()->Reset();
13501 }
13502
13503
13504 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13505   LocalContext context;
13506   v8::Isolate* isolate = context->GetIsolate();
13507
13508   v8::Persistent<v8::Object> handle1, handle2;
13509   {
13510     v8::HandleScope scope(isolate);
13511     some_object.Reset(isolate, v8::Object::New(isolate));
13512     handle1.Reset(isolate, v8::Object::New(isolate));
13513     handle2.Reset(isolate, v8::Object::New(isolate));
13514   }
13515   // Note: order is implementation dependent alas: currently
13516   // global handle nodes are processed by PostGarbageCollectionProcessing
13517   // in reverse allocation order, so if second allocated handle is deleted,
13518   // weak callback of the first handle would be able to 'reallocate' it.
13519   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13520   handle2.Reset();
13521   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13522 }
13523
13524
13525 v8::Persistent<v8::Object> to_be_disposed;
13526
13527 void DisposeAndForceGcCallback(
13528     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13529   to_be_disposed.Reset();
13530   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13531   data.GetParameter()->Reset();
13532 }
13533
13534
13535 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13536   LocalContext context;
13537   v8::Isolate* isolate = context->GetIsolate();
13538
13539   v8::Persistent<v8::Object> handle1, handle2;
13540   {
13541     v8::HandleScope scope(isolate);
13542     handle1.Reset(isolate, v8::Object::New(isolate));
13543     handle2.Reset(isolate, v8::Object::New(isolate));
13544   }
13545   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13546   to_be_disposed.Reset(isolate, handle2);
13547   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13548 }
13549
13550 void DisposingCallback(
13551     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13552   data.GetParameter()->Reset();
13553 }
13554
13555 void HandleCreatingCallback(
13556     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13557   v8::HandleScope scope(data.GetIsolate());
13558   v8::Persistent<v8::Object>(data.GetIsolate(),
13559                              v8::Object::New(data.GetIsolate()));
13560   data.GetParameter()->Reset();
13561 }
13562
13563
13564 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13565   LocalContext context;
13566   v8::Isolate* isolate = context->GetIsolate();
13567
13568   v8::Persistent<v8::Object> handle1, handle2, handle3;
13569   {
13570     v8::HandleScope scope(isolate);
13571     handle3.Reset(isolate, v8::Object::New(isolate));
13572     handle2.Reset(isolate, v8::Object::New(isolate));
13573     handle1.Reset(isolate, v8::Object::New(isolate));
13574   }
13575   handle2.SetWeak(&handle2, DisposingCallback);
13576   handle3.SetWeak(&handle3, HandleCreatingCallback);
13577   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13578 }
13579
13580
13581 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13582   v8::V8::Initialize();
13583
13584   const int nof = 2;
13585   const char* sources[nof] = {
13586     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13587     "Object()"
13588   };
13589
13590   for (int i = 0; i < nof; i++) {
13591     const char* source = sources[i];
13592     { v8::HandleScope scope(CcTest::isolate());
13593       LocalContext context;
13594       CompileRun(source);
13595     }
13596     { v8::HandleScope scope(CcTest::isolate());
13597       LocalContext context;
13598       CompileRun(source);
13599     }
13600   }
13601 }
13602
13603
13604 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13605   v8::EscapableHandleScope inner(env->GetIsolate());
13606   env->Enter();
13607   v8::Local<Value> three = v8_num(3);
13608   v8::Local<Value> value = inner.Escape(three);
13609   env->Exit();
13610   return value;
13611 }
13612
13613
13614 THREADED_TEST(NestedHandleScopeAndContexts) {
13615   v8::Isolate* isolate = CcTest::isolate();
13616   v8::HandleScope outer(isolate);
13617   v8::Local<Context> env = Context::New(isolate);
13618   env->Enter();
13619   v8::Handle<Value> value = NestedScope(env);
13620   v8::Handle<String> str(value->ToString());
13621   CHECK(!str.IsEmpty());
13622   env->Exit();
13623 }
13624
13625
13626 static bool MatchPointers(void* key1, void* key2) {
13627   return key1 == key2;
13628 }
13629
13630
13631 struct SymbolInfo {
13632   size_t id;
13633   size_t size;
13634   std::string name;
13635 };
13636
13637
13638 class SetFunctionEntryHookTest {
13639  public:
13640   SetFunctionEntryHookTest() {
13641     CHECK(instance_ == NULL);
13642     instance_ = this;
13643   }
13644   ~SetFunctionEntryHookTest() {
13645     CHECK(instance_ == this);
13646     instance_ = NULL;
13647   }
13648   void Reset() {
13649     symbols_.clear();
13650     symbol_locations_.clear();
13651     invocations_.clear();
13652   }
13653   void RunTest();
13654   void OnJitEvent(const v8::JitCodeEvent* event);
13655   static void JitEvent(const v8::JitCodeEvent* event) {
13656     CHECK(instance_ != NULL);
13657     instance_->OnJitEvent(event);
13658   }
13659
13660   void OnEntryHook(uintptr_t function,
13661                    uintptr_t return_addr_location);
13662   static void EntryHook(uintptr_t function,
13663                         uintptr_t return_addr_location) {
13664     CHECK(instance_ != NULL);
13665     instance_->OnEntryHook(function, return_addr_location);
13666   }
13667
13668   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13669     CHECK(instance_ != NULL);
13670     args.GetReturnValue().Set(v8_num(42));
13671   }
13672   void RunLoopInNewEnv(v8::Isolate* isolate);
13673
13674   // Records addr as location of symbol.
13675   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13676
13677   // Finds the symbol containing addr
13678   SymbolInfo* FindSymbolForAddr(i::Address addr);
13679   // Returns the number of invocations where the caller name contains
13680   // \p caller_name and the function name contains \p function_name.
13681   int CountInvocations(const char* caller_name,
13682                        const char* function_name);
13683
13684   i::Handle<i::JSFunction> foo_func_;
13685   i::Handle<i::JSFunction> bar_func_;
13686
13687   typedef std::map<size_t, SymbolInfo> SymbolMap;
13688   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13689   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13690   SymbolMap symbols_;
13691   SymbolLocationMap symbol_locations_;
13692   InvocationMap invocations_;
13693
13694   static SetFunctionEntryHookTest* instance_;
13695 };
13696 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13697
13698
13699 // Returns true if addr is in the range [start, start+len).
13700 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13701   if (start <= addr && start + len > addr)
13702     return true;
13703
13704   return false;
13705 }
13706
13707 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13708                                               SymbolInfo* symbol) {
13709   // Insert the symbol at the new location.
13710   SymbolLocationMap::iterator it =
13711       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13712   // Now erase symbols to the left and right that overlap this one.
13713   while (it != symbol_locations_.begin()) {
13714     SymbolLocationMap::iterator left = it;
13715     --left;
13716     if (!Overlaps(left->first, left->second->size, addr))
13717       break;
13718     symbol_locations_.erase(left);
13719   }
13720
13721   // Now erase symbols to the left and right that overlap this one.
13722   while (true) {
13723     SymbolLocationMap::iterator right = it;
13724     ++right;
13725     if (right == symbol_locations_.end())
13726         break;
13727     if (!Overlaps(addr, symbol->size, right->first))
13728       break;
13729     symbol_locations_.erase(right);
13730   }
13731 }
13732
13733
13734 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13735   switch (event->type) {
13736     case v8::JitCodeEvent::CODE_ADDED: {
13737         CHECK(event->code_start != NULL);
13738         CHECK_NE(0, static_cast<int>(event->code_len));
13739         CHECK(event->name.str != NULL);
13740         size_t symbol_id = symbols_.size();
13741
13742         // Record the new symbol.
13743         SymbolInfo& info = symbols_[symbol_id];
13744         info.id = symbol_id;
13745         info.size = event->code_len;
13746         info.name.assign(event->name.str, event->name.str + event->name.len);
13747
13748         // And record it's location.
13749         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13750       }
13751       break;
13752
13753     case v8::JitCodeEvent::CODE_MOVED: {
13754         // We would like to never see code move that we haven't seen before,
13755         // but the code creation event does not happen until the line endings
13756         // have been calculated (this is so that we can report the line in the
13757         // script at which the function source is found, see
13758         // Compiler::RecordFunctionCompilation) and the line endings
13759         // calculations can cause a GC, which can move the newly created code
13760         // before its existence can be logged.
13761         SymbolLocationMap::iterator it(
13762             symbol_locations_.find(
13763                 reinterpret_cast<i::Address>(event->code_start)));
13764         if (it != symbol_locations_.end()) {
13765           // Found a symbol at this location, move it.
13766           SymbolInfo* info = it->second;
13767           symbol_locations_.erase(it);
13768           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13769                          info);
13770         }
13771       }
13772     default:
13773       break;
13774   }
13775 }
13776
13777 void SetFunctionEntryHookTest::OnEntryHook(
13778     uintptr_t function, uintptr_t return_addr_location) {
13779   // Get the function's code object.
13780   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13781       reinterpret_cast<i::Address>(function));
13782   CHECK(function_code != NULL);
13783
13784   // Then try and look up the caller's code object.
13785   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13786
13787   // Count the invocation.
13788   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13789   SymbolInfo* function_symbol =
13790       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13791   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13792
13793   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13794     // Check that we have a symbol for the "bar" function at the right location.
13795     SymbolLocationMap::iterator it(
13796         symbol_locations_.find(function_code->instruction_start()));
13797     CHECK(it != symbol_locations_.end());
13798   }
13799
13800   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13801     // Check that we have a symbol for "foo" at the right location.
13802     SymbolLocationMap::iterator it(
13803         symbol_locations_.find(function_code->instruction_start()));
13804     CHECK(it != symbol_locations_.end());
13805   }
13806 }
13807
13808
13809 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13810   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13811   // Do we have a direct hit on a symbol?
13812   if (it != symbol_locations_.end()) {
13813     if (it->first == addr)
13814       return it->second;
13815   }
13816
13817   // If not a direct hit, it'll have to be the previous symbol.
13818   if (it == symbol_locations_.begin())
13819     return NULL;
13820
13821   --it;
13822   size_t offs = addr - it->first;
13823   if (offs < it->second->size)
13824     return it->second;
13825
13826   return NULL;
13827 }
13828
13829
13830 int SetFunctionEntryHookTest::CountInvocations(
13831     const char* caller_name, const char* function_name) {
13832   InvocationMap::iterator it(invocations_.begin());
13833   int invocations = 0;
13834   for (; it != invocations_.end(); ++it) {
13835     SymbolInfo* caller = it->first.first;
13836     SymbolInfo* function = it->first.second;
13837
13838     // Filter out non-matching functions.
13839     if (function_name != NULL) {
13840       if (function->name.find(function_name) == std::string::npos)
13841         continue;
13842     }
13843
13844     // Filter out non-matching callers.
13845     if (caller_name != NULL) {
13846       if (caller == NULL)
13847         continue;
13848       if (caller->name.find(caller_name) == std::string::npos)
13849         continue;
13850     }
13851
13852     // It matches add the invocation count to the tally.
13853     invocations += it->second;
13854   }
13855
13856   return invocations;
13857 }
13858
13859
13860 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13861   v8::HandleScope outer(isolate);
13862   v8::Local<Context> env = Context::New(isolate);
13863   env->Enter();
13864
13865   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13866   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13867   env->Global()->Set(v8_str("obj"), t->NewInstance());
13868
13869   const char* script =
13870       "function bar() {\n"
13871       "  var sum = 0;\n"
13872       "  for (i = 0; i < 100; ++i)\n"
13873       "    sum = foo(i);\n"
13874       "  return sum;\n"
13875       "}\n"
13876       "function foo(i) { return i * i; }\n"
13877       "// Invoke on the runtime function.\n"
13878       "obj.asdf()";
13879   CompileRun(script);
13880   bar_func_ = i::Handle<i::JSFunction>::cast(
13881           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13882   ASSERT(!bar_func_.is_null());
13883
13884   foo_func_ =
13885       i::Handle<i::JSFunction>::cast(
13886            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13887   ASSERT(!foo_func_.is_null());
13888
13889   v8::Handle<v8::Value> value = CompileRun("bar();");
13890   CHECK(value->IsNumber());
13891   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13892
13893   // Test the optimized codegen path.
13894   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13895                      "bar();");
13896   CHECK(value->IsNumber());
13897   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13898
13899   env->Exit();
13900 }
13901
13902
13903 void SetFunctionEntryHookTest::RunTest() {
13904   // Work in a new isolate throughout.
13905   v8::Isolate* isolate = v8::Isolate::New();
13906
13907   // Test setting the entry hook on the new isolate.
13908   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13909
13910   // Replacing the hook, once set should fail.
13911   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13912
13913   {
13914     v8::Isolate::Scope scope(isolate);
13915
13916     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13917
13918     RunLoopInNewEnv(isolate);
13919
13920     // Check the exepected invocation counts.
13921     CHECK_EQ(2, CountInvocations(NULL, "bar"));
13922     CHECK_EQ(200, CountInvocations("bar", "foo"));
13923     CHECK_EQ(200, CountInvocations(NULL, "foo"));
13924
13925     // Verify that we have an entry hook on some specific stubs.
13926     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13927     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13928     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13929   }
13930   isolate->Dispose();
13931
13932   Reset();
13933
13934   // Make sure a second isolate is unaffected by the previous entry hook.
13935   isolate = v8::Isolate::New();
13936   {
13937     v8::Isolate::Scope scope(isolate);
13938
13939     // Reset the entry count to zero and set the entry hook.
13940     RunLoopInNewEnv(isolate);
13941
13942     // We should record no invocations in this isolate.
13943     CHECK_EQ(0, static_cast<int>(invocations_.size()));
13944   }
13945   // Since the isolate has been used, we shouldn't be able to set an entry
13946   // hook anymore.
13947   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13948
13949   isolate->Dispose();
13950 }
13951
13952
13953 TEST(SetFunctionEntryHook) {
13954   // FunctionEntryHook does not work well with experimental natives.
13955   // Experimental natives are compiled during snapshot deserialization.
13956   // This test breaks because InstallGetter (function from snapshot that
13957   // only gets called from experimental natives) is compiled with entry hooks.
13958   i::FLAG_allow_natives_syntax = true;
13959   i::FLAG_use_inlining = false;
13960
13961   SetFunctionEntryHookTest test;
13962   test.RunTest();
13963 }
13964
13965
13966 static i::HashMap* code_map = NULL;
13967 static i::HashMap* jitcode_line_info = NULL;
13968 static int saw_bar = 0;
13969 static int move_events = 0;
13970
13971
13972 static bool FunctionNameIs(const char* expected,
13973                            const v8::JitCodeEvent* event) {
13974   // Log lines for functions are of the general form:
13975   // "LazyCompile:<type><function_name>", where the type is one of
13976   // "*", "~" or "".
13977   static const char kPreamble[] = "LazyCompile:";
13978   static size_t kPreambleLen = sizeof(kPreamble) - 1;
13979
13980   if (event->name.len < sizeof(kPreamble) - 1 ||
13981       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13982     return false;
13983   }
13984
13985   const char* tail = event->name.str + kPreambleLen;
13986   size_t tail_len = event->name.len - kPreambleLen;
13987   size_t expected_len = strlen(expected);
13988   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13989     --tail_len;
13990     ++tail;
13991   }
13992
13993   // Check for tails like 'bar :1'.
13994   if (tail_len > expected_len + 2 &&
13995       tail[expected_len] == ' ' &&
13996       tail[expected_len + 1] == ':' &&
13997       tail[expected_len + 2] &&
13998       !strncmp(tail, expected, expected_len)) {
13999     return true;
14000   }
14001
14002   if (tail_len != expected_len)
14003     return false;
14004
14005   return strncmp(tail, expected, expected_len) == 0;
14006 }
14007
14008
14009 static void event_handler(const v8::JitCodeEvent* event) {
14010   CHECK(event != NULL);
14011   CHECK(code_map != NULL);
14012   CHECK(jitcode_line_info != NULL);
14013
14014   class DummyJitCodeLineInfo {
14015   };
14016
14017   switch (event->type) {
14018     case v8::JitCodeEvent::CODE_ADDED: {
14019         CHECK(event->code_start != NULL);
14020         CHECK_NE(0, static_cast<int>(event->code_len));
14021         CHECK(event->name.str != NULL);
14022         i::HashMap::Entry* entry =
14023             code_map->Lookup(event->code_start,
14024                              i::ComputePointerHash(event->code_start),
14025                              true);
14026         entry->value = reinterpret_cast<void*>(event->code_len);
14027
14028         if (FunctionNameIs("bar", event)) {
14029           ++saw_bar;
14030         }
14031       }
14032       break;
14033
14034     case v8::JitCodeEvent::CODE_MOVED: {
14035         uint32_t hash = i::ComputePointerHash(event->code_start);
14036         // We would like to never see code move that we haven't seen before,
14037         // but the code creation event does not happen until the line endings
14038         // have been calculated (this is so that we can report the line in the
14039         // script at which the function source is found, see
14040         // Compiler::RecordFunctionCompilation) and the line endings
14041         // calculations can cause a GC, which can move the newly created code
14042         // before its existence can be logged.
14043         i::HashMap::Entry* entry =
14044             code_map->Lookup(event->code_start, hash, false);
14045         if (entry != NULL) {
14046           ++move_events;
14047
14048           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14049           code_map->Remove(event->code_start, hash);
14050
14051           entry = code_map->Lookup(event->new_code_start,
14052                                    i::ComputePointerHash(event->new_code_start),
14053                                    true);
14054           CHECK(entry != NULL);
14055           entry->value = reinterpret_cast<void*>(event->code_len);
14056         }
14057       }
14058       break;
14059
14060     case v8::JitCodeEvent::CODE_REMOVED:
14061       // Object/code removal events are currently not dispatched from the GC.
14062       CHECK(false);
14063       break;
14064
14065     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14066     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14067     // record it in jitcode_line_info.
14068     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14069         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14070         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14071         temp_event->user_data = line_info;
14072         i::HashMap::Entry* entry =
14073             jitcode_line_info->Lookup(line_info,
14074                                       i::ComputePointerHash(line_info),
14075                                       true);
14076         entry->value = reinterpret_cast<void*>(line_info);
14077       }
14078       break;
14079     // For these two events, we will check whether the event->user_data
14080     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14081     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14082     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14083         CHECK(event->user_data != NULL);
14084         uint32_t hash = i::ComputePointerHash(event->user_data);
14085         i::HashMap::Entry* entry =
14086             jitcode_line_info->Lookup(event->user_data, hash, false);
14087         CHECK(entry != NULL);
14088         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14089       }
14090       break;
14091
14092     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14093         CHECK(event->user_data != NULL);
14094         uint32_t hash = i::ComputePointerHash(event->user_data);
14095         i::HashMap::Entry* entry =
14096             jitcode_line_info->Lookup(event->user_data, hash, false);
14097         CHECK(entry != NULL);
14098       }
14099       break;
14100
14101     default:
14102       // Impossible event.
14103       CHECK(false);
14104       break;
14105   }
14106 }
14107
14108
14109 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14110   i::FLAG_stress_compaction = true;
14111   i::FLAG_incremental_marking = false;
14112   const char* script =
14113     "function bar() {"
14114     "  var sum = 0;"
14115     "  for (i = 0; i < 100; ++i)"
14116     "    sum = foo(i);"
14117     "  return sum;"
14118     "}"
14119     "function foo(i) { return i * i; };"
14120     "bar();";
14121
14122   // Run this test in a new isolate to make sure we don't
14123   // have remnants of state from other code.
14124   v8::Isolate* isolate = v8::Isolate::New();
14125   isolate->Enter();
14126   i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
14127
14128   {
14129     v8::HandleScope scope(isolate);
14130     i::HashMap code(MatchPointers);
14131     code_map = &code;
14132
14133     i::HashMap lineinfo(MatchPointers);
14134     jitcode_line_info = &lineinfo;
14135
14136     saw_bar = 0;
14137     move_events = 0;
14138
14139     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14140
14141     // Generate new code objects sparsely distributed across several
14142     // different fragmented code-space pages.
14143     const int kIterations = 10;
14144     for (int i = 0; i < kIterations; ++i) {
14145       LocalContext env(isolate);
14146       i::AlwaysAllocateScope always_allocate;
14147       SimulateFullSpace(heap->code_space());
14148       CompileRun(script);
14149
14150       // Keep a strong reference to the code object in the handle scope.
14151       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14152           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14153       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14154           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14155
14156       // Clear the compilation cache to get more wastage.
14157       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14158     }
14159
14160     // Force code movement.
14161     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14162
14163     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14164
14165     CHECK_LE(kIterations, saw_bar);
14166     CHECK_LT(0, move_events);
14167
14168     code_map = NULL;
14169     jitcode_line_info = NULL;
14170   }
14171
14172   isolate->Exit();
14173   isolate->Dispose();
14174
14175   // Do this in a new isolate.
14176   isolate = v8::Isolate::New();
14177   isolate->Enter();
14178
14179   // Verify that we get callbacks for existing code objects when we
14180   // request enumeration of existing code.
14181   {
14182     v8::HandleScope scope(isolate);
14183     LocalContext env(isolate);
14184     CompileRun(script);
14185
14186     // Now get code through initial iteration.
14187     i::HashMap code(MatchPointers);
14188     code_map = &code;
14189
14190     i::HashMap lineinfo(MatchPointers);
14191     jitcode_line_info = &lineinfo;
14192
14193     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14194     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14195
14196     jitcode_line_info = NULL;
14197     // We expect that we got some events. Note that if we could get code removal
14198     // notifications, we could compare two collections, one created by listening
14199     // from the time of creation of an isolate, and the other by subscribing
14200     // with EnumExisting.
14201     CHECK_LT(0, code.occupancy());
14202
14203     code_map = NULL;
14204   }
14205
14206   isolate->Exit();
14207   isolate->Dispose();
14208 }
14209
14210
14211 THREADED_TEST(ExternalAllocatedMemory) {
14212   v8::Isolate* isolate = CcTest::isolate();
14213   v8::HandleScope outer(isolate);
14214   v8::Local<Context> env(Context::New(isolate));
14215   CHECK(!env.IsEmpty());
14216   const int64_t kSize = 1024*1024;
14217   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14218   CHECK_EQ(baseline + kSize,
14219            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14220   CHECK_EQ(baseline,
14221            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14222 }
14223
14224
14225 // Regression test for issue 54, object templates with internal fields
14226 // but no accessors or interceptors did not get their internal field
14227 // count set on instances.
14228 THREADED_TEST(Regress54) {
14229   LocalContext context;
14230   v8::Isolate* isolate = context->GetIsolate();
14231   v8::HandleScope outer(isolate);
14232   static v8::Persistent<v8::ObjectTemplate> templ;
14233   if (templ.IsEmpty()) {
14234     v8::EscapableHandleScope inner(isolate);
14235     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14236     local->SetInternalFieldCount(1);
14237     templ.Reset(isolate, inner.Escape(local));
14238   }
14239   v8::Handle<v8::Object> result =
14240       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14241   CHECK_EQ(1, result->InternalFieldCount());
14242 }
14243
14244
14245 // If part of the threaded tests, this test makes ThreadingTest fail
14246 // on mac.
14247 TEST(CatchStackOverflow) {
14248   LocalContext context;
14249   v8::HandleScope scope(context->GetIsolate());
14250   v8::TryCatch try_catch;
14251   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::NewFromUtf8(
14252     context->GetIsolate(),
14253     "function f() {"
14254     "  return f();"
14255     "}"
14256     ""
14257     "f();"));
14258   v8::Handle<v8::Value> result = script->Run();
14259   CHECK(result.IsEmpty());
14260 }
14261
14262
14263 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14264                                     const char* resource_name,
14265                                     int line_offset) {
14266   v8::HandleScope scope(CcTest::isolate());
14267   v8::TryCatch try_catch;
14268   v8::Handle<v8::Value> result = script->Run();
14269   CHECK(result.IsEmpty());
14270   CHECK(try_catch.HasCaught());
14271   v8::Handle<v8::Message> message = try_catch.Message();
14272   CHECK(!message.IsEmpty());
14273   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14274   CHECK_EQ(91, message->GetStartPosition());
14275   CHECK_EQ(92, message->GetEndPosition());
14276   CHECK_EQ(2, message->GetStartColumn());
14277   CHECK_EQ(3, message->GetEndColumn());
14278   v8::String::Utf8Value line(message->GetSourceLine());
14279   CHECK_EQ("  throw 'nirk';", *line);
14280   v8::String::Utf8Value name(message->GetScriptResourceName());
14281   CHECK_EQ(resource_name, *name);
14282 }
14283
14284
14285 THREADED_TEST(TryCatchSourceInfo) {
14286   LocalContext context;
14287   v8::HandleScope scope(context->GetIsolate());
14288   v8::Handle<v8::String> source = v8::String::NewFromUtf8(
14289       context->GetIsolate(),
14290       "function Foo() {\n"
14291       "  return Bar();\n"
14292       "}\n"
14293       "\n"
14294       "function Bar() {\n"
14295       "  return Baz();\n"
14296       "}\n"
14297       "\n"
14298       "function Baz() {\n"
14299       "  throw 'nirk';\n"
14300       "}\n"
14301       "\n"
14302       "Foo();\n");
14303
14304   const char* resource_name;
14305   v8::Handle<v8::Script> script;
14306   resource_name = "test.js";
14307   script = v8::Script::Compile(
14308       source, v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14309   CheckTryCatchSourceInfo(script, resource_name, 0);
14310
14311   resource_name = "test1.js";
14312   v8::ScriptOrigin origin1(
14313       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14314   script = v8::Script::Compile(source, &origin1);
14315   CheckTryCatchSourceInfo(script, resource_name, 0);
14316
14317   resource_name = "test2.js";
14318   v8::ScriptOrigin origin2(
14319       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14320       v8::Integer::New(context->GetIsolate(), 7));
14321   script = v8::Script::Compile(source, &origin2);
14322   CheckTryCatchSourceInfo(script, resource_name, 7);
14323 }
14324
14325
14326 THREADED_TEST(CompilationCache) {
14327   LocalContext context;
14328   v8::HandleScope scope(context->GetIsolate());
14329   v8::Handle<v8::String> source0 =
14330       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14331   v8::Handle<v8::String> source1 =
14332       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14333   v8::Handle<v8::Script> script0 = v8::Script::Compile(
14334       source0, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14335   v8::Handle<v8::Script> script1 = v8::Script::Compile(
14336       source1, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14337   v8::Handle<v8::Script> script2 =
14338       v8::Script::Compile(source0);  // different origin
14339   CHECK_EQ(1234, script0->Run()->Int32Value());
14340   CHECK_EQ(1234, script1->Run()->Int32Value());
14341   CHECK_EQ(1234, script2->Run()->Int32Value());
14342 }
14343
14344
14345 static void FunctionNameCallback(
14346     const v8::FunctionCallbackInfo<v8::Value>& args) {
14347   ApiTestFuzzer::Fuzz();
14348   args.GetReturnValue().Set(v8_num(42));
14349 }
14350
14351
14352 THREADED_TEST(CallbackFunctionName) {
14353   LocalContext context;
14354   v8::Isolate* isolate = context->GetIsolate();
14355   v8::HandleScope scope(isolate);
14356   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14357   t->Set(v8_str("asdf"),
14358          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14359   context->Global()->Set(v8_str("obj"), t->NewInstance());
14360   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14361   CHECK(value->IsString());
14362   v8::String::Utf8Value name(value);
14363   CHECK_EQ("asdf", *name);
14364 }
14365
14366
14367 THREADED_TEST(DateAccess) {
14368   LocalContext context;
14369   v8::HandleScope scope(context->GetIsolate());
14370   v8::Handle<v8::Value> date =
14371       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14372   CHECK(date->IsDate());
14373   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14374 }
14375
14376
14377 void CheckProperties(v8::Isolate* isolate,
14378                      v8::Handle<v8::Value> val,
14379                      int elmc,
14380                      const char* elmv[]) {
14381   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14382   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14383   CHECK_EQ(elmc, props->Length());
14384   for (int i = 0; i < elmc; i++) {
14385     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14386     CHECK_EQ(elmv[i], *elm);
14387   }
14388 }
14389
14390
14391 void CheckOwnProperties(v8::Isolate* isolate,
14392                         v8::Handle<v8::Value> val,
14393                         int elmc,
14394                         const char* elmv[]) {
14395   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14396   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14397   CHECK_EQ(elmc, props->Length());
14398   for (int i = 0; i < elmc; i++) {
14399     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14400     CHECK_EQ(elmv[i], *elm);
14401   }
14402 }
14403
14404
14405 THREADED_TEST(PropertyEnumeration) {
14406   LocalContext context;
14407   v8::Isolate* isolate = context->GetIsolate();
14408   v8::HandleScope scope(isolate);
14409   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14410       context->GetIsolate(),
14411       "var result = [];"
14412       "result[0] = {};"
14413       "result[1] = {a: 1, b: 2};"
14414       "result[2] = [1, 2, 3];"
14415       "var proto = {x: 1, y: 2, z: 3};"
14416       "var x = { __proto__: proto, w: 0, z: 1 };"
14417       "result[3] = x;"
14418       "result;"))->Run();
14419   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14420   CHECK_EQ(4, elms->Length());
14421   int elmc0 = 0;
14422   const char** elmv0 = NULL;
14423   CheckProperties(
14424       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14425   CheckOwnProperties(
14426       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14427   int elmc1 = 2;
14428   const char* elmv1[] = {"a", "b"};
14429   CheckProperties(
14430       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14431   CheckOwnProperties(
14432       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14433   int elmc2 = 3;
14434   const char* elmv2[] = {"0", "1", "2"};
14435   CheckProperties(
14436       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14437   CheckOwnProperties(
14438       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14439   int elmc3 = 4;
14440   const char* elmv3[] = {"w", "z", "x", "y"};
14441   CheckProperties(
14442       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14443   int elmc4 = 2;
14444   const char* elmv4[] = {"w", "z"};
14445   CheckOwnProperties(
14446       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14447 }
14448
14449
14450 THREADED_TEST(PropertyEnumeration2) {
14451   LocalContext context;
14452   v8::Isolate* isolate = context->GetIsolate();
14453   v8::HandleScope scope(isolate);
14454   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14455       context->GetIsolate(),
14456       "var result = [];"
14457       "result[0] = {};"
14458       "result[1] = {a: 1, b: 2};"
14459       "result[2] = [1, 2, 3];"
14460       "var proto = {x: 1, y: 2, z: 3};"
14461       "var x = { __proto__: proto, w: 0, z: 1 };"
14462       "result[3] = x;"
14463       "result;"))->Run();
14464   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14465   CHECK_EQ(4, elms->Length());
14466   int elmc0 = 0;
14467   const char** elmv0 = NULL;
14468   CheckProperties(isolate,
14469                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14470
14471   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14472   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14473   CHECK_EQ(0, props->Length());
14474   for (uint32_t i = 0; i < props->Length(); i++) {
14475     printf("p[%d]\n", i);
14476   }
14477 }
14478
14479 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14480                                   Local<Value> name,
14481                                   v8::AccessType type,
14482                                   Local<Value> data) {
14483   return type != v8::ACCESS_SET;
14484 }
14485
14486
14487 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14488                                     uint32_t key,
14489                                     v8::AccessType type,
14490                                     Local<Value> data) {
14491   return type != v8::ACCESS_SET;
14492 }
14493
14494
14495 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14496   LocalContext context;
14497   v8::Isolate* isolate = context->GetIsolate();
14498   v8::HandleScope scope(isolate);
14499   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14500   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14501                                  IndexedSetAccessBlocker);
14502   templ->Set(v8_str("x"), v8::True(isolate));
14503   Local<v8::Object> instance = templ->NewInstance();
14504   context->Global()->Set(v8_str("obj"), instance);
14505   Local<Value> value = CompileRun("obj.x");
14506   CHECK(value->BooleanValue());
14507 }
14508
14509
14510 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14511                                   Local<Value> name,
14512                                   v8::AccessType type,
14513                                   Local<Value> data) {
14514   return false;
14515 }
14516
14517
14518 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14519                                     uint32_t key,
14520                                     v8::AccessType type,
14521                                     Local<Value> data) {
14522   return false;
14523 }
14524
14525
14526
14527 THREADED_TEST(AccessChecksReenabledCorrectly) {
14528   LocalContext context;
14529   v8::Isolate* isolate = context->GetIsolate();
14530   v8::HandleScope scope(isolate);
14531   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14532   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14533                                  IndexedGetAccessBlocker);
14534   templ->Set(v8_str("a"), v8_str("a"));
14535   // Add more than 8 (see kMaxFastProperties) properties
14536   // so that the constructor will force copying map.
14537   // Cannot sprintf, gcc complains unsafety.
14538   char buf[4];
14539   for (char i = '0'; i <= '9' ; i++) {
14540     buf[0] = i;
14541     for (char j = '0'; j <= '9'; j++) {
14542       buf[1] = j;
14543       for (char k = '0'; k <= '9'; k++) {
14544         buf[2] = k;
14545         buf[3] = 0;
14546         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14547       }
14548     }
14549   }
14550
14551   Local<v8::Object> instance_1 = templ->NewInstance();
14552   context->Global()->Set(v8_str("obj_1"), instance_1);
14553
14554   Local<Value> value_1 = CompileRun("obj_1.a");
14555   CHECK(value_1->IsUndefined());
14556
14557   Local<v8::Object> instance_2 = templ->NewInstance();
14558   context->Global()->Set(v8_str("obj_2"), instance_2);
14559
14560   Local<Value> value_2 = CompileRun("obj_2.a");
14561   CHECK(value_2->IsUndefined());
14562 }
14563
14564
14565 // This tests that access check information remains on the global
14566 // object template when creating contexts.
14567 THREADED_TEST(AccessControlRepeatedContextCreation) {
14568   v8::Isolate* isolate = CcTest::isolate();
14569   v8::HandleScope handle_scope(isolate);
14570   v8::Handle<v8::ObjectTemplate> global_template =
14571       v8::ObjectTemplate::New(isolate);
14572   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14573                                            IndexedSetAccessBlocker);
14574   i::Handle<i::ObjectTemplateInfo> internal_template =
14575       v8::Utils::OpenHandle(*global_template);
14576   CHECK(!internal_template->constructor()->IsUndefined());
14577   i::Handle<i::FunctionTemplateInfo> constructor(
14578       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14579   CHECK(!constructor->access_check_info()->IsUndefined());
14580   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14581   CHECK(!context0.IsEmpty());
14582   CHECK(!constructor->access_check_info()->IsUndefined());
14583 }
14584
14585
14586 THREADED_TEST(TurnOnAccessCheck) {
14587   v8::Isolate* isolate = CcTest::isolate();
14588   v8::HandleScope handle_scope(isolate);
14589
14590   // Create an environment with access check to the global object disabled by
14591   // default.
14592   v8::Handle<v8::ObjectTemplate> global_template =
14593       v8::ObjectTemplate::New(isolate);
14594   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14595                                            IndexedGetAccessBlocker,
14596                                            v8::Handle<v8::Value>(),
14597                                            false);
14598   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14599   Context::Scope context_scope(context);
14600
14601   // Set up a property and a number of functions.
14602   context->Global()->Set(v8_str("a"), v8_num(1));
14603   CompileRun("function f1() {return a;}"
14604              "function f2() {return a;}"
14605              "function g1() {return h();}"
14606              "function g2() {return h();}"
14607              "function h() {return 1;}");
14608   Local<Function> f1 =
14609       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14610   Local<Function> f2 =
14611       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14612   Local<Function> g1 =
14613       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14614   Local<Function> g2 =
14615       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14616   Local<Function> h =
14617       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14618
14619   // Get the global object.
14620   v8::Handle<v8::Object> global = context->Global();
14621
14622   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14623   // uses the runtime system to retreive property a whereas f2 uses global load
14624   // inline cache.
14625   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14626   for (int i = 0; i < 4; i++) {
14627     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14628   }
14629
14630   // Same for g1 and g2.
14631   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14632   for (int i = 0; i < 4; i++) {
14633     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14634   }
14635
14636   // Detach the global and turn on access check.
14637   Local<Object> hidden_global = Local<Object>::Cast(
14638       context->Global()->GetPrototype());
14639   context->DetachGlobal();
14640   hidden_global->TurnOnAccessCheck();
14641
14642   // Failing access check to property get results in undefined.
14643   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14644   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14645
14646   // Failing access check to function call results in exception.
14647   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14648   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14649
14650   // No failing access check when just returning a constant.
14651   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14652 }
14653
14654
14655 static const char* kPropertyA = "a";
14656 static const char* kPropertyH = "h";
14657
14658 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14659                                        Local<Value> name,
14660                                        v8::AccessType type,
14661                                        Local<Value> data) {
14662   if (!name->IsString()) return false;
14663   i::Handle<i::String> name_handle =
14664       v8::Utils::OpenHandle(String::Cast(*name));
14665   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14666       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14667 }
14668
14669
14670 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14671   v8::Isolate* isolate = CcTest::isolate();
14672   v8::HandleScope handle_scope(isolate);
14673
14674   // Create an environment with access check to the global object disabled by
14675   // default. When the registered access checker will block access to properties
14676   // a and h.
14677   v8::Handle<v8::ObjectTemplate> global_template =
14678      v8::ObjectTemplate::New(isolate);
14679   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14680                                            IndexedGetAccessBlocker,
14681                                            v8::Handle<v8::Value>(),
14682                                            false);
14683   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14684   Context::Scope context_scope(context);
14685
14686   // Set up a property and a number of functions.
14687   context->Global()->Set(v8_str("a"), v8_num(1));
14688   static const char* source = "function f1() {return a;}"
14689                               "function f2() {return a;}"
14690                               "function g1() {return h();}"
14691                               "function g2() {return h();}"
14692                               "function h() {return 1;}";
14693
14694   CompileRun(source);
14695   Local<Function> f1;
14696   Local<Function> f2;
14697   Local<Function> g1;
14698   Local<Function> g2;
14699   Local<Function> h;
14700   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14701   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14702   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14703   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14704   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14705
14706   // Get the global object.
14707   v8::Handle<v8::Object> global = context->Global();
14708
14709   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14710   // uses the runtime system to retreive property a whereas f2 uses global load
14711   // inline cache.
14712   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14713   for (int i = 0; i < 4; i++) {
14714     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14715   }
14716
14717   // Same for g1 and g2.
14718   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14719   for (int i = 0; i < 4; i++) {
14720     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14721   }
14722
14723   // Detach the global and turn on access check now blocking access to property
14724   // a and function h.
14725   Local<Object> hidden_global = Local<Object>::Cast(
14726       context->Global()->GetPrototype());
14727   context->DetachGlobal();
14728   hidden_global->TurnOnAccessCheck();
14729
14730   // Failing access check to property get results in undefined.
14731   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14732   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14733
14734   // Failing access check to function call results in exception.
14735   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14736   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14737
14738   // No failing access check when just returning a constant.
14739   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14740
14741   // Now compile the source again. And get the newly compiled functions, except
14742   // for h for which access is blocked.
14743   CompileRun(source);
14744   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14745   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14746   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14747   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14748   CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14749
14750   // Failing access check to property get results in undefined.
14751   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14752   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14753
14754   // Failing access check to function call results in exception.
14755   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14756   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14757 }
14758
14759
14760 // This test verifies that pre-compilation (aka preparsing) can be called
14761 // without initializing the whole VM. Thus we cannot run this test in a
14762 // multi-threaded setup.
14763 TEST(PreCompile) {
14764   // TODO(155): This test would break without the initialization of V8. This is
14765   // a workaround for now to make this test not fail.
14766   v8::V8::Initialize();
14767   v8::Isolate* isolate = CcTest::isolate();
14768   HandleScope handle_scope(isolate);
14769   const char* script = "function foo(a) { return a+1; }";
14770   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14771       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14772   CHECK_NE(sd->Length(), 0);
14773   CHECK_NE(sd->Data(), NULL);
14774   CHECK(!sd->HasError());
14775   delete sd;
14776 }
14777
14778
14779 TEST(PreCompileWithError) {
14780   v8::V8::Initialize();
14781   v8::Isolate* isolate = CcTest::isolate();
14782   HandleScope handle_scope(isolate);
14783   const char* script = "function foo(a) { return 1 * * 2; }";
14784   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14785       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14786   CHECK(sd->HasError());
14787   delete sd;
14788 }
14789
14790
14791 TEST(Regress31661) {
14792   v8::V8::Initialize();
14793   v8::Isolate* isolate = CcTest::isolate();
14794   HandleScope handle_scope(isolate);
14795   const char* script = " The Definintive Guide";
14796   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14797       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14798   CHECK(sd->HasError());
14799   delete sd;
14800 }
14801
14802
14803 // Tests that ScriptData can be serialized and deserialized.
14804 TEST(PreCompileSerialization) {
14805   v8::V8::Initialize();
14806   v8::Isolate* isolate = CcTest::isolate();
14807   HandleScope handle_scope(isolate);
14808   const char* script = "function foo(a) { return a+1; }";
14809   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14810       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14811
14812   // Serialize.
14813   int serialized_data_length = sd->Length();
14814   char* serialized_data = i::NewArray<char>(serialized_data_length);
14815   i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14816
14817   // Deserialize.
14818   v8::ScriptData* deserialized_sd =
14819       v8::ScriptData::New(serialized_data, serialized_data_length);
14820
14821   // Verify that the original is the same as the deserialized.
14822   CHECK_EQ(sd->Length(), deserialized_sd->Length());
14823   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14824   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14825
14826   delete sd;
14827   delete deserialized_sd;
14828   i::DeleteArray(serialized_data);
14829 }
14830
14831
14832 // Attempts to deserialize bad data.
14833 TEST(PreCompileDeserializationError) {
14834   v8::V8::Initialize();
14835   const char* data = "DONT CARE";
14836   int invalid_size = 3;
14837   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14838
14839   CHECK_EQ(0, sd->Length());
14840
14841   delete sd;
14842 }
14843
14844
14845 // Attempts to deserialize bad data.
14846 TEST(PreCompileInvalidPreparseDataError) {
14847   v8::V8::Initialize();
14848   v8::Isolate* isolate = CcTest::isolate();
14849   LocalContext context;
14850   v8::HandleScope scope(context->GetIsolate());
14851
14852   const char* script = "function foo(){ return 5;}\n"
14853       "function bar(){ return 6 + 7;}  foo();";
14854   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14855       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14856   CHECK(!sd->HasError());
14857   // ScriptDataImpl private implementation details
14858   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14859   const int kFunctionEntrySize = i::FunctionEntry::kSize;
14860   const int kFunctionEntryStartOffset = 0;
14861   const int kFunctionEntryEndOffset = 1;
14862   unsigned* sd_data =
14863       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14864
14865   // Overwrite function bar's end position with 0.
14866   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14867   v8::TryCatch try_catch;
14868
14869   Local<String> source = String::NewFromUtf8(isolate, script);
14870   Local<Script> compiled_script = Script::New(source, NULL, sd);
14871   CHECK(try_catch.HasCaught());
14872   String::Utf8Value exception_value(try_catch.Message()->Get());
14873   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14874            *exception_value);
14875
14876   try_catch.Reset();
14877   delete sd;
14878
14879   // Overwrite function bar's start position with 200.  The function entry
14880   // will not be found when searching for it by position and we should fall
14881   // back on eager compilation.
14882   sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14883       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14884   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14885   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14886       200;
14887   compiled_script = Script::New(source, NULL, sd);
14888   CHECK(!try_catch.HasCaught());
14889
14890   delete sd;
14891 }
14892
14893
14894 // This tests that we do not allow dictionary load/call inline caches
14895 // to use functions that have not yet been compiled.  The potential
14896 // problem of loading a function that has not yet been compiled can
14897 // arise because we share code between contexts via the compilation
14898 // cache.
14899 THREADED_TEST(DictionaryICLoadedFunction) {
14900   v8::HandleScope scope(CcTest::isolate());
14901   // Test LoadIC.
14902   for (int i = 0; i < 2; i++) {
14903     LocalContext context;
14904     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14905     context->Global()->Delete(v8_str("tmp"));
14906     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14907   }
14908   // Test CallIC.
14909   for (int i = 0; i < 2; i++) {
14910     LocalContext context;
14911     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14912     context->Global()->Delete(v8_str("tmp"));
14913     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14914   }
14915 }
14916
14917
14918 // Test that cross-context new calls use the context of the callee to
14919 // create the new JavaScript object.
14920 THREADED_TEST(CrossContextNew) {
14921   v8::Isolate* isolate = CcTest::isolate();
14922   v8::HandleScope scope(isolate);
14923   v8::Local<Context> context0 = Context::New(isolate);
14924   v8::Local<Context> context1 = Context::New(isolate);
14925
14926   // Allow cross-domain access.
14927   Local<String> token = v8_str("<security token>");
14928   context0->SetSecurityToken(token);
14929   context1->SetSecurityToken(token);
14930
14931   // Set an 'x' property on the Object prototype and define a
14932   // constructor function in context0.
14933   context0->Enter();
14934   CompileRun("Object.prototype.x = 42; function C() {};");
14935   context0->Exit();
14936
14937   // Call the constructor function from context0 and check that the
14938   // result has the 'x' property.
14939   context1->Enter();
14940   context1->Global()->Set(v8_str("other"), context0->Global());
14941   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14942   CHECK(value->IsInt32());
14943   CHECK_EQ(42, value->Int32Value());
14944   context1->Exit();
14945 }
14946
14947
14948 // Verify that we can clone an object
14949 TEST(ObjectClone) {
14950   LocalContext env;
14951   v8::Isolate* isolate = env->GetIsolate();
14952   v8::HandleScope scope(isolate);
14953
14954   const char* sample =
14955     "var rv = {};"      \
14956     "rv.alpha = 'hello';" \
14957     "rv.beta = 123;"     \
14958     "rv;";
14959
14960   // Create an object, verify basics.
14961   Local<Value> val = CompileRun(sample);
14962   CHECK(val->IsObject());
14963   Local<v8::Object> obj = val.As<v8::Object>();
14964   obj->Set(v8_str("gamma"), v8_str("cloneme"));
14965
14966   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14967   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14968   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14969
14970   // Clone it.
14971   Local<v8::Object> clone = obj->Clone();
14972   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14973   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
14974   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14975
14976   // Set a property on the clone, verify each object.
14977   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
14978   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14979   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
14980 }
14981
14982
14983 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14984  public:
14985   explicit AsciiVectorResource(i::Vector<const char> vector)
14986       : data_(vector) {}
14987   virtual ~AsciiVectorResource() {}
14988   virtual size_t length() const { return data_.length(); }
14989   virtual const char* data() const { return data_.start(); }
14990  private:
14991   i::Vector<const char> data_;
14992 };
14993
14994
14995 class UC16VectorResource : public v8::String::ExternalStringResource {
14996  public:
14997   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14998       : data_(vector) {}
14999   virtual ~UC16VectorResource() {}
15000   virtual size_t length() const { return data_.length(); }
15001   virtual const i::uc16* data() const { return data_.start(); }
15002  private:
15003   i::Vector<const i::uc16> data_;
15004 };
15005
15006
15007 static void MorphAString(i::String* string,
15008                          AsciiVectorResource* ascii_resource,
15009                          UC16VectorResource* uc16_resource) {
15010   CHECK(i::StringShape(string).IsExternal());
15011   if (string->IsOneByteRepresentation()) {
15012     // Check old map is not internalized or long.
15013     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15014     // Morph external string to be TwoByte string.
15015     string->set_map(CcTest::heap()->external_string_map());
15016     i::ExternalTwoByteString* morphed =
15017          i::ExternalTwoByteString::cast(string);
15018     morphed->set_resource(uc16_resource);
15019   } else {
15020     // Check old map is not internalized or long.
15021     CHECK(string->map() == CcTest::heap()->external_string_map());
15022     // Morph external string to be ASCII string.
15023     string->set_map(CcTest::heap()->external_ascii_string_map());
15024     i::ExternalAsciiString* morphed =
15025          i::ExternalAsciiString::cast(string);
15026     morphed->set_resource(ascii_resource);
15027   }
15028 }
15029
15030
15031 // Test that we can still flatten a string if the components it is built up
15032 // from have been turned into 16 bit strings in the mean time.
15033 THREADED_TEST(MorphCompositeStringTest) {
15034   char utf_buffer[129];
15035   const char* c_string = "Now is the time for all good men"
15036                          " to come to the aid of the party";
15037   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15038   {
15039     LocalContext env;
15040     i::Factory* factory = CcTest::i_isolate()->factory();
15041     v8::HandleScope scope(env->GetIsolate());
15042     AsciiVectorResource ascii_resource(
15043         i::Vector<const char>(c_string, i::StrLength(c_string)));
15044     UC16VectorResource uc16_resource(
15045         i::Vector<const uint16_t>(two_byte_string,
15046                                   i::StrLength(c_string)));
15047
15048     Local<String> lhs(v8::Utils::ToLocal(
15049         factory->NewExternalStringFromAscii(&ascii_resource)));
15050     Local<String> rhs(v8::Utils::ToLocal(
15051         factory->NewExternalStringFromAscii(&ascii_resource)));
15052
15053     env->Global()->Set(v8_str("lhs"), lhs);
15054     env->Global()->Set(v8_str("rhs"), rhs);
15055
15056     CompileRun(
15057         "var cons = lhs + rhs;"
15058         "var slice = lhs.substring(1, lhs.length - 1);"
15059         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15060
15061     CHECK(lhs->IsOneByte());
15062     CHECK(rhs->IsOneByte());
15063
15064     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15065     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15066
15067     // This should UTF-8 without flattening, since everything is ASCII.
15068     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15069     CHECK_EQ(128, cons->Utf8Length());
15070     int nchars = -1;
15071     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15072     CHECK_EQ(128, nchars);
15073     CHECK_EQ(0, strcmp(
15074         utf_buffer,
15075         "Now is the time for all good men to come to the aid of the party"
15076         "Now is the time for all good men to come to the aid of the party"));
15077
15078     // Now do some stuff to make sure the strings are flattened, etc.
15079     CompileRun(
15080         "/[^a-z]/.test(cons);"
15081         "/[^a-z]/.test(slice);"
15082         "/[^a-z]/.test(slice_on_cons);");
15083     const char* expected_cons =
15084         "Now is the time for all good men to come to the aid of the party"
15085         "Now is the time for all good men to come to the aid of the party";
15086     const char* expected_slice =
15087         "ow is the time for all good men to come to the aid of the part";
15088     const char* expected_slice_on_cons =
15089         "ow is the time for all good men to come to the aid of the party"
15090         "Now is the time for all good men to come to the aid of the part";
15091     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15092              env->Global()->Get(v8_str("cons")));
15093     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15094              env->Global()->Get(v8_str("slice")));
15095     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15096              env->Global()->Get(v8_str("slice_on_cons")));
15097   }
15098   i::DeleteArray(two_byte_string);
15099 }
15100
15101
15102 TEST(CompileExternalTwoByteSource) {
15103   LocalContext context;
15104   v8::HandleScope scope(context->GetIsolate());
15105
15106   // This is a very short list of sources, which currently is to check for a
15107   // regression caused by r2703.
15108   const char* ascii_sources[] = {
15109     "0.5",
15110     "-0.5",   // This mainly testes PushBack in the Scanner.
15111     "--0.5",  // This mainly testes PushBack in the Scanner.
15112     NULL
15113   };
15114
15115   // Compile the sources as external two byte strings.
15116   for (int i = 0; ascii_sources[i] != NULL; i++) {
15117     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15118     TestResource* uc16_resource = new TestResource(two_byte_string);
15119     v8::Local<v8::String> source =
15120         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15121     v8::Script::Compile(source);
15122   }
15123 }
15124
15125
15126 #ifndef V8_INTERPRETED_REGEXP
15127
15128 struct RegExpInterruptionData {
15129   int loop_count;
15130   UC16VectorResource* string_resource;
15131   v8::Persistent<v8::String> string;
15132 } regexp_interruption_data;
15133
15134
15135 class RegExpInterruptionThread : public i::Thread {
15136  public:
15137   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15138       : Thread("TimeoutThread"), isolate_(isolate) {}
15139
15140   virtual void Run() {
15141     for (regexp_interruption_data.loop_count = 0;
15142          regexp_interruption_data.loop_count < 7;
15143          regexp_interruption_data.loop_count++) {
15144       i::OS::Sleep(50);  // Wait a bit before requesting GC.
15145       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15146     }
15147     i::OS::Sleep(50);  // Wait a bit before terminating.
15148     v8::V8::TerminateExecution(isolate_);
15149   }
15150
15151  private:
15152   v8::Isolate* isolate_;
15153 };
15154
15155
15156 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15157   if (regexp_interruption_data.loop_count != 2) return;
15158   v8::HandleScope scope(CcTest::isolate());
15159   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15160       CcTest::isolate(), regexp_interruption_data.string);
15161   string->MakeExternal(regexp_interruption_data.string_resource);
15162 }
15163
15164
15165 // Test that RegExp execution can be interrupted.  Specifically, we test
15166 // * interrupting with GC
15167 // * turn the subject string from one-byte internal to two-byte external string
15168 // * force termination
15169 TEST(RegExpInterruption) {
15170   v8::HandleScope scope(CcTest::isolate());
15171   LocalContext env;
15172
15173   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15174
15175   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15176   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15177   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15178   v8::Local<v8::String> string = v8_str(ascii_content);
15179
15180   CcTest::global()->Set(v8_str("a"), string);
15181   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15182   regexp_interruption_data.string_resource = new UC16VectorResource(
15183       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15184
15185   v8::TryCatch try_catch;
15186   timeout_thread.Start();
15187
15188   CompileRun("/((a*)*)*b/.exec(a)");
15189   CHECK(try_catch.HasTerminated());
15190
15191   timeout_thread.Join();
15192
15193   regexp_interruption_data.string.Reset();
15194   i::DeleteArray(uc16_content);
15195 }
15196
15197 #endif  // V8_INTERPRETED_REGEXP
15198
15199
15200 // Test that we cannot set a property on the global object if there
15201 // is a read-only property in the prototype chain.
15202 TEST(ReadOnlyPropertyInGlobalProto) {
15203   i::FLAG_es5_readonly = true;
15204   v8::Isolate* isolate = CcTest::isolate();
15205   v8::HandleScope scope(isolate);
15206   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15207   LocalContext context(0, templ);
15208   v8::Handle<v8::Object> global = context->Global();
15209   v8::Handle<v8::Object> global_proto =
15210       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15211   global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15212   global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15213   // Check without 'eval' or 'with'.
15214   v8::Handle<v8::Value> res =
15215       CompileRun("function f() { x = 42; return x; }; f()");
15216   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15217   // Check with 'eval'.
15218   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15219   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15220   // Check with 'with'.
15221   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15222   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15223 }
15224
15225 static int force_set_set_count = 0;
15226 static int force_set_get_count = 0;
15227 bool pass_on_get = false;
15228
15229 static void ForceSetGetter(v8::Local<v8::String> name,
15230                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15231   force_set_get_count++;
15232   if (pass_on_get) {
15233     return;
15234   }
15235   info.GetReturnValue().Set(3);
15236 }
15237
15238 static void ForceSetSetter(v8::Local<v8::String> name,
15239                            v8::Local<v8::Value> value,
15240                            const v8::PropertyCallbackInfo<void>& info) {
15241   force_set_set_count++;
15242 }
15243
15244 static void ForceSetInterceptSetter(
15245     v8::Local<v8::String> name,
15246     v8::Local<v8::Value> value,
15247     const v8::PropertyCallbackInfo<v8::Value>& info) {
15248   force_set_set_count++;
15249   info.GetReturnValue().SetUndefined();
15250 }
15251
15252
15253 TEST(ForceSet) {
15254   force_set_get_count = 0;
15255   force_set_set_count = 0;
15256   pass_on_get = false;
15257
15258   v8::Isolate* isolate = CcTest::isolate();
15259   v8::HandleScope scope(isolate);
15260   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15261   v8::Handle<v8::String> access_property =
15262       v8::String::NewFromUtf8(isolate, "a");
15263   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15264   LocalContext context(NULL, templ);
15265   v8::Handle<v8::Object> global = context->Global();
15266
15267   // Ordinary properties
15268   v8::Handle<v8::String> simple_property =
15269       v8::String::NewFromUtf8(isolate, "p");
15270   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15271   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15272   // This should fail because the property is read-only
15273   global->Set(simple_property, v8::Int32::New(isolate, 5));
15274   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15275   // This should succeed even though the property is read-only
15276   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15277   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15278
15279   // Accessors
15280   CHECK_EQ(0, force_set_set_count);
15281   CHECK_EQ(0, force_set_get_count);
15282   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15283   // CHECK_EQ the property shouldn't override it, just call the setter
15284   // which in this case does nothing.
15285   global->Set(access_property, v8::Int32::New(isolate, 7));
15286   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15287   CHECK_EQ(1, force_set_set_count);
15288   CHECK_EQ(2, force_set_get_count);
15289   // Forcing the property to be set should override the accessor without
15290   // calling it
15291   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15292   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15293   CHECK_EQ(1, force_set_set_count);
15294   CHECK_EQ(2, force_set_get_count);
15295 }
15296
15297
15298 TEST(ForceSetWithInterceptor) {
15299   force_set_get_count = 0;
15300   force_set_set_count = 0;
15301   pass_on_get = false;
15302
15303   v8::Isolate* isolate = CcTest::isolate();
15304   v8::HandleScope scope(isolate);
15305   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15306   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15307   LocalContext context(NULL, templ);
15308   v8::Handle<v8::Object> global = context->Global();
15309
15310   v8::Handle<v8::String> some_property =
15311       v8::String::NewFromUtf8(isolate, "a");
15312   CHECK_EQ(0, force_set_set_count);
15313   CHECK_EQ(0, force_set_get_count);
15314   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15315   // Setting the property shouldn't override it, just call the setter
15316   // which in this case does nothing.
15317   global->Set(some_property, v8::Int32::New(isolate, 7));
15318   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15319   CHECK_EQ(1, force_set_set_count);
15320   CHECK_EQ(2, force_set_get_count);
15321   // Getting the property when the interceptor returns an empty handle
15322   // should yield undefined, since the property isn't present on the
15323   // object itself yet.
15324   pass_on_get = true;
15325   CHECK(global->Get(some_property)->IsUndefined());
15326   CHECK_EQ(1, force_set_set_count);
15327   CHECK_EQ(3, force_set_get_count);
15328   // Forcing the property to be set should cause the value to be
15329   // set locally without calling the interceptor.
15330   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15331   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15332   CHECK_EQ(1, force_set_set_count);
15333   CHECK_EQ(4, force_set_get_count);
15334   // Reenabling the interceptor should cause it to take precedence over
15335   // the property
15336   pass_on_get = false;
15337   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15338   CHECK_EQ(1, force_set_set_count);
15339   CHECK_EQ(5, force_set_get_count);
15340   // The interceptor should also work for other properties
15341   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15342                   ->Int32Value());
15343   CHECK_EQ(1, force_set_set_count);
15344   CHECK_EQ(6, force_set_get_count);
15345 }
15346
15347
15348 THREADED_TEST(ForceDelete) {
15349   v8::Isolate* isolate = CcTest::isolate();
15350   v8::HandleScope scope(isolate);
15351   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15352   LocalContext context(NULL, templ);
15353   v8::Handle<v8::Object> global = context->Global();
15354
15355   // Ordinary properties
15356   v8::Handle<v8::String> simple_property =
15357       v8::String::NewFromUtf8(isolate, "p");
15358   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15359   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15360   // This should fail because the property is dont-delete.
15361   CHECK(!global->Delete(simple_property));
15362   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15363   // This should succeed even though the property is dont-delete.
15364   CHECK(global->ForceDelete(simple_property));
15365   CHECK(global->Get(simple_property)->IsUndefined());
15366 }
15367
15368
15369 static int force_delete_interceptor_count = 0;
15370 static bool pass_on_delete = false;
15371
15372
15373 static void ForceDeleteDeleter(
15374     v8::Local<v8::String> name,
15375     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15376   force_delete_interceptor_count++;
15377   if (pass_on_delete) return;
15378   info.GetReturnValue().Set(true);
15379 }
15380
15381
15382 THREADED_TEST(ForceDeleteWithInterceptor) {
15383   force_delete_interceptor_count = 0;
15384   pass_on_delete = false;
15385
15386   v8::Isolate* isolate = CcTest::isolate();
15387   v8::HandleScope scope(isolate);
15388   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15389   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15390   LocalContext context(NULL, templ);
15391   v8::Handle<v8::Object> global = context->Global();
15392
15393   v8::Handle<v8::String> some_property =
15394       v8::String::NewFromUtf8(isolate, "a");
15395   global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15396
15397   // Deleting a property should get intercepted and nothing should
15398   // happen.
15399   CHECK_EQ(0, force_delete_interceptor_count);
15400   CHECK(global->Delete(some_property));
15401   CHECK_EQ(1, force_delete_interceptor_count);
15402   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15403   // Deleting the property when the interceptor returns an empty
15404   // handle should not delete the property since it is DontDelete.
15405   pass_on_delete = true;
15406   CHECK(!global->Delete(some_property));
15407   CHECK_EQ(2, force_delete_interceptor_count);
15408   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15409   // Forcing the property to be deleted should delete the value
15410   // without calling the interceptor.
15411   CHECK(global->ForceDelete(some_property));
15412   CHECK(global->Get(some_property)->IsUndefined());
15413   CHECK_EQ(2, force_delete_interceptor_count);
15414 }
15415
15416
15417 // Make sure that forcing a delete invalidates any IC stubs, so we
15418 // don't read the hole value.
15419 THREADED_TEST(ForceDeleteIC) {
15420   LocalContext context;
15421   v8::HandleScope scope(context->GetIsolate());
15422   // Create a DontDelete variable on the global object.
15423   CompileRun("this.__proto__ = { foo: 'horse' };"
15424              "var foo = 'fish';"
15425              "function f() { return foo.length; }");
15426   // Initialize the IC for foo in f.
15427   CompileRun("for (var i = 0; i < 4; i++) f();");
15428   // Make sure the value of foo is correct before the deletion.
15429   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15430   // Force the deletion of foo.
15431   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15432   // Make sure the value for foo is read from the prototype, and that
15433   // we don't get in trouble with reading the deleted cell value
15434   // sentinel.
15435   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15436 }
15437
15438
15439 TEST(InlinedFunctionAcrossContexts) {
15440   i::FLAG_allow_natives_syntax = true;
15441   v8::Isolate* isolate = CcTest::isolate();
15442   v8::HandleScope outer_scope(isolate);
15443   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15444   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15445   ctx1->Enter();
15446
15447   {
15448     v8::HandleScope inner_scope(CcTest::isolate());
15449     CompileRun("var G = 42; function foo() { return G; }");
15450     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15451     ctx2->Enter();
15452     ctx2->Global()->Set(v8_str("o"), foo);
15453     v8::Local<v8::Value> res = CompileRun(
15454         "function f() { return o(); }"
15455         "for (var i = 0; i < 10; ++i) f();"
15456         "%OptimizeFunctionOnNextCall(f);"
15457         "f();");
15458     CHECK_EQ(42, res->Int32Value());
15459     ctx2->Exit();
15460     v8::Handle<v8::String> G_property =
15461         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15462     CHECK(ctx1->Global()->ForceDelete(G_property));
15463     ctx2->Enter();
15464     ExpectString(
15465         "(function() {"
15466         "  try {"
15467         "    return f();"
15468         "  } catch(e) {"
15469         "    return e.toString();"
15470         "  }"
15471         " })()",
15472         "ReferenceError: G is not defined");
15473     ctx2->Exit();
15474     ctx1->Exit();
15475   }
15476 }
15477
15478
15479 static v8::Local<Context> calling_context0;
15480 static v8::Local<Context> calling_context1;
15481 static v8::Local<Context> calling_context2;
15482
15483
15484 // Check that the call to the callback is initiated in
15485 // calling_context2, the directly calling context is calling_context1
15486 // and the callback itself is in calling_context0.
15487 static void GetCallingContextCallback(
15488     const v8::FunctionCallbackInfo<v8::Value>& args) {
15489   ApiTestFuzzer::Fuzz();
15490   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15491   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15492   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15493   args.GetReturnValue().Set(42);
15494 }
15495
15496
15497 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15498   i::Isolate* isolate = CcTest::i_isolate();
15499   CHECK(isolate != NULL);
15500   CHECK(isolate->context() == NULL);
15501   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15502   v8::HandleScope scope(v8_isolate);
15503   // The following should not crash, but return an empty handle.
15504   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15505   CHECK(current.IsEmpty());
15506 }
15507
15508
15509 THREADED_TEST(GetCallingContext) {
15510   v8::Isolate* isolate = CcTest::isolate();
15511   v8::HandleScope scope(isolate);
15512
15513   Local<Context> calling_context0(Context::New(isolate));
15514   Local<Context> calling_context1(Context::New(isolate));
15515   Local<Context> calling_context2(Context::New(isolate));
15516   ::calling_context0 = calling_context0;
15517   ::calling_context1 = calling_context1;
15518   ::calling_context2 = calling_context2;
15519
15520   // Allow cross-domain access.
15521   Local<String> token = v8_str("<security token>");
15522   calling_context0->SetSecurityToken(token);
15523   calling_context1->SetSecurityToken(token);
15524   calling_context2->SetSecurityToken(token);
15525
15526   // Create an object with a C++ callback in context0.
15527   calling_context0->Enter();
15528   Local<v8::FunctionTemplate> callback_templ =
15529       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15530   calling_context0->Global()->Set(v8_str("callback"),
15531                                   callback_templ->GetFunction());
15532   calling_context0->Exit();
15533
15534   // Expose context0 in context1 and set up a function that calls the
15535   // callback function.
15536   calling_context1->Enter();
15537   calling_context1->Global()->Set(v8_str("context0"),
15538                                   calling_context0->Global());
15539   CompileRun("function f() { context0.callback() }");
15540   calling_context1->Exit();
15541
15542   // Expose context1 in context2 and call the callback function in
15543   // context0 indirectly through f in context1.
15544   calling_context2->Enter();
15545   calling_context2->Global()->Set(v8_str("context1"),
15546                                   calling_context1->Global());
15547   CompileRun("context1.f()");
15548   calling_context2->Exit();
15549   ::calling_context0.Clear();
15550   ::calling_context1.Clear();
15551   ::calling_context2.Clear();
15552 }
15553
15554
15555 // Check that a variable declaration with no explicit initialization
15556 // value does shadow an existing property in the prototype chain.
15557 THREADED_TEST(InitGlobalVarInProtoChain) {
15558   i::FLAG_es52_globals = true;
15559   LocalContext context;
15560   v8::HandleScope scope(context->GetIsolate());
15561   // Introduce a variable in the prototype chain.
15562   CompileRun("__proto__.x = 42");
15563   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15564   CHECK(!result->IsUndefined());
15565   CHECK_EQ(43, result->Int32Value());
15566 }
15567
15568
15569 // Regression test for issue 398.
15570 // If a function is added to an object, creating a constant function
15571 // field, and the result is cloned, replacing the constant function on the
15572 // original should not affect the clone.
15573 // See http://code.google.com/p/v8/issues/detail?id=398
15574 THREADED_TEST(ReplaceConstantFunction) {
15575   LocalContext context;
15576   v8::Isolate* isolate = context->GetIsolate();
15577   v8::HandleScope scope(isolate);
15578   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15579   v8::Handle<v8::FunctionTemplate> func_templ =
15580       v8::FunctionTemplate::New(isolate);
15581   v8::Handle<v8::String> foo_string =
15582       v8::String::NewFromUtf8(isolate, "foo");
15583   obj->Set(foo_string, func_templ->GetFunction());
15584   v8::Handle<v8::Object> obj_clone = obj->Clone();
15585   obj_clone->Set(foo_string,
15586                  v8::String::NewFromUtf8(isolate, "Hello"));
15587   CHECK(!obj->Get(foo_string)->IsUndefined());
15588 }
15589
15590
15591 static void CheckElementValue(i::Isolate* isolate,
15592                               int expected,
15593                               i::Handle<i::Object> obj,
15594                               int offset) {
15595   i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15596   CHECK_EQ(expected, i::Smi::cast(element)->value());
15597 }
15598
15599
15600 THREADED_TEST(PixelArray) {
15601   LocalContext context;
15602   i::Isolate* isolate = CcTest::i_isolate();
15603   i::Factory* factory = isolate->factory();
15604   v8::HandleScope scope(context->GetIsolate());
15605   const int kElementCount = 260;
15606   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15607   i::Handle<i::ExternalUint8ClampedArray> pixels =
15608       i::Handle<i::ExternalUint8ClampedArray>::cast(
15609           factory->NewExternalArray(kElementCount,
15610                                     v8::kExternalUint8ClampedArray,
15611                                     pixel_data));
15612   // Force GC to trigger verification.
15613   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15614   for (int i = 0; i < kElementCount; i++) {
15615     pixels->set(i, i % 256);
15616   }
15617   // Force GC to trigger verification.
15618   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15619   for (int i = 0; i < kElementCount; i++) {
15620     CHECK_EQ(i % 256, pixels->get_scalar(i));
15621     CHECK_EQ(i % 256, pixel_data[i]);
15622   }
15623
15624   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15625   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15626   // Set the elements to be the pixels.
15627   // jsobj->set_elements(*pixels);
15628   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15629   CheckElementValue(isolate, 1, jsobj, 1);
15630   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15631   context->Global()->Set(v8_str("pixels"), obj);
15632   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15633   CHECK_EQ(1503, result->Int32Value());
15634   result = CompileRun("pixels[1]");
15635   CHECK_EQ(1, result->Int32Value());
15636
15637   result = CompileRun("var sum = 0;"
15638                       "for (var i = 0; i < 8; i++) {"
15639                       "  sum += pixels[i] = pixels[i] = -i;"
15640                       "}"
15641                       "sum;");
15642   CHECK_EQ(-28, result->Int32Value());
15643
15644   result = CompileRun("var sum = 0;"
15645                       "for (var i = 0; i < 8; i++) {"
15646                       "  sum += pixels[i] = pixels[i] = 0;"
15647                       "}"
15648                       "sum;");
15649   CHECK_EQ(0, result->Int32Value());
15650
15651   result = CompileRun("var sum = 0;"
15652                       "for (var i = 0; i < 8; i++) {"
15653                       "  sum += pixels[i] = pixels[i] = 255;"
15654                       "}"
15655                       "sum;");
15656   CHECK_EQ(8 * 255, result->Int32Value());
15657
15658   result = CompileRun("var sum = 0;"
15659                       "for (var i = 0; i < 8; i++) {"
15660                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15661                       "}"
15662                       "sum;");
15663   CHECK_EQ(2076, result->Int32Value());
15664
15665   result = CompileRun("var sum = 0;"
15666                       "for (var i = 0; i < 8; i++) {"
15667                       "  sum += pixels[i] = pixels[i] = i;"
15668                       "}"
15669                       "sum;");
15670   CHECK_EQ(28, result->Int32Value());
15671
15672   result = CompileRun("var sum = 0;"
15673                       "for (var i = 0; i < 8; i++) {"
15674                       "  sum += pixels[i];"
15675                       "}"
15676                       "sum;");
15677   CHECK_EQ(28, result->Int32Value());
15678
15679   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15680                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15681   i::Handle<i::Object> no_failure;
15682   no_failure =
15683       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15684   ASSERT(!no_failure.is_null());
15685   i::USE(no_failure);
15686   CheckElementValue(isolate, 2, jsobj, 1);
15687   *value.location() = i::Smi::FromInt(256);
15688   no_failure =
15689       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15690   ASSERT(!no_failure.is_null());
15691   i::USE(no_failure);
15692   CheckElementValue(isolate, 255, jsobj, 1);
15693   *value.location() = i::Smi::FromInt(-1);
15694   no_failure =
15695       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15696   ASSERT(!no_failure.is_null());
15697   i::USE(no_failure);
15698   CheckElementValue(isolate, 0, jsobj, 1);
15699
15700   result = CompileRun("for (var i = 0; i < 8; i++) {"
15701                       "  pixels[i] = (i * 65) - 109;"
15702                       "}"
15703                       "pixels[1] + pixels[6];");
15704   CHECK_EQ(255, result->Int32Value());
15705   CheckElementValue(isolate, 0, jsobj, 0);
15706   CheckElementValue(isolate, 0, jsobj, 1);
15707   CheckElementValue(isolate, 21, jsobj, 2);
15708   CheckElementValue(isolate, 86, jsobj, 3);
15709   CheckElementValue(isolate, 151, jsobj, 4);
15710   CheckElementValue(isolate, 216, jsobj, 5);
15711   CheckElementValue(isolate, 255, jsobj, 6);
15712   CheckElementValue(isolate, 255, jsobj, 7);
15713   result = CompileRun("var sum = 0;"
15714                       "for (var i = 0; i < 8; i++) {"
15715                       "  sum += pixels[i];"
15716                       "}"
15717                       "sum;");
15718   CHECK_EQ(984, result->Int32Value());
15719
15720   result = CompileRun("for (var i = 0; i < 8; i++) {"
15721                       "  pixels[i] = (i * 1.1);"
15722                       "}"
15723                       "pixels[1] + pixels[6];");
15724   CHECK_EQ(8, result->Int32Value());
15725   CheckElementValue(isolate, 0, jsobj, 0);
15726   CheckElementValue(isolate, 1, jsobj, 1);
15727   CheckElementValue(isolate, 2, jsobj, 2);
15728   CheckElementValue(isolate, 3, jsobj, 3);
15729   CheckElementValue(isolate, 4, jsobj, 4);
15730   CheckElementValue(isolate, 6, jsobj, 5);
15731   CheckElementValue(isolate, 7, jsobj, 6);
15732   CheckElementValue(isolate, 8, jsobj, 7);
15733
15734   result = CompileRun("for (var i = 0; i < 8; i++) {"
15735                       "  pixels[7] = undefined;"
15736                       "}"
15737                       "pixels[7];");
15738   CHECK_EQ(0, result->Int32Value());
15739   CheckElementValue(isolate, 0, jsobj, 7);
15740
15741   result = CompileRun("for (var i = 0; i < 8; i++) {"
15742                       "  pixels[6] = '2.3';"
15743                       "}"
15744                       "pixels[6];");
15745   CHECK_EQ(2, result->Int32Value());
15746   CheckElementValue(isolate, 2, jsobj, 6);
15747
15748   result = CompileRun("for (var i = 0; i < 8; i++) {"
15749                       "  pixels[5] = NaN;"
15750                       "}"
15751                       "pixels[5];");
15752   CHECK_EQ(0, result->Int32Value());
15753   CheckElementValue(isolate, 0, jsobj, 5);
15754
15755   result = CompileRun("for (var i = 0; i < 8; i++) {"
15756                       "  pixels[8] = Infinity;"
15757                       "}"
15758                       "pixels[8];");
15759   CHECK_EQ(255, result->Int32Value());
15760   CheckElementValue(isolate, 255, jsobj, 8);
15761
15762   result = CompileRun("for (var i = 0; i < 8; i++) {"
15763                       "  pixels[9] = -Infinity;"
15764                       "}"
15765                       "pixels[9];");
15766   CHECK_EQ(0, result->Int32Value());
15767   CheckElementValue(isolate, 0, jsobj, 9);
15768
15769   result = CompileRun("pixels[3] = 33;"
15770                       "delete pixels[3];"
15771                       "pixels[3];");
15772   CHECK_EQ(33, result->Int32Value());
15773
15774   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15775                       "pixels[2] = 12; pixels[3] = 13;"
15776                       "pixels.__defineGetter__('2',"
15777                       "function() { return 120; });"
15778                       "pixels[2];");
15779   CHECK_EQ(12, result->Int32Value());
15780
15781   result = CompileRun("var js_array = new Array(40);"
15782                       "js_array[0] = 77;"
15783                       "js_array;");
15784   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15785
15786   result = CompileRun("pixels[1] = 23;"
15787                       "pixels.__proto__ = [];"
15788                       "js_array.__proto__ = pixels;"
15789                       "js_array.concat(pixels);");
15790   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15791   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15792
15793   result = CompileRun("pixels[1] = 23;");
15794   CHECK_EQ(23, result->Int32Value());
15795
15796   // Test for index greater than 255.  Regression test for:
15797   // http://code.google.com/p/chromium/issues/detail?id=26337.
15798   result = CompileRun("pixels[256] = 255;");
15799   CHECK_EQ(255, result->Int32Value());
15800   result = CompileRun("var i = 0;"
15801                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15802                       "i");
15803   CHECK_EQ(255, result->Int32Value());
15804
15805   // Make sure that pixel array ICs recognize when a non-pixel array
15806   // is passed to it.
15807   result = CompileRun("function pa_load(p) {"
15808                       "  var sum = 0;"
15809                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15810                       "  return sum;"
15811                       "}"
15812                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15813                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15814                       "just_ints = new Object();"
15815                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15816                       "for (var i = 0; i < 10; ++i) {"
15817                       "  result = pa_load(just_ints);"
15818                       "}"
15819                       "result");
15820   CHECK_EQ(32640, result->Int32Value());
15821
15822   // Make sure that pixel array ICs recognize out-of-bound accesses.
15823   result = CompileRun("function pa_load(p, start) {"
15824                       "  var sum = 0;"
15825                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15826                       "  return sum;"
15827                       "}"
15828                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15829                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15830                       "for (var i = 0; i < 10; ++i) {"
15831                       "  result = pa_load(pixels,-10);"
15832                       "}"
15833                       "result");
15834   CHECK_EQ(0, result->Int32Value());
15835
15836   // Make sure that generic ICs properly handles a pixel array.
15837   result = CompileRun("function pa_load(p) {"
15838                       "  var sum = 0;"
15839                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15840                       "  return sum;"
15841                       "}"
15842                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15843                       "just_ints = new Object();"
15844                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15845                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15846                       "for (var i = 0; i < 10; ++i) {"
15847                       "  result = pa_load(pixels);"
15848                       "}"
15849                       "result");
15850   CHECK_EQ(32640, result->Int32Value());
15851
15852   // Make sure that generic load ICs recognize out-of-bound accesses in
15853   // pixel arrays.
15854   result = CompileRun("function pa_load(p, start) {"
15855                       "  var sum = 0;"
15856                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15857                       "  return sum;"
15858                       "}"
15859                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15860                       "just_ints = new Object();"
15861                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15862                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15863                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15864                       "for (var i = 0; i < 10; ++i) {"
15865                       "  result = pa_load(pixels,-10);"
15866                       "}"
15867                       "result");
15868   CHECK_EQ(0, result->Int32Value());
15869
15870   // Make sure that generic ICs properly handles other types than pixel
15871   // arrays (that the inlined fast pixel array test leaves the right information
15872   // in the right registers).
15873   result = CompileRun("function pa_load(p) {"
15874                       "  var sum = 0;"
15875                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15876                       "  return sum;"
15877                       "}"
15878                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15879                       "just_ints = new Object();"
15880                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15881                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15882                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15883                       "sparse_array = new Object();"
15884                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15885                       "sparse_array[1000000] = 3;"
15886                       "for (var i = 0; i < 10; ++i) {"
15887                       "  result = pa_load(sparse_array);"
15888                       "}"
15889                       "result");
15890   CHECK_EQ(32640, result->Int32Value());
15891
15892   // Make sure that pixel array store ICs clamp values correctly.
15893   result = CompileRun("function pa_store(p) {"
15894                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15895                       "}"
15896                       "pa_store(pixels);"
15897                       "var sum = 0;"
15898                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15899                       "sum");
15900   CHECK_EQ(48896, result->Int32Value());
15901
15902   // Make sure that pixel array stores correctly handle accesses outside
15903   // of the pixel array..
15904   result = CompileRun("function pa_store(p,start) {"
15905                       "  for (var j = 0; j < 256; j++) {"
15906                       "    p[j+start] = j * 2;"
15907                       "  }"
15908                       "}"
15909                       "pa_store(pixels,0);"
15910                       "pa_store(pixels,-128);"
15911                       "var sum = 0;"
15912                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15913                       "sum");
15914   CHECK_EQ(65280, result->Int32Value());
15915
15916   // Make sure that the generic store stub correctly handle accesses outside
15917   // of the pixel array..
15918   result = CompileRun("function pa_store(p,start) {"
15919                       "  for (var j = 0; j < 256; j++) {"
15920                       "    p[j+start] = j * 2;"
15921                       "  }"
15922                       "}"
15923                       "pa_store(pixels,0);"
15924                       "just_ints = new Object();"
15925                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15926                       "pa_store(just_ints, 0);"
15927                       "pa_store(pixels,-128);"
15928                       "var sum = 0;"
15929                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15930                       "sum");
15931   CHECK_EQ(65280, result->Int32Value());
15932
15933   // Make sure that the generic keyed store stub clamps pixel array values
15934   // correctly.
15935   result = CompileRun("function pa_store(p) {"
15936                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15937                       "}"
15938                       "pa_store(pixels);"
15939                       "just_ints = new Object();"
15940                       "pa_store(just_ints);"
15941                       "pa_store(pixels);"
15942                       "var sum = 0;"
15943                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15944                       "sum");
15945   CHECK_EQ(48896, result->Int32Value());
15946
15947   // Make sure that pixel array loads are optimized by crankshaft.
15948   result = CompileRun("function pa_load(p) {"
15949                       "  var sum = 0;"
15950                       "  for (var i=0; i<256; ++i) {"
15951                       "    sum += p[i];"
15952                       "  }"
15953                       "  return sum; "
15954                       "}"
15955                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15956                       "for (var i = 0; i < 5000; ++i) {"
15957                       "  result = pa_load(pixels);"
15958                       "}"
15959                       "result");
15960   CHECK_EQ(32640, result->Int32Value());
15961
15962   // Make sure that pixel array stores are optimized by crankshaft.
15963   result = CompileRun("function pa_init(p) {"
15964                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15965                       "}"
15966                       "function pa_load(p) {"
15967                       "  var sum = 0;"
15968                       "  for (var i=0; i<256; ++i) {"
15969                       "    sum += p[i];"
15970                       "  }"
15971                       "  return sum; "
15972                       "}"
15973                       "for (var i = 0; i < 5000; ++i) {"
15974                       "  pa_init(pixels);"
15975                       "}"
15976                       "result = pa_load(pixels);"
15977                       "result");
15978   CHECK_EQ(32640, result->Int32Value());
15979
15980   free(pixel_data);
15981 }
15982
15983
15984 THREADED_TEST(PixelArrayInfo) {
15985   LocalContext context;
15986   v8::HandleScope scope(context->GetIsolate());
15987   for (int size = 0; size < 100; size += 10) {
15988     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15989     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15990     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15991     CHECK(obj->HasIndexedPropertiesInPixelData());
15992     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15993     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15994     free(pixel_data);
15995   }
15996 }
15997
15998
15999 static void NotHandledIndexedPropertyGetter(
16000     uint32_t index,
16001     const v8::PropertyCallbackInfo<v8::Value>& info) {
16002   ApiTestFuzzer::Fuzz();
16003 }
16004
16005
16006 static void NotHandledIndexedPropertySetter(
16007     uint32_t index,
16008     Local<Value> value,
16009     const v8::PropertyCallbackInfo<v8::Value>& info) {
16010   ApiTestFuzzer::Fuzz();
16011 }
16012
16013
16014 THREADED_TEST(PixelArrayWithInterceptor) {
16015   LocalContext context;
16016   i::Factory* factory = CcTest::i_isolate()->factory();
16017   v8::Isolate* isolate = context->GetIsolate();
16018   v8::HandleScope scope(isolate);
16019   const int kElementCount = 260;
16020   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16021   i::Handle<i::ExternalUint8ClampedArray> pixels =
16022       i::Handle<i::ExternalUint8ClampedArray>::cast(
16023           factory->NewExternalArray(kElementCount,
16024                                     v8::kExternalUint8ClampedArray,
16025                                     pixel_data));
16026   for (int i = 0; i < kElementCount; i++) {
16027     pixels->set(i, i % 256);
16028   }
16029   v8::Handle<v8::ObjectTemplate> templ =
16030       v8::ObjectTemplate::New(context->GetIsolate());
16031   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16032                                    NotHandledIndexedPropertySetter);
16033   v8::Handle<v8::Object> obj = templ->NewInstance();
16034   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16035   context->Global()->Set(v8_str("pixels"), obj);
16036   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16037   CHECK_EQ(1, result->Int32Value());
16038   result = CompileRun("var sum = 0;"
16039                       "for (var i = 0; i < 8; i++) {"
16040                       "  sum += pixels[i] = pixels[i] = -i;"
16041                       "}"
16042                       "sum;");
16043   CHECK_EQ(-28, result->Int32Value());
16044   result = CompileRun("pixels.hasOwnProperty('1')");
16045   CHECK(result->BooleanValue());
16046   free(pixel_data);
16047 }
16048
16049
16050 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16051   switch (array_type) {
16052     case v8::kExternalInt8Array:
16053     case v8::kExternalUint8Array:
16054     case v8::kExternalUint8ClampedArray:
16055       return 1;
16056       break;
16057     case v8::kExternalInt16Array:
16058     case v8::kExternalUint16Array:
16059       return 2;
16060       break;
16061     case v8::kExternalInt32Array:
16062     case v8::kExternalUint32Array:
16063     case v8::kExternalFloat32Array:
16064       return 4;
16065       break;
16066     case v8::kExternalFloat64Array:
16067       return 8;
16068       break;
16069     default:
16070       UNREACHABLE();
16071       return -1;
16072   }
16073   UNREACHABLE();
16074   return -1;
16075 }
16076
16077
16078 template <class ExternalArrayClass, class ElementType>
16079 static void ObjectWithExternalArrayTestHelper(
16080     Handle<Context> context,
16081     v8::Handle<Object> obj,
16082     int element_count,
16083     v8::ExternalArrayType array_type,
16084     int64_t low, int64_t high) {
16085   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16086   i::Isolate* isolate = jsobj->GetIsolate();
16087   obj->Set(v8_str("field"),
16088            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16089   context->Global()->Set(v8_str("ext_array"), obj);
16090   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16091   CHECK_EQ(1503, result->Int32Value());
16092   result = CompileRun("ext_array[1]");
16093   CHECK_EQ(1, result->Int32Value());
16094
16095   // Check assigned smis
16096   result = CompileRun("for (var i = 0; i < 8; i++) {"
16097                       "  ext_array[i] = i;"
16098                       "}"
16099                       "var sum = 0;"
16100                       "for (var i = 0; i < 8; i++) {"
16101                       "  sum += ext_array[i];"
16102                       "}"
16103                       "sum;");
16104
16105   CHECK_EQ(28, result->Int32Value());
16106   // Check pass through of assigned smis
16107   result = CompileRun("var sum = 0;"
16108                       "for (var i = 0; i < 8; i++) {"
16109                       "  sum += ext_array[i] = ext_array[i] = -i;"
16110                       "}"
16111                       "sum;");
16112   CHECK_EQ(-28, result->Int32Value());
16113
16114
16115   // Check assigned smis in reverse order
16116   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16117                       "  ext_array[i] = i;"
16118                       "}"
16119                       "var sum = 0;"
16120                       "for (var i = 0; i < 8; i++) {"
16121                       "  sum += ext_array[i];"
16122                       "}"
16123                       "sum;");
16124   CHECK_EQ(28, result->Int32Value());
16125
16126   // Check pass through of assigned HeapNumbers
16127   result = CompileRun("var sum = 0;"
16128                       "for (var i = 0; i < 16; i+=2) {"
16129                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16130                       "}"
16131                       "sum;");
16132   CHECK_EQ(-28, result->Int32Value());
16133
16134   // Check assigned HeapNumbers
16135   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16136                       "  ext_array[i] = (i * 0.5);"
16137                       "}"
16138                       "var sum = 0;"
16139                       "for (var i = 0; i < 16; i+=2) {"
16140                       "  sum += ext_array[i];"
16141                       "}"
16142                       "sum;");
16143   CHECK_EQ(28, result->Int32Value());
16144
16145   // Check assigned HeapNumbers in reverse order
16146   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16147                       "  ext_array[i] = (i * 0.5);"
16148                       "}"
16149                       "var sum = 0;"
16150                       "for (var i = 0; i < 16; i+=2) {"
16151                       "  sum += ext_array[i];"
16152                       "}"
16153                       "sum;");
16154   CHECK_EQ(28, result->Int32Value());
16155
16156   i::ScopedVector<char> test_buf(1024);
16157
16158   // Check legal boundary conditions.
16159   // The repeated loads and stores ensure the ICs are exercised.
16160   const char* boundary_program =
16161       "var res = 0;"
16162       "for (var i = 0; i < 16; i++) {"
16163       "  ext_array[i] = %lld;"
16164       "  if (i > 8) {"
16165       "    res = ext_array[i];"
16166       "  }"
16167       "}"
16168       "res;";
16169   i::OS::SNPrintF(test_buf,
16170                   boundary_program,
16171                   low);
16172   result = CompileRun(test_buf.start());
16173   CHECK_EQ(low, result->IntegerValue());
16174
16175   i::OS::SNPrintF(test_buf,
16176                   boundary_program,
16177                   high);
16178   result = CompileRun(test_buf.start());
16179   CHECK_EQ(high, result->IntegerValue());
16180
16181   // Check misprediction of type in IC.
16182   result = CompileRun("var tmp_array = ext_array;"
16183                       "var sum = 0;"
16184                       "for (var i = 0; i < 8; i++) {"
16185                       "  tmp_array[i] = i;"
16186                       "  sum += tmp_array[i];"
16187                       "  if (i == 4) {"
16188                       "    tmp_array = {};"
16189                       "  }"
16190                       "}"
16191                       "sum;");
16192   // Force GC to trigger verification.
16193   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16194   CHECK_EQ(28, result->Int32Value());
16195
16196   // Make sure out-of-range loads do not throw.
16197   i::OS::SNPrintF(test_buf,
16198                   "var caught_exception = false;"
16199                   "try {"
16200                   "  ext_array[%d];"
16201                   "} catch (e) {"
16202                   "  caught_exception = true;"
16203                   "}"
16204                   "caught_exception;",
16205                   element_count);
16206   result = CompileRun(test_buf.start());
16207   CHECK_EQ(false, result->BooleanValue());
16208
16209   // Make sure out-of-range stores do not throw.
16210   i::OS::SNPrintF(test_buf,
16211                   "var caught_exception = false;"
16212                   "try {"
16213                   "  ext_array[%d] = 1;"
16214                   "} catch (e) {"
16215                   "  caught_exception = true;"
16216                   "}"
16217                   "caught_exception;",
16218                   element_count);
16219   result = CompileRun(test_buf.start());
16220   CHECK_EQ(false, result->BooleanValue());
16221
16222   // Check other boundary conditions, values and operations.
16223   result = CompileRun("for (var i = 0; i < 8; i++) {"
16224                       "  ext_array[7] = undefined;"
16225                       "}"
16226                       "ext_array[7];");
16227   CHECK_EQ(0, result->Int32Value());
16228   if (array_type == v8::kExternalFloat64Array ||
16229       array_type == v8::kExternalFloat32Array) {
16230     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16231              static_cast<int>(
16232                  jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
16233   } else {
16234     CheckElementValue(isolate, 0, jsobj, 7);
16235   }
16236
16237   result = CompileRun("for (var i = 0; i < 8; i++) {"
16238                       "  ext_array[6] = '2.3';"
16239                       "}"
16240                       "ext_array[6];");
16241   CHECK_EQ(2, result->Int32Value());
16242   CHECK_EQ(2,
16243            static_cast<int>(
16244                jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
16245
16246   if (array_type != v8::kExternalFloat32Array &&
16247       array_type != v8::kExternalFloat64Array) {
16248     // Though the specification doesn't state it, be explicit about
16249     // converting NaNs and +/-Infinity to zero.
16250     result = CompileRun("for (var i = 0; i < 8; i++) {"
16251                         "  ext_array[i] = 5;"
16252                         "}"
16253                         "for (var i = 0; i < 8; i++) {"
16254                         "  ext_array[i] = NaN;"
16255                         "}"
16256                         "ext_array[5];");
16257     CHECK_EQ(0, result->Int32Value());
16258     CheckElementValue(isolate, 0, jsobj, 5);
16259
16260     result = CompileRun("for (var i = 0; i < 8; i++) {"
16261                         "  ext_array[i] = 5;"
16262                         "}"
16263                         "for (var i = 0; i < 8; i++) {"
16264                         "  ext_array[i] = Infinity;"
16265                         "}"
16266                         "ext_array[5];");
16267     int expected_value =
16268         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16269     CHECK_EQ(expected_value, result->Int32Value());
16270     CheckElementValue(isolate, expected_value, jsobj, 5);
16271
16272     result = CompileRun("for (var i = 0; i < 8; i++) {"
16273                         "  ext_array[i] = 5;"
16274                         "}"
16275                         "for (var i = 0; i < 8; i++) {"
16276                         "  ext_array[i] = -Infinity;"
16277                         "}"
16278                         "ext_array[5];");
16279     CHECK_EQ(0, result->Int32Value());
16280     CheckElementValue(isolate, 0, jsobj, 5);
16281
16282     // Check truncation behavior of integral arrays.
16283     const char* unsigned_data =
16284         "var source_data = [0.6, 10.6];"
16285         "var expected_results = [0, 10];";
16286     const char* signed_data =
16287         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16288         "var expected_results = [0, 10, 0, -10];";
16289     const char* pixel_data =
16290         "var source_data = [0.6, 10.6];"
16291         "var expected_results = [1, 11];";
16292     bool is_unsigned =
16293         (array_type == v8::kExternalUint8Array ||
16294          array_type == v8::kExternalUint16Array ||
16295          array_type == v8::kExternalUint32Array);
16296     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16297
16298     i::OS::SNPrintF(test_buf,
16299                     "%s"
16300                     "var all_passed = true;"
16301                     "for (var i = 0; i < source_data.length; i++) {"
16302                     "  for (var j = 0; j < 8; j++) {"
16303                     "    ext_array[j] = source_data[i];"
16304                     "  }"
16305                     "  all_passed = all_passed &&"
16306                     "               (ext_array[5] == expected_results[i]);"
16307                     "}"
16308                     "all_passed;",
16309                     (is_unsigned ?
16310                          unsigned_data :
16311                          (is_pixel_data ? pixel_data : signed_data)));
16312     result = CompileRun(test_buf.start());
16313     CHECK_EQ(true, result->BooleanValue());
16314   }
16315
16316   i::Handle<ExternalArrayClass> array(
16317       ExternalArrayClass::cast(jsobj->elements()));
16318   for (int i = 0; i < element_count; i++) {
16319     array->set(i, static_cast<ElementType>(i));
16320   }
16321
16322   // Test complex assignments
16323   result = CompileRun("function ee_op_test_complex_func(sum) {"
16324                       " for (var i = 0; i < 40; ++i) {"
16325                       "   sum += (ext_array[i] += 1);"
16326                       "   sum += (ext_array[i] -= 1);"
16327                       " } "
16328                       " return sum;"
16329                       "}"
16330                       "sum=0;"
16331                       "for (var i=0;i<10000;++i) {"
16332                       "  sum=ee_op_test_complex_func(sum);"
16333                       "}"
16334                       "sum;");
16335   CHECK_EQ(16000000, result->Int32Value());
16336
16337   // Test count operations
16338   result = CompileRun("function ee_op_test_count_func(sum) {"
16339                       " for (var i = 0; i < 40; ++i) {"
16340                       "   sum += (++ext_array[i]);"
16341                       "   sum += (--ext_array[i]);"
16342                       " } "
16343                       " return sum;"
16344                       "}"
16345                       "sum=0;"
16346                       "for (var i=0;i<10000;++i) {"
16347                       "  sum=ee_op_test_count_func(sum);"
16348                       "}"
16349                       "sum;");
16350   CHECK_EQ(16000000, result->Int32Value());
16351
16352   result = CompileRun("ext_array[3] = 33;"
16353                       "delete ext_array[3];"
16354                       "ext_array[3];");
16355   CHECK_EQ(33, result->Int32Value());
16356
16357   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16358                       "ext_array[2] = 12; ext_array[3] = 13;"
16359                       "ext_array.__defineGetter__('2',"
16360                       "function() { return 120; });"
16361                       "ext_array[2];");
16362   CHECK_EQ(12, result->Int32Value());
16363
16364   result = CompileRun("var js_array = new Array(40);"
16365                       "js_array[0] = 77;"
16366                       "js_array;");
16367   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16368
16369   result = CompileRun("ext_array[1] = 23;"
16370                       "ext_array.__proto__ = [];"
16371                       "js_array.__proto__ = ext_array;"
16372                       "js_array.concat(ext_array);");
16373   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16374   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16375
16376   result = CompileRun("ext_array[1] = 23;");
16377   CHECK_EQ(23, result->Int32Value());
16378 }
16379
16380
16381 template <class FixedTypedArrayClass,
16382           i::ElementsKind elements_kind,
16383           class ElementType>
16384 static void FixedTypedArrayTestHelper(
16385     v8::ExternalArrayType array_type,
16386     ElementType low,
16387     ElementType high) {
16388   i::FLAG_allow_natives_syntax = true;
16389   LocalContext context;
16390   i::Isolate* isolate = CcTest::i_isolate();
16391   i::Factory* factory = isolate->factory();
16392   v8::HandleScope scope(context->GetIsolate());
16393   const int kElementCount = 260;
16394   i::Handle<FixedTypedArrayClass> fixed_array =
16395     i::Handle<FixedTypedArrayClass>::cast(
16396         factory->NewFixedTypedArray(kElementCount, array_type));
16397   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16398            fixed_array->map()->instance_type());
16399   CHECK_EQ(kElementCount, fixed_array->length());
16400   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16401   for (int i = 0; i < kElementCount; i++) {
16402     fixed_array->set(i, static_cast<ElementType>(i));
16403   }
16404   // Force GC to trigger verification.
16405   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16406   for (int i = 0; i < kElementCount; i++) {
16407     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16408              static_cast<int64_t>(fixed_array->get_scalar(i)));
16409   }
16410   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16411   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16412   i::Handle<i::Map> fixed_array_map =
16413       isolate->factory()->GetElementsTransitionMap(jsobj, elements_kind);
16414   jsobj->set_map(*fixed_array_map);
16415   jsobj->set_elements(*fixed_array);
16416
16417   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16418       context.local(), obj, kElementCount, array_type,
16419       static_cast<int64_t>(low),
16420       static_cast<int64_t>(high));
16421 }
16422
16423
16424 THREADED_TEST(FixedUint8Array) {
16425   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16426     v8::kExternalUint8Array,
16427     0x0, 0xFF);
16428 }
16429
16430
16431 THREADED_TEST(FixedUint8ClampedArray) {
16432   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16433                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16434     v8::kExternalUint8ClampedArray,
16435     0x0, 0xFF);
16436 }
16437
16438
16439 THREADED_TEST(FixedInt8Array) {
16440   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16441     v8::kExternalInt8Array,
16442     -0x80, 0x7F);
16443 }
16444
16445
16446 THREADED_TEST(FixedUint16Array) {
16447   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16448     v8::kExternalUint16Array,
16449     0x0, 0xFFFF);
16450 }
16451
16452
16453 THREADED_TEST(FixedInt16Array) {
16454   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16455     v8::kExternalInt16Array,
16456     -0x8000, 0x7FFF);
16457 }
16458
16459
16460 THREADED_TEST(FixedUint32Array) {
16461   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16462     v8::kExternalUint32Array,
16463     0x0, UINT_MAX);
16464 }
16465
16466
16467 THREADED_TEST(FixedInt32Array) {
16468   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16469     v8::kExternalInt32Array,
16470     INT_MIN, INT_MAX);
16471 }
16472
16473
16474 THREADED_TEST(FixedFloat32Array) {
16475   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16476     v8::kExternalFloat32Array,
16477     -500, 500);
16478 }
16479
16480
16481 THREADED_TEST(FixedFloat64Array) {
16482   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16483     v8::kExternalFloat64Array,
16484     -500, 500);
16485 }
16486
16487
16488 template <class ExternalArrayClass, class ElementType>
16489 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16490                                     int64_t low,
16491                                     int64_t high) {
16492   LocalContext context;
16493   i::Isolate* isolate = CcTest::i_isolate();
16494   i::Factory* factory = isolate->factory();
16495   v8::HandleScope scope(context->GetIsolate());
16496   const int kElementCount = 40;
16497   int element_size = ExternalArrayElementSize(array_type);
16498   ElementType* array_data =
16499       static_cast<ElementType*>(malloc(kElementCount * element_size));
16500   i::Handle<ExternalArrayClass> array =
16501       i::Handle<ExternalArrayClass>::cast(
16502           factory->NewExternalArray(kElementCount, array_type, array_data));
16503   // Force GC to trigger verification.
16504   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16505   for (int i = 0; i < kElementCount; i++) {
16506     array->set(i, static_cast<ElementType>(i));
16507   }
16508   // Force GC to trigger verification.
16509   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16510   for (int i = 0; i < kElementCount; i++) {
16511     CHECK_EQ(static_cast<int64_t>(i),
16512              static_cast<int64_t>(array->get_scalar(i)));
16513     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16514   }
16515
16516   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16517   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16518   // Set the elements to be the external array.
16519   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16520                                                array_type,
16521                                                kElementCount);
16522   CHECK_EQ(1,
16523            static_cast<int>(
16524                jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
16525
16526   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16527       context.local(), obj, kElementCount, array_type, low, high);
16528
16529   v8::Handle<v8::Value> result;
16530
16531   // Test more complex manipulations which cause eax to contain values
16532   // that won't be completely overwritten by loads from the arrays.
16533   // This catches bugs in the instructions used for the KeyedLoadIC
16534   // for byte and word types.
16535   {
16536     const int kXSize = 300;
16537     const int kYSize = 300;
16538     const int kLargeElementCount = kXSize * kYSize * 4;
16539     ElementType* large_array_data =
16540         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16541     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16542     // Set the elements to be the external array.
16543     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16544                                                        array_type,
16545                                                        kLargeElementCount);
16546     context->Global()->Set(v8_str("large_array"), large_obj);
16547     // Initialize contents of a few rows.
16548     for (int x = 0; x < 300; x++) {
16549       int row = 0;
16550       int offset = row * 300 * 4;
16551       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16552       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16553       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16554       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16555       row = 150;
16556       offset = row * 300 * 4;
16557       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16558       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16559       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16560       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16561       row = 298;
16562       offset = row * 300 * 4;
16563       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16564       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16565       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16566       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16567     }
16568     // The goal of the code below is to make "offset" large enough
16569     // that the computation of the index (which goes into eax) has
16570     // high bits set which will not be overwritten by a byte or short
16571     // load.
16572     result = CompileRun("var failed = false;"
16573                         "var offset = 0;"
16574                         "for (var i = 0; i < 300; i++) {"
16575                         "  if (large_array[4 * i] != 127 ||"
16576                         "      large_array[4 * i + 1] != 0 ||"
16577                         "      large_array[4 * i + 2] != 0 ||"
16578                         "      large_array[4 * i + 3] != 127) {"
16579                         "    failed = true;"
16580                         "  }"
16581                         "}"
16582                         "offset = 150 * 300 * 4;"
16583                         "for (var i = 0; i < 300; i++) {"
16584                         "  if (large_array[offset + 4 * i] != 127 ||"
16585                         "      large_array[offset + 4 * i + 1] != 0 ||"
16586                         "      large_array[offset + 4 * i + 2] != 0 ||"
16587                         "      large_array[offset + 4 * i + 3] != 127) {"
16588                         "    failed = true;"
16589                         "  }"
16590                         "}"
16591                         "offset = 298 * 300 * 4;"
16592                         "for (var i = 0; i < 300; i++) {"
16593                         "  if (large_array[offset + 4 * i] != 127 ||"
16594                         "      large_array[offset + 4 * i + 1] != 0 ||"
16595                         "      large_array[offset + 4 * i + 2] != 0 ||"
16596                         "      large_array[offset + 4 * i + 3] != 127) {"
16597                         "    failed = true;"
16598                         "  }"
16599                         "}"
16600                         "!failed;");
16601     CHECK_EQ(true, result->BooleanValue());
16602     free(large_array_data);
16603   }
16604
16605   // The "" property descriptor is overloaded to store information about
16606   // the external array. Ensure that setting and accessing the "" property
16607   // works (it should overwrite the information cached about the external
16608   // array in the DescriptorArray) in various situations.
16609   result = CompileRun("ext_array[''] = 23; ext_array['']");
16610   CHECK_EQ(23, result->Int32Value());
16611
16612   // Property "" set after the external array is associated with the object.
16613   {
16614     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16615     obj2->Set(v8_str("ee_test_field"),
16616               v8::Int32::New(context->GetIsolate(), 256));
16617     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16618     // Set the elements to be the external array.
16619     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16620                                                   array_type,
16621                                                   kElementCount);
16622     context->Global()->Set(v8_str("ext_array"), obj2);
16623     result = CompileRun("ext_array['']");
16624     CHECK_EQ(1503, result->Int32Value());
16625   }
16626
16627   // Property "" set after the external array is associated with the object.
16628   {
16629     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16630     obj2->Set(v8_str("ee_test_field_2"),
16631               v8::Int32::New(context->GetIsolate(), 256));
16632     // Set the elements to be the external array.
16633     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16634                                                   array_type,
16635                                                   kElementCount);
16636     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16637     context->Global()->Set(v8_str("ext_array"), obj2);
16638     result = CompileRun("ext_array['']");
16639     CHECK_EQ(1503, result->Int32Value());
16640   }
16641
16642   // Should reuse the map from previous test.
16643   {
16644     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16645     obj2->Set(v8_str("ee_test_field_2"),
16646               v8::Int32::New(context->GetIsolate(), 256));
16647     // Set the elements to be the external array. Should re-use the map
16648     // from previous test.
16649     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16650                                                   array_type,
16651                                                   kElementCount);
16652     context->Global()->Set(v8_str("ext_array"), obj2);
16653     result = CompileRun("ext_array['']");
16654   }
16655
16656   // Property "" is a constant function that shouldn't not be interfered with
16657   // when an external array is set.
16658   {
16659     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16660     // Start
16661     obj2->Set(v8_str("ee_test_field3"),
16662               v8::Int32::New(context->GetIsolate(), 256));
16663
16664     // Add a constant function to an object.
16665     context->Global()->Set(v8_str("ext_array"), obj2);
16666     result = CompileRun("ext_array[''] = function() {return 1503;};"
16667                         "ext_array['']();");
16668
16669     // Add an external array transition to the same map that
16670     // has the constant transition.
16671     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16672     obj3->Set(v8_str("ee_test_field3"),
16673               v8::Int32::New(context->GetIsolate(), 256));
16674     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16675                                                   array_type,
16676                                                   kElementCount);
16677     context->Global()->Set(v8_str("ext_array"), obj3);
16678   }
16679
16680   // If a external array transition is in the map, it should get clobbered
16681   // by a constant function.
16682   {
16683     // Add an external array transition.
16684     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16685     obj3->Set(v8_str("ee_test_field4"),
16686               v8::Int32::New(context->GetIsolate(), 256));
16687     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16688                                                   array_type,
16689                                                   kElementCount);
16690
16691     // Add a constant function to the same map that just got an external array
16692     // transition.
16693     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16694     obj2->Set(v8_str("ee_test_field4"),
16695               v8::Int32::New(context->GetIsolate(), 256));
16696     context->Global()->Set(v8_str("ext_array"), obj2);
16697     result = CompileRun("ext_array[''] = function() {return 1503;};"
16698                         "ext_array['']();");
16699   }
16700
16701   free(array_data);
16702 }
16703
16704
16705 THREADED_TEST(ExternalInt8Array) {
16706   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16707       v8::kExternalInt8Array,
16708       -128,
16709       127);
16710 }
16711
16712
16713 THREADED_TEST(ExternalUint8Array) {
16714   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16715       v8::kExternalUint8Array,
16716       0,
16717       255);
16718 }
16719
16720
16721 THREADED_TEST(ExternalUint8ClampedArray) {
16722   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16723       v8::kExternalUint8ClampedArray,
16724       0,
16725       255);
16726 }
16727
16728
16729 THREADED_TEST(ExternalInt16Array) {
16730   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16731       v8::kExternalInt16Array,
16732       -32768,
16733       32767);
16734 }
16735
16736
16737 THREADED_TEST(ExternalUint16Array) {
16738   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16739       v8::kExternalUint16Array,
16740       0,
16741       65535);
16742 }
16743
16744
16745 THREADED_TEST(ExternalInt32Array) {
16746   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16747       v8::kExternalInt32Array,
16748       INT_MIN,   // -2147483648
16749       INT_MAX);  //  2147483647
16750 }
16751
16752
16753 THREADED_TEST(ExternalUint32Array) {
16754   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16755       v8::kExternalUint32Array,
16756       0,
16757       UINT_MAX);  // 4294967295
16758 }
16759
16760
16761 THREADED_TEST(ExternalFloat32Array) {
16762   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16763       v8::kExternalFloat32Array,
16764       -500,
16765       500);
16766 }
16767
16768
16769 THREADED_TEST(ExternalFloat64Array) {
16770   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16771       v8::kExternalFloat64Array,
16772       -500,
16773       500);
16774 }
16775
16776
16777 THREADED_TEST(ExternalArrays) {
16778   TestExternalInt8Array();
16779   TestExternalUint8Array();
16780   TestExternalInt16Array();
16781   TestExternalUint16Array();
16782   TestExternalInt32Array();
16783   TestExternalUint32Array();
16784   TestExternalFloat32Array();
16785 }
16786
16787
16788 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16789   LocalContext context;
16790   v8::HandleScope scope(context->GetIsolate());
16791   for (int size = 0; size < 100; size += 10) {
16792     int element_size = ExternalArrayElementSize(array_type);
16793     void* external_data = malloc(size * element_size);
16794     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16795     obj->SetIndexedPropertiesToExternalArrayData(
16796         external_data, array_type, size);
16797     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16798     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16799     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16800     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16801     free(external_data);
16802   }
16803 }
16804
16805
16806 THREADED_TEST(ExternalArrayInfo) {
16807   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16808   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16809   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16810   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16811   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16812   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16813   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16814   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16815   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16816 }
16817
16818
16819 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16820                           v8::ExternalArrayType array_type,
16821                           int size) {
16822   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16823   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16824   last_location = last_message = NULL;
16825   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16826   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16827   CHECK_NE(NULL, last_location);
16828   CHECK_NE(NULL, last_message);
16829 }
16830
16831
16832 TEST(ExternalArrayLimits) {
16833   LocalContext context;
16834   v8::Isolate* isolate = context->GetIsolate();
16835   v8::HandleScope scope(isolate);
16836   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16837   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16838   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16839   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16840   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16841   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16842   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16843   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16844   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16845   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16846   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16847   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16848   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16849   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16850   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16851   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16852   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16853   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16854 }
16855
16856
16857 template <typename ElementType, typename TypedArray,
16858           class ExternalArrayClass>
16859 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16860                           int64_t low, int64_t high) {
16861   const int kElementCount = 50;
16862
16863   i::ScopedVector<ElementType> backing_store(kElementCount+2);
16864
16865   LocalContext env;
16866   v8::Isolate* isolate = env->GetIsolate();
16867   v8::HandleScope handle_scope(isolate);
16868
16869   Local<v8::ArrayBuffer> ab =
16870       v8::ArrayBuffer::New(isolate, backing_store.start(),
16871                            (kElementCount + 2) * sizeof(ElementType));
16872   Local<TypedArray> ta =
16873       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16874   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16875   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16876   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16877   CHECK_EQ(kElementCount*sizeof(ElementType),
16878            static_cast<int>(ta->ByteLength()));
16879   CHECK_EQ(ab, ta->Buffer());
16880
16881   ElementType* data = backing_store.start() + 2;
16882   for (int i = 0; i < kElementCount; i++) {
16883     data[i] = static_cast<ElementType>(i);
16884   }
16885
16886   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16887       env.local(), ta, kElementCount, array_type, low, high);
16888 }
16889
16890
16891 THREADED_TEST(Uint8Array) {
16892   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16893       v8::kExternalUint8Array, 0, 0xFF);
16894 }
16895
16896
16897 THREADED_TEST(Int8Array) {
16898   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
16899       v8::kExternalInt8Array, -0x80, 0x7F);
16900 }
16901
16902
16903 THREADED_TEST(Uint16Array) {
16904   TypedArrayTestHelper<uint16_t,
16905                        v8::Uint16Array,
16906                        i::ExternalUint16Array>(
16907       v8::kExternalUint16Array, 0, 0xFFFF);
16908 }
16909
16910
16911 THREADED_TEST(Int16Array) {
16912   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
16913       v8::kExternalInt16Array, -0x8000, 0x7FFF);
16914 }
16915
16916
16917 THREADED_TEST(Uint32Array) {
16918   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
16919       v8::kExternalUint32Array, 0, UINT_MAX);
16920 }
16921
16922
16923 THREADED_TEST(Int32Array) {
16924   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
16925       v8::kExternalInt32Array, INT_MIN, INT_MAX);
16926 }
16927
16928
16929 THREADED_TEST(Float32Array) {
16930   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
16931       v8::kExternalFloat32Array, -500, 500);
16932 }
16933
16934
16935 THREADED_TEST(Float64Array) {
16936   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
16937       v8::kExternalFloat64Array, -500, 500);
16938 }
16939
16940
16941 THREADED_TEST(Uint8ClampedArray) {
16942   TypedArrayTestHelper<uint8_t,
16943                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
16944       v8::kExternalUint8ClampedArray, 0, 0xFF);
16945 }
16946
16947
16948 THREADED_TEST(DataView) {
16949   const int kSize = 50;
16950
16951   i::ScopedVector<uint8_t> backing_store(kSize+2);
16952
16953   LocalContext env;
16954   v8::Isolate* isolate = env->GetIsolate();
16955   v8::HandleScope handle_scope(isolate);
16956
16957   Local<v8::ArrayBuffer> ab =
16958       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16959   Local<v8::DataView> dv =
16960       v8::DataView::New(ab, 2, kSize);
16961   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16962   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16963   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16964   CHECK_EQ(ab, dv->Buffer());
16965 }
16966
16967
16968 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
16969   THREADED_TEST(Is##View) {                                                   \
16970     LocalContext env;                                                         \
16971     v8::Isolate* isolate = env->GetIsolate();                                 \
16972     v8::HandleScope handle_scope(isolate);                                    \
16973                                                                               \
16974     Handle<Value> result = CompileRun(                                        \
16975         "var ab = new ArrayBuffer(128);"                                      \
16976         "new " #View "(ab)");                                                 \
16977     CHECK(result->IsArrayBufferView());                                       \
16978     CHECK(result->Is##View());                                                \
16979     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
16980   }
16981
16982 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16983 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16984 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16985 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16986 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16987 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16988 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16989 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16990 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16991 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16992
16993 #undef IS_ARRAY_BUFFER_VIEW_TEST
16994
16995
16996
16997 THREADED_TEST(ScriptContextDependence) {
16998   LocalContext c1;
16999   v8::HandleScope scope(c1->GetIsolate());
17000   const char *source = "foo";
17001   v8::Handle<v8::Script> dep =
17002       v8::Script::Compile(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17003   v8::Handle<v8::Script> indep =
17004       v8::Script::New(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17005   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17006                     v8::Integer::New(c1->GetIsolate(), 100));
17007   CHECK_EQ(dep->Run()->Int32Value(), 100);
17008   CHECK_EQ(indep->Run()->Int32Value(), 100);
17009   LocalContext c2;
17010   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17011                     v8::Integer::New(c2->GetIsolate(), 101));
17012   CHECK_EQ(dep->Run()->Int32Value(), 100);
17013   CHECK_EQ(indep->Run()->Int32Value(), 101);
17014 }
17015
17016
17017 THREADED_TEST(StackTrace) {
17018   LocalContext context;
17019   v8::HandleScope scope(context->GetIsolate());
17020   v8::TryCatch try_catch;
17021   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17022   v8::Handle<v8::String> src =
17023       v8::String::NewFromUtf8(context->GetIsolate(), source);
17024   v8::Handle<v8::String> origin =
17025       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17026   v8::Script::New(src, origin)->Run();
17027   CHECK(try_catch.HasCaught());
17028   v8::String::Utf8Value stack(try_catch.StackTrace());
17029   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17030 }
17031
17032
17033 // Checks that a StackFrame has certain expected values.
17034 void checkStackFrame(const char* expected_script_name,
17035     const char* expected_func_name, int expected_line_number,
17036     int expected_column, bool is_eval, bool is_constructor,
17037     v8::Handle<v8::StackFrame> frame) {
17038   v8::HandleScope scope(CcTest::isolate());
17039   v8::String::Utf8Value func_name(frame->GetFunctionName());
17040   v8::String::Utf8Value script_name(frame->GetScriptName());
17041   if (*script_name == NULL) {
17042     // The situation where there is no associated script, like for evals.
17043     CHECK(expected_script_name == NULL);
17044   } else {
17045     CHECK(strstr(*script_name, expected_script_name) != NULL);
17046   }
17047   CHECK(strstr(*func_name, expected_func_name) != NULL);
17048   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17049   CHECK_EQ(expected_column, frame->GetColumn());
17050   CHECK_EQ(is_eval, frame->IsEval());
17051   CHECK_EQ(is_constructor, frame->IsConstructor());
17052 }
17053
17054
17055 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17056   v8::HandleScope scope(args.GetIsolate());
17057   const char* origin = "capture-stack-trace-test";
17058   const int kOverviewTest = 1;
17059   const int kDetailedTest = 2;
17060
17061   ASSERT(args.Length() == 1);
17062
17063   int testGroup = args[0]->Int32Value();
17064   if (testGroup == kOverviewTest) {
17065     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17066         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17067     CHECK_EQ(4, stackTrace->GetFrameCount());
17068     checkStackFrame(origin, "bar", 2, 10, false, false,
17069                     stackTrace->GetFrame(0));
17070     checkStackFrame(origin, "foo", 6, 3, false, false,
17071                     stackTrace->GetFrame(1));
17072     // This is the source string inside the eval which has the call to foo.
17073     checkStackFrame(NULL, "", 1, 5, false, false,
17074                     stackTrace->GetFrame(2));
17075     // The last frame is an anonymous function which has the initial eval call.
17076     checkStackFrame(origin, "", 8, 7, false, false,
17077                     stackTrace->GetFrame(3));
17078
17079     CHECK(stackTrace->AsArray()->IsArray());
17080   } else if (testGroup == kDetailedTest) {
17081     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17082         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17083     CHECK_EQ(4, stackTrace->GetFrameCount());
17084     checkStackFrame(origin, "bat", 4, 22, false, false,
17085                     stackTrace->GetFrame(0));
17086     checkStackFrame(origin, "baz", 8, 3, false, true,
17087                     stackTrace->GetFrame(1));
17088 #ifdef ENABLE_DEBUGGER_SUPPORT
17089     bool is_eval = true;
17090 #else  // ENABLE_DEBUGGER_SUPPORT
17091     bool is_eval = false;
17092 #endif  // ENABLE_DEBUGGER_SUPPORT
17093
17094     // This is the source string inside the eval which has the call to baz.
17095     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17096                     stackTrace->GetFrame(2));
17097     // The last frame is an anonymous function which has the initial eval call.
17098     checkStackFrame(origin, "", 10, 1, false, false,
17099                     stackTrace->GetFrame(3));
17100
17101     CHECK(stackTrace->AsArray()->IsArray());
17102   }
17103 }
17104
17105
17106 // Tests the C++ StackTrace API.
17107 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17108 // THREADED_TEST(CaptureStackTrace) {
17109 TEST(CaptureStackTrace) {
17110   v8::Isolate* isolate = CcTest::isolate();
17111   v8::HandleScope scope(isolate);
17112   v8::Handle<v8::String> origin =
17113       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17114   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17115   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17116              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17117   LocalContext context(0, templ);
17118
17119   // Test getting OVERVIEW information. Should ignore information that is not
17120   // script name, function name, line number, and column offset.
17121   const char *overview_source =
17122     "function bar() {\n"
17123     "  var y; AnalyzeStackInNativeCode(1);\n"
17124     "}\n"
17125     "function foo() {\n"
17126     "\n"
17127     "  bar();\n"
17128     "}\n"
17129     "var x;eval('new foo();');";
17130   v8::Handle<v8::String> overview_src =
17131       v8::String::NewFromUtf8(isolate, overview_source);
17132   v8::Handle<Value> overview_result(
17133       v8::Script::New(overview_src, origin)->Run());
17134   CHECK(!overview_result.IsEmpty());
17135   CHECK(overview_result->IsObject());
17136
17137   // Test getting DETAILED information.
17138   const char *detailed_source =
17139     "function bat() {AnalyzeStackInNativeCode(2);\n"
17140     "}\n"
17141     "\n"
17142     "function baz() {\n"
17143     "  bat();\n"
17144     "}\n"
17145     "eval('new baz();');";
17146   v8::Handle<v8::String> detailed_src =
17147       v8::String::NewFromUtf8(isolate, detailed_source);
17148   // Make the script using a non-zero line and column offset.
17149   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17150   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17151   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17152   v8::Handle<v8::Script> detailed_script(
17153       v8::Script::New(detailed_src, &detailed_origin));
17154   v8::Handle<Value> detailed_result(detailed_script->Run());
17155   CHECK(!detailed_result.IsEmpty());
17156   CHECK(detailed_result->IsObject());
17157 }
17158
17159
17160 static void StackTraceForUncaughtExceptionListener(
17161     v8::Handle<v8::Message> message,
17162     v8::Handle<Value>) {
17163   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17164   CHECK_EQ(2, stack_trace->GetFrameCount());
17165   checkStackFrame("origin", "foo", 2, 3, false, false,
17166                   stack_trace->GetFrame(0));
17167   checkStackFrame("origin", "bar", 5, 3, false, false,
17168                   stack_trace->GetFrame(1));
17169 }
17170
17171
17172 TEST(CaptureStackTraceForUncaughtException) {
17173   report_count = 0;
17174   LocalContext env;
17175   v8::HandleScope scope(env->GetIsolate());
17176   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17177   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17178
17179   Script::Compile(v8_str("function foo() {\n"
17180                          "  throw 1;\n"
17181                          "};\n"
17182                          "function bar() {\n"
17183                          "  foo();\n"
17184                          "};"),
17185                   v8_str("origin"))->Run();
17186   v8::Local<v8::Object> global = env->Global();
17187   Local<Value> trouble = global->Get(v8_str("bar"));
17188   CHECK(trouble->IsFunction());
17189   Function::Cast(*trouble)->Call(global, 0, NULL);
17190   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17191   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17192 }
17193
17194
17195 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17196   LocalContext env;
17197   v8::HandleScope scope(env->GetIsolate());
17198   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17199                                                     1024,
17200                                                     v8::StackTrace::kDetailed);
17201
17202   CompileRun(
17203       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17204       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17205       "    'isConstructor'];\n"
17206       "for (var i = 0; i < setters.length; i++) {\n"
17207       "  var prop = setters[i];\n"
17208       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17209       "}\n");
17210   CompileRun("throw 'exception';");
17211   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17212 }
17213
17214
17215 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17216                                      v8::Handle<v8::Value> data) {
17217   // Use the frame where JavaScript is called from.
17218   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17219   CHECK(!stack_trace.IsEmpty());
17220   int frame_count = stack_trace->GetFrameCount();
17221   CHECK_EQ(3, frame_count);
17222   int line_number[] = {1, 2, 5};
17223   for (int i = 0; i < frame_count; i++) {
17224     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17225   }
17226 }
17227
17228
17229 // Test that we only return the stack trace at the site where the exception
17230 // is first thrown (not where it is rethrown).
17231 TEST(RethrowStackTrace) {
17232   LocalContext env;
17233   v8::HandleScope scope(env->GetIsolate());
17234   // We make sure that
17235   // - the stack trace of the ReferenceError in g() is reported.
17236   // - the stack trace is not overwritten when e1 is rethrown by t().
17237   // - the stack trace of e2 does not overwrite that of e1.
17238   const char* source =
17239       "function g() { error; }          \n"
17240       "function f() { g(); }            \n"
17241       "function t(e) { throw e; }       \n"
17242       "try {                            \n"
17243       "  f();                           \n"
17244       "} catch (e1) {                   \n"
17245       "  try {                          \n"
17246       "    error;                       \n"
17247       "  } catch (e2) {                 \n"
17248       "    t(e1);                       \n"
17249       "  }                              \n"
17250       "}                                \n";
17251   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17252   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17253   CompileRun(source);
17254   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17255   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17256 }
17257
17258
17259 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17260                                               v8::Handle<v8::Value> data) {
17261   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17262   CHECK(!stack_trace.IsEmpty());
17263   int frame_count = stack_trace->GetFrameCount();
17264   CHECK_EQ(2, frame_count);
17265   int line_number[] = {3, 7};
17266   for (int i = 0; i < frame_count; i++) {
17267     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17268   }
17269 }
17270
17271
17272 // Test that we do not recognize identity for primitive exceptions.
17273 TEST(RethrowPrimitiveStackTrace) {
17274   LocalContext env;
17275   v8::HandleScope scope(env->GetIsolate());
17276   // We do not capture stack trace for non Error objects on creation time.
17277   // Instead, we capture the stack trace on last throw.
17278   const char* source =
17279       "function g() { throw 404; }      \n"
17280       "function f() { g(); }            \n"
17281       "function t(e) { throw e; }       \n"
17282       "try {                            \n"
17283       "  f();                           \n"
17284       "} catch (e1) {                   \n"
17285       "  t(e1)                          \n"
17286       "}                                \n";
17287   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17288   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17289   CompileRun(source);
17290   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17291   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17292 }
17293
17294
17295 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17296                                               v8::Handle<v8::Value> data) {
17297   // Use the frame where JavaScript is called from.
17298   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17299   CHECK(!stack_trace.IsEmpty());
17300   CHECK_EQ(1, stack_trace->GetFrameCount());
17301   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17302 }
17303
17304
17305 // Test that the stack trace is captured when the error object is created and
17306 // not where it is thrown.
17307 TEST(RethrowExistingStackTrace) {
17308   LocalContext env;
17309   v8::HandleScope scope(env->GetIsolate());
17310   const char* source =
17311       "var e = new Error();           \n"
17312       "throw e;                       \n";
17313   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17314   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17315   CompileRun(source);
17316   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17317   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17318 }
17319
17320
17321 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17322                                                v8::Handle<v8::Value> data) {
17323   // Use the frame where JavaScript is called from.
17324   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17325   CHECK(!stack_trace.IsEmpty());
17326   CHECK_EQ(1, stack_trace->GetFrameCount());
17327   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17328 }
17329
17330
17331 // Test that the stack trace is captured where the bogus Error object is thrown.
17332 TEST(RethrowBogusErrorStackTrace) {
17333   LocalContext env;
17334   v8::HandleScope scope(env->GetIsolate());
17335   const char* source =
17336       "var e = {__proto__: new Error()} \n"
17337       "throw e;                         \n";
17338   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17339   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17340   CompileRun(source);
17341   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17342   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17343 }
17344
17345
17346 void AnalyzeStackOfEvalWithSourceURL(
17347     const v8::FunctionCallbackInfo<v8::Value>& args) {
17348   v8::HandleScope scope(args.GetIsolate());
17349   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17350       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17351   CHECK_EQ(5, stackTrace->GetFrameCount());
17352   v8::Handle<v8::String> url = v8_str("eval_url");
17353   for (int i = 0; i < 3; i++) {
17354     v8::Handle<v8::String> name =
17355         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17356     CHECK(!name.IsEmpty());
17357     CHECK_EQ(url, name);
17358   }
17359 }
17360
17361
17362 TEST(SourceURLInStackTrace) {
17363   v8::Isolate* isolate = CcTest::isolate();
17364   v8::HandleScope scope(isolate);
17365   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17366   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17367              v8::FunctionTemplate::New(isolate,
17368                                        AnalyzeStackOfEvalWithSourceURL));
17369   LocalContext context(0, templ);
17370
17371   const char *source =
17372     "function outer() {\n"
17373     "function bar() {\n"
17374     "  AnalyzeStackOfEvalWithSourceURL();\n"
17375     "}\n"
17376     "function foo() {\n"
17377     "\n"
17378     "  bar();\n"
17379     "}\n"
17380     "foo();\n"
17381     "}\n"
17382     "eval('(' + outer +')()%s');";
17383
17384   i::ScopedVector<char> code(1024);
17385   i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17386   CHECK(CompileRun(code.start())->IsUndefined());
17387   i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17388   CHECK(CompileRun(code.start())->IsUndefined());
17389 }
17390
17391
17392 static int scriptIdInStack[2];
17393
17394 void AnalyzeScriptIdInStack(
17395     const v8::FunctionCallbackInfo<v8::Value>& args) {
17396   v8::HandleScope scope(args.GetIsolate());
17397   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17398       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17399   CHECK_EQ(2, stackTrace->GetFrameCount());
17400   for (int i = 0; i < 2; i++) {
17401     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17402   }
17403 }
17404
17405
17406 TEST(ScriptIdInStackTrace) {
17407   v8::Isolate* isolate = CcTest::isolate();
17408   v8::HandleScope scope(isolate);
17409   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17410   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17411              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17412   LocalContext context(0, templ);
17413
17414   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17415     isolate,
17416     "function foo() {\n"
17417     "  AnalyzeScriptIdInStack();"
17418     "}\n"
17419     "foo();\n");
17420   v8::ScriptOrigin origin =
17421       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"));
17422   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17423   script->Run();
17424   for (int i = 0; i < 2; i++) {
17425     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17426     CHECK_EQ(scriptIdInStack[i], script->GetId());
17427   }
17428 }
17429
17430
17431 void AnalyzeStackOfInlineScriptWithSourceURL(
17432     const v8::FunctionCallbackInfo<v8::Value>& args) {
17433   v8::HandleScope scope(args.GetIsolate());
17434   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17435       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17436   CHECK_EQ(4, stackTrace->GetFrameCount());
17437   v8::Handle<v8::String> url = v8_str("url");
17438   for (int i = 0; i < 3; i++) {
17439     v8::Handle<v8::String> name =
17440         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17441     CHECK(!name.IsEmpty());
17442     CHECK_EQ(url, name);
17443   }
17444 }
17445
17446
17447 TEST(InlineScriptWithSourceURLInStackTrace) {
17448   v8::Isolate* isolate = CcTest::isolate();
17449   v8::HandleScope scope(isolate);
17450   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17451   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17452              v8::FunctionTemplate::New(
17453                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17454   LocalContext context(0, templ);
17455
17456   const char *source =
17457     "function outer() {\n"
17458     "function bar() {\n"
17459     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17460     "}\n"
17461     "function foo() {\n"
17462     "\n"
17463     "  bar();\n"
17464     "}\n"
17465     "foo();\n"
17466     "}\n"
17467     "outer()\n%s";
17468
17469   i::ScopedVector<char> code(1024);
17470   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17471   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17472   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17473   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17474 }
17475
17476
17477 void AnalyzeStackOfDynamicScriptWithSourceURL(
17478     const v8::FunctionCallbackInfo<v8::Value>& args) {
17479   v8::HandleScope scope(args.GetIsolate());
17480   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17481       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17482   CHECK_EQ(4, stackTrace->GetFrameCount());
17483   v8::Handle<v8::String> url = v8_str("source_url");
17484   for (int i = 0; i < 3; i++) {
17485     v8::Handle<v8::String> name =
17486         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17487     CHECK(!name.IsEmpty());
17488     CHECK_EQ(url, name);
17489   }
17490 }
17491
17492
17493 TEST(DynamicWithSourceURLInStackTrace) {
17494   v8::Isolate* isolate = CcTest::isolate();
17495   v8::HandleScope scope(isolate);
17496   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17497   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17498              v8::FunctionTemplate::New(
17499                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17500   LocalContext context(0, templ);
17501
17502   const char *source =
17503     "function outer() {\n"
17504     "function bar() {\n"
17505     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17506     "}\n"
17507     "function foo() {\n"
17508     "\n"
17509     "  bar();\n"
17510     "}\n"
17511     "foo();\n"
17512     "}\n"
17513     "outer()\n%s";
17514
17515   i::ScopedVector<char> code(1024);
17516   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17517   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17518   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17519   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17520 }
17521
17522
17523 static void CreateGarbageInOldSpace() {
17524   i::Factory* factory = CcTest::i_isolate()->factory();
17525   v8::HandleScope scope(CcTest::isolate());
17526   i::AlwaysAllocateScope always_allocate;
17527   for (int i = 0; i < 1000; i++) {
17528     factory->NewFixedArray(1000, i::TENURED);
17529   }
17530 }
17531
17532
17533 // Test that idle notification can be handled and eventually returns true.
17534 TEST(IdleNotification) {
17535   const intptr_t MB = 1024 * 1024;
17536   LocalContext env;
17537   v8::HandleScope scope(env->GetIsolate());
17538   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17539   CreateGarbageInOldSpace();
17540   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17541   CHECK_GT(size_with_garbage, initial_size + MB);
17542   bool finished = false;
17543   for (int i = 0; i < 200 && !finished; i++) {
17544     finished = v8::V8::IdleNotification();
17545   }
17546   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17547   CHECK(finished);
17548   CHECK_LT(final_size, initial_size + 1);
17549 }
17550
17551
17552 // Test that idle notification can be handled and eventually collects garbage.
17553 TEST(IdleNotificationWithSmallHint) {
17554   const intptr_t MB = 1024 * 1024;
17555   const int IdlePauseInMs = 900;
17556   LocalContext env;
17557   v8::HandleScope scope(env->GetIsolate());
17558   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17559   CreateGarbageInOldSpace();
17560   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17561   CHECK_GT(size_with_garbage, initial_size + MB);
17562   bool finished = false;
17563   for (int i = 0; i < 200 && !finished; i++) {
17564     finished = v8::V8::IdleNotification(IdlePauseInMs);
17565   }
17566   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17567   CHECK(finished);
17568   CHECK_LT(final_size, initial_size + 1);
17569 }
17570
17571
17572 // Test that idle notification can be handled and eventually collects garbage.
17573 TEST(IdleNotificationWithLargeHint) {
17574   const intptr_t MB = 1024 * 1024;
17575   const int IdlePauseInMs = 900;
17576   LocalContext env;
17577   v8::HandleScope scope(env->GetIsolate());
17578   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17579   CreateGarbageInOldSpace();
17580   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17581   CHECK_GT(size_with_garbage, initial_size + MB);
17582   bool finished = false;
17583   for (int i = 0; i < 200 && !finished; i++) {
17584     finished = v8::V8::IdleNotification(IdlePauseInMs);
17585   }
17586   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17587   CHECK(finished);
17588   CHECK_LT(final_size, initial_size + 1);
17589 }
17590
17591
17592 TEST(Regress2107) {
17593   const intptr_t MB = 1024 * 1024;
17594   const int kShortIdlePauseInMs = 100;
17595   const int kLongIdlePauseInMs = 1000;
17596   LocalContext env;
17597   v8::Isolate* isolate = env->GetIsolate();
17598   v8::HandleScope scope(env->GetIsolate());
17599   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17600   // Send idle notification to start a round of incremental GCs.
17601   v8::V8::IdleNotification(kShortIdlePauseInMs);
17602   // Emulate 7 page reloads.
17603   for (int i = 0; i < 7; i++) {
17604     {
17605       v8::HandleScope inner_scope(env->GetIsolate());
17606       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17607       ctx->Enter();
17608       CreateGarbageInOldSpace();
17609       ctx->Exit();
17610     }
17611     v8::V8::ContextDisposedNotification();
17612     v8::V8::IdleNotification(kLongIdlePauseInMs);
17613   }
17614   // Create garbage and check that idle notification still collects it.
17615   CreateGarbageInOldSpace();
17616   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17617   CHECK_GT(size_with_garbage, initial_size + MB);
17618   bool finished = false;
17619   for (int i = 0; i < 200 && !finished; i++) {
17620     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17621   }
17622   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17623   CHECK_LT(final_size, initial_size + 1);
17624 }
17625
17626
17627 TEST(Regress2333) {
17628   LocalContext env;
17629   for (int i = 0; i < 3; i++) {
17630     CcTest::heap()->PerformScavenge();
17631   }
17632 }
17633
17634 static uint32_t* stack_limit;
17635
17636 static void GetStackLimitCallback(
17637     const v8::FunctionCallbackInfo<v8::Value>& args) {
17638   stack_limit = reinterpret_cast<uint32_t*>(
17639       CcTest::i_isolate()->stack_guard()->real_climit());
17640 }
17641
17642
17643 // Uses the address of a local variable to determine the stack top now.
17644 // Given a size, returns an address that is that far from the current
17645 // top of stack.
17646 static uint32_t* ComputeStackLimit(uint32_t size) {
17647   uint32_t* answer = &size - (size / sizeof(size));
17648   // If the size is very large and the stack is very near the bottom of
17649   // memory then the calculation above may wrap around and give an address
17650   // that is above the (downwards-growing) stack.  In that case we return
17651   // a very low address.
17652   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17653   return answer;
17654 }
17655
17656
17657 // We need at least 165kB for an x64 debug build with clang and ASAN.
17658 static const int stack_breathing_room = 256 * i::KB;
17659
17660
17661 TEST(SetResourceConstraints) {
17662   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17663
17664   // Set stack limit.
17665   v8::ResourceConstraints constraints;
17666   constraints.set_stack_limit(set_limit);
17667   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17668
17669   // Execute a script.
17670   LocalContext env;
17671   v8::HandleScope scope(env->GetIsolate());
17672   Local<v8::FunctionTemplate> fun_templ =
17673       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17674   Local<Function> fun = fun_templ->GetFunction();
17675   env->Global()->Set(v8_str("get_stack_limit"), fun);
17676   CompileRun("get_stack_limit();");
17677
17678   CHECK(stack_limit == set_limit);
17679 }
17680
17681
17682 TEST(SetResourceConstraintsInThread) {
17683   uint32_t* set_limit;
17684   {
17685     v8::Locker locker(CcTest::isolate());
17686     set_limit = ComputeStackLimit(stack_breathing_room);
17687
17688     // Set stack limit.
17689     v8::ResourceConstraints constraints;
17690     constraints.set_stack_limit(set_limit);
17691     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17692
17693     // Execute a script.
17694     v8::HandleScope scope(CcTest::isolate());
17695     LocalContext env;
17696     Local<v8::FunctionTemplate> fun_templ =
17697         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17698     Local<Function> fun = fun_templ->GetFunction();
17699     env->Global()->Set(v8_str("get_stack_limit"), fun);
17700     CompileRun("get_stack_limit();");
17701
17702     CHECK(stack_limit == set_limit);
17703   }
17704   {
17705     v8::Locker locker(CcTest::isolate());
17706     CHECK(stack_limit == set_limit);
17707   }
17708 }
17709
17710
17711 THREADED_TEST(GetHeapStatistics) {
17712   LocalContext c1;
17713   v8::HandleScope scope(c1->GetIsolate());
17714   v8::HeapStatistics heap_statistics;
17715   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17716   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17717   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17718   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17719   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17720 }
17721
17722
17723 class VisitorImpl : public v8::ExternalResourceVisitor {
17724  public:
17725   explicit VisitorImpl(TestResource** resource) {
17726     for (int i = 0; i < 4; i++) {
17727       resource_[i] = resource[i];
17728       found_resource_[i] = false;
17729     }
17730   }
17731   virtual ~VisitorImpl() {}
17732   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17733     if (!string->IsExternal()) {
17734       CHECK(string->IsExternalAscii());
17735       return;
17736     }
17737     v8::String::ExternalStringResource* resource =
17738         string->GetExternalStringResource();
17739     CHECK(resource);
17740     for (int i = 0; i < 4; i++) {
17741       if (resource_[i] == resource) {
17742         CHECK(!found_resource_[i]);
17743         found_resource_[i] = true;
17744       }
17745     }
17746   }
17747   void CheckVisitedResources() {
17748     for (int i = 0; i < 4; i++) {
17749       CHECK(found_resource_[i]);
17750     }
17751   }
17752
17753  private:
17754   v8::String::ExternalStringResource* resource_[4];
17755   bool found_resource_[4];
17756 };
17757
17758
17759 TEST(ExternalizeOldSpaceTwoByteCons) {
17760   LocalContext env;
17761   v8::HandleScope scope(env->GetIsolate());
17762   v8::Local<v8::String> cons =
17763       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17764   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17765   CcTest::heap()->CollectAllAvailableGarbage();
17766   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17767             *v8::Utils::OpenHandle(*cons)));
17768
17769   TestResource* resource = new TestResource(
17770       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17771   cons->MakeExternal(resource);
17772
17773   CHECK(cons->IsExternal());
17774   CHECK_EQ(resource, cons->GetExternalStringResource());
17775   String::Encoding encoding;
17776   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17777   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17778 }
17779
17780
17781 TEST(ExternalizeOldSpaceOneByteCons) {
17782   LocalContext env;
17783   v8::HandleScope scope(env->GetIsolate());
17784   v8::Local<v8::String> cons =
17785       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17786   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17787   CcTest::heap()->CollectAllAvailableGarbage();
17788   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17789             *v8::Utils::OpenHandle(*cons)));
17790
17791   TestAsciiResource* resource =
17792       new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17793   cons->MakeExternal(resource);
17794
17795   CHECK(cons->IsExternalAscii());
17796   CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17797   String::Encoding encoding;
17798   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17799   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17800 }
17801
17802
17803 TEST(VisitExternalStrings) {
17804   LocalContext env;
17805   v8::HandleScope scope(env->GetIsolate());
17806   const char* string = "Some string";
17807   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17808   TestResource* resource[4];
17809   resource[0] = new TestResource(two_byte_string);
17810   v8::Local<v8::String> string0 =
17811       v8::String::NewExternal(env->GetIsolate(), resource[0]);
17812   resource[1] = new TestResource(two_byte_string, NULL, false);
17813   v8::Local<v8::String> string1 =
17814       v8::String::NewExternal(env->GetIsolate(), resource[1]);
17815
17816   // Externalized symbol.
17817   resource[2] = new TestResource(two_byte_string, NULL, false);
17818   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17819       env->GetIsolate(), string, v8::String::kInternalizedString);
17820   CHECK(string2->MakeExternal(resource[2]));
17821
17822   // Symbolized External.
17823   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17824   v8::Local<v8::String> string3 =
17825       v8::String::NewExternal(env->GetIsolate(), resource[3]);
17826   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
17827   // Turn into a symbol.
17828   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17829   CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17830   CHECK(string3_i->IsInternalizedString());
17831
17832   // We need to add usages for string* to avoid warnings in GCC 4.7
17833   CHECK(string0->IsExternal());
17834   CHECK(string1->IsExternal());
17835   CHECK(string2->IsExternal());
17836   CHECK(string3->IsExternal());
17837
17838   VisitorImpl visitor(resource);
17839   v8::V8::VisitExternalResources(&visitor);
17840   visitor.CheckVisitedResources();
17841 }
17842
17843
17844 TEST(ExternalStringCollectedAtTearDown) {
17845   int destroyed = 0;
17846   v8::Isolate* isolate = v8::Isolate::New();
17847   { v8::Isolate::Scope isolate_scope(isolate);
17848     v8::HandleScope handle_scope(isolate);
17849     const char* s = "One string to test them all, one string to find them.";
17850     TestAsciiResource* inscription =
17851         new TestAsciiResource(i::StrDup(s), &destroyed);
17852     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17853     // Ring is still alive.  Orcs are roaming freely across our lands.
17854     CHECK_EQ(0, destroyed);
17855     USE(ring);
17856   }
17857
17858   isolate->Dispose();
17859   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17860   CHECK_EQ(1, destroyed);
17861 }
17862
17863
17864 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17865   int destroyed = 0;
17866   v8::Isolate* isolate = v8::Isolate::New();
17867   { v8::Isolate::Scope isolate_scope(isolate);
17868     LocalContext env(isolate);
17869     v8::HandleScope handle_scope(isolate);
17870     CompileRun("var ring = 'One string to test them all';");
17871     const char* s = "One string to test them all";
17872     TestAsciiResource* inscription =
17873         new TestAsciiResource(i::StrDup(s), &destroyed);
17874     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17875     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17876     ring->MakeExternal(inscription);
17877     // Ring is still alive.  Orcs are roaming freely across our lands.
17878     CHECK_EQ(0, destroyed);
17879     USE(ring);
17880   }
17881
17882   isolate->Dispose();
17883   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17884   CHECK_EQ(1, destroyed);
17885 }
17886
17887
17888 TEST(ExternalInternalizedStringCollectedAtGC) {
17889   int destroyed = 0;
17890   { LocalContext env;
17891     v8::HandleScope handle_scope(env->GetIsolate());
17892     CompileRun("var ring = 'One string to test them all';");
17893     const char* s = "One string to test them all";
17894     TestAsciiResource* inscription =
17895         new TestAsciiResource(i::StrDup(s), &destroyed);
17896     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17897     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17898     ring->MakeExternal(inscription);
17899     // Ring is still alive.  Orcs are roaming freely across our lands.
17900     CHECK_EQ(0, destroyed);
17901     USE(ring);
17902   }
17903
17904   // Garbage collector deals swift blows to evil.
17905   CcTest::i_isolate()->compilation_cache()->Clear();
17906   CcTest::heap()->CollectAllAvailableGarbage();
17907
17908   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17909   CHECK_EQ(1, destroyed);
17910 }
17911
17912
17913 static double DoubleFromBits(uint64_t value) {
17914   double target;
17915   i::OS::MemCopy(&target, &value, sizeof(target));
17916   return target;
17917 }
17918
17919
17920 static uint64_t DoubleToBits(double value) {
17921   uint64_t target;
17922   i::OS::MemCopy(&target, &value, sizeof(target));
17923   return target;
17924 }
17925
17926
17927 static double DoubleToDateTime(double input) {
17928   double date_limit = 864e13;
17929   if (std::isnan(input) || input < -date_limit || input > date_limit) {
17930     return i::OS::nan_value();
17931   }
17932   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
17933 }
17934
17935
17936 // We don't have a consistent way to write 64-bit constants syntactically, so we
17937 // split them into two 32-bit constants and combine them programmatically.
17938 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17939   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17940 }
17941
17942
17943 THREADED_TEST(QuietSignalingNaNs) {
17944   LocalContext context;
17945   v8::Isolate* isolate = context->GetIsolate();
17946   v8::HandleScope scope(isolate);
17947   v8::TryCatch try_catch;
17948
17949   // Special double values.
17950   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17951   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17952   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17953   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
17954   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
17955   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
17956   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
17957
17958   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
17959   // on either side of the epoch.
17960   double date_limit = 864e13;
17961
17962   double test_values[] = {
17963       snan,
17964       qnan,
17965       infinity,
17966       max_normal,
17967       date_limit + 1,
17968       date_limit,
17969       min_normal,
17970       max_denormal,
17971       min_denormal,
17972       0,
17973       -0,
17974       -min_denormal,
17975       -max_denormal,
17976       -min_normal,
17977       -date_limit,
17978       -date_limit - 1,
17979       -max_normal,
17980       -infinity,
17981       -qnan,
17982       -snan
17983   };
17984   int num_test_values = 20;
17985
17986   for (int i = 0; i < num_test_values; i++) {
17987     double test_value = test_values[i];
17988
17989     // Check that Number::New preserves non-NaNs and quiets SNaNs.
17990     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
17991     double stored_number = number->NumberValue();
17992     if (!std::isnan(test_value)) {
17993       CHECK_EQ(test_value, stored_number);
17994     } else {
17995       uint64_t stored_bits = DoubleToBits(stored_number);
17996       // Check if quiet nan (bits 51..62 all set).
17997 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17998       // Most significant fraction bit for quiet nan is set to 0
17999       // on MIPS architecture. Allowed by IEEE-754.
18000       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18001 #else
18002       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18003 #endif
18004     }
18005
18006     // Check that Date::New preserves non-NaNs in the date range and
18007     // quiets SNaNs.
18008     v8::Handle<v8::Value> date =
18009         v8::Date::New(isolate, test_value);
18010     double expected_stored_date = DoubleToDateTime(test_value);
18011     double stored_date = date->NumberValue();
18012     if (!std::isnan(expected_stored_date)) {
18013       CHECK_EQ(expected_stored_date, stored_date);
18014     } else {
18015       uint64_t stored_bits = DoubleToBits(stored_date);
18016       // Check if quiet nan (bits 51..62 all set).
18017 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18018       // Most significant fraction bit for quiet nan is set to 0
18019       // on MIPS architecture. Allowed by IEEE-754.
18020       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18021 #else
18022       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18023 #endif
18024     }
18025   }
18026 }
18027
18028
18029 static void SpaghettiIncident(
18030     const v8::FunctionCallbackInfo<v8::Value>& args) {
18031   v8::HandleScope scope(args.GetIsolate());
18032   v8::TryCatch tc;
18033   v8::Handle<v8::String> str(args[0]->ToString());
18034   USE(str);
18035   if (tc.HasCaught())
18036     tc.ReThrow();
18037 }
18038
18039
18040 // Test that an exception can be propagated down through a spaghetti
18041 // stack using ReThrow.
18042 THREADED_TEST(SpaghettiStackReThrow) {
18043   v8::Isolate* isolate = CcTest::isolate();
18044   v8::HandleScope scope(isolate);
18045   LocalContext context;
18046   context->Global()->Set(
18047       v8::String::NewFromUtf8(isolate, "s"),
18048       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18049   v8::TryCatch try_catch;
18050   CompileRun(
18051       "var i = 0;"
18052       "var o = {"
18053       "  toString: function () {"
18054       "    if (i == 10) {"
18055       "      throw 'Hey!';"
18056       "    } else {"
18057       "      i++;"
18058       "      return s(o);"
18059       "    }"
18060       "  }"
18061       "};"
18062       "s(o);");
18063   CHECK(try_catch.HasCaught());
18064   v8::String::Utf8Value value(try_catch.Exception());
18065   CHECK_EQ(0, strcmp(*value, "Hey!"));
18066 }
18067
18068
18069 TEST(Regress528) {
18070   v8::V8::Initialize();
18071   v8::Isolate* isolate = CcTest::isolate();
18072   v8::HandleScope scope(isolate);
18073   v8::Local<Context> other_context;
18074   int gc_count;
18075
18076   // Create a context used to keep the code from aging in the compilation
18077   // cache.
18078   other_context = Context::New(isolate);
18079
18080   // Context-dependent context data creates reference from the compilation
18081   // cache to the global object.
18082   const char* source_simple = "1";
18083   {
18084     v8::HandleScope scope(isolate);
18085     v8::Local<Context> context = Context::New(isolate);
18086
18087     context->Enter();
18088     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18089     context->SetEmbedderData(0, obj);
18090     CompileRun(source_simple);
18091     context->Exit();
18092   }
18093   v8::V8::ContextDisposedNotification();
18094   for (gc_count = 1; gc_count < 10; gc_count++) {
18095     other_context->Enter();
18096     CompileRun(source_simple);
18097     other_context->Exit();
18098     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18099     if (GetGlobalObjectsCount() == 1) break;
18100   }
18101   CHECK_GE(2, gc_count);
18102   CHECK_EQ(1, GetGlobalObjectsCount());
18103
18104   // Eval in a function creates reference from the compilation cache to the
18105   // global object.
18106   const char* source_eval = "function f(){eval('1')}; f()";
18107   {
18108     v8::HandleScope scope(isolate);
18109     v8::Local<Context> context = Context::New(isolate);
18110
18111     context->Enter();
18112     CompileRun(source_eval);
18113     context->Exit();
18114   }
18115   v8::V8::ContextDisposedNotification();
18116   for (gc_count = 1; gc_count < 10; gc_count++) {
18117     other_context->Enter();
18118     CompileRun(source_eval);
18119     other_context->Exit();
18120     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18121     if (GetGlobalObjectsCount() == 1) break;
18122   }
18123   CHECK_GE(2, gc_count);
18124   CHECK_EQ(1, GetGlobalObjectsCount());
18125
18126   // Looking up the line number for an exception creates reference from the
18127   // compilation cache to the global object.
18128   const char* source_exception = "function f(){throw 1;} f()";
18129   {
18130     v8::HandleScope scope(isolate);
18131     v8::Local<Context> context = Context::New(isolate);
18132
18133     context->Enter();
18134     v8::TryCatch try_catch;
18135     CompileRun(source_exception);
18136     CHECK(try_catch.HasCaught());
18137     v8::Handle<v8::Message> message = try_catch.Message();
18138     CHECK(!message.IsEmpty());
18139     CHECK_EQ(1, message->GetLineNumber());
18140     context->Exit();
18141   }
18142   v8::V8::ContextDisposedNotification();
18143   for (gc_count = 1; gc_count < 10; gc_count++) {
18144     other_context->Enter();
18145     CompileRun(source_exception);
18146     other_context->Exit();
18147     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18148     if (GetGlobalObjectsCount() == 1) break;
18149   }
18150   CHECK_GE(2, gc_count);
18151   CHECK_EQ(1, GetGlobalObjectsCount());
18152
18153   v8::V8::ContextDisposedNotification();
18154 }
18155
18156
18157 THREADED_TEST(ScriptOrigin) {
18158   LocalContext env;
18159   v8::HandleScope scope(env->GetIsolate());
18160   v8::ScriptOrigin origin =
18161       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18162   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18163       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18164   v8::Script::Compile(script, &origin)->Run();
18165   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18166       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18167   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18168       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18169
18170   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18171   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18172   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18173
18174   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18175   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18176   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18177 }
18178
18179
18180 THREADED_TEST(FunctionGetInferredName) {
18181   LocalContext env;
18182   v8::HandleScope scope(env->GetIsolate());
18183   v8::ScriptOrigin origin =
18184       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18185   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18186       env->GetIsolate(),
18187       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18188   v8::Script::Compile(script, &origin)->Run();
18189   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18190       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18191   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18192 }
18193
18194
18195 THREADED_TEST(FunctionGetDisplayName) {
18196   LocalContext env;
18197   v8::HandleScope scope(env->GetIsolate());
18198   const char* code = "var error = false;"
18199                      "function a() { this.x = 1; };"
18200                      "a.displayName = 'display_a';"
18201                      "var b = (function() {"
18202                      "  var f = function() { this.x = 2; };"
18203                      "  f.displayName = 'display_b';"
18204                      "  return f;"
18205                      "})();"
18206                      "var c = function() {};"
18207                      "c.__defineGetter__('displayName', function() {"
18208                      "  error = true;"
18209                      "  throw new Error();"
18210                      "});"
18211                      "function d() {};"
18212                      "d.__defineGetter__('displayName', function() {"
18213                      "  error = true;"
18214                      "  return 'wrong_display_name';"
18215                      "});"
18216                      "function e() {};"
18217                      "e.displayName = 'wrong_display_name';"
18218                      "e.__defineSetter__('displayName', function() {"
18219                      "  error = true;"
18220                      "  throw new Error();"
18221                      "});"
18222                      "function f() {};"
18223                      "f.displayName = { 'foo': 6, toString: function() {"
18224                      "  error = true;"
18225                      "  return 'wrong_display_name';"
18226                      "}};"
18227                      "var g = function() {"
18228                      "  arguments.callee.displayName = 'set_in_runtime';"
18229                      "}; g();"
18230                      ;
18231   v8::ScriptOrigin origin =
18232       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18233   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18234       ->Run();
18235   v8::Local<v8::Value> error =
18236       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18237   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18238       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18239   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18240       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18241   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18242       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18243   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18244       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18245   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18246       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18247   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18248       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18249   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18250       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18251   CHECK_EQ(false, error->BooleanValue());
18252   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18253   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18254   CHECK(c->GetDisplayName()->IsUndefined());
18255   CHECK(d->GetDisplayName()->IsUndefined());
18256   CHECK(e->GetDisplayName()->IsUndefined());
18257   CHECK(f->GetDisplayName()->IsUndefined());
18258   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18259 }
18260
18261
18262 THREADED_TEST(ScriptLineNumber) {
18263   LocalContext env;
18264   v8::HandleScope scope(env->GetIsolate());
18265   v8::ScriptOrigin origin =
18266       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18267   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18268       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18269   v8::Script::Compile(script, &origin)->Run();
18270   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18271       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18272   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18273       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18274   CHECK_EQ(0, f->GetScriptLineNumber());
18275   CHECK_EQ(2, g->GetScriptLineNumber());
18276 }
18277
18278
18279 THREADED_TEST(ScriptColumnNumber) {
18280   LocalContext env;
18281   v8::Isolate* isolate = env->GetIsolate();
18282   v8::HandleScope scope(isolate);
18283   v8::ScriptOrigin origin =
18284       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18285                        v8::Integer::New(isolate, 3),
18286                        v8::Integer::New(isolate, 2));
18287   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18288       isolate, "function foo() {}\n\n     function bar() {}");
18289   v8::Script::Compile(script, &origin)->Run();
18290   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18291       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18292   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18293       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18294   CHECK_EQ(14, foo->GetScriptColumnNumber());
18295   CHECK_EQ(17, bar->GetScriptColumnNumber());
18296 }
18297
18298
18299 THREADED_TEST(FunctionIsBuiltin) {
18300   LocalContext env;
18301   v8::Isolate* isolate = env->GetIsolate();
18302   v8::HandleScope scope(isolate);
18303   v8::Local<v8::Function> f;
18304   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18305   CHECK(f->IsBuiltin());
18306   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18307   CHECK(f->IsBuiltin());
18308   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18309   CHECK(f->IsBuiltin());
18310   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18311   CHECK(f->IsBuiltin());
18312   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18313   CHECK(!f->IsBuiltin());
18314 }
18315
18316
18317 THREADED_TEST(FunctionGetScriptId) {
18318   LocalContext env;
18319   v8::Isolate* isolate = env->GetIsolate();
18320   v8::HandleScope scope(isolate);
18321   v8::ScriptOrigin origin =
18322       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18323                        v8::Integer::New(isolate, 3),
18324                        v8::Integer::New(isolate, 2));
18325   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18326       isolate, "function foo() {}\n\n     function bar() {}");
18327   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18328   script->Run();
18329   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18330       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18331   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18332       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18333   CHECK_EQ(script->GetId(), foo->ScriptId());
18334   CHECK_EQ(script->GetId(), bar->ScriptId());
18335 }
18336
18337
18338 THREADED_TEST(FunctionGetBoundFunction) {
18339   LocalContext env;
18340   v8::HandleScope scope(env->GetIsolate());
18341   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18342       env->GetIsolate(), "test"));
18343   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18344       env->GetIsolate(),
18345       "var a = new Object();\n"
18346       "a.x = 1;\n"
18347       "function f () { return this.x };\n"
18348       "var g = f.bind(a);\n"
18349       "var b = g();");
18350   v8::Script::Compile(script, &origin)->Run();
18351   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18352       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18353   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18354       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18355   CHECK(g->GetBoundFunction()->IsFunction());
18356   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18357       g->GetBoundFunction());
18358   CHECK_EQ(f->GetName(), original_function->GetName());
18359   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18360   CHECK_EQ(f->GetScriptColumnNumber(),
18361            original_function->GetScriptColumnNumber());
18362 }
18363
18364
18365 static void GetterWhichReturns42(
18366     Local<String> name,
18367     const v8::PropertyCallbackInfo<v8::Value>& info) {
18368   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18369   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18370   info.GetReturnValue().Set(v8_num(42));
18371 }
18372
18373
18374 static void SetterWhichSetsYOnThisTo23(
18375     Local<String> name,
18376     Local<Value> value,
18377     const v8::PropertyCallbackInfo<void>& info) {
18378   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18379   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18380   info.This()->Set(v8_str("y"), v8_num(23));
18381 }
18382
18383
18384 void FooGetInterceptor(Local<String> name,
18385                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18386   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18387   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18388   if (!name->Equals(v8_str("foo"))) return;
18389   info.GetReturnValue().Set(v8_num(42));
18390 }
18391
18392
18393 void FooSetInterceptor(Local<String> name,
18394                        Local<Value> value,
18395                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18396   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18397   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18398   if (!name->Equals(v8_str("foo"))) return;
18399   info.This()->Set(v8_str("y"), v8_num(23));
18400   info.GetReturnValue().Set(v8_num(23));
18401 }
18402
18403
18404 TEST(SetterOnConstructorPrototype) {
18405   v8::Isolate* isolate = CcTest::isolate();
18406   v8::HandleScope scope(isolate);
18407   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18408   templ->SetAccessor(v8_str("x"),
18409                      GetterWhichReturns42,
18410                      SetterWhichSetsYOnThisTo23);
18411   LocalContext context;
18412   context->Global()->Set(v8_str("P"), templ->NewInstance());
18413   CompileRun("function C1() {"
18414              "  this.x = 23;"
18415              "};"
18416              "C1.prototype = P;"
18417              "function C2() {"
18418              "  this.x = 23"
18419              "};"
18420              "C2.prototype = { };"
18421              "C2.prototype.__proto__ = P;");
18422
18423   v8::Local<v8::Script> script;
18424   script = v8::Script::Compile(v8_str("new C1();"));
18425   for (int i = 0; i < 10; i++) {
18426     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18427     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18428     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18429   }
18430
18431   script = v8::Script::Compile(v8_str("new C2();"));
18432   for (int i = 0; i < 10; i++) {
18433     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18434     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18435     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18436   }
18437 }
18438
18439
18440 static void NamedPropertyGetterWhichReturns42(
18441     Local<String> name,
18442     const v8::PropertyCallbackInfo<v8::Value>& info) {
18443   info.GetReturnValue().Set(v8_num(42));
18444 }
18445
18446
18447 static void NamedPropertySetterWhichSetsYOnThisTo23(
18448     Local<String> name,
18449     Local<Value> value,
18450     const v8::PropertyCallbackInfo<v8::Value>& info) {
18451   if (name->Equals(v8_str("x"))) {
18452     info.This()->Set(v8_str("y"), v8_num(23));
18453   }
18454 }
18455
18456
18457 THREADED_TEST(InterceptorOnConstructorPrototype) {
18458   v8::Isolate* isolate = CcTest::isolate();
18459   v8::HandleScope scope(isolate);
18460   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18461   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18462                                  NamedPropertySetterWhichSetsYOnThisTo23);
18463   LocalContext context;
18464   context->Global()->Set(v8_str("P"), templ->NewInstance());
18465   CompileRun("function C1() {"
18466              "  this.x = 23;"
18467              "};"
18468              "C1.prototype = P;"
18469              "function C2() {"
18470              "  this.x = 23"
18471              "};"
18472              "C2.prototype = { };"
18473              "C2.prototype.__proto__ = P;");
18474
18475   v8::Local<v8::Script> script;
18476   script = v8::Script::Compile(v8_str("new C1();"));
18477   for (int i = 0; i < 10; i++) {
18478     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18479     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18480     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18481   }
18482
18483   script = v8::Script::Compile(v8_str("new C2();"));
18484   for (int i = 0; i < 10; i++) {
18485     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18486     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18487     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18488   }
18489 }
18490
18491
18492 TEST(Regress618) {
18493   const char* source = "function C1() {"
18494                        "  this.x = 23;"
18495                        "};"
18496                        "C1.prototype = P;";
18497
18498   LocalContext context;
18499   v8::Isolate* isolate = context->GetIsolate();
18500   v8::HandleScope scope(isolate);
18501   v8::Local<v8::Script> script;
18502
18503   // Use a simple object as prototype.
18504   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18505   prototype->Set(v8_str("y"), v8_num(42));
18506   context->Global()->Set(v8_str("P"), prototype);
18507
18508   // This compile will add the code to the compilation cache.
18509   CompileRun(source);
18510
18511   script = v8::Script::Compile(v8_str("new C1();"));
18512   // Allow enough iterations for the inobject slack tracking logic
18513   // to finalize instance size and install the fast construct stub.
18514   for (int i = 0; i < 256; i++) {
18515     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18516     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18517     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18518   }
18519
18520   // Use an API object with accessors as prototype.
18521   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18522   templ->SetAccessor(v8_str("x"),
18523                      GetterWhichReturns42,
18524                      SetterWhichSetsYOnThisTo23);
18525   context->Global()->Set(v8_str("P"), templ->NewInstance());
18526
18527   // This compile will get the code from the compilation cache.
18528   CompileRun(source);
18529
18530   script = v8::Script::Compile(v8_str("new C1();"));
18531   for (int i = 0; i < 10; i++) {
18532     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18533     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18534     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18535   }
18536 }
18537
18538 v8::Isolate* gc_callbacks_isolate = NULL;
18539 int prologue_call_count = 0;
18540 int epilogue_call_count = 0;
18541 int prologue_call_count_second = 0;
18542 int epilogue_call_count_second = 0;
18543
18544 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18545   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18546   ++prologue_call_count;
18547 }
18548
18549
18550 void PrologueCallback(v8::Isolate* isolate,
18551                       v8::GCType,
18552                       v8::GCCallbackFlags flags) {
18553   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18554   CHECK_EQ(gc_callbacks_isolate, isolate);
18555   ++prologue_call_count;
18556 }
18557
18558
18559 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18560   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18561   ++epilogue_call_count;
18562 }
18563
18564
18565 void EpilogueCallback(v8::Isolate* isolate,
18566                       v8::GCType,
18567                       v8::GCCallbackFlags flags) {
18568   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18569   CHECK_EQ(gc_callbacks_isolate, isolate);
18570   ++epilogue_call_count;
18571 }
18572
18573
18574 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18575   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18576   ++prologue_call_count_second;
18577 }
18578
18579
18580 void PrologueCallbackSecond(v8::Isolate* isolate,
18581                             v8::GCType,
18582                             v8::GCCallbackFlags flags) {
18583   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18584   CHECK_EQ(gc_callbacks_isolate, isolate);
18585   ++prologue_call_count_second;
18586 }
18587
18588
18589 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18590   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18591   ++epilogue_call_count_second;
18592 }
18593
18594
18595 void EpilogueCallbackSecond(v8::Isolate* isolate,
18596                             v8::GCType,
18597                             v8::GCCallbackFlags flags) {
18598   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18599   CHECK_EQ(gc_callbacks_isolate, isolate);
18600   ++epilogue_call_count_second;
18601 }
18602
18603
18604 TEST(GCCallbacksOld) {
18605   LocalContext context;
18606
18607   v8::V8::AddGCPrologueCallback(PrologueCallback);
18608   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18609   CHECK_EQ(0, prologue_call_count);
18610   CHECK_EQ(0, epilogue_call_count);
18611   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18612   CHECK_EQ(1, prologue_call_count);
18613   CHECK_EQ(1, epilogue_call_count);
18614   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18615   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18616   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18617   CHECK_EQ(2, prologue_call_count);
18618   CHECK_EQ(2, epilogue_call_count);
18619   CHECK_EQ(1, prologue_call_count_second);
18620   CHECK_EQ(1, epilogue_call_count_second);
18621   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18622   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18623   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18624   CHECK_EQ(2, prologue_call_count);
18625   CHECK_EQ(2, epilogue_call_count);
18626   CHECK_EQ(2, prologue_call_count_second);
18627   CHECK_EQ(2, epilogue_call_count_second);
18628   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18629   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18630   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18631   CHECK_EQ(2, prologue_call_count);
18632   CHECK_EQ(2, epilogue_call_count);
18633   CHECK_EQ(2, prologue_call_count_second);
18634   CHECK_EQ(2, epilogue_call_count_second);
18635 }
18636
18637
18638 TEST(GCCallbacks) {
18639   LocalContext context;
18640   v8::Isolate* isolate = context->GetIsolate();
18641   gc_callbacks_isolate = isolate;
18642   isolate->AddGCPrologueCallback(PrologueCallback);
18643   isolate->AddGCEpilogueCallback(EpilogueCallback);
18644   CHECK_EQ(0, prologue_call_count);
18645   CHECK_EQ(0, epilogue_call_count);
18646   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18647   CHECK_EQ(1, prologue_call_count);
18648   CHECK_EQ(1, epilogue_call_count);
18649   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18650   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18651   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18652   CHECK_EQ(2, prologue_call_count);
18653   CHECK_EQ(2, epilogue_call_count);
18654   CHECK_EQ(1, prologue_call_count_second);
18655   CHECK_EQ(1, epilogue_call_count_second);
18656   isolate->RemoveGCPrologueCallback(PrologueCallback);
18657   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18658   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18659   CHECK_EQ(2, prologue_call_count);
18660   CHECK_EQ(2, epilogue_call_count);
18661   CHECK_EQ(2, prologue_call_count_second);
18662   CHECK_EQ(2, epilogue_call_count_second);
18663   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18664   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18665   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18666   CHECK_EQ(2, prologue_call_count);
18667   CHECK_EQ(2, epilogue_call_count);
18668   CHECK_EQ(2, prologue_call_count_second);
18669   CHECK_EQ(2, epilogue_call_count_second);
18670 }
18671
18672
18673 THREADED_TEST(AddToJSFunctionResultCache) {
18674   i::FLAG_stress_compaction = false;
18675   i::FLAG_allow_natives_syntax = true;
18676   v8::HandleScope scope(CcTest::isolate());
18677
18678   LocalContext context;
18679
18680   const char* code =
18681       "(function() {"
18682       "  var key0 = 'a';"
18683       "  var key1 = 'b';"
18684       "  var r0 = %_GetFromCache(0, key0);"
18685       "  var r1 = %_GetFromCache(0, key1);"
18686       "  var r0_ = %_GetFromCache(0, key0);"
18687       "  if (r0 !== r0_)"
18688       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18689       "  var r1_ = %_GetFromCache(0, key1);"
18690       "  if (r1 !== r1_)"
18691       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18692       "  return 'PASSED';"
18693       "})()";
18694   CcTest::heap()->ClearJSFunctionResultCaches();
18695   ExpectString(code, "PASSED");
18696 }
18697
18698
18699 THREADED_TEST(FillJSFunctionResultCache) {
18700   i::FLAG_allow_natives_syntax = true;
18701   LocalContext context;
18702   v8::HandleScope scope(context->GetIsolate());
18703
18704   const char* code =
18705       "(function() {"
18706       "  var k = 'a';"
18707       "  var r = %_GetFromCache(0, k);"
18708       "  for (var i = 0; i < 16; i++) {"
18709       "    %_GetFromCache(0, 'a' + i);"
18710       "  };"
18711       "  if (r === %_GetFromCache(0, k))"
18712       "    return 'FAILED: k0CacheSize is too small';"
18713       "  return 'PASSED';"
18714       "})()";
18715   CcTest::heap()->ClearJSFunctionResultCaches();
18716   ExpectString(code, "PASSED");
18717 }
18718
18719
18720 THREADED_TEST(RoundRobinGetFromCache) {
18721   i::FLAG_allow_natives_syntax = true;
18722   LocalContext context;
18723   v8::HandleScope scope(context->GetIsolate());
18724
18725   const char* code =
18726       "(function() {"
18727       "  var keys = [];"
18728       "  for (var i = 0; i < 16; i++) keys.push(i);"
18729       "  var values = [];"
18730       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18731       "  for (var i = 0; i < 16; i++) {"
18732       "    var v = %_GetFromCache(0, keys[i]);"
18733       "    if (v.toString() !== values[i].toString())"
18734       "      return 'Wrong value for ' + "
18735       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18736       "  };"
18737       "  return 'PASSED';"
18738       "})()";
18739   CcTest::heap()->ClearJSFunctionResultCaches();
18740   ExpectString(code, "PASSED");
18741 }
18742
18743
18744 THREADED_TEST(ReverseGetFromCache) {
18745   i::FLAG_allow_natives_syntax = true;
18746   LocalContext context;
18747   v8::HandleScope scope(context->GetIsolate());
18748
18749   const char* code =
18750       "(function() {"
18751       "  var keys = [];"
18752       "  for (var i = 0; i < 16; i++) keys.push(i);"
18753       "  var values = [];"
18754       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18755       "  for (var i = 15; i >= 16; i--) {"
18756       "    var v = %_GetFromCache(0, keys[i]);"
18757       "    if (v !== values[i])"
18758       "      return 'Wrong value for ' + "
18759       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18760       "  };"
18761       "  return 'PASSED';"
18762       "})()";
18763   CcTest::heap()->ClearJSFunctionResultCaches();
18764   ExpectString(code, "PASSED");
18765 }
18766
18767
18768 THREADED_TEST(TestEviction) {
18769   i::FLAG_allow_natives_syntax = true;
18770   LocalContext context;
18771   v8::HandleScope scope(context->GetIsolate());
18772
18773   const char* code =
18774       "(function() {"
18775       "  for (var i = 0; i < 2*16; i++) {"
18776       "    %_GetFromCache(0, 'a' + i);"
18777       "  };"
18778       "  return 'PASSED';"
18779       "})()";
18780   CcTest::heap()->ClearJSFunctionResultCaches();
18781   ExpectString(code, "PASSED");
18782 }
18783
18784
18785 THREADED_TEST(TwoByteStringInAsciiCons) {
18786   // See Chromium issue 47824.
18787   LocalContext context;
18788   v8::HandleScope scope(context->GetIsolate());
18789
18790   const char* init_code =
18791       "var str1 = 'abelspendabel';"
18792       "var str2 = str1 + str1 + str1;"
18793       "str2;";
18794   Local<Value> result = CompileRun(init_code);
18795
18796   Local<Value> indexof = CompileRun("str2.indexOf('els')");
18797   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18798
18799   CHECK(result->IsString());
18800   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18801   int length = string->length();
18802   CHECK(string->IsOneByteRepresentation());
18803
18804   FlattenString(string);
18805   i::Handle<i::String> flat_string = FlattenGetString(string);
18806
18807   CHECK(string->IsOneByteRepresentation());
18808   CHECK(flat_string->IsOneByteRepresentation());
18809
18810   // Create external resource.
18811   uint16_t* uc16_buffer = new uint16_t[length + 1];
18812
18813   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18814   uc16_buffer[length] = 0;
18815
18816   TestResource resource(uc16_buffer);
18817
18818   flat_string->MakeExternal(&resource);
18819
18820   CHECK(flat_string->IsTwoByteRepresentation());
18821
18822   // If the cons string has been short-circuited, skip the following checks.
18823   if (!string.is_identical_to(flat_string)) {
18824     // At this point, we should have a Cons string which is flat and ASCII,
18825     // with a first half that is a two-byte string (although it only contains
18826     // ASCII characters). This is a valid sequence of steps, and it can happen
18827     // in real pages.
18828     CHECK(string->IsOneByteRepresentation());
18829     i::ConsString* cons = i::ConsString::cast(*string);
18830     CHECK_EQ(0, cons->second()->length());
18831     CHECK(cons->first()->IsTwoByteRepresentation());
18832   }
18833
18834   // Check that some string operations work.
18835
18836   // Atom RegExp.
18837   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18838   CHECK_EQ(6, reresult->Int32Value());
18839
18840   // Nonatom RegExp.
18841   reresult = CompileRun("str2.match(/abe./g).length;");
18842   CHECK_EQ(6, reresult->Int32Value());
18843
18844   reresult = CompileRun("str2.search(/bel/g);");
18845   CHECK_EQ(1, reresult->Int32Value());
18846
18847   reresult = CompileRun("str2.search(/be./g);");
18848   CHECK_EQ(1, reresult->Int32Value());
18849
18850   ExpectTrue("/bel/g.test(str2);");
18851
18852   ExpectTrue("/be./g.test(str2);");
18853
18854   reresult = CompileRun("/bel/g.exec(str2);");
18855   CHECK(!reresult->IsNull());
18856
18857   reresult = CompileRun("/be./g.exec(str2);");
18858   CHECK(!reresult->IsNull());
18859
18860   ExpectString("str2.substring(2, 10);", "elspenda");
18861
18862   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18863
18864   ExpectString("str2.charAt(2);", "e");
18865
18866   ExpectObject("str2.indexOf('els');", indexof);
18867
18868   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18869
18870   reresult = CompileRun("str2.charCodeAt(2);");
18871   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18872 }
18873
18874
18875 TEST(ContainsOnlyOneByte) {
18876   v8::V8::Initialize();
18877   v8::Isolate* isolate = CcTest::isolate();
18878   v8::HandleScope scope(isolate);
18879   // Make a buffer long enough that it won't automatically be converted.
18880   const int length = 512;
18881   // Ensure word aligned assignment.
18882   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18883   i::SmartArrayPointer<uintptr_t>
18884   aligned_contents(new uintptr_t[aligned_length]);
18885   uint16_t* string_contents =
18886       reinterpret_cast<uint16_t*>(aligned_contents.get());
18887   // Set to contain only one byte.
18888   for (int i = 0; i < length-1; i++) {
18889     string_contents[i] = 0x41;
18890   }
18891   string_contents[length-1] = 0;
18892   // Simple case.
18893   Handle<String> string =
18894       String::NewExternal(isolate,
18895                           new TestResource(string_contents, NULL, false));
18896   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18897   // Counter example.
18898   string = String::NewFromTwoByte(isolate, string_contents);
18899   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18900   // Test left right and balanced cons strings.
18901   Handle<String> base = String::NewFromUtf8(isolate, "a");
18902   Handle<String> left = base;
18903   Handle<String> right = base;
18904   for (int i = 0; i < 1000; i++) {
18905     left = String::Concat(base, left);
18906     right = String::Concat(right, base);
18907   }
18908   Handle<String> balanced = String::Concat(left, base);
18909   balanced = String::Concat(balanced, right);
18910   Handle<String> cons_strings[] = {left, balanced, right};
18911   Handle<String> two_byte =
18912       String::NewExternal(isolate,
18913                           new TestResource(string_contents, NULL, false));
18914   USE(two_byte); USE(cons_strings);
18915   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
18916     // Base assumptions.
18917     string = cons_strings[i];
18918     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18919     // Test left and right concatentation.
18920     string = String::Concat(two_byte, cons_strings[i]);
18921     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18922     string = String::Concat(cons_strings[i], two_byte);
18923     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18924   }
18925   // Set bits in different positions
18926   // for strings of different lengths and alignments.
18927   for (int alignment = 0; alignment < 7; alignment++) {
18928     for (int size = 2; alignment + size < length; size *= 2) {
18929       int zero_offset = size + alignment;
18930       string_contents[zero_offset] = 0;
18931       for (int i = 0; i < size; i++) {
18932         int shift = 8 + (i % 7);
18933         string_contents[alignment + i] = 1 << shift;
18934         string = String::NewExternal(
18935             isolate,
18936             new TestResource(string_contents + alignment, NULL, false));
18937         CHECK_EQ(size, string->Length());
18938         CHECK(!string->ContainsOnlyOneByte());
18939         string_contents[alignment + i] = 0x41;
18940       }
18941       string_contents[zero_offset] = 0x41;
18942     }
18943   }
18944 }
18945
18946
18947 // Failed access check callback that performs a GC on each invocation.
18948 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
18949                                  v8::AccessType type,
18950                                  Local<v8::Value> data) {
18951   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18952 }
18953
18954
18955 TEST(GCInFailedAccessCheckCallback) {
18956   // Install a failed access check callback that performs a GC on each
18957   // invocation. Then force the callback to be called from va
18958
18959   v8::V8::Initialize();
18960   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
18961
18962   v8::Isolate* isolate = CcTest::isolate();
18963   v8::HandleScope scope(isolate);
18964
18965   // Create an ObjectTemplate for global objects and install access
18966   // check callbacks that will block access.
18967   v8::Handle<v8::ObjectTemplate> global_template =
18968       v8::ObjectTemplate::New(isolate);
18969   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
18970                                            IndexedGetAccessBlocker,
18971                                            v8::Handle<v8::Value>(),
18972                                            false);
18973
18974   // Create a context and set an x property on it's global object.
18975   LocalContext context0(NULL, global_template);
18976   context0->Global()->Set(v8_str("x"), v8_num(42));
18977   v8::Handle<v8::Object> global0 = context0->Global();
18978
18979   // Create a context with a different security token so that the
18980   // failed access check callback will be called on each access.
18981   LocalContext context1(NULL, global_template);
18982   context1->Global()->Set(v8_str("other"), global0);
18983
18984   // Get property with failed access check.
18985   ExpectUndefined("other.x");
18986
18987   // Get element with failed access check.
18988   ExpectUndefined("other[0]");
18989
18990   // Set property with failed access check.
18991   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
18992   CHECK(result->IsObject());
18993
18994   // Set element with failed access check.
18995   result = CompileRun("other[0] = new Object()");
18996   CHECK(result->IsObject());
18997
18998   // Get property attribute with failed access check.
18999   ExpectFalse("\'x\' in other");
19000
19001   // Get property attribute for element with failed access check.
19002   ExpectFalse("0 in other");
19003
19004   // Delete property.
19005   ExpectFalse("delete other.x");
19006
19007   // Delete element.
19008   CHECK_EQ(false, global0->Delete(0));
19009
19010   // DefineAccessor.
19011   CHECK_EQ(false,
19012            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19013
19014   // Define JavaScript accessor.
19015   ExpectUndefined("Object.prototype.__defineGetter__.call("
19016                   "    other, \'x\', function() { return 42; })");
19017
19018   // LookupAccessor.
19019   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19020                   "    other, \'x\')");
19021
19022   // HasLocalElement.
19023   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19024
19025   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19026   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19027   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19028
19029   // Reset the failed access check callback so it does not influence
19030   // the other tests.
19031   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19032 }
19033
19034
19035 TEST(IsolateNewDispose) {
19036   v8::Isolate* current_isolate = CcTest::isolate();
19037   v8::Isolate* isolate = v8::Isolate::New();
19038   CHECK(isolate != NULL);
19039   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19040   CHECK(current_isolate != isolate);
19041   CHECK(current_isolate == CcTest::isolate());
19042
19043   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19044   last_location = last_message = NULL;
19045   isolate->Dispose();
19046   CHECK_EQ(last_location, NULL);
19047   CHECK_EQ(last_message, NULL);
19048 }
19049
19050
19051 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19052   v8::Isolate* isolate = v8::Isolate::New();
19053   {
19054     v8::Isolate::Scope i_scope(isolate);
19055     v8::HandleScope scope(isolate);
19056     LocalContext context(isolate);
19057     // Run something in this isolate.
19058     ExpectTrue("true");
19059     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19060     last_location = last_message = NULL;
19061     // Still entered, should fail.
19062     isolate->Dispose();
19063     CHECK_NE(last_location, NULL);
19064     CHECK_NE(last_message, NULL);
19065   }
19066   isolate->Dispose();
19067 }
19068
19069
19070 TEST(RunTwoIsolatesOnSingleThread) {
19071   // Run isolate 1.
19072   v8::Isolate* isolate1 = v8::Isolate::New();
19073   isolate1->Enter();
19074   v8::Persistent<v8::Context> context1;
19075   {
19076     v8::HandleScope scope(isolate1);
19077     context1.Reset(isolate1, Context::New(isolate1));
19078   }
19079
19080   {
19081     v8::HandleScope scope(isolate1);
19082     v8::Local<v8::Context> context =
19083         v8::Local<v8::Context>::New(isolate1, context1);
19084     v8::Context::Scope context_scope(context);
19085     // Run something in new isolate.
19086     CompileRun("var foo = 'isolate 1';");
19087     ExpectString("function f() { return foo; }; f()", "isolate 1");
19088   }
19089
19090   // Run isolate 2.
19091   v8::Isolate* isolate2 = v8::Isolate::New();
19092   v8::Persistent<v8::Context> context2;
19093
19094   {
19095     v8::Isolate::Scope iscope(isolate2);
19096     v8::HandleScope scope(isolate2);
19097     context2.Reset(isolate2, Context::New(isolate2));
19098     v8::Local<v8::Context> context =
19099         v8::Local<v8::Context>::New(isolate2, context2);
19100     v8::Context::Scope context_scope(context);
19101
19102     // Run something in new isolate.
19103     CompileRun("var foo = 'isolate 2';");
19104     ExpectString("function f() { return foo; }; f()", "isolate 2");
19105   }
19106
19107   {
19108     v8::HandleScope scope(isolate1);
19109     v8::Local<v8::Context> context =
19110         v8::Local<v8::Context>::New(isolate1, context1);
19111     v8::Context::Scope context_scope(context);
19112     // Now again in isolate 1
19113     ExpectString("function f() { return foo; }; f()", "isolate 1");
19114   }
19115
19116   isolate1->Exit();
19117
19118   // Run some stuff in default isolate.
19119   v8::Persistent<v8::Context> context_default;
19120   {
19121     v8::Isolate* isolate = CcTest::isolate();
19122     v8::Isolate::Scope iscope(isolate);
19123     v8::HandleScope scope(isolate);
19124     context_default.Reset(isolate, Context::New(isolate));
19125   }
19126
19127   {
19128     v8::HandleScope scope(CcTest::isolate());
19129     v8::Local<v8::Context> context =
19130         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19131     v8::Context::Scope context_scope(context);
19132     // Variables in other isolates should be not available, verify there
19133     // is an exception.
19134     ExpectTrue("function f() {"
19135                "  try {"
19136                "    foo;"
19137                "    return false;"
19138                "  } catch(e) {"
19139                "    return true;"
19140                "  }"
19141                "};"
19142                "var isDefaultIsolate = true;"
19143                "f()");
19144   }
19145
19146   isolate1->Enter();
19147
19148   {
19149     v8::Isolate::Scope iscope(isolate2);
19150     v8::HandleScope scope(isolate2);
19151     v8::Local<v8::Context> context =
19152         v8::Local<v8::Context>::New(isolate2, context2);
19153     v8::Context::Scope context_scope(context);
19154     ExpectString("function f() { return foo; }; f()", "isolate 2");
19155   }
19156
19157   {
19158     v8::HandleScope scope(v8::Isolate::GetCurrent());
19159     v8::Local<v8::Context> context =
19160         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19161     v8::Context::Scope context_scope(context);
19162     ExpectString("function f() { return foo; }; f()", "isolate 1");
19163   }
19164
19165   {
19166     v8::Isolate::Scope iscope(isolate2);
19167     context2.Reset();
19168   }
19169
19170   context1.Reset();
19171   isolate1->Exit();
19172
19173   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19174   last_location = last_message = NULL;
19175
19176   isolate1->Dispose();
19177   CHECK_EQ(last_location, NULL);
19178   CHECK_EQ(last_message, NULL);
19179
19180   isolate2->Dispose();
19181   CHECK_EQ(last_location, NULL);
19182   CHECK_EQ(last_message, NULL);
19183
19184   // Check that default isolate still runs.
19185   {
19186     v8::HandleScope scope(CcTest::isolate());
19187     v8::Local<v8::Context> context =
19188         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19189     v8::Context::Scope context_scope(context);
19190     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19191   }
19192 }
19193
19194
19195 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19196   v8::Isolate::Scope isolate_scope(isolate);
19197   v8::HandleScope scope(isolate);
19198   LocalContext context(isolate);
19199   i::ScopedVector<char> code(1024);
19200   i::OS::SNPrintF(code, "function fib(n) {"
19201                         "  if (n <= 2) return 1;"
19202                         "  return fib(n-1) + fib(n-2);"
19203                         "}"
19204                         "fib(%d)", limit);
19205   Local<Value> value = CompileRun(code.start());
19206   CHECK(value->IsNumber());
19207   return static_cast<int>(value->NumberValue());
19208 }
19209
19210 class IsolateThread : public v8::internal::Thread {
19211  public:
19212   IsolateThread(v8::Isolate* isolate, int fib_limit)
19213       : Thread("IsolateThread"),
19214         isolate_(isolate),
19215         fib_limit_(fib_limit),
19216         result_(0) { }
19217
19218   void Run() {
19219     result_ = CalcFibonacci(isolate_, fib_limit_);
19220   }
19221
19222   int result() { return result_; }
19223
19224  private:
19225   v8::Isolate* isolate_;
19226   int fib_limit_;
19227   int result_;
19228 };
19229
19230
19231 TEST(MultipleIsolatesOnIndividualThreads) {
19232   v8::Isolate* isolate1 = v8::Isolate::New();
19233   v8::Isolate* isolate2 = v8::Isolate::New();
19234
19235   IsolateThread thread1(isolate1, 21);
19236   IsolateThread thread2(isolate2, 12);
19237
19238   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19239   thread1.Start();
19240   thread2.Start();
19241
19242   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19243   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19244
19245   thread1.Join();
19246   thread2.Join();
19247
19248   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19249   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19250   CHECK_EQ(result1, 10946);
19251   CHECK_EQ(result2, 144);
19252   CHECK_EQ(result1, thread1.result());
19253   CHECK_EQ(result2, thread2.result());
19254
19255   isolate1->Dispose();
19256   isolate2->Dispose();
19257 }
19258
19259
19260 TEST(IsolateDifferentContexts) {
19261   v8::Isolate* isolate = v8::Isolate::New();
19262   Local<v8::Context> context;
19263   {
19264     v8::Isolate::Scope isolate_scope(isolate);
19265     v8::HandleScope handle_scope(isolate);
19266     context = v8::Context::New(isolate);
19267     v8::Context::Scope context_scope(context);
19268     Local<Value> v = CompileRun("2");
19269     CHECK(v->IsNumber());
19270     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19271   }
19272   {
19273     v8::Isolate::Scope isolate_scope(isolate);
19274     v8::HandleScope handle_scope(isolate);
19275     context = v8::Context::New(isolate);
19276     v8::Context::Scope context_scope(context);
19277     Local<Value> v = CompileRun("22");
19278     CHECK(v->IsNumber());
19279     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19280   }
19281   isolate->Dispose();
19282 }
19283
19284 class InitDefaultIsolateThread : public v8::internal::Thread {
19285  public:
19286   enum TestCase {
19287     IgnoreOOM,
19288     SetResourceConstraints,
19289     SetFatalHandler,
19290     SetCounterFunction,
19291     SetCreateHistogramFunction,
19292     SetAddHistogramSampleFunction
19293   };
19294
19295   explicit InitDefaultIsolateThread(TestCase testCase)
19296       : Thread("InitDefaultIsolateThread"),
19297         testCase_(testCase),
19298         result_(false) { }
19299
19300   void Run() {
19301     v8::Isolate* isolate = v8::Isolate::New();
19302     isolate->Enter();
19303     switch (testCase_) {
19304     case IgnoreOOM:
19305       v8::V8::IgnoreOutOfMemoryException();
19306       break;
19307
19308     case SetResourceConstraints: {
19309       static const int K = 1024;
19310       v8::ResourceConstraints constraints;
19311       constraints.set_max_young_space_size(256 * K);
19312       constraints.set_max_old_space_size(4 * K * K);
19313       v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19314       break;
19315     }
19316
19317     case SetFatalHandler:
19318       v8::V8::SetFatalErrorHandler(NULL);
19319       break;
19320
19321     case SetCounterFunction:
19322       v8::V8::SetCounterFunction(NULL);
19323       break;
19324
19325     case SetCreateHistogramFunction:
19326       v8::V8::SetCreateHistogramFunction(NULL);
19327       break;
19328
19329     case SetAddHistogramSampleFunction:
19330       v8::V8::SetAddHistogramSampleFunction(NULL);
19331       break;
19332     }
19333     isolate->Exit();
19334     isolate->Dispose();
19335     result_ = true;
19336   }
19337
19338   bool result() { return result_; }
19339
19340  private:
19341   TestCase testCase_;
19342   bool result_;
19343 };
19344
19345
19346 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19347   InitDefaultIsolateThread thread(testCase);
19348   thread.Start();
19349   thread.Join();
19350   CHECK_EQ(thread.result(), true);
19351 }
19352
19353
19354 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19355   InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
19356 }
19357
19358
19359 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19360   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19361 }
19362
19363
19364 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19365   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19366 }
19367
19368
19369 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19370   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19371 }
19372
19373
19374 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19375   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19376 }
19377
19378
19379 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
19380   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19381 }
19382
19383
19384 TEST(StringCheckMultipleContexts) {
19385   const char* code =
19386       "(function() { return \"a\".charAt(0); })()";
19387
19388   {
19389     // Run the code twice in the first context to initialize the call IC.
19390     LocalContext context1;
19391     v8::HandleScope scope(context1->GetIsolate());
19392     ExpectString(code, "a");
19393     ExpectString(code, "a");
19394   }
19395
19396   {
19397     // Change the String.prototype in the second context and check
19398     // that the right function gets called.
19399     LocalContext context2;
19400     v8::HandleScope scope(context2->GetIsolate());
19401     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19402     ExpectString(code, "not a");
19403   }
19404 }
19405
19406
19407 TEST(NumberCheckMultipleContexts) {
19408   const char* code =
19409       "(function() { return (42).toString(); })()";
19410
19411   {
19412     // Run the code twice in the first context to initialize the call IC.
19413     LocalContext context1;
19414     v8::HandleScope scope(context1->GetIsolate());
19415     ExpectString(code, "42");
19416     ExpectString(code, "42");
19417   }
19418
19419   {
19420     // Change the Number.prototype in the second context and check
19421     // that the right function gets called.
19422     LocalContext context2;
19423     v8::HandleScope scope(context2->GetIsolate());
19424     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19425     ExpectString(code, "not 42");
19426   }
19427 }
19428
19429
19430 TEST(BooleanCheckMultipleContexts) {
19431   const char* code =
19432       "(function() { return true.toString(); })()";
19433
19434   {
19435     // Run the code twice in the first context to initialize the call IC.
19436     LocalContext context1;
19437     v8::HandleScope scope(context1->GetIsolate());
19438     ExpectString(code, "true");
19439     ExpectString(code, "true");
19440   }
19441
19442   {
19443     // Change the Boolean.prototype in the second context and check
19444     // that the right function gets called.
19445     LocalContext context2;
19446     v8::HandleScope scope(context2->GetIsolate());
19447     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19448     ExpectString(code, "");
19449   }
19450 }
19451
19452
19453 TEST(DontDeleteCellLoadIC) {
19454   const char* function_code =
19455       "function readCell() { while (true) { return cell; } }";
19456
19457   {
19458     // Run the code twice in the first context to initialize the load
19459     // IC for a don't delete cell.
19460     LocalContext context1;
19461     v8::HandleScope scope(context1->GetIsolate());
19462     CompileRun("var cell = \"first\";");
19463     ExpectBoolean("delete cell", false);
19464     CompileRun(function_code);
19465     ExpectString("readCell()", "first");
19466     ExpectString("readCell()", "first");
19467   }
19468
19469   {
19470     // Use a deletable cell in the second context.
19471     LocalContext context2;
19472     v8::HandleScope scope(context2->GetIsolate());
19473     CompileRun("cell = \"second\";");
19474     CompileRun(function_code);
19475     ExpectString("readCell()", "second");
19476     ExpectBoolean("delete cell", true);
19477     ExpectString("(function() {"
19478                  "  try {"
19479                  "    return readCell();"
19480                  "  } catch(e) {"
19481                  "    return e.toString();"
19482                  "  }"
19483                  "})()",
19484                  "ReferenceError: cell is not defined");
19485     CompileRun("cell = \"new_second\";");
19486     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19487     ExpectString("readCell()", "new_second");
19488     ExpectString("readCell()", "new_second");
19489   }
19490 }
19491
19492
19493 TEST(DontDeleteCellLoadICForceDelete) {
19494   const char* function_code =
19495       "function readCell() { while (true) { return cell; } }";
19496
19497   // Run the code twice to initialize the load IC for a don't delete
19498   // cell.
19499   LocalContext context;
19500   v8::HandleScope scope(context->GetIsolate());
19501   CompileRun("var cell = \"value\";");
19502   ExpectBoolean("delete cell", false);
19503   CompileRun(function_code);
19504   ExpectString("readCell()", "value");
19505   ExpectString("readCell()", "value");
19506
19507   // Delete the cell using the API and check the inlined code works
19508   // correctly.
19509   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19510   ExpectString("(function() {"
19511                "  try {"
19512                "    return readCell();"
19513                "  } catch(e) {"
19514                "    return e.toString();"
19515                "  }"
19516                "})()",
19517                "ReferenceError: cell is not defined");
19518 }
19519
19520
19521 TEST(DontDeleteCellLoadICAPI) {
19522   const char* function_code =
19523       "function readCell() { while (true) { return cell; } }";
19524
19525   // Run the code twice to initialize the load IC for a don't delete
19526   // cell created using the API.
19527   LocalContext context;
19528   v8::HandleScope scope(context->GetIsolate());
19529   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19530   ExpectBoolean("delete cell", false);
19531   CompileRun(function_code);
19532   ExpectString("readCell()", "value");
19533   ExpectString("readCell()", "value");
19534
19535   // Delete the cell using the API and check the inlined code works
19536   // correctly.
19537   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19538   ExpectString("(function() {"
19539                "  try {"
19540                "    return readCell();"
19541                "  } catch(e) {"
19542                "    return e.toString();"
19543                "  }"
19544                "})()",
19545                "ReferenceError: cell is not defined");
19546 }
19547
19548
19549 class Visitor42 : public v8::PersistentHandleVisitor {
19550  public:
19551   explicit Visitor42(v8::Persistent<v8::Object>* object)
19552       : counter_(0), object_(object) { }
19553
19554   virtual void VisitPersistentHandle(Persistent<Value>* value,
19555                                      uint16_t class_id) {
19556     if (class_id != 42) return;
19557     CHECK_EQ(42, value->WrapperClassId());
19558     v8::Isolate* isolate = CcTest::isolate();
19559     v8::HandleScope handle_scope(isolate);
19560     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19561     v8::Handle<v8::Value> object =
19562         v8::Local<v8::Object>::New(isolate, *object_);
19563     CHECK(handle->IsObject());
19564     CHECK_EQ(Handle<Object>::Cast(handle), object);
19565     ++counter_;
19566   }
19567
19568   int counter_;
19569   v8::Persistent<v8::Object>* object_;
19570 };
19571
19572
19573 TEST(PersistentHandleVisitor) {
19574   LocalContext context;
19575   v8::Isolate* isolate = context->GetIsolate();
19576   v8::HandleScope scope(isolate);
19577   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19578   CHECK_EQ(0, object.WrapperClassId());
19579   object.SetWrapperClassId(42);
19580   CHECK_EQ(42, object.WrapperClassId());
19581
19582   Visitor42 visitor(&object);
19583   v8::V8::VisitHandlesWithClassIds(&visitor);
19584   CHECK_EQ(1, visitor.counter_);
19585
19586   object.Reset();
19587 }
19588
19589
19590 TEST(WrapperClassId) {
19591   LocalContext context;
19592   v8::Isolate* isolate = context->GetIsolate();
19593   v8::HandleScope scope(isolate);
19594   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19595   CHECK_EQ(0, object.WrapperClassId());
19596   object.SetWrapperClassId(65535);
19597   CHECK_EQ(65535, object.WrapperClassId());
19598   object.Reset();
19599 }
19600
19601
19602 TEST(PersistentHandleInNewSpaceVisitor) {
19603   LocalContext context;
19604   v8::Isolate* isolate = context->GetIsolate();
19605   v8::HandleScope scope(isolate);
19606   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19607   CHECK_EQ(0, object1.WrapperClassId());
19608   object1.SetWrapperClassId(42);
19609   CHECK_EQ(42, object1.WrapperClassId());
19610
19611   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19612
19613   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19614   CHECK_EQ(0, object2.WrapperClassId());
19615   object2.SetWrapperClassId(42);
19616   CHECK_EQ(42, object2.WrapperClassId());
19617
19618   Visitor42 visitor(&object2);
19619   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19620   CHECK_EQ(1, visitor.counter_);
19621
19622   object1.Reset();
19623   object2.Reset();
19624 }
19625
19626
19627 TEST(RegExp) {
19628   LocalContext context;
19629   v8::HandleScope scope(context->GetIsolate());
19630
19631   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19632   CHECK(re->IsRegExp());
19633   CHECK(re->GetSource()->Equals(v8_str("foo")));
19634   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19635
19636   re = v8::RegExp::New(v8_str("bar"),
19637                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19638                                                       v8::RegExp::kGlobal));
19639   CHECK(re->IsRegExp());
19640   CHECK(re->GetSource()->Equals(v8_str("bar")));
19641   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19642            static_cast<int>(re->GetFlags()));
19643
19644   re = v8::RegExp::New(v8_str("baz"),
19645                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19646                                                       v8::RegExp::kMultiline));
19647   CHECK(re->IsRegExp());
19648   CHECK(re->GetSource()->Equals(v8_str("baz")));
19649   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19650            static_cast<int>(re->GetFlags()));
19651
19652   re = CompileRun("/quux/").As<v8::RegExp>();
19653   CHECK(re->IsRegExp());
19654   CHECK(re->GetSource()->Equals(v8_str("quux")));
19655   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19656
19657   re = CompileRun("/quux/gm").As<v8::RegExp>();
19658   CHECK(re->IsRegExp());
19659   CHECK(re->GetSource()->Equals(v8_str("quux")));
19660   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19661            static_cast<int>(re->GetFlags()));
19662
19663   // Override the RegExp constructor and check the API constructor
19664   // still works.
19665   CompileRun("RegExp = function() {}");
19666
19667   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19668   CHECK(re->IsRegExp());
19669   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19670   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19671
19672   re = v8::RegExp::New(v8_str("foobarbaz"),
19673                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19674                                                       v8::RegExp::kMultiline));
19675   CHECK(re->IsRegExp());
19676   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19677   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19678            static_cast<int>(re->GetFlags()));
19679
19680   context->Global()->Set(v8_str("re"), re);
19681   ExpectTrue("re.test('FoobarbaZ')");
19682
19683   // RegExps are objects on which you can set properties.
19684   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19685   v8::Handle<v8::Value> value(CompileRun("re.property"));
19686   CHECK_EQ(32, value->Int32Value());
19687
19688   v8::TryCatch try_catch;
19689   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19690   CHECK(re.IsEmpty());
19691   CHECK(try_catch.HasCaught());
19692   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19693   ExpectTrue("ex instanceof SyntaxError");
19694 }
19695
19696
19697 THREADED_TEST(Equals) {
19698   LocalContext localContext;
19699   v8::HandleScope handleScope(localContext->GetIsolate());
19700
19701   v8::Handle<v8::Object> globalProxy = localContext->Global();
19702   v8::Handle<Value> global = globalProxy->GetPrototype();
19703
19704   CHECK(global->StrictEquals(global));
19705   CHECK(!global->StrictEquals(globalProxy));
19706   CHECK(!globalProxy->StrictEquals(global));
19707   CHECK(globalProxy->StrictEquals(globalProxy));
19708
19709   CHECK(global->Equals(global));
19710   CHECK(!global->Equals(globalProxy));
19711   CHECK(!globalProxy->Equals(global));
19712   CHECK(globalProxy->Equals(globalProxy));
19713 }
19714
19715
19716 static void Getter(v8::Local<v8::String> property,
19717                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19718   info.GetReturnValue().Set(v8_str("42!"));
19719 }
19720
19721
19722 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19723   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19724   result->Set(0, v8_str("universalAnswer"));
19725   info.GetReturnValue().Set(result);
19726 }
19727
19728
19729 TEST(NamedEnumeratorAndForIn) {
19730   LocalContext context;
19731   v8::Isolate* isolate = context->GetIsolate();
19732   v8::HandleScope handle_scope(isolate);
19733   v8::Context::Scope context_scope(context.local());
19734
19735   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19736   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19737   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19738   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19739         "var result = []; for (var k in o) result.push(k); result"));
19740   CHECK_EQ(1, result->Length());
19741   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19742 }
19743
19744
19745 TEST(DefinePropertyPostDetach) {
19746   LocalContext context;
19747   v8::HandleScope scope(context->GetIsolate());
19748   v8::Handle<v8::Object> proxy = context->Global();
19749   v8::Handle<v8::Function> define_property =
19750       CompileRun("(function() {"
19751                  "  Object.defineProperty("
19752                  "    this,"
19753                  "    1,"
19754                  "    { configurable: true, enumerable: true, value: 3 });"
19755                  "})").As<Function>();
19756   context->DetachGlobal();
19757   define_property->Call(proxy, 0, NULL);
19758 }
19759
19760
19761 static void InstallContextId(v8::Handle<Context> context, int id) {
19762   Context::Scope scope(context);
19763   CompileRun("Object.prototype").As<Object>()->
19764       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19765 }
19766
19767
19768 static void CheckContextId(v8::Handle<Object> object, int expected) {
19769   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19770 }
19771
19772
19773 THREADED_TEST(CreationContext) {
19774   v8::Isolate* isolate = CcTest::isolate();
19775   HandleScope handle_scope(isolate);
19776   Handle<Context> context1 = Context::New(isolate);
19777   InstallContextId(context1, 1);
19778   Handle<Context> context2 = Context::New(isolate);
19779   InstallContextId(context2, 2);
19780   Handle<Context> context3 = Context::New(isolate);
19781   InstallContextId(context3, 3);
19782
19783   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19784
19785   Local<Object> object1;
19786   Local<Function> func1;
19787   {
19788     Context::Scope scope(context1);
19789     object1 = Object::New(isolate);
19790     func1 = tmpl->GetFunction();
19791   }
19792
19793   Local<Object> object2;
19794   Local<Function> func2;
19795   {
19796     Context::Scope scope(context2);
19797     object2 = Object::New(isolate);
19798     func2 = tmpl->GetFunction();
19799   }
19800
19801   Local<Object> instance1;
19802   Local<Object> instance2;
19803
19804   {
19805     Context::Scope scope(context3);
19806     instance1 = func1->NewInstance();
19807     instance2 = func2->NewInstance();
19808   }
19809
19810   CHECK(object1->CreationContext() == context1);
19811   CheckContextId(object1, 1);
19812   CHECK(func1->CreationContext() == context1);
19813   CheckContextId(func1, 1);
19814   CHECK(instance1->CreationContext() == context1);
19815   CheckContextId(instance1, 1);
19816   CHECK(object2->CreationContext() == context2);
19817   CheckContextId(object2, 2);
19818   CHECK(func2->CreationContext() == context2);
19819   CheckContextId(func2, 2);
19820   CHECK(instance2->CreationContext() == context2);
19821   CheckContextId(instance2, 2);
19822
19823   {
19824     Context::Scope scope(context1);
19825     CHECK(object1->CreationContext() == context1);
19826     CheckContextId(object1, 1);
19827     CHECK(func1->CreationContext() == context1);
19828     CheckContextId(func1, 1);
19829     CHECK(instance1->CreationContext() == context1);
19830     CheckContextId(instance1, 1);
19831     CHECK(object2->CreationContext() == context2);
19832     CheckContextId(object2, 2);
19833     CHECK(func2->CreationContext() == context2);
19834     CheckContextId(func2, 2);
19835     CHECK(instance2->CreationContext() == context2);
19836     CheckContextId(instance2, 2);
19837   }
19838
19839   {
19840     Context::Scope scope(context2);
19841     CHECK(object1->CreationContext() == context1);
19842     CheckContextId(object1, 1);
19843     CHECK(func1->CreationContext() == context1);
19844     CheckContextId(func1, 1);
19845     CHECK(instance1->CreationContext() == context1);
19846     CheckContextId(instance1, 1);
19847     CHECK(object2->CreationContext() == context2);
19848     CheckContextId(object2, 2);
19849     CHECK(func2->CreationContext() == context2);
19850     CheckContextId(func2, 2);
19851     CHECK(instance2->CreationContext() == context2);
19852     CheckContextId(instance2, 2);
19853   }
19854 }
19855
19856
19857 THREADED_TEST(CreationContextOfJsFunction) {
19858   HandleScope handle_scope(CcTest::isolate());
19859   Handle<Context> context = Context::New(CcTest::isolate());
19860   InstallContextId(context, 1);
19861
19862   Local<Object> function;
19863   {
19864     Context::Scope scope(context);
19865     function = CompileRun("function foo() {}; foo").As<Object>();
19866   }
19867
19868   CHECK(function->CreationContext() == context);
19869   CheckContextId(function, 1);
19870 }
19871
19872
19873 void HasOwnPropertyIndexedPropertyGetter(
19874     uint32_t index,
19875     const v8::PropertyCallbackInfo<v8::Value>& info) {
19876   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19877 }
19878
19879
19880 void HasOwnPropertyNamedPropertyGetter(
19881     Local<String> property,
19882     const v8::PropertyCallbackInfo<v8::Value>& info) {
19883   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19884 }
19885
19886
19887 void HasOwnPropertyIndexedPropertyQuery(
19888     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19889   if (index == 42) info.GetReturnValue().Set(1);
19890 }
19891
19892
19893 void HasOwnPropertyNamedPropertyQuery(
19894     Local<String> property,
19895     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19896   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19897 }
19898
19899
19900 void HasOwnPropertyNamedPropertyQuery2(
19901     Local<String> property,
19902     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19903   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19904 }
19905
19906
19907 void HasOwnPropertyAccessorGetter(
19908     Local<String> property,
19909     const v8::PropertyCallbackInfo<v8::Value>& info) {
19910   info.GetReturnValue().Set(v8_str("yes"));
19911 }
19912
19913
19914 TEST(HasOwnProperty) {
19915   LocalContext env;
19916   v8::Isolate* isolate = env->GetIsolate();
19917   v8::HandleScope scope(isolate);
19918   { // Check normal properties and defined getters.
19919     Handle<Value> value = CompileRun(
19920         "function Foo() {"
19921         "    this.foo = 11;"
19922         "    this.__defineGetter__('baz', function() { return 1; });"
19923         "};"
19924         "function Bar() { "
19925         "    this.bar = 13;"
19926         "    this.__defineGetter__('bla', function() { return 2; });"
19927         "};"
19928         "Bar.prototype = new Foo();"
19929         "new Bar();");
19930     CHECK(value->IsObject());
19931     Handle<Object> object = value->ToObject();
19932     CHECK(object->Has(v8_str("foo")));
19933     CHECK(!object->HasOwnProperty(v8_str("foo")));
19934     CHECK(object->HasOwnProperty(v8_str("bar")));
19935     CHECK(object->Has(v8_str("baz")));
19936     CHECK(!object->HasOwnProperty(v8_str("baz")));
19937     CHECK(object->HasOwnProperty(v8_str("bla")));
19938   }
19939   { // Check named getter interceptors.
19940     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19941     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19942     Handle<Object> instance = templ->NewInstance();
19943     CHECK(!instance->HasOwnProperty(v8_str("42")));
19944     CHECK(instance->HasOwnProperty(v8_str("foo")));
19945     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19946   }
19947   { // Check indexed getter interceptors.
19948     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19949     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
19950     Handle<Object> instance = templ->NewInstance();
19951     CHECK(instance->HasOwnProperty(v8_str("42")));
19952     CHECK(!instance->HasOwnProperty(v8_str("43")));
19953     CHECK(!instance->HasOwnProperty(v8_str("foo")));
19954   }
19955   { // Check named query interceptors.
19956     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19957     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
19958     Handle<Object> instance = templ->NewInstance();
19959     CHECK(instance->HasOwnProperty(v8_str("foo")));
19960     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19961   }
19962   { // Check indexed query interceptors.
19963     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19964     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
19965     Handle<Object> instance = templ->NewInstance();
19966     CHECK(instance->HasOwnProperty(v8_str("42")));
19967     CHECK(!instance->HasOwnProperty(v8_str("41")));
19968   }
19969   { // Check callbacks.
19970     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19971     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
19972     Handle<Object> instance = templ->NewInstance();
19973     CHECK(instance->HasOwnProperty(v8_str("foo")));
19974     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19975   }
19976   { // Check that query wins on disagreement.
19977     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19978     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
19979                                    0,
19980                                    HasOwnPropertyNamedPropertyQuery2);
19981     Handle<Object> instance = templ->NewInstance();
19982     CHECK(!instance->HasOwnProperty(v8_str("foo")));
19983     CHECK(instance->HasOwnProperty(v8_str("bar")));
19984   }
19985 }
19986
19987
19988 TEST(IndexedInterceptorWithStringProto) {
19989   v8::Isolate* isolate = CcTest::isolate();
19990   v8::HandleScope scope(isolate);
19991   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19992   templ->SetIndexedPropertyHandler(NULL,
19993                                    NULL,
19994                                    HasOwnPropertyIndexedPropertyQuery);
19995   LocalContext context;
19996   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19997   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
19998   // These should be intercepted.
19999   CHECK(CompileRun("42 in obj")->BooleanValue());
20000   CHECK(CompileRun("'42' in obj")->BooleanValue());
20001   // These should fall through to the String prototype.
20002   CHECK(CompileRun("0 in obj")->BooleanValue());
20003   CHECK(CompileRun("'0' in obj")->BooleanValue());
20004   // And these should both fail.
20005   CHECK(!CompileRun("32 in obj")->BooleanValue());
20006   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20007 }
20008
20009
20010 void CheckCodeGenerationAllowed() {
20011   Handle<Value> result = CompileRun("eval('42')");
20012   CHECK_EQ(42, result->Int32Value());
20013   result = CompileRun("(function(e) { return e('42'); })(eval)");
20014   CHECK_EQ(42, result->Int32Value());
20015   result = CompileRun("var f = new Function('return 42'); f()");
20016   CHECK_EQ(42, result->Int32Value());
20017 }
20018
20019
20020 void CheckCodeGenerationDisallowed() {
20021   TryCatch try_catch;
20022
20023   Handle<Value> result = CompileRun("eval('42')");
20024   CHECK(result.IsEmpty());
20025   CHECK(try_catch.HasCaught());
20026   try_catch.Reset();
20027
20028   result = CompileRun("(function(e) { return e('42'); })(eval)");
20029   CHECK(result.IsEmpty());
20030   CHECK(try_catch.HasCaught());
20031   try_catch.Reset();
20032
20033   result = CompileRun("var f = new Function('return 42'); f()");
20034   CHECK(result.IsEmpty());
20035   CHECK(try_catch.HasCaught());
20036 }
20037
20038
20039 bool CodeGenerationAllowed(Local<Context> context) {
20040   ApiTestFuzzer::Fuzz();
20041   return true;
20042 }
20043
20044
20045 bool CodeGenerationDisallowed(Local<Context> context) {
20046   ApiTestFuzzer::Fuzz();
20047   return false;
20048 }
20049
20050
20051 THREADED_TEST(AllowCodeGenFromStrings) {
20052   LocalContext context;
20053   v8::HandleScope scope(context->GetIsolate());
20054
20055   // eval and the Function constructor allowed by default.
20056   CHECK(context->IsCodeGenerationFromStringsAllowed());
20057   CheckCodeGenerationAllowed();
20058
20059   // Disallow eval and the Function constructor.
20060   context->AllowCodeGenerationFromStrings(false);
20061   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20062   CheckCodeGenerationDisallowed();
20063
20064   // Allow again.
20065   context->AllowCodeGenerationFromStrings(true);
20066   CheckCodeGenerationAllowed();
20067
20068   // Disallow but setting a global callback that will allow the calls.
20069   context->AllowCodeGenerationFromStrings(false);
20070   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20071   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20072   CheckCodeGenerationAllowed();
20073
20074   // Set a callback that disallows the code generation.
20075   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20076   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20077   CheckCodeGenerationDisallowed();
20078 }
20079
20080
20081 TEST(SetErrorMessageForCodeGenFromStrings) {
20082   LocalContext context;
20083   v8::HandleScope scope(context->GetIsolate());
20084   TryCatch try_catch;
20085
20086   Handle<String> message = v8_str("Message") ;
20087   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20088   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20089   context->AllowCodeGenerationFromStrings(false);
20090   context->SetErrorMessageForCodeGenerationFromStrings(message);
20091   Handle<Value> result = CompileRun("eval('42')");
20092   CHECK(result.IsEmpty());
20093   CHECK(try_catch.HasCaught());
20094   Handle<String> actual_message = try_catch.Message()->Get();
20095   CHECK(expected_message->Equals(actual_message));
20096 }
20097
20098
20099 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20100 }
20101
20102
20103 THREADED_TEST(CallAPIFunctionOnNonObject) {
20104   LocalContext context;
20105   v8::Isolate* isolate = context->GetIsolate();
20106   v8::HandleScope scope(isolate);
20107   Handle<FunctionTemplate> templ =
20108       v8::FunctionTemplate::New(isolate, NonObjectThis);
20109   Handle<Function> function = templ->GetFunction();
20110   context->Global()->Set(v8_str("f"), function);
20111   TryCatch try_catch;
20112   CompileRun("f.call(2)");
20113 }
20114
20115
20116 // Regression test for issue 1470.
20117 THREADED_TEST(ReadOnlyIndexedProperties) {
20118   v8::Isolate* isolate = CcTest::isolate();
20119   v8::HandleScope scope(isolate);
20120   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20121
20122   LocalContext context;
20123   Local<v8::Object> obj = templ->NewInstance();
20124   context->Global()->Set(v8_str("obj"), obj);
20125   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20126   obj->Set(v8_str("1"), v8_str("foobar"));
20127   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20128   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20129   obj->Set(v8_num(2), v8_str("foobar"));
20130   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20131
20132   // Test non-smi case.
20133   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20134   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20135   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20136 }
20137
20138
20139 THREADED_TEST(Regress1516) {
20140   LocalContext context;
20141   v8::HandleScope scope(context->GetIsolate());
20142
20143   { v8::HandleScope temp_scope(context->GetIsolate());
20144     CompileRun("({'a': 0})");
20145   }
20146
20147   int elements;
20148   { i::MapCache* map_cache =
20149         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20150     elements = map_cache->NumberOfElements();
20151     CHECK_LE(1, elements);
20152   }
20153
20154   CcTest::heap()->CollectAllGarbage(
20155       i::Heap::kAbortIncrementalMarkingMask);
20156   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20157     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20158       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20159       CHECK_GT(elements, map_cache->NumberOfElements());
20160     }
20161   }
20162 }
20163
20164
20165 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20166                                                 Local<Value> name,
20167                                                 v8::AccessType type,
20168                                                 Local<Value> data) {
20169   // Only block read access to __proto__.
20170   if (type == v8::ACCESS_GET &&
20171       name->IsString() &&
20172       name->ToString()->Length() == 9 &&
20173       name->ToString()->Utf8Length() == 9) {
20174     char buffer[10];
20175     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20176     return strncmp(buffer, "__proto__", 9) != 0;
20177   }
20178
20179   return true;
20180 }
20181
20182
20183 THREADED_TEST(Regress93759) {
20184   v8::Isolate* isolate = CcTest::isolate();
20185   HandleScope scope(isolate);
20186
20187   // Template for object with security check.
20188   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20189   // We don't do indexing, so any callback can be used for that.
20190   no_proto_template->SetAccessCheckCallbacks(
20191       BlockProtoNamedSecurityTestCallback,
20192       IndexedSecurityTestCallback);
20193
20194   // Templates for objects with hidden prototypes and possibly security check.
20195   Local<FunctionTemplate> hidden_proto_template =
20196       v8::FunctionTemplate::New(isolate);
20197   hidden_proto_template->SetHiddenPrototype(true);
20198
20199   Local<FunctionTemplate> protected_hidden_proto_template =
20200       v8::FunctionTemplate::New(isolate);
20201   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20202       BlockProtoNamedSecurityTestCallback,
20203       IndexedSecurityTestCallback);
20204   protected_hidden_proto_template->SetHiddenPrototype(true);
20205
20206   // Context for "foreign" objects used in test.
20207   Local<Context> context = v8::Context::New(isolate);
20208   context->Enter();
20209
20210   // Plain object, no security check.
20211   Local<Object> simple_object = Object::New(isolate);
20212
20213   // Object with explicit security check.
20214   Local<Object> protected_object =
20215       no_proto_template->NewInstance();
20216
20217   // JSGlobalProxy object, always have security check.
20218   Local<Object> proxy_object =
20219       context->Global();
20220
20221   // Global object, the  prototype of proxy_object. No security checks.
20222   Local<Object> global_object =
20223       proxy_object->GetPrototype()->ToObject();
20224
20225   // Hidden prototype without security check.
20226   Local<Object> hidden_prototype =
20227       hidden_proto_template->GetFunction()->NewInstance();
20228   Local<Object> object_with_hidden =
20229     Object::New(isolate);
20230   object_with_hidden->SetPrototype(hidden_prototype);
20231
20232   // Hidden prototype with security check on the hidden prototype.
20233   Local<Object> protected_hidden_prototype =
20234       protected_hidden_proto_template->GetFunction()->NewInstance();
20235   Local<Object> object_with_protected_hidden =
20236     Object::New(isolate);
20237   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20238
20239   context->Exit();
20240
20241   // Template for object for second context. Values to test are put on it as
20242   // properties.
20243   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20244   global_template->Set(v8_str("simple"), simple_object);
20245   global_template->Set(v8_str("protected"), protected_object);
20246   global_template->Set(v8_str("global"), global_object);
20247   global_template->Set(v8_str("proxy"), proxy_object);
20248   global_template->Set(v8_str("hidden"), object_with_hidden);
20249   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20250
20251   LocalContext context2(NULL, global_template);
20252
20253   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20254   CHECK(result1->Equals(simple_object->GetPrototype()));
20255
20256   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20257   CHECK(result2->Equals(Undefined(isolate)));
20258
20259   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20260   CHECK(result3->Equals(global_object->GetPrototype()));
20261
20262   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20263   CHECK(result4->Equals(Undefined(isolate)));
20264
20265   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20266   CHECK(result5->Equals(
20267       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20268
20269   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20270   CHECK(result6->Equals(Undefined(isolate)));
20271 }
20272
20273
20274 THREADED_TEST(Regress125988) {
20275   v8::HandleScope scope(CcTest::isolate());
20276   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20277   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20278   LocalContext env;
20279   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20280   CompileRun("var a = new Object();"
20281              "var b = new Intercept();"
20282              "var c = new Object();"
20283              "c.__proto__ = b;"
20284              "b.__proto__ = a;"
20285              "a.x = 23;"
20286              "for (var i = 0; i < 3; i++) c.x;");
20287   ExpectBoolean("c.hasOwnProperty('x')", false);
20288   ExpectInt32("c.x", 23);
20289   CompileRun("a.y = 42;"
20290              "for (var i = 0; i < 3; i++) c.x;");
20291   ExpectBoolean("c.hasOwnProperty('x')", false);
20292   ExpectInt32("c.x", 23);
20293   ExpectBoolean("c.hasOwnProperty('y')", false);
20294   ExpectInt32("c.y", 42);
20295 }
20296
20297
20298 static void TestReceiver(Local<Value> expected_result,
20299                          Local<Value> expected_receiver,
20300                          const char* code) {
20301   Local<Value> result = CompileRun(code);
20302   CHECK(result->IsObject());
20303   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20304   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20305 }
20306
20307
20308 THREADED_TEST(ForeignFunctionReceiver) {
20309   v8::Isolate* isolate = CcTest::isolate();
20310   HandleScope scope(isolate);
20311
20312   // Create two contexts with different "id" properties ('i' and 'o').
20313   // Call a function both from its own context and from a the foreign
20314   // context, and see what "this" is bound to (returning both "this"
20315   // and "this.id" for comparison).
20316
20317   Local<Context> foreign_context = v8::Context::New(isolate);
20318   foreign_context->Enter();
20319   Local<Value> foreign_function =
20320     CompileRun("function func() { return { 0: this.id, "
20321                "                           1: this, "
20322                "                           toString: function() { "
20323                "                               return this[0];"
20324                "                           }"
20325                "                         };"
20326                "}"
20327                "var id = 'i';"
20328                "func;");
20329   CHECK(foreign_function->IsFunction());
20330   foreign_context->Exit();
20331
20332   LocalContext context;
20333
20334   Local<String> password = v8_str("Password");
20335   // Don't get hit by security checks when accessing foreign_context's
20336   // global receiver (aka. global proxy).
20337   context->SetSecurityToken(password);
20338   foreign_context->SetSecurityToken(password);
20339
20340   Local<String> i = v8_str("i");
20341   Local<String> o = v8_str("o");
20342   Local<String> id = v8_str("id");
20343
20344   CompileRun("function ownfunc() { return { 0: this.id, "
20345              "                              1: this, "
20346              "                              toString: function() { "
20347              "                                  return this[0];"
20348              "                              }"
20349              "                             };"
20350              "}"
20351              "var id = 'o';"
20352              "ownfunc");
20353   context->Global()->Set(v8_str("func"), foreign_function);
20354
20355   // Sanity check the contexts.
20356   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20357   CHECK(o->Equals(context->Global()->Get(id)));
20358
20359   // Checking local function's receiver.
20360   // Calling function using its call/apply methods.
20361   TestReceiver(o, context->Global(), "ownfunc.call()");
20362   TestReceiver(o, context->Global(), "ownfunc.apply()");
20363   // Making calls through built-in functions.
20364   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20365   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20366   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20367   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20368   // Calling with environment record as base.
20369   TestReceiver(o, context->Global(), "ownfunc()");
20370   // Calling with no base.
20371   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20372
20373   // Checking foreign function return value.
20374   // Calling function using its call/apply methods.
20375   TestReceiver(i, foreign_context->Global(), "func.call()");
20376   TestReceiver(i, foreign_context->Global(), "func.apply()");
20377   // Calling function using another context's call/apply methods.
20378   TestReceiver(i, foreign_context->Global(),
20379                "Function.prototype.call.call(func)");
20380   TestReceiver(i, foreign_context->Global(),
20381                "Function.prototype.call.apply(func)");
20382   TestReceiver(i, foreign_context->Global(),
20383                "Function.prototype.apply.call(func)");
20384   TestReceiver(i, foreign_context->Global(),
20385                "Function.prototype.apply.apply(func)");
20386   // Making calls through built-in functions.
20387   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20388   // ToString(func()) is func()[0], i.e., the returned this.id.
20389   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20390   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20391   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20392
20393   // Calling with environment record as base.
20394   TestReceiver(i, foreign_context->Global(), "func()");
20395   // Calling with no base.
20396   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20397 }
20398
20399
20400 uint8_t callback_fired = 0;
20401
20402
20403 void CallCompletedCallback1() {
20404   i::OS::Print("Firing callback 1.\n");
20405   callback_fired ^= 1;  // Toggle first bit.
20406 }
20407
20408
20409 void CallCompletedCallback2() {
20410   i::OS::Print("Firing callback 2.\n");
20411   callback_fired ^= 2;  // Toggle second bit.
20412 }
20413
20414
20415 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20416   int32_t level = args[0]->Int32Value();
20417   if (level < 3) {
20418     level++;
20419     i::OS::Print("Entering recursion level %d.\n", level);
20420     char script[64];
20421     i::Vector<char> script_vector(script, sizeof(script));
20422     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20423     CompileRun(script_vector.start());
20424     i::OS::Print("Leaving recursion level %d.\n", level);
20425     CHECK_EQ(0, callback_fired);
20426   } else {
20427     i::OS::Print("Recursion ends.\n");
20428     CHECK_EQ(0, callback_fired);
20429   }
20430 }
20431
20432
20433 TEST(CallCompletedCallback) {
20434   LocalContext env;
20435   v8::HandleScope scope(env->GetIsolate());
20436   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20437       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20438   env->Global()->Set(v8_str("recursion"),
20439                      recursive_runtime->GetFunction());
20440   // Adding the same callback a second time has no effect.
20441   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20442   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20443   v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
20444   i::OS::Print("--- Script (1) ---\n");
20445   Local<Script> script = v8::Script::Compile(
20446       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20447   script->Run();
20448   CHECK_EQ(3, callback_fired);
20449
20450   i::OS::Print("\n--- Script (2) ---\n");
20451   callback_fired = 0;
20452   v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
20453   script->Run();
20454   CHECK_EQ(2, callback_fired);
20455
20456   i::OS::Print("\n--- Function ---\n");
20457   callback_fired = 0;
20458   Local<Function> recursive_function =
20459       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20460   v8::Handle<Value> args[] = { v8_num(0) };
20461   recursive_function->Call(env->Global(), 1, args);
20462   CHECK_EQ(2, callback_fired);
20463 }
20464
20465
20466 void CallCompletedCallbackNoException() {
20467   v8::HandleScope scope(CcTest::isolate());
20468   CompileRun("1+1;");
20469 }
20470
20471
20472 void CallCompletedCallbackException() {
20473   v8::HandleScope scope(CcTest::isolate());
20474   CompileRun("throw 'second exception';");
20475 }
20476
20477
20478 TEST(CallCompletedCallbackOneException) {
20479   LocalContext env;
20480   v8::HandleScope scope(env->GetIsolate());
20481   v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
20482   CompileRun("throw 'exception';");
20483 }
20484
20485
20486 TEST(CallCompletedCallbackTwoExceptions) {
20487   LocalContext env;
20488   v8::HandleScope scope(env->GetIsolate());
20489   v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
20490   CompileRun("throw 'first exception';");
20491 }
20492
20493
20494 static int probes_counter = 0;
20495 static int misses_counter = 0;
20496 static int updates_counter = 0;
20497
20498
20499 static int* LookupCounter(const char* name) {
20500   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20501     return &probes_counter;
20502   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20503     return &misses_counter;
20504   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20505     return &updates_counter;
20506   }
20507   return NULL;
20508 }
20509
20510
20511 static const char* kMegamorphicTestProgram =
20512     "function ClassA() { };"
20513     "function ClassB() { };"
20514     "ClassA.prototype.foo = function() { };"
20515     "ClassB.prototype.foo = function() { };"
20516     "function fooify(obj) { obj.foo(); };"
20517     "var a = new ClassA();"
20518     "var b = new ClassB();"
20519     "for (var i = 0; i < 10000; i++) {"
20520     "  fooify(a);"
20521     "  fooify(b);"
20522     "}";
20523
20524
20525 static void StubCacheHelper(bool primary) {
20526   V8::SetCounterFunction(LookupCounter);
20527   USE(kMegamorphicTestProgram);
20528 #ifdef DEBUG
20529   i::FLAG_native_code_counters = true;
20530   if (primary) {
20531     i::FLAG_test_primary_stub_cache = true;
20532   } else {
20533     i::FLAG_test_secondary_stub_cache = true;
20534   }
20535   i::FLAG_crankshaft = false;
20536   LocalContext env;
20537   v8::HandleScope scope(env->GetIsolate());
20538   int initial_probes = probes_counter;
20539   int initial_misses = misses_counter;
20540   int initial_updates = updates_counter;
20541   CompileRun(kMegamorphicTestProgram);
20542   int probes = probes_counter - initial_probes;
20543   int misses = misses_counter - initial_misses;
20544   int updates = updates_counter - initial_updates;
20545   CHECK_LT(updates, 10);
20546   CHECK_LT(misses, 10);
20547   // TODO(verwaest): Update this test to overflow the degree of polymorphism
20548   // before megamorphism. The number of probes will only work once we teach the
20549   // serializer to embed references to counters in the stubs, given that the
20550   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20551   CHECK_GE(probes, 0);
20552 #endif
20553 }
20554
20555
20556 TEST(SecondaryStubCache) {
20557   StubCacheHelper(true);
20558 }
20559
20560
20561 TEST(PrimaryStubCache) {
20562   StubCacheHelper(false);
20563 }
20564
20565
20566 static int cow_arrays_created_runtime = 0;
20567
20568
20569 static int* LookupCounterCOWArrays(const char* name) {
20570   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20571     return &cow_arrays_created_runtime;
20572   }
20573   return NULL;
20574 }
20575
20576
20577 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20578   V8::SetCounterFunction(LookupCounterCOWArrays);
20579 #ifdef DEBUG
20580   i::FLAG_native_code_counters = true;
20581   LocalContext env;
20582   v8::HandleScope scope(env->GetIsolate());
20583   int initial_cow_arrays = cow_arrays_created_runtime;
20584   CompileRun("var o = [1, 2, 3];");
20585   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20586   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20587   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20588   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20589   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20590 #endif
20591 }
20592
20593
20594 TEST(StaticGetters) {
20595   LocalContext context;
20596   i::Factory* factory = CcTest::i_isolate()->factory();
20597   v8::Isolate* isolate = CcTest::isolate();
20598   v8::HandleScope scope(isolate);
20599   i::Handle<i::Object> undefined_value = factory->undefined_value();
20600   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20601   i::Handle<i::Object> null_value = factory->null_value();
20602   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20603   i::Handle<i::Object> true_value = factory->true_value();
20604   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20605   i::Handle<i::Object> false_value = factory->false_value();
20606   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20607 }
20608
20609
20610 UNINITIALIZED_TEST(IsolateEmbedderData) {
20611   CcTest::DisableAutomaticDispose();
20612   v8::Isolate* isolate = v8::Isolate::New();
20613   isolate->Enter();
20614   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20615   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20616     CHECK_EQ(NULL, isolate->GetData(slot));
20617     CHECK_EQ(NULL, i_isolate->GetData(slot));
20618   }
20619   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20620     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20621     isolate->SetData(slot, data);
20622   }
20623   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20624     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20625     CHECK_EQ(data, isolate->GetData(slot));
20626     CHECK_EQ(data, i_isolate->GetData(slot));
20627   }
20628   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20629     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20630     isolate->SetData(slot, data);
20631   }
20632   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20633     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20634     CHECK_EQ(data, isolate->GetData(slot));
20635     CHECK_EQ(data, i_isolate->GetData(slot));
20636   }
20637   isolate->Exit();
20638   isolate->Dispose();
20639 }
20640
20641
20642 TEST(StringEmpty) {
20643   LocalContext context;
20644   i::Factory* factory = CcTest::i_isolate()->factory();
20645   v8::Isolate* isolate = CcTest::isolate();
20646   v8::HandleScope scope(isolate);
20647   i::Handle<i::Object> empty_string = factory->empty_string();
20648   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20649 }
20650
20651
20652 static int instance_checked_getter_count = 0;
20653 static void InstanceCheckedGetter(
20654     Local<String> name,
20655     const v8::PropertyCallbackInfo<v8::Value>& info) {
20656   CHECK_EQ(name, v8_str("foo"));
20657   instance_checked_getter_count++;
20658   info.GetReturnValue().Set(v8_num(11));
20659 }
20660
20661
20662 static int instance_checked_setter_count = 0;
20663 static void InstanceCheckedSetter(Local<String> name,
20664                       Local<Value> value,
20665                       const v8::PropertyCallbackInfo<void>& info) {
20666   CHECK_EQ(name, v8_str("foo"));
20667   CHECK_EQ(value, v8_num(23));
20668   instance_checked_setter_count++;
20669 }
20670
20671
20672 static void CheckInstanceCheckedResult(int getters,
20673                                        int setters,
20674                                        bool expects_callbacks,
20675                                        TryCatch* try_catch) {
20676   if (expects_callbacks) {
20677     CHECK(!try_catch->HasCaught());
20678     CHECK_EQ(getters, instance_checked_getter_count);
20679     CHECK_EQ(setters, instance_checked_setter_count);
20680   } else {
20681     CHECK(try_catch->HasCaught());
20682     CHECK_EQ(0, instance_checked_getter_count);
20683     CHECK_EQ(0, instance_checked_setter_count);
20684   }
20685   try_catch->Reset();
20686 }
20687
20688
20689 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
20690   instance_checked_getter_count = 0;
20691   instance_checked_setter_count = 0;
20692   TryCatch try_catch;
20693
20694   // Test path through generic runtime code.
20695   CompileRun("obj.foo");
20696   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
20697   CompileRun("obj.foo = 23");
20698   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
20699
20700   // Test path through generated LoadIC and StoredIC.
20701   CompileRun("function test_get(o) { o.foo; }"
20702              "test_get(obj);");
20703   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
20704   CompileRun("test_get(obj);");
20705   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
20706   CompileRun("test_get(obj);");
20707   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
20708   CompileRun("function test_set(o) { o.foo = 23; }"
20709              "test_set(obj);");
20710   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
20711   CompileRun("test_set(obj);");
20712   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
20713   CompileRun("test_set(obj);");
20714   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
20715
20716   // Test path through optimized code.
20717   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
20718              "test_get(obj);");
20719   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
20720   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
20721              "test_set(obj);");
20722   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
20723
20724   // Cleanup so that closures start out fresh in next check.
20725   CompileRun("%DeoptimizeFunction(test_get);"
20726              "%ClearFunctionTypeFeedback(test_get);"
20727              "%DeoptimizeFunction(test_set);"
20728              "%ClearFunctionTypeFeedback(test_set);");
20729 }
20730
20731
20732 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
20733   v8::internal::FLAG_allow_natives_syntax = true;
20734   LocalContext context;
20735   v8::HandleScope scope(context->GetIsolate());
20736
20737   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20738   Local<ObjectTemplate> inst = templ->InstanceTemplate();
20739   inst->SetAccessor(v8_str("foo"),
20740                     InstanceCheckedGetter, InstanceCheckedSetter,
20741                     Handle<Value>(),
20742                     v8::DEFAULT,
20743                     v8::None,
20744                     v8::AccessorSignature::New(context->GetIsolate(), templ));
20745   context->Global()->Set(v8_str("f"), templ->GetFunction());
20746
20747   printf("Testing positive ...\n");
20748   CompileRun("var obj = new f();");
20749   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20750   CheckInstanceCheckedAccessors(true);
20751
20752   printf("Testing negative ...\n");
20753   CompileRun("var obj = {};"
20754              "obj.__proto__ = new f();");
20755   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20756   CheckInstanceCheckedAccessors(false);
20757 }
20758
20759
20760 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
20761   v8::internal::FLAG_allow_natives_syntax = true;
20762   LocalContext context;
20763   v8::HandleScope scope(context->GetIsolate());
20764
20765   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20766   Local<ObjectTemplate> inst = templ->InstanceTemplate();
20767   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20768   inst->SetAccessor(v8_str("foo"),
20769                     InstanceCheckedGetter, InstanceCheckedSetter,
20770                     Handle<Value>(),
20771                     v8::DEFAULT,
20772                     v8::None,
20773                     v8::AccessorSignature::New(context->GetIsolate(), templ));
20774   context->Global()->Set(v8_str("f"), templ->GetFunction());
20775
20776   printf("Testing positive ...\n");
20777   CompileRun("var obj = new f();");
20778   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20779   CheckInstanceCheckedAccessors(true);
20780
20781   printf("Testing negative ...\n");
20782   CompileRun("var obj = {};"
20783              "obj.__proto__ = new f();");
20784   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20785   CheckInstanceCheckedAccessors(false);
20786 }
20787
20788
20789 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20790   v8::internal::FLAG_allow_natives_syntax = true;
20791   LocalContext context;
20792   v8::HandleScope scope(context->GetIsolate());
20793
20794   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20795   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20796   proto->SetAccessor(v8_str("foo"),
20797                      InstanceCheckedGetter, InstanceCheckedSetter,
20798                      Handle<Value>(),
20799                      v8::DEFAULT,
20800                      v8::None,
20801                      v8::AccessorSignature::New(context->GetIsolate(), templ));
20802   context->Global()->Set(v8_str("f"), templ->GetFunction());
20803
20804   printf("Testing positive ...\n");
20805   CompileRun("var obj = new f();");
20806   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20807   CheckInstanceCheckedAccessors(true);
20808
20809   printf("Testing negative ...\n");
20810   CompileRun("var obj = {};"
20811              "obj.__proto__ = new f();");
20812   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20813   CheckInstanceCheckedAccessors(false);
20814
20815   printf("Testing positive with modified prototype chain ...\n");
20816   CompileRun("var obj = new f();"
20817              "var pro = {};"
20818              "pro.__proto__ = obj.__proto__;"
20819              "obj.__proto__ = pro;");
20820   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20821   CheckInstanceCheckedAccessors(true);
20822 }
20823
20824
20825 TEST(TryFinallyMessage) {
20826   LocalContext context;
20827   v8::HandleScope scope(context->GetIsolate());
20828   {
20829     // Test that the original error message is not lost if there is a
20830     // recursive call into Javascript is done in the finally block, e.g. to
20831     // initialize an IC. (crbug.com/129171)
20832     TryCatch try_catch;
20833     const char* trigger_ic =
20834         "try {                      \n"
20835         "  throw new Error('test'); \n"
20836         "} finally {                \n"
20837         "  var x = 0;               \n"
20838         "  x++;                     \n"  // Trigger an IC initialization here.
20839         "}                          \n";
20840     CompileRun(trigger_ic);
20841     CHECK(try_catch.HasCaught());
20842     Local<Message> message = try_catch.Message();
20843     CHECK(!message.IsEmpty());
20844     CHECK_EQ(2, message->GetLineNumber());
20845   }
20846
20847   {
20848     // Test that the original exception message is indeed overwritten if
20849     // a new error is thrown in the finally block.
20850     TryCatch try_catch;
20851     const char* throw_again =
20852         "try {                       \n"
20853         "  throw new Error('test');  \n"
20854         "} finally {                 \n"
20855         "  var x = 0;                \n"
20856         "  x++;                      \n"
20857         "  throw new Error('again'); \n"  // This is the new uncaught error.
20858         "}                           \n";
20859     CompileRun(throw_again);
20860     CHECK(try_catch.HasCaught());
20861     Local<Message> message = try_catch.Message();
20862     CHECK(!message.IsEmpty());
20863     CHECK_EQ(6, message->GetLineNumber());
20864   }
20865 }
20866
20867
20868 static void Helper137002(bool do_store,
20869                          bool polymorphic,
20870                          bool remove_accessor,
20871                          bool interceptor) {
20872   LocalContext context;
20873   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
20874   if (interceptor) {
20875     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
20876   } else {
20877     templ->SetAccessor(v8_str("foo"),
20878                        GetterWhichReturns42,
20879                        SetterWhichSetsYOnThisTo23);
20880   }
20881   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20882
20883   // Turn monomorphic on slow object with native accessor, then turn
20884   // polymorphic, finally optimize to create negative lookup and fail.
20885   CompileRun(do_store ?
20886              "function f(x) { x.foo = void 0; }" :
20887              "function f(x) { return x.foo; }");
20888   CompileRun("obj.y = void 0;");
20889   if (!interceptor) {
20890     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20891   }
20892   CompileRun("obj.__proto__ = null;"
20893              "f(obj); f(obj); f(obj);");
20894   if (polymorphic) {
20895     CompileRun("f({});");
20896   }
20897   CompileRun("obj.y = void 0;"
20898              "%OptimizeFunctionOnNextCall(f);");
20899   if (remove_accessor) {
20900     CompileRun("delete obj.foo;");
20901   }
20902   CompileRun("var result = f(obj);");
20903   if (do_store) {
20904     CompileRun("result = obj.y;");
20905   }
20906   if (remove_accessor && !interceptor) {
20907     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20908   } else {
20909     CHECK_EQ(do_store ? 23 : 42,
20910              context->Global()->Get(v8_str("result"))->Int32Value());
20911   }
20912 }
20913
20914
20915 THREADED_TEST(Regress137002a) {
20916   i::FLAG_allow_natives_syntax = true;
20917   i::FLAG_compilation_cache = false;
20918   v8::HandleScope scope(CcTest::isolate());
20919   for (int i = 0; i < 16; i++) {
20920     Helper137002(i & 8, i & 4, i & 2, i & 1);
20921   }
20922 }
20923
20924
20925 THREADED_TEST(Regress137002b) {
20926   i::FLAG_allow_natives_syntax = true;
20927   LocalContext context;
20928   v8::Isolate* isolate = context->GetIsolate();
20929   v8::HandleScope scope(isolate);
20930   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20931   templ->SetAccessor(v8_str("foo"),
20932                      GetterWhichReturns42,
20933                      SetterWhichSetsYOnThisTo23);
20934   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20935
20936   // Turn monomorphic on slow object with native accessor, then just
20937   // delete the property and fail.
20938   CompileRun("function load(x) { return x.foo; }"
20939              "function store(x) { x.foo = void 0; }"
20940              "function keyed_load(x, key) { return x[key]; }"
20941              // Second version of function has a different source (add void 0)
20942              // so that it does not share code with the first version.  This
20943              // ensures that the ICs are monomorphic.
20944              "function load2(x) { void 0; return x.foo; }"
20945              "function store2(x) { void 0; x.foo = void 0; }"
20946              "function keyed_load2(x, key) { void 0; return x[key]; }"
20947
20948              "obj.y = void 0;"
20949              "obj.__proto__ = null;"
20950              "var subobj = {};"
20951              "subobj.y = void 0;"
20952              "subobj.__proto__ = obj;"
20953              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20954
20955              // Make the ICs monomorphic.
20956              "load(obj); load(obj);"
20957              "load2(subobj); load2(subobj);"
20958              "store(obj); store(obj);"
20959              "store2(subobj); store2(subobj);"
20960              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
20961              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
20962
20963              // Actually test the shiny new ICs and better not crash. This
20964              // serves as a regression test for issue 142088 as well.
20965              "load(obj);"
20966              "load2(subobj);"
20967              "store(obj);"
20968              "store2(subobj);"
20969              "keyed_load(obj, 'foo');"
20970              "keyed_load2(subobj, 'foo');"
20971
20972              // Delete the accessor.  It better not be called any more now.
20973              "delete obj.foo;"
20974              "obj.y = void 0;"
20975              "subobj.y = void 0;"
20976
20977              "var load_result = load(obj);"
20978              "var load_result2 = load2(subobj);"
20979              "var keyed_load_result = keyed_load(obj, 'foo');"
20980              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
20981              "store(obj);"
20982              "store2(subobj);"
20983              "var y_from_obj = obj.y;"
20984              "var y_from_subobj = subobj.y;");
20985   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
20986   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
20987   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
20988   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
20989   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
20990   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
20991 }
20992
20993
20994 THREADED_TEST(Regress142088) {
20995   i::FLAG_allow_natives_syntax = true;
20996   LocalContext context;
20997   v8::Isolate* isolate = context->GetIsolate();
20998   v8::HandleScope scope(isolate);
20999   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21000   templ->SetAccessor(v8_str("foo"),
21001                      GetterWhichReturns42,
21002                      SetterWhichSetsYOnThisTo23);
21003   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21004
21005   CompileRun("function load(x) { return x.foo; }"
21006              "var o = Object.create(obj);"
21007              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21008              "load(o); load(o); load(o); load(o);");
21009 }
21010
21011
21012 THREADED_TEST(Regress137496) {
21013   i::FLAG_expose_gc = true;
21014   LocalContext context;
21015   v8::HandleScope scope(context->GetIsolate());
21016
21017   // Compile a try-finally clause where the finally block causes a GC
21018   // while there still is a message pending for external reporting.
21019   TryCatch try_catch;
21020   try_catch.SetVerbose(true);
21021   CompileRun("try { throw new Error(); } finally { gc(); }");
21022   CHECK(try_catch.HasCaught());
21023 }
21024
21025
21026 THREADED_TEST(Regress149912) {
21027   LocalContext context;
21028   v8::HandleScope scope(context->GetIsolate());
21029   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21030   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21031   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21032   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21033 }
21034
21035
21036 THREADED_TEST(Regress157124) {
21037   LocalContext context;
21038   v8::Isolate* isolate = context->GetIsolate();
21039   v8::HandleScope scope(isolate);
21040   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21041   Local<Object> obj = templ->NewInstance();
21042   obj->GetIdentityHash();
21043   obj->DeleteHiddenValue(v8_str("Bug"));
21044 }
21045
21046
21047 THREADED_TEST(Regress2535) {
21048   i::FLAG_harmony_collections = true;
21049   LocalContext context;
21050   v8::HandleScope scope(context->GetIsolate());
21051   Local<Value> set_value = CompileRun("new Set();");
21052   Local<Object> set_object(Local<Object>::Cast(set_value));
21053   CHECK_EQ(0, set_object->InternalFieldCount());
21054   Local<Value> map_value = CompileRun("new Map();");
21055   Local<Object> map_object(Local<Object>::Cast(map_value));
21056   CHECK_EQ(0, map_object->InternalFieldCount());
21057 }
21058
21059
21060 THREADED_TEST(Regress2746) {
21061   LocalContext context;
21062   v8::Isolate* isolate = context->GetIsolate();
21063   v8::HandleScope scope(isolate);
21064   Local<Object> obj = Object::New(isolate);
21065   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21066   obj->SetHiddenValue(key, v8::Undefined(isolate));
21067   Local<Value> value = obj->GetHiddenValue(key);
21068   CHECK(!value.IsEmpty());
21069   CHECK(value->IsUndefined());
21070 }
21071
21072
21073 THREADED_TEST(Regress260106) {
21074   LocalContext context;
21075   v8::Isolate* isolate = context->GetIsolate();
21076   v8::HandleScope scope(isolate);
21077   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21078                                                         DummyCallHandler);
21079   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21080   Local<Function> function = templ->GetFunction();
21081   CHECK(!function.IsEmpty());
21082   CHECK(function->IsFunction());
21083 }
21084
21085
21086 THREADED_TEST(JSONParseObject) {
21087   LocalContext context;
21088   HandleScope scope(context->GetIsolate());
21089   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21090   Handle<Object> global = context->Global();
21091   global->Set(v8_str("obj"), obj);
21092   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21093 }
21094
21095
21096 THREADED_TEST(JSONParseNumber) {
21097   LocalContext context;
21098   HandleScope scope(context->GetIsolate());
21099   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21100   Handle<Object> global = context->Global();
21101   global->Set(v8_str("obj"), obj);
21102   ExpectString("JSON.stringify(obj)", "42");
21103 }
21104
21105
21106 #if V8_OS_POSIX
21107 class ThreadInterruptTest {
21108  public:
21109   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21110   ~ThreadInterruptTest() {}
21111
21112   void RunTest() {
21113     InterruptThread i_thread(this);
21114     i_thread.Start();
21115
21116     sem_.Wait();
21117     CHECK_EQ(kExpectedValue, sem_value_);
21118   }
21119
21120  private:
21121   static const int kExpectedValue = 1;
21122
21123   class InterruptThread : public i::Thread {
21124    public:
21125     explicit InterruptThread(ThreadInterruptTest* test)
21126         : Thread("InterruptThread"), test_(test) {}
21127
21128     virtual void Run() {
21129       struct sigaction action;
21130
21131       // Ensure that we'll enter waiting condition
21132       i::OS::Sleep(100);
21133
21134       // Setup signal handler
21135       memset(&action, 0, sizeof(action));
21136       action.sa_handler = SignalHandler;
21137       sigaction(SIGCHLD, &action, NULL);
21138
21139       // Send signal
21140       kill(getpid(), SIGCHLD);
21141
21142       // Ensure that if wait has returned because of error
21143       i::OS::Sleep(100);
21144
21145       // Set value and signal semaphore
21146       test_->sem_value_ = 1;
21147       test_->sem_.Signal();
21148     }
21149
21150     static void SignalHandler(int signal) {
21151     }
21152
21153    private:
21154      ThreadInterruptTest* test_;
21155   };
21156
21157   i::Semaphore sem_;
21158   volatile int sem_value_;
21159 };
21160
21161
21162 THREADED_TEST(SemaphoreInterruption) {
21163   ThreadInterruptTest().RunTest();
21164 }
21165
21166
21167 #endif  // V8_OS_POSIX
21168
21169
21170 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21171                                      Local<Value> name,
21172                                      v8::AccessType type,
21173                                      Local<Value> data) {
21174   i::PrintF("Named access blocked.\n");
21175   return false;
21176 }
21177
21178
21179 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21180                                      uint32_t key,
21181                                      v8::AccessType type,
21182                                      Local<Value> data) {
21183   i::PrintF("Indexed access blocked.\n");
21184   return false;
21185 }
21186
21187
21188 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21189   CHECK(false);
21190 }
21191
21192
21193 TEST(JSONStringifyAccessCheck) {
21194   v8::V8::Initialize();
21195   v8::Isolate* isolate = CcTest::isolate();
21196   v8::HandleScope scope(isolate);
21197
21198   // Create an ObjectTemplate for global objects and install access
21199   // check callbacks that will block access.
21200   v8::Handle<v8::ObjectTemplate> global_template =
21201       v8::ObjectTemplate::New(isolate);
21202   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21203                                            IndexAccessAlwaysBlocked);
21204
21205   // Create a context and set an x property on it's global object.
21206   LocalContext context0(NULL, global_template);
21207   v8::Handle<v8::Object> global0 = context0->Global();
21208   global0->Set(v8_str("x"), v8_num(42));
21209   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21210
21211   for (int i = 0; i < 2; i++) {
21212     if (i == 1) {
21213       // Install a toJSON function on the second run.
21214       v8::Handle<v8::FunctionTemplate> toJSON =
21215           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21216
21217       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21218     }
21219     // Create a context with a different security token so that the
21220     // failed access check callback will be called on each access.
21221     LocalContext context1(NULL, global_template);
21222     context1->Global()->Set(v8_str("other"), global0);
21223
21224     ExpectString("JSON.stringify(other)", "{}");
21225     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21226                  "{\"a\":{},\"b\":[\"c\"]}");
21227     ExpectString("JSON.stringify([other, 'b', 'c'])",
21228                  "[{},\"b\",\"c\"]");
21229
21230     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21231     array->Set(0, v8_str("a"));
21232     array->Set(1, v8_str("b"));
21233     context1->Global()->Set(v8_str("array"), array);
21234     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21235     array->TurnOnAccessCheck();
21236     ExpectString("JSON.stringify(array)", "[]");
21237     ExpectString("JSON.stringify([array])", "[[]]");
21238     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21239   }
21240 }
21241
21242
21243 bool access_check_fail_thrown = false;
21244 bool catch_callback_called = false;
21245
21246
21247 // Failed access check callback that performs a GC on each invocation.
21248 void FailedAccessCheckThrows(Local<v8::Object> target,
21249                              v8::AccessType type,
21250                              Local<v8::Value> data) {
21251   access_check_fail_thrown = true;
21252   i::PrintF("Access check failed. Error thrown.\n");
21253   CcTest::isolate()->ThrowException(
21254       v8::Exception::Error(v8_str("cross context")));
21255 }
21256
21257
21258 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21259   for (int i = 0; i < args.Length(); i++) {
21260     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21261   }
21262   catch_callback_called = true;
21263 }
21264
21265
21266 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21267   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21268 }
21269
21270
21271 void CheckCorrectThrow(const char* script) {
21272   // Test that the script, when wrapped into a try-catch, triggers the catch
21273   // clause due to failed access check throwing an exception.
21274   // The subsequent try-catch should run without any exception.
21275   access_check_fail_thrown = false;
21276   catch_callback_called = false;
21277   i::ScopedVector<char> source(1024);
21278   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21279   CompileRun(source.start());
21280   CHECK(access_check_fail_thrown);
21281   CHECK(catch_callback_called);
21282
21283   access_check_fail_thrown = false;
21284   catch_callback_called = false;
21285   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21286   CHECK(!access_check_fail_thrown);
21287   CHECK(!catch_callback_called);
21288 }
21289
21290
21291 TEST(AccessCheckThrows) {
21292   i::FLAG_allow_natives_syntax = true;
21293   v8::V8::Initialize();
21294   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21295   v8::Isolate* isolate = CcTest::isolate();
21296   v8::HandleScope scope(isolate);
21297
21298   // Create an ObjectTemplate for global objects and install access
21299   // check callbacks that will block access.
21300   v8::Handle<v8::ObjectTemplate> global_template =
21301       v8::ObjectTemplate::New(isolate);
21302   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21303                                            IndexAccessAlwaysBlocked);
21304
21305   // Create a context and set an x property on it's global object.
21306   LocalContext context0(NULL, global_template);
21307   context0->Global()->Set(v8_str("x"), v8_num(42));
21308   v8::Handle<v8::Object> global0 = context0->Global();
21309
21310   // Create a context with a different security token so that the
21311   // failed access check callback will be called on each access.
21312   LocalContext context1(NULL, global_template);
21313   context1->Global()->Set(v8_str("other"), global0);
21314
21315   v8::Handle<v8::FunctionTemplate> catcher_fun =
21316       v8::FunctionTemplate::New(isolate, CatcherCallback);
21317   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21318
21319   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21320       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21321   context1->Global()->Set(v8_str("has_own_property"),
21322                           has_own_property_fun->GetFunction());
21323
21324   { v8::TryCatch try_catch;
21325     access_check_fail_thrown = false;
21326     CompileRun("other.x;");
21327     CHECK(access_check_fail_thrown);
21328     CHECK(try_catch.HasCaught());
21329   }
21330
21331   CheckCorrectThrow("other.x");
21332   CheckCorrectThrow("other[1]");
21333   CheckCorrectThrow("JSON.stringify(other)");
21334   CheckCorrectThrow("has_own_property(other, 'x')");
21335   CheckCorrectThrow("%GetProperty(other, 'x')");
21336   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21337   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21338   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21339   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21340   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21341   CheckCorrectThrow("%HasProperty(other, 'x')");
21342   CheckCorrectThrow("%HasElement(other, 1)");
21343   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21344   CheckCorrectThrow("%GetPropertyNames(other)");
21345   // PROPERTY_ATTRIBUTES_NONE = 0
21346   CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21347   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21348                         "other, 'x', null, null, 1)");
21349
21350   // Reset the failed access check callback so it does not influence
21351   // the other tests.
21352   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21353 }
21354
21355
21356 THREADED_TEST(Regress256330) {
21357   i::FLAG_allow_natives_syntax = true;
21358   LocalContext context;
21359   v8::HandleScope scope(context->GetIsolate());
21360   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21361   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21362   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21363   CompileRun("\"use strict\"; var o = new Bug;"
21364              "function f(o) { o.x = 10; };"
21365              "f(o); f(o); f(o);"
21366              "%OptimizeFunctionOnNextCall(f);"
21367              "f(o);");
21368   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21369 }
21370
21371
21372 THREADED_TEST(CrankshaftInterceptorSetter) {
21373   i::FLAG_allow_natives_syntax = true;
21374   v8::HandleScope scope(CcTest::isolate());
21375   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21376   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21377   LocalContext env;
21378   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21379   CompileRun("var obj = new Obj;"
21380              // Initialize fields to avoid transitions later.
21381              "obj.age = 0;"
21382              "obj.accessor_age = 42;"
21383              "function setter(i) { this.accessor_age = i; };"
21384              "function getter() { return this.accessor_age; };"
21385              "function setAge(i) { obj.age = i; };"
21386              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21387              "setAge(1);"
21388              "setAge(2);"
21389              "setAge(3);"
21390              "%OptimizeFunctionOnNextCall(setAge);"
21391              "setAge(4);");
21392   // All stores went through the interceptor.
21393   ExpectInt32("obj.interceptor_age", 4);
21394   ExpectInt32("obj.accessor_age", 42);
21395 }
21396
21397
21398 THREADED_TEST(CrankshaftInterceptorGetter) {
21399   i::FLAG_allow_natives_syntax = true;
21400   v8::HandleScope scope(CcTest::isolate());
21401   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21402   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21403   LocalContext env;
21404   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21405   CompileRun("var obj = new Obj;"
21406              // Initialize fields to avoid transitions later.
21407              "obj.age = 1;"
21408              "obj.accessor_age = 42;"
21409              "function getter() { return this.accessor_age; };"
21410              "function getAge() { return obj.interceptor_age; };"
21411              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21412              "getAge();"
21413              "getAge();"
21414              "getAge();"
21415              "%OptimizeFunctionOnNextCall(getAge);");
21416   // Access through interceptor.
21417   ExpectInt32("getAge()", 1);
21418 }
21419
21420
21421 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21422   i::FLAG_allow_natives_syntax = true;
21423   v8::HandleScope scope(CcTest::isolate());
21424   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21425   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21426   LocalContext env;
21427   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21428   CompileRun("var obj = new Obj;"
21429              "obj.__proto__.interceptor_age = 42;"
21430              "obj.age = 100;"
21431              "function getAge() { return obj.interceptor_age; };");
21432   ExpectInt32("getAge();", 100);
21433   ExpectInt32("getAge();", 100);
21434   ExpectInt32("getAge();", 100);
21435   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21436   // Access through interceptor.
21437   ExpectInt32("getAge();", 100);
21438 }
21439
21440
21441 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21442   i::FLAG_allow_natives_syntax = true;
21443   v8::HandleScope scope(CcTest::isolate());
21444   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21445   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21446   LocalContext env;
21447   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21448   CompileRun("var obj = new Obj;"
21449              "obj.age = 100000;"
21450              "function setAge(i) { obj.age = i };"
21451              "setAge(100);"
21452              "setAge(101);"
21453              "setAge(102);"
21454              "%OptimizeFunctionOnNextCall(setAge);"
21455              "setAge(103);");
21456   ExpectInt32("obj.age", 100000);
21457   ExpectInt32("obj.interceptor_age", 103);
21458 }
21459
21460
21461 class RequestInterruptTestBase {
21462  public:
21463   RequestInterruptTestBase()
21464       : env_(),
21465         isolate_(env_->GetIsolate()),
21466         sem_(0),
21467         warmup_(20000),
21468         should_continue_(true) {
21469   }
21470
21471   virtual ~RequestInterruptTestBase() { }
21472
21473   virtual void TestBody() = 0;
21474
21475   void RunTest() {
21476     InterruptThread i_thread(this);
21477     i_thread.Start();
21478
21479     v8::HandleScope handle_scope(isolate_);
21480
21481     TestBody();
21482
21483     isolate_->ClearInterrupt();
21484
21485     // Verify we arrived here because interruptor was called
21486     // not due to a bug causing us to exit the loop too early.
21487     CHECK(!should_continue());
21488   }
21489
21490   void WakeUpInterruptor() {
21491     sem_.Signal();
21492   }
21493
21494   bool should_continue() const { return should_continue_; }
21495
21496   bool ShouldContinue() {
21497     if (warmup_ > 0) {
21498       if (--warmup_ == 0) {
21499         WakeUpInterruptor();
21500       }
21501     }
21502
21503     return should_continue_;
21504   }
21505
21506  protected:
21507   static void ShouldContinueCallback(
21508       const v8::FunctionCallbackInfo<Value>& info) {
21509     RequestInterruptTestBase* test =
21510         reinterpret_cast<RequestInterruptTestBase*>(
21511             info.Data().As<v8::External>()->Value());
21512     info.GetReturnValue().Set(test->ShouldContinue());
21513   }
21514
21515   class InterruptThread : public i::Thread {
21516    public:
21517     explicit InterruptThread(RequestInterruptTestBase* test)
21518         : Thread("RequestInterruptTest"), test_(test) {}
21519
21520     virtual void Run() {
21521       test_->sem_.Wait();
21522       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21523     }
21524
21525     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21526       reinterpret_cast<RequestInterruptTestBase*>(data)->
21527           should_continue_ = false;
21528     }
21529
21530    private:
21531      RequestInterruptTestBase* test_;
21532   };
21533
21534   LocalContext env_;
21535   v8::Isolate* isolate_;
21536   i::Semaphore sem_;
21537   int warmup_;
21538   bool should_continue_;
21539 };
21540
21541
21542 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21543  public:
21544   virtual void TestBody() {
21545     Local<Function> func = Function::New(
21546         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21547     env_->Global()->Set(v8_str("ShouldContinue"), func);
21548
21549     CompileRun("while (ShouldContinue()) { }");
21550   }
21551 };
21552
21553
21554 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21555  public:
21556   virtual void TestBody() {
21557     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21558     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21559     proto->Set(v8_str("shouldContinue"), Function::New(
21560         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21561     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21562
21563     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21564   }
21565 };
21566
21567
21568 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21569  public:
21570   virtual void TestBody() {
21571     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21572     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21573     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21574         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21575     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21576
21577     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21578   }
21579 };
21580
21581
21582 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21583  public:
21584   virtual void TestBody() {
21585     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21586     t->InstanceTemplate()->SetNativeDataProperty(
21587         v8_str("shouldContinue"),
21588         &ShouldContinueNativeGetter,
21589         NULL,
21590         v8::External::New(isolate_, this));
21591     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21592
21593     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21594   }
21595
21596  private:
21597   static void ShouldContinueNativeGetter(
21598       Local<String> property,
21599       const v8::PropertyCallbackInfo<v8::Value>& info) {
21600     RequestInterruptTestBase* test =
21601         reinterpret_cast<RequestInterruptTestBase*>(
21602             info.Data().As<v8::External>()->Value());
21603     info.GetReturnValue().Set(test->ShouldContinue());
21604   }
21605 };
21606
21607
21608 class RequestInterruptTestWithMethodCallAndInterceptor
21609     : public RequestInterruptTestBase {
21610  public:
21611   virtual void TestBody() {
21612     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21613     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21614     proto->Set(v8_str("shouldContinue"), Function::New(
21615         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21616     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21617     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21618
21619     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21620
21621     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21622   }
21623
21624  private:
21625   static void EmptyInterceptor(
21626       Local<String> property,
21627       const v8::PropertyCallbackInfo<v8::Value>& info) {
21628   }
21629 };
21630
21631
21632 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21633  public:
21634   virtual void TestBody() {
21635     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21636         isolate_,
21637         WakeUpInterruptorCallback,
21638         v8::External::New(isolate_, this)));
21639
21640     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21641         isolate_,
21642         ShouldContinueCallback,
21643         v8::External::New(isolate_, this)));
21644
21645     i::FLAG_allow_natives_syntax = true;
21646     CompileRun("function loopish(o) {"
21647                "  var pre = 10;"
21648                "  while (o.abs(1) > 0) {"
21649                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21650                "    if (pre > 0) {"
21651                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
21652                "    }"
21653                "  }"
21654                "}"
21655                "var i = 50;"
21656                "var obj = {abs: function () { return i-- }, x: null};"
21657                "delete obj.x;"
21658                "loopish(obj);"
21659                "%OptimizeFunctionOnNextCall(loopish);"
21660                "loopish(Math);");
21661
21662     i::FLAG_allow_natives_syntax = false;
21663   }
21664
21665  private:
21666   static void WakeUpInterruptorCallback(
21667       const v8::FunctionCallbackInfo<Value>& info) {
21668     if (!info[0]->BooleanValue()) return;
21669
21670     RequestInterruptTestBase* test =
21671         reinterpret_cast<RequestInterruptTestBase*>(
21672             info.Data().As<v8::External>()->Value());
21673     test->WakeUpInterruptor();
21674   }
21675
21676   static void ShouldContinueCallback(
21677       const v8::FunctionCallbackInfo<Value>& info) {
21678     RequestInterruptTestBase* test =
21679         reinterpret_cast<RequestInterruptTestBase*>(
21680             info.Data().As<v8::External>()->Value());
21681     info.GetReturnValue().Set(test->should_continue());
21682   }
21683 };
21684
21685
21686 TEST(RequestInterruptTestWithFunctionCall) {
21687   RequestInterruptTestWithFunctionCall().RunTest();
21688 }
21689
21690
21691 TEST(RequestInterruptTestWithMethodCall) {
21692   RequestInterruptTestWithMethodCall().RunTest();
21693 }
21694
21695
21696 TEST(RequestInterruptTestWithAccessor) {
21697   RequestInterruptTestWithAccessor().RunTest();
21698 }
21699
21700
21701 TEST(RequestInterruptTestWithNativeAccessor) {
21702   RequestInterruptTestWithNativeAccessor().RunTest();
21703 }
21704
21705
21706 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
21707   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
21708 }
21709
21710
21711 TEST(RequestInterruptTestWithMathAbs) {
21712   RequestInterruptTestWithMathAbs().RunTest();
21713 }
21714
21715
21716 static Local<Value> function_new_expected_env;
21717 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
21718   CHECK_EQ(function_new_expected_env, info.Data());
21719   info.GetReturnValue().Set(17);
21720 }
21721
21722
21723 THREADED_TEST(FunctionNew) {
21724   LocalContext env;
21725   v8::Isolate* isolate = env->GetIsolate();
21726   v8::HandleScope scope(isolate);
21727   Local<Object> data = v8::Object::New(isolate);
21728   function_new_expected_env = data;
21729   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
21730   env->Global()->Set(v8_str("func"), func);
21731   Local<Value> result = CompileRun("func();");
21732   CHECK_EQ(v8::Integer::New(isolate, 17), result);
21733   // Verify function not cached
21734   int serial_number =
21735       i::Smi::cast(v8::Utils::OpenHandle(*func)
21736           ->shared()->get_api_func_data()->serial_number())->value();
21737   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21738   i::Object* elm = i_isolate->native_context()->function_cache()
21739       ->GetElementNoExceptionThrown(i_isolate, serial_number);
21740   CHECK(elm->IsUndefined());
21741   // Verify that each Function::New creates a new function instance
21742   Local<Object> data2 = v8::Object::New(isolate);
21743   function_new_expected_env = data2;
21744   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
21745   CHECK(!func2->IsNull());
21746   CHECK_NE(func, func2);
21747   env->Global()->Set(v8_str("func2"), func2);
21748   Local<Value> result2 = CompileRun("func2();");
21749   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
21750 }
21751
21752
21753 TEST(EscapeableHandleScope) {
21754   HandleScope outer_scope(CcTest::isolate());
21755   LocalContext context;
21756   const int runs = 10;
21757   Local<String> values[runs];
21758   for (int i = 0; i < runs; i++) {
21759     v8::EscapableHandleScope inner_scope(CcTest::isolate());
21760     Local<String> value;
21761     if (i != 0) value = v8_str("escape value");
21762     values[i] = inner_scope.Escape(value);
21763   }
21764   for (int i = 0; i < runs; i++) {
21765     Local<String> expected;
21766     if (i != 0) {
21767       CHECK_EQ(v8_str("escape value"), values[i]);
21768     } else {
21769       CHECK(values[i].IsEmpty());
21770     }
21771   }
21772 }
21773
21774
21775 static void SetterWhichExpectsThisAndHolderToDiffer(
21776     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
21777   CHECK(info.Holder() != info.This());
21778 }
21779
21780
21781 TEST(Regress239669) {
21782   LocalContext context;
21783   v8::Isolate* isolate = context->GetIsolate();
21784   v8::HandleScope scope(isolate);
21785   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21786   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
21787   context->Global()->Set(v8_str("P"), templ->NewInstance());
21788   CompileRun(
21789       "function C1() {"
21790       "  this.x = 23;"
21791       "};"
21792       "C1.prototype = P;"
21793       "for (var i = 0; i < 4; i++ ) {"
21794       "  new C1();"
21795       "}");
21796 }
21797
21798
21799 class ApiCallOptimizationChecker {
21800  private:
21801   static Local<Object> data;
21802   static Local<Object> receiver;
21803   static Local<Object> holder;
21804   static Local<Object> callee;
21805   static int count;
21806
21807   static void OptimizationCallback(
21808       const v8::FunctionCallbackInfo<v8::Value>& info) {
21809     CHECK(callee == info.Callee());
21810     CHECK(data == info.Data());
21811     CHECK(receiver == info.This());
21812     if (info.Length() == 1) {
21813       CHECK_EQ(v8_num(1), info[0]);
21814     }
21815     CHECK(holder == info.Holder());
21816     count++;
21817   }
21818
21819   // TODO(dcarney): move this to v8.h
21820   static void SetAccessorProperty(Local<Object> object,
21821                                   Local<String> name,
21822                                   Local<Function> getter,
21823                                   Local<Function> setter = Local<Function>()) {
21824     i::Isolate* isolate = CcTest::i_isolate();
21825     v8::AccessControl settings = v8::DEFAULT;
21826     v8::PropertyAttribute attribute = v8::None;
21827     i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
21828     i::Handle<i::Object> setter_i = v8::Utils::OpenHandle(*setter, true);
21829     if (setter_i.is_null()) setter_i = isolate->factory()->null_value();
21830     i::JSObject::DefineAccessor(v8::Utils::OpenHandle(*object),
21831                                 v8::Utils::OpenHandle(*name),
21832                                 getter_i,
21833                                 setter_i,
21834                                 static_cast<PropertyAttributes>(attribute),
21835                                 settings);
21836   }
21837
21838   public:
21839     void Run(bool use_signature, bool global) {
21840       v8::Isolate* isolate = CcTest::isolate();
21841       v8::HandleScope scope(isolate);
21842       // Build a template for signature checks.
21843       Local<v8::ObjectTemplate> signature_template;
21844       Local<v8::Signature> signature;
21845       {
21846         Local<v8::FunctionTemplate> parent_template =
21847           FunctionTemplate::New(isolate);
21848         parent_template->SetHiddenPrototype(true);
21849         Local<v8::FunctionTemplate> function_template
21850             = FunctionTemplate::New(isolate);
21851         function_template->Inherit(parent_template);
21852         if (use_signature) {
21853           signature = v8::Signature::New(isolate, parent_template);
21854         }
21855         signature_template = function_template->InstanceTemplate();
21856       }
21857       // Global object must pass checks.
21858       Local<v8::Context> context =
21859           v8::Context::New(isolate, NULL, signature_template);
21860       v8::Context::Scope context_scope(context);
21861       // Install regular object that can pass signature checks.
21862       Local<Object> function_receiver = signature_template->NewInstance();
21863       context->Global()->Set(v8_str("function_receiver"), function_receiver);
21864       // Get the holder objects.
21865       Local<Object> inner_global =
21866           Local<Object>::Cast(context->Global()->GetPrototype());
21867       Local<Object> function_holder =
21868           Local<Object>::Cast(function_receiver->GetPrototype());
21869       // Install function on hidden prototype object.
21870       data = Object::New(isolate);
21871       Local<FunctionTemplate> function_template = FunctionTemplate::New(
21872           isolate, OptimizationCallback, data, signature);
21873       Local<Function> function = function_template->GetFunction();
21874       Local<Object> global_holder = Local<Object>::Cast(
21875           inner_global->GetPrototype());
21876       global_holder->Set(v8_str("g_f"), function);
21877       SetAccessorProperty(global_holder, v8_str("g_acc"), function, function);
21878       function_holder->Set(v8_str("f"), function);
21879       SetAccessorProperty(function_holder, v8_str("acc"), function, function);
21880       // Initialize expected values.
21881       callee = function;
21882       count = 0;
21883       if (global) {
21884         receiver = context->Global();
21885         holder = inner_global;
21886       } else {
21887         holder = function_receiver;
21888         // If not using a signature, add something else to the prototype chain
21889         // to test the case that holder != receiver
21890         if (!use_signature) {
21891           receiver = Local<Object>::Cast(CompileRun(
21892               "var receiver_subclass = {};\n"
21893               "receiver_subclass.__proto__ = function_receiver;\n"
21894               "receiver_subclass"));
21895         } else {
21896           receiver = Local<Object>::Cast(CompileRun(
21897             "var receiver_subclass = function_receiver;\n"
21898             "receiver_subclass"));
21899         }
21900       }
21901       // With no signature, the holder is not set.
21902       if (!use_signature) holder = receiver;
21903       // build wrap_function
21904       int key = (use_signature ? 1 : 0) + 2 * (global ? 1 : 0);
21905       i::ScopedVector<char> wrap_function(200);
21906       if (global) {
21907         i::OS::SNPrintF(
21908             wrap_function,
21909             "function wrap_f_%d() { var f = g_f; return f(); }\n"
21910             "function wrap_get_%d() { return this.g_acc; }\n"
21911             "function wrap_set_%d() { this.g_acc = 1; }\n",
21912             key, key, key);
21913       } else {
21914         i::OS::SNPrintF(
21915             wrap_function,
21916             "function wrap_f_%d() { return receiver_subclass.f(); }\n"
21917             "function wrap_get_%d() { return receiver_subclass.acc; }\n"
21918             "function wrap_set_%d() { receiver_subclass.acc = 1; }\n",
21919             key, key, key);
21920       }
21921       // build source string
21922       i::ScopedVector<char> source(500);
21923       i::OS::SNPrintF(
21924           source,
21925           "%s\n"  // wrap functions
21926           "function wrap_f() { wrap_f_%d(); }\n"
21927           "function wrap_get() { wrap_get_%d(); }\n"
21928           "function wrap_set() { wrap_set_%d(); }\n"
21929           "\n"
21930           "wrap_f();\n"
21931           "wrap_f();\n"
21932           "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
21933           "wrap_f();\n"
21934           "\n"
21935           "wrap_get();\n"
21936           "wrap_get();\n"
21937           "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
21938           "wrap_get();\n"
21939           "\n"
21940           "wrap_set();\n"
21941           "wrap_set();\n"
21942           "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
21943           "wrap_set();\n",
21944           wrap_function.start(), key, key, key, key, key, key);
21945       v8::TryCatch try_catch;
21946       CompileRun(source.start());
21947       ASSERT(!try_catch.HasCaught());
21948       CHECK_EQ(9, count);
21949     }
21950 };
21951
21952
21953 Local<Object> ApiCallOptimizationChecker::data;
21954 Local<Object> ApiCallOptimizationChecker::receiver;
21955 Local<Object> ApiCallOptimizationChecker::holder;
21956 Local<Object> ApiCallOptimizationChecker::callee;
21957 int ApiCallOptimizationChecker::count = 0;
21958
21959
21960 TEST(TestFunctionCallOptimization) {
21961   i::FLAG_allow_natives_syntax = true;
21962   ApiCallOptimizationChecker checker;
21963   checker.Run(true, true);
21964   checker.Run(false, true);
21965   checker.Run(true, false);
21966   checker.Run(false, false);
21967 }