Upstream version 7.36.149.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 #include "../include/v8-util.h"
54
55 static const bool kLogThreading = false;
56
57 using ::v8::Boolean;
58 using ::v8::BooleanObject;
59 using ::v8::Context;
60 using ::v8::Extension;
61 using ::v8::Function;
62 using ::v8::FunctionTemplate;
63 using ::v8::Handle;
64 using ::v8::HandleScope;
65 using ::v8::Local;
66 using ::v8::Message;
67 using ::v8::MessageCallback;
68 using ::v8::Object;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
71 using ::v8::Script;
72 using ::v8::StackTrace;
73 using ::v8::String;
74 using ::v8::TryCatch;
75 using ::v8::Undefined;
76 using ::v8::UniqueId;
77 using ::v8::V8;
78 using ::v8::Value;
79
80
81 #define THREADED_PROFILED_TEST(Name)                                 \
82   static void Test##Name();                                          \
83   TEST(Name##WithProfiler) {                                         \
84     RunWithProfiler(&Test##Name);                                    \
85   }                                                                  \
86   THREADED_TEST(Name)
87
88
89 void RunWithProfiler(void (*test)()) {
90   LocalContext env;
91   v8::HandleScope scope(env->GetIsolate());
92   v8::Local<v8::String> profile_name =
93       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
95
96   cpu_profiler->StartProfiling(profile_name);
97   (*test)();
98   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
99 }
100
101
102 static void ExpectString(const char* code, const char* expected) {
103   Local<Value> result = CompileRun(code);
104   CHECK(result->IsString());
105   String::Utf8Value utf8(result);
106   CHECK_EQ(expected, *utf8);
107 }
108
109
110 static void ExpectInt32(const char* code, int expected) {
111   Local<Value> result = CompileRun(code);
112   CHECK(result->IsInt32());
113   CHECK_EQ(expected, result->Int32Value());
114 }
115
116
117 static void ExpectBoolean(const char* code, bool expected) {
118   Local<Value> result = CompileRun(code);
119   CHECK(result->IsBoolean());
120   CHECK_EQ(expected, result->BooleanValue());
121 }
122
123
124 static void ExpectTrue(const char* code) {
125   ExpectBoolean(code, true);
126 }
127
128
129 static void ExpectFalse(const char* code) {
130   ExpectBoolean(code, false);
131 }
132
133
134 static void ExpectObject(const char* code, Local<Value> expected) {
135   Local<Value> result = CompileRun(code);
136   CHECK(result->Equals(expected));
137 }
138
139
140 static void ExpectUndefined(const char* code) {
141   Local<Value> result = CompileRun(code);
142   CHECK(result->IsUndefined());
143 }
144
145
146 static int signature_callback_count;
147 static Local<Value> signature_expected_receiver;
148 static void IncrementingSignatureCallback(
149     const v8::FunctionCallbackInfo<v8::Value>& args) {
150   ApiTestFuzzer::Fuzz();
151   signature_callback_count++;
152   CHECK_EQ(signature_expected_receiver, args.Holder());
153   CHECK_EQ(signature_expected_receiver, args.This());
154   v8::Handle<v8::Array> result =
155       v8::Array::New(args.GetIsolate(), args.Length());
156   for (int i = 0; i < args.Length(); i++)
157     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
158   args.GetReturnValue().Set(result);
159 }
160
161
162 static void SignatureCallback(
163     const v8::FunctionCallbackInfo<v8::Value>& args) {
164   ApiTestFuzzer::Fuzz();
165   v8::Handle<v8::Array> result =
166       v8::Array::New(args.GetIsolate(), args.Length());
167   for (int i = 0; i < args.Length(); i++) {
168     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
169   }
170   args.GetReturnValue().Set(result);
171 }
172
173
174 // Tests that call v8::V8::Dispose() cannot be threaded.
175 TEST(InitializeAndDisposeOnce) {
176   CHECK(v8::V8::Initialize());
177   CHECK(v8::V8::Dispose());
178 }
179
180
181 // Tests that call v8::V8::Dispose() cannot be threaded.
182 TEST(InitializeAndDisposeMultiple) {
183   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
184   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
185   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
186   // TODO(mstarzinger): This should fail gracefully instead of asserting.
187   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
188   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
189 }
190
191
192 THREADED_TEST(Handles) {
193   v8::HandleScope scope(CcTest::isolate());
194   Local<Context> local_env;
195   {
196     LocalContext env;
197     local_env = env.local();
198   }
199
200   // Local context should still be live.
201   CHECK(!local_env.IsEmpty());
202   local_env->Enter();
203
204   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
205   CHECK(!undef.IsEmpty());
206   CHECK(undef->IsUndefined());
207
208   const char* source = "1 + 2 + 3";
209   Local<Script> script = v8_compile(source);
210   CHECK_EQ(6, script->Run()->Int32Value());
211
212   local_env->Exit();
213 }
214
215
216 THREADED_TEST(IsolateOfContext) {
217   v8::HandleScope scope(CcTest::isolate());
218   v8::Handle<Context> env = Context::New(CcTest::isolate());
219
220   CHECK(!env->GetIsolate()->InContext());
221   CHECK(env->GetIsolate() == CcTest::isolate());
222   env->Enter();
223   CHECK(env->GetIsolate()->InContext());
224   CHECK(env->GetIsolate() == CcTest::isolate());
225   env->Exit();
226   CHECK(!env->GetIsolate()->InContext());
227   CHECK(env->GetIsolate() == CcTest::isolate());
228 }
229
230
231 static void TestSignature(const char* loop_js, Local<Value> receiver) {
232   i::ScopedVector<char> source(200);
233   i::OS::SNPrintF(source,
234                   "for (var i = 0; i < 10; i++) {"
235                   "  %s"
236                   "}",
237                   loop_js);
238   signature_callback_count = 0;
239   signature_expected_receiver = receiver;
240   bool expected_to_throw = receiver.IsEmpty();
241   v8::TryCatch try_catch;
242   CompileRun(source.start());
243   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
244   if (!expected_to_throw) {
245     CHECK_EQ(10, signature_callback_count);
246   } else {
247     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
248              try_catch.Exception()->ToString());
249   }
250 }
251
252
253 THREADED_TEST(ReceiverSignature) {
254   LocalContext env;
255   v8::Isolate* isolate = env->GetIsolate();
256   v8::HandleScope scope(isolate);
257   // Setup templates.
258   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
259   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
260   v8::Handle<v8::FunctionTemplate> callback_sig =
261       v8::FunctionTemplate::New(
262           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
263   v8::Handle<v8::FunctionTemplate> callback =
264       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
265   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
266   sub_fun->Inherit(fun);
267   v8::Handle<v8::FunctionTemplate> unrel_fun =
268       v8::FunctionTemplate::New(isolate);
269   // Install properties.
270   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
271   fun_proto->Set(v8_str("prop_sig"), callback_sig);
272   fun_proto->Set(v8_str("prop"), callback);
273   fun_proto->SetAccessorProperty(
274       v8_str("accessor_sig"), callback_sig, callback_sig);
275   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
276   // Instantiate templates.
277   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
278   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
279   // Setup global variables.
280   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
281   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
282   env->Global()->Set(v8_str("fun_instance"), fun_instance);
283   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
284   CompileRun(
285       "var accessor_sig_key = 'accessor_sig';"
286       "var accessor_key = 'accessor';"
287       "var prop_sig_key = 'prop_sig';"
288       "var prop_key = 'prop';"
289       ""
290       "function copy_props(obj) {"
291       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
292       "  var source = Fun.prototype;"
293       "  for (var i in keys) {"
294       "    var key = keys[i];"
295       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
296       "    Object.defineProperty(obj, key, desc);"
297       "  }"
298       "}"
299       ""
300       "var obj = {};"
301       "copy_props(obj);"
302       "var unrel = new UnrelFun();"
303       "copy_props(unrel);");
304   // Test with and without ICs
305   const char* test_objects[] = {
306       "fun_instance", "sub_fun_instance", "obj", "unrel" };
307   unsigned bad_signature_start_offset = 2;
308   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
309     i::ScopedVector<char> source(200);
310     i::OS::SNPrintF(
311         source, "var test_object = %s; test_object", test_objects[i]);
312     Local<Value> test_object = CompileRun(source.start());
313     TestSignature("test_object.prop();", test_object);
314     TestSignature("test_object.accessor;", test_object);
315     TestSignature("test_object[accessor_key];", test_object);
316     TestSignature("test_object.accessor = 1;", test_object);
317     TestSignature("test_object[accessor_key] = 1;", test_object);
318     if (i >= bad_signature_start_offset) test_object = Local<Value>();
319     TestSignature("test_object.prop_sig();", test_object);
320     TestSignature("test_object.accessor_sig;", test_object);
321     TestSignature("test_object[accessor_sig_key];", test_object);
322     TestSignature("test_object.accessor_sig = 1;", test_object);
323     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
324   }
325 }
326
327
328 THREADED_TEST(ArgumentSignature) {
329   LocalContext env;
330   v8::Isolate* isolate = env->GetIsolate();
331   v8::HandleScope scope(isolate);
332   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
333   cons->SetClassName(v8_str("Cons"));
334   v8::Handle<v8::Signature> sig = v8::Signature::New(
335       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
336   v8::Handle<v8::FunctionTemplate> fun =
337       v8::FunctionTemplate::New(isolate,
338                                 SignatureCallback,
339                                 v8::Handle<Value>(),
340                                 sig);
341   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
342   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
343
344   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
345   CHECK(value1->IsTrue());
346
347   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
348   CHECK(value2->IsTrue());
349
350   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
351   CHECK(value3->IsTrue());
352
353   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
354   cons1->SetClassName(v8_str("Cons1"));
355   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
356   cons2->SetClassName(v8_str("Cons2"));
357   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
358   cons3->SetClassName(v8_str("Cons3"));
359
360   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
361   v8::Handle<v8::Signature> wsig = v8::Signature::New(
362       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
363   v8::Handle<v8::FunctionTemplate> fun2 =
364       v8::FunctionTemplate::New(isolate,
365                                 SignatureCallback,
366                                 v8::Handle<Value>(),
367                                 wsig);
368
369   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
370   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
371   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
372   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
373   v8::Handle<Value> value4 = CompileRun(
374       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
375       "'[object Cons1],[object Cons2],[object Cons3]'");
376   CHECK(value4->IsTrue());
377
378   v8::Handle<Value> value5 = CompileRun(
379       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
380   CHECK(value5->IsTrue());
381
382   v8::Handle<Value> value6 = CompileRun(
383       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
384   CHECK(value6->IsTrue());
385
386   v8::Handle<Value> value7 = CompileRun(
387       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
388       "'[object Cons1],[object Cons2],[object Cons3],d';");
389   CHECK(value7->IsTrue());
390
391   v8::Handle<Value> value8 = CompileRun(
392       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
393   CHECK(value8->IsTrue());
394 }
395
396
397 THREADED_TEST(HulIgennem) {
398   LocalContext env;
399   v8::Isolate* isolate = env->GetIsolate();
400   v8::HandleScope scope(isolate);
401   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
402   Local<String> undef_str = undef->ToString();
403   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
404   undef_str->WriteUtf8(value);
405   CHECK_EQ(0, strcmp(value, "undefined"));
406   i::DeleteArray(value);
407 }
408
409
410 THREADED_TEST(Access) {
411   LocalContext env;
412   v8::Isolate* isolate = env->GetIsolate();
413   v8::HandleScope scope(isolate);
414   Local<v8::Object> obj = v8::Object::New(isolate);
415   Local<Value> foo_before = obj->Get(v8_str("foo"));
416   CHECK(foo_before->IsUndefined());
417   Local<String> bar_str = v8_str("bar");
418   obj->Set(v8_str("foo"), bar_str);
419   Local<Value> foo_after = obj->Get(v8_str("foo"));
420   CHECK(!foo_after->IsUndefined());
421   CHECK(foo_after->IsString());
422   CHECK_EQ(bar_str, foo_after);
423 }
424
425
426 THREADED_TEST(AccessElement) {
427   LocalContext env;
428   v8::HandleScope scope(env->GetIsolate());
429   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
430   Local<Value> before = obj->Get(1);
431   CHECK(before->IsUndefined());
432   Local<String> bar_str = v8_str("bar");
433   obj->Set(1, bar_str);
434   Local<Value> after = obj->Get(1);
435   CHECK(!after->IsUndefined());
436   CHECK(after->IsString());
437   CHECK_EQ(bar_str, after);
438
439   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
440   CHECK_EQ(v8_str("a"), value->Get(0));
441   CHECK_EQ(v8_str("b"), value->Get(1));
442 }
443
444
445 THREADED_TEST(Script) {
446   LocalContext env;
447   v8::HandleScope scope(env->GetIsolate());
448   const char* source = "1 + 2 + 3";
449   Local<Script> script = v8_compile(source);
450   CHECK_EQ(6, script->Run()->Int32Value());
451 }
452
453
454 static uint16_t* AsciiToTwoByteString(const char* source) {
455   int array_length = i::StrLength(source) + 1;
456   uint16_t* converted = i::NewArray<uint16_t>(array_length);
457   for (int i = 0; i < array_length; i++) converted[i] = source[i];
458   return converted;
459 }
460
461
462 class TestResource: public String::ExternalStringResource {
463  public:
464   TestResource(uint16_t* data, int* counter = NULL, bool owning_data = true)
465       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
466     while (data[length_]) ++length_;
467   }
468
469   ~TestResource() {
470     if (owning_data_) i::DeleteArray(data_);
471     if (counter_ != NULL) ++*counter_;
472   }
473
474   const uint16_t* data() const {
475     return data_;
476   }
477
478   size_t length() const {
479     return length_;
480   }
481
482  private:
483   uint16_t* data_;
484   size_t length_;
485   int* counter_;
486   bool owning_data_;
487 };
488
489
490 class TestAsciiResource: public String::ExternalAsciiStringResource {
491  public:
492   TestAsciiResource(const char* data, int* counter = NULL, size_t offset = 0)
493       : orig_data_(data),
494         data_(data + offset),
495         length_(strlen(data) - offset),
496         counter_(counter) { }
497
498   ~TestAsciiResource() {
499     i::DeleteArray(orig_data_);
500     if (counter_ != NULL) ++*counter_;
501   }
502
503   const char* data() const {
504     return data_;
505   }
506
507   size_t length() const {
508     return length_;
509   }
510
511  private:
512   const char* orig_data_;
513   const char* data_;
514   size_t length_;
515   int* counter_;
516 };
517
518
519 THREADED_TEST(ScriptUsingStringResource) {
520   int dispose_count = 0;
521   const char* c_source = "1 + 2 * 3";
522   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
523   {
524     LocalContext env;
525     v8::HandleScope scope(env->GetIsolate());
526     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
527     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
528     Local<Script> script = v8_compile(source);
529     Local<Value> value = script->Run();
530     CHECK(value->IsNumber());
531     CHECK_EQ(7, value->Int32Value());
532     CHECK(source->IsExternal());
533     CHECK_EQ(resource,
534              static_cast<TestResource*>(source->GetExternalStringResource()));
535     String::Encoding encoding = String::UNKNOWN_ENCODING;
536     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
537              source->GetExternalStringResourceBase(&encoding));
538     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
539     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
540     CHECK_EQ(0, dispose_count);
541   }
542   CcTest::i_isolate()->compilation_cache()->Clear();
543   CcTest::heap()->CollectAllAvailableGarbage();
544   CHECK_EQ(1, dispose_count);
545 }
546
547
548 THREADED_TEST(ScriptUsingAsciiStringResource) {
549   int dispose_count = 0;
550   const char* c_source = "1 + 2 * 3";
551   {
552     LocalContext env;
553     v8::HandleScope scope(env->GetIsolate());
554     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
555                                                         &dispose_count);
556     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
557     CHECK(source->IsExternalAscii());
558     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
559              source->GetExternalAsciiStringResource());
560     String::Encoding encoding = String::UNKNOWN_ENCODING;
561     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
562              source->GetExternalStringResourceBase(&encoding));
563     CHECK_EQ(String::ASCII_ENCODING, encoding);
564     Local<Script> script = v8_compile(source);
565     Local<Value> value = script->Run();
566     CHECK(value->IsNumber());
567     CHECK_EQ(7, value->Int32Value());
568     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
569     CHECK_EQ(0, dispose_count);
570   }
571   CcTest::i_isolate()->compilation_cache()->Clear();
572   CcTest::heap()->CollectAllAvailableGarbage();
573   CHECK_EQ(1, dispose_count);
574 }
575
576
577 THREADED_TEST(ScriptMakingExternalString) {
578   int dispose_count = 0;
579   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
580   {
581     LocalContext env;
582     v8::HandleScope scope(env->GetIsolate());
583     Local<String> source =
584         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
585     // Trigger GCs so that the newly allocated string moves to old gen.
586     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
587     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
588     CHECK_EQ(source->IsExternal(), false);
589     CHECK_EQ(source->IsExternalAscii(), false);
590     String::Encoding encoding = String::UNKNOWN_ENCODING;
591     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
592     CHECK_EQ(String::ASCII_ENCODING, encoding);
593     bool success = source->MakeExternal(new TestResource(two_byte_source,
594                                                          &dispose_count));
595     CHECK(success);
596     Local<Script> script = v8_compile(source);
597     Local<Value> value = script->Run();
598     CHECK(value->IsNumber());
599     CHECK_EQ(7, value->Int32Value());
600     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
601     CHECK_EQ(0, dispose_count);
602   }
603   CcTest::i_isolate()->compilation_cache()->Clear();
604   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
605   CHECK_EQ(1, dispose_count);
606 }
607
608
609 THREADED_TEST(ScriptMakingExternalAsciiString) {
610   int dispose_count = 0;
611   const char* c_source = "1 + 2 * 3";
612   {
613     LocalContext env;
614     v8::HandleScope scope(env->GetIsolate());
615     Local<String> source = v8_str(c_source);
616     // Trigger GCs so that the newly allocated string moves to old gen.
617     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
618     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
619     bool success = source->MakeExternal(
620         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
621     CHECK(success);
622     Local<Script> script = v8_compile(source);
623     Local<Value> value = script->Run();
624     CHECK(value->IsNumber());
625     CHECK_EQ(7, value->Int32Value());
626     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
627     CHECK_EQ(0, dispose_count);
628   }
629   CcTest::i_isolate()->compilation_cache()->Clear();
630   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
631   CHECK_EQ(1, dispose_count);
632 }
633
634
635 TEST(MakingExternalStringConditions) {
636   LocalContext env;
637   v8::HandleScope scope(env->GetIsolate());
638
639   // Free some space in the new space so that we can check freshness.
640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642
643   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
644   Local<String> small_string =
645       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
646   i::DeleteArray(two_byte_string);
647
648   // We should refuse to externalize newly created small string.
649   CHECK(!small_string->CanMakeExternal());
650   // Trigger GCs so that the newly allocated string moves to old gen.
651   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
652   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
653   // Old space strings should be accepted.
654   CHECK(small_string->CanMakeExternal());
655
656   two_byte_string = AsciiToTwoByteString("small string 2");
657   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
658   i::DeleteArray(two_byte_string);
659
660   // We should refuse externalizing newly created small string.
661   CHECK(!small_string->CanMakeExternal());
662   for (int i = 0; i < 100; i++) {
663     String::Value value(small_string);
664   }
665   // Frequently used strings should be accepted.
666   CHECK(small_string->CanMakeExternal());
667
668   const int buf_size = 10 * 1024;
669   char* buf = i::NewArray<char>(buf_size);
670   memset(buf, 'a', buf_size);
671   buf[buf_size - 1] = '\0';
672
673   two_byte_string = AsciiToTwoByteString(buf);
674   Local<String> large_string =
675       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
676   i::DeleteArray(buf);
677   i::DeleteArray(two_byte_string);
678   // Large strings should be immediately accepted.
679   CHECK(large_string->CanMakeExternal());
680 }
681
682
683 TEST(MakingExternalAsciiStringConditions) {
684   LocalContext env;
685   v8::HandleScope scope(env->GetIsolate());
686
687   // Free some space in the new space so that we can check freshness.
688   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
689   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
690
691   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
692   // We should refuse to externalize newly created small string.
693   CHECK(!small_string->CanMakeExternal());
694   // Trigger GCs so that the newly allocated string moves to old gen.
695   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
696   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
697   // Old space strings should be accepted.
698   CHECK(small_string->CanMakeExternal());
699
700   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
701   // We should refuse externalizing newly created small string.
702   CHECK(!small_string->CanMakeExternal());
703   for (int i = 0; i < 100; i++) {
704     String::Value value(small_string);
705   }
706   // Frequently used strings should be accepted.
707   CHECK(small_string->CanMakeExternal());
708
709   const int buf_size = 10 * 1024;
710   char* buf = i::NewArray<char>(buf_size);
711   memset(buf, 'a', buf_size);
712   buf[buf_size - 1] = '\0';
713   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
714   i::DeleteArray(buf);
715   // Large strings should be immediately accepted.
716   CHECK(large_string->CanMakeExternal());
717 }
718
719
720 TEST(MakingExternalUnalignedAsciiString) {
721   LocalContext env;
722   v8::HandleScope scope(env->GetIsolate());
723
724   CompileRun("function cons(a, b) { return a + b; }"
725              "function slice(a) { return a.substring(1); }");
726   // Create a cons string that will land in old pointer space.
727   Local<String> cons = Local<String>::Cast(CompileRun(
728       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
729   // Create a sliced string that will land in old pointer space.
730   Local<String> slice = Local<String>::Cast(CompileRun(
731       "slice('abcdefghijklmnopqrstuvwxyz');"));
732
733   // Trigger GCs so that the newly allocated string moves to old gen.
734   SimulateFullSpace(CcTest::heap()->old_pointer_space());
735   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
736   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
737
738   // Turn into external string with unaligned resource data.
739   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
740   bool success = cons->MakeExternal(
741       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
742   CHECK(success);
743   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
744   success = slice->MakeExternal(
745       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
746   CHECK(success);
747
748   // Trigger GCs and force evacuation.
749   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
750   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
751 }
752
753
754 THREADED_TEST(UsingExternalString) {
755   i::Factory* factory = CcTest::i_isolate()->factory();
756   {
757     v8::HandleScope scope(CcTest::isolate());
758     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
759     Local<String> string = String::NewExternal(
760         CcTest::isolate(), new TestResource(two_byte_string));
761     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
762     // Trigger GCs so that the newly allocated string moves to old gen.
763     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
764     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
765     i::Handle<i::String> isymbol =
766         factory->InternalizeString(istring);
767     CHECK(isymbol->IsInternalizedString());
768   }
769   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
770   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
771 }
772
773
774 THREADED_TEST(UsingExternalAsciiString) {
775   i::Factory* factory = CcTest::i_isolate()->factory();
776   {
777     v8::HandleScope scope(CcTest::isolate());
778     const char* one_byte_string = "test string";
779     Local<String> string = String::NewExternal(
780         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
781     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
782     // Trigger GCs so that the newly allocated string moves to old gen.
783     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
784     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
785     i::Handle<i::String> isymbol =
786         factory->InternalizeString(istring);
787     CHECK(isymbol->IsInternalizedString());
788   }
789   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
790   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
791 }
792
793
794 THREADED_TEST(ScavengeExternalString) {
795   i::FLAG_stress_compaction = false;
796   i::FLAG_gc_global = false;
797   int dispose_count = 0;
798   bool in_new_space = false;
799   {
800     v8::HandleScope scope(CcTest::isolate());
801     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
802     Local<String> string = String::NewExternal(
803         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
804     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
805     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
806     in_new_space = CcTest::heap()->InNewSpace(*istring);
807     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
808     CHECK_EQ(0, dispose_count);
809   }
810   CcTest::heap()->CollectGarbage(
811       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
812   CHECK_EQ(1, dispose_count);
813 }
814
815
816 THREADED_TEST(ScavengeExternalAsciiString) {
817   i::FLAG_stress_compaction = false;
818   i::FLAG_gc_global = false;
819   int dispose_count = 0;
820   bool in_new_space = false;
821   {
822     v8::HandleScope scope(CcTest::isolate());
823     const char* one_byte_string = "test string";
824     Local<String> string = String::NewExternal(
825         CcTest::isolate(),
826         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
827     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
828     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
829     in_new_space = CcTest::heap()->InNewSpace(*istring);
830     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
831     CHECK_EQ(0, dispose_count);
832   }
833   CcTest::heap()->CollectGarbage(
834       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
835   CHECK_EQ(1, dispose_count);
836 }
837
838
839 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
840  public:
841   // Only used by non-threaded tests, so it can use static fields.
842   static int dispose_calls;
843   static int dispose_count;
844
845   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
846       : TestAsciiResource(data, &dispose_count),
847         dispose_(dispose) { }
848
849   void Dispose() {
850     ++dispose_calls;
851     if (dispose_) delete this;
852   }
853  private:
854   bool dispose_;
855 };
856
857
858 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
859 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
860
861
862 TEST(ExternalStringWithDisposeHandling) {
863   const char* c_source = "1 + 2 * 3";
864
865   // Use a stack allocated external string resource allocated object.
866   TestAsciiResourceWithDisposeControl::dispose_count = 0;
867   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
868   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
869   {
870     LocalContext env;
871     v8::HandleScope scope(env->GetIsolate());
872     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
873     Local<Script> script = v8_compile(source);
874     Local<Value> value = script->Run();
875     CHECK(value->IsNumber());
876     CHECK_EQ(7, value->Int32Value());
877     CcTest::heap()->CollectAllAvailableGarbage();
878     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
879   }
880   CcTest::i_isolate()->compilation_cache()->Clear();
881   CcTest::heap()->CollectAllAvailableGarbage();
882   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
883   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
884
885   // Use a heap allocated external string resource allocated object.
886   TestAsciiResourceWithDisposeControl::dispose_count = 0;
887   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
888   TestAsciiResource* res_heap =
889       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
890   {
891     LocalContext env;
892     v8::HandleScope scope(env->GetIsolate());
893     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
894     Local<Script> script = v8_compile(source);
895     Local<Value> value = script->Run();
896     CHECK(value->IsNumber());
897     CHECK_EQ(7, value->Int32Value());
898     CcTest::heap()->CollectAllAvailableGarbage();
899     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
900   }
901   CcTest::i_isolate()->compilation_cache()->Clear();
902   CcTest::heap()->CollectAllAvailableGarbage();
903   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
904   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
905 }
906
907
908 THREADED_TEST(StringConcat) {
909   {
910     LocalContext env;
911     v8::HandleScope scope(env->GetIsolate());
912     const char* one_byte_string_1 = "function a_times_t";
913     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
914     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
915     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
916     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
917     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
918     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
919     Local<String> left = v8_str(one_byte_string_1);
920
921     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
922     Local<String> right =
923         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
924     i::DeleteArray(two_byte_source);
925
926     Local<String> source = String::Concat(left, right);
927     right = String::NewExternal(
928         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
929     source = String::Concat(source, right);
930     right = String::NewExternal(
931         env->GetIsolate(),
932         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
933     source = String::Concat(source, right);
934     right = v8_str(one_byte_string_2);
935     source = String::Concat(source, right);
936
937     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
938     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
939     i::DeleteArray(two_byte_source);
940
941     source = String::Concat(source, right);
942     right = String::NewExternal(
943         env->GetIsolate(),
944         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
945     source = String::Concat(source, right);
946     Local<Script> script = v8_compile(source);
947     Local<Value> value = script->Run();
948     CHECK(value->IsNumber());
949     CHECK_EQ(68, value->Int32Value());
950   }
951   CcTest::i_isolate()->compilation_cache()->Clear();
952   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
953   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
954 }
955
956
957 THREADED_TEST(GlobalProperties) {
958   LocalContext env;
959   v8::HandleScope scope(env->GetIsolate());
960   v8::Handle<v8::Object> global = env->Global();
961   global->Set(v8_str("pi"), v8_num(3.1415926));
962   Local<Value> pi = global->Get(v8_str("pi"));
963   CHECK_EQ(3.1415926, pi->NumberValue());
964 }
965
966
967 template<typename T>
968 static void CheckReturnValue(const T& t, i::Address callback) {
969   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
970   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
971   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
972   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
973   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
974   // Verify reset
975   bool is_runtime = (*o)->IsTheHole();
976   rv.Set(true);
977   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
978   rv.Set(v8::Handle<v8::Object>());
979   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
980   CHECK_EQ(is_runtime, (*o)->IsTheHole());
981
982   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
983   // If CPU profiler is active check that when API callback is invoked
984   // VMState is set to EXTERNAL.
985   if (isolate->cpu_profiler()->is_profiling()) {
986     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
987     CHECK(isolate->external_callback_scope());
988     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
989   }
990 }
991
992
993 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
994                                  i::Address callback) {
995   ApiTestFuzzer::Fuzz();
996   CheckReturnValue(info, callback);
997   info.GetReturnValue().Set(v8_str("bad value"));
998   info.GetReturnValue().Set(v8_num(102));
999 }
1000
1001
1002 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1003   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1004 }
1005
1006
1007 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1008   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1009 }
1010
1011 static void construct_callback(
1012     const v8::FunctionCallbackInfo<Value>& info) {
1013   ApiTestFuzzer::Fuzz();
1014   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1015   info.This()->Set(v8_str("x"), v8_num(1));
1016   info.This()->Set(v8_str("y"), v8_num(2));
1017   info.GetReturnValue().Set(v8_str("bad value"));
1018   info.GetReturnValue().Set(info.This());
1019 }
1020
1021
1022 static void Return239Callback(
1023     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1024   ApiTestFuzzer::Fuzz();
1025   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1026   info.GetReturnValue().Set(v8_str("bad value"));
1027   info.GetReturnValue().Set(v8_num(239));
1028 }
1029
1030
1031 template<typename Handler>
1032 static void TestFunctionTemplateInitializer(Handler handler,
1033                                             Handler handler_2) {
1034   // Test constructor calls.
1035   {
1036     LocalContext env;
1037     v8::Isolate* isolate = env->GetIsolate();
1038     v8::HandleScope scope(isolate);
1039
1040     Local<v8::FunctionTemplate> fun_templ =
1041         v8::FunctionTemplate::New(isolate, handler);
1042     Local<Function> fun = fun_templ->GetFunction();
1043     env->Global()->Set(v8_str("obj"), fun);
1044     Local<Script> script = v8_compile("obj()");
1045     for (int i = 0; i < 30; i++) {
1046       CHECK_EQ(102, script->Run()->Int32Value());
1047     }
1048   }
1049   // Use SetCallHandler to initialize a function template, should work like
1050   // the previous one.
1051   {
1052     LocalContext env;
1053     v8::Isolate* isolate = env->GetIsolate();
1054     v8::HandleScope scope(isolate);
1055
1056     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1057     fun_templ->SetCallHandler(handler_2);
1058     Local<Function> fun = fun_templ->GetFunction();
1059     env->Global()->Set(v8_str("obj"), fun);
1060     Local<Script> script = v8_compile("obj()");
1061     for (int i = 0; i < 30; i++) {
1062       CHECK_EQ(102, script->Run()->Int32Value());
1063     }
1064   }
1065 }
1066
1067
1068 template<typename Constructor, typename Accessor>
1069 static void TestFunctionTemplateAccessor(Constructor constructor,
1070                                          Accessor accessor) {
1071   LocalContext env;
1072   v8::HandleScope scope(env->GetIsolate());
1073
1074   Local<v8::FunctionTemplate> fun_templ =
1075       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1076   fun_templ->SetClassName(v8_str("funky"));
1077   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1078   Local<Function> fun = fun_templ->GetFunction();
1079   env->Global()->Set(v8_str("obj"), fun);
1080   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1081   CHECK_EQ(v8_str("[object funky]"), result);
1082   CompileRun("var obj_instance = new obj();");
1083   Local<Script> script;
1084   script = v8_compile("obj_instance.x");
1085   for (int i = 0; i < 30; i++) {
1086     CHECK_EQ(1, script->Run()->Int32Value());
1087   }
1088   script = v8_compile("obj_instance.m");
1089   for (int i = 0; i < 30; i++) {
1090     CHECK_EQ(239, script->Run()->Int32Value());
1091   }
1092 }
1093
1094
1095 THREADED_PROFILED_TEST(FunctionTemplate) {
1096   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1097   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1098 }
1099
1100
1101 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1102   ApiTestFuzzer::Fuzz();
1103   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1104   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1105 }
1106
1107
1108 template<typename Callback>
1109 static void TestSimpleCallback(Callback callback) {
1110   LocalContext env;
1111   v8::Isolate* isolate = env->GetIsolate();
1112   v8::HandleScope scope(isolate);
1113
1114   v8::Handle<v8::ObjectTemplate> object_template =
1115       v8::ObjectTemplate::New(isolate);
1116   object_template->Set(isolate, "callback",
1117                        v8::FunctionTemplate::New(isolate, callback));
1118   v8::Local<v8::Object> object = object_template->NewInstance();
1119   (*env)->Global()->Set(v8_str("callback_object"), object);
1120   v8::Handle<v8::Script> script;
1121   script = v8_compile("callback_object.callback(17)");
1122   for (int i = 0; i < 30; i++) {
1123     CHECK_EQ(51424, script->Run()->Int32Value());
1124   }
1125   script = v8_compile("callback_object.callback(17, 24)");
1126   for (int i = 0; i < 30; i++) {
1127     CHECK_EQ(51425, script->Run()->Int32Value());
1128   }
1129 }
1130
1131
1132 THREADED_PROFILED_TEST(SimpleCallback) {
1133   TestSimpleCallback(SimpleCallback);
1134 }
1135
1136
1137 template<typename T>
1138 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1139
1140 // constant return values
1141 static int32_t fast_return_value_int32 = 471;
1142 static uint32_t fast_return_value_uint32 = 571;
1143 static const double kFastReturnValueDouble = 2.7;
1144 // variable return values
1145 static bool fast_return_value_bool = false;
1146 enum ReturnValueOddball {
1147   kNullReturnValue,
1148   kUndefinedReturnValue,
1149   kEmptyStringReturnValue
1150 };
1151 static ReturnValueOddball fast_return_value_void;
1152 static bool fast_return_value_object_is_empty = false;
1153
1154 // Helper function to avoid compiler error: insufficient contextual information
1155 // to determine type when applying FUNCTION_ADDR to a template function.
1156 static i::Address address_of(v8::FunctionCallback callback) {
1157   return FUNCTION_ADDR(callback);
1158 }
1159
1160 template<>
1161 void FastReturnValueCallback<int32_t>(
1162     const v8::FunctionCallbackInfo<v8::Value>& info) {
1163   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1164   info.GetReturnValue().Set(fast_return_value_int32);
1165 }
1166
1167 template<>
1168 void FastReturnValueCallback<uint32_t>(
1169     const v8::FunctionCallbackInfo<v8::Value>& info) {
1170   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1171   info.GetReturnValue().Set(fast_return_value_uint32);
1172 }
1173
1174 template<>
1175 void FastReturnValueCallback<double>(
1176     const v8::FunctionCallbackInfo<v8::Value>& info) {
1177   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1178   info.GetReturnValue().Set(kFastReturnValueDouble);
1179 }
1180
1181 template<>
1182 void FastReturnValueCallback<bool>(
1183     const v8::FunctionCallbackInfo<v8::Value>& info) {
1184   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1185   info.GetReturnValue().Set(fast_return_value_bool);
1186 }
1187
1188 template<>
1189 void FastReturnValueCallback<void>(
1190     const v8::FunctionCallbackInfo<v8::Value>& info) {
1191   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1192   switch (fast_return_value_void) {
1193     case kNullReturnValue:
1194       info.GetReturnValue().SetNull();
1195       break;
1196     case kUndefinedReturnValue:
1197       info.GetReturnValue().SetUndefined();
1198       break;
1199     case kEmptyStringReturnValue:
1200       info.GetReturnValue().SetEmptyString();
1201       break;
1202   }
1203 }
1204
1205 template<>
1206 void FastReturnValueCallback<Object>(
1207     const v8::FunctionCallbackInfo<v8::Value>& info) {
1208   v8::Handle<v8::Object> object;
1209   if (!fast_return_value_object_is_empty) {
1210     object = Object::New(info.GetIsolate());
1211   }
1212   info.GetReturnValue().Set(object);
1213 }
1214
1215 template<typename T>
1216 Handle<Value> TestFastReturnValues() {
1217   LocalContext env;
1218   v8::Isolate* isolate = env->GetIsolate();
1219   v8::EscapableHandleScope scope(isolate);
1220   v8::Handle<v8::ObjectTemplate> object_template =
1221       v8::ObjectTemplate::New(isolate);
1222   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1223   object_template->Set(isolate, "callback",
1224                        v8::FunctionTemplate::New(isolate, callback));
1225   v8::Local<v8::Object> object = object_template->NewInstance();
1226   (*env)->Global()->Set(v8_str("callback_object"), object);
1227   return scope.Escape(CompileRun("callback_object.callback()"));
1228 }
1229
1230
1231 THREADED_PROFILED_TEST(FastReturnValues) {
1232   LocalContext env;
1233   v8::HandleScope scope(CcTest::isolate());
1234   v8::Handle<v8::Value> value;
1235   // check int32_t and uint32_t
1236   int32_t int_values[] = {
1237       0, 234, -723,
1238       i::Smi::kMinValue, i::Smi::kMaxValue
1239   };
1240   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1241     for (int modifier = -1; modifier <= 1; modifier++) {
1242       int int_value = int_values[i] + modifier;
1243       // check int32_t
1244       fast_return_value_int32 = int_value;
1245       value = TestFastReturnValues<int32_t>();
1246       CHECK(value->IsInt32());
1247       CHECK(fast_return_value_int32 == value->Int32Value());
1248       // check uint32_t
1249       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1250       value = TestFastReturnValues<uint32_t>();
1251       CHECK(value->IsUint32());
1252       CHECK(fast_return_value_uint32 == value->Uint32Value());
1253     }
1254   }
1255   // check double
1256   value = TestFastReturnValues<double>();
1257   CHECK(value->IsNumber());
1258   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1259   // check bool values
1260   for (int i = 0; i < 2; i++) {
1261     fast_return_value_bool = i == 0;
1262     value = TestFastReturnValues<bool>();
1263     CHECK(value->IsBoolean());
1264     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1265   }
1266   // check oddballs
1267   ReturnValueOddball oddballs[] = {
1268       kNullReturnValue,
1269       kUndefinedReturnValue,
1270       kEmptyStringReturnValue
1271   };
1272   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1273     fast_return_value_void = oddballs[i];
1274     value = TestFastReturnValues<void>();
1275     switch (fast_return_value_void) {
1276       case kNullReturnValue:
1277         CHECK(value->IsNull());
1278         break;
1279       case kUndefinedReturnValue:
1280         CHECK(value->IsUndefined());
1281         break;
1282       case kEmptyStringReturnValue:
1283         CHECK(value->IsString());
1284         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1285         break;
1286     }
1287   }
1288   // check handles
1289   fast_return_value_object_is_empty = false;
1290   value = TestFastReturnValues<Object>();
1291   CHECK(value->IsObject());
1292   fast_return_value_object_is_empty = true;
1293   value = TestFastReturnValues<Object>();
1294   CHECK(value->IsUndefined());
1295 }
1296
1297
1298 THREADED_TEST(FunctionTemplateSetLength) {
1299   LocalContext env;
1300   v8::Isolate* isolate = env->GetIsolate();
1301   v8::HandleScope scope(isolate);
1302   {
1303     Local<v8::FunctionTemplate> fun_templ =
1304         v8::FunctionTemplate::New(isolate,
1305                                   handle_callback,
1306                                   Handle<v8::Value>(),
1307                                   Handle<v8::Signature>(),
1308                                   23);
1309     Local<Function> fun = fun_templ->GetFunction();
1310     env->Global()->Set(v8_str("obj"), fun);
1311     Local<Script> script = v8_compile("obj.length");
1312     CHECK_EQ(23, script->Run()->Int32Value());
1313   }
1314   {
1315     Local<v8::FunctionTemplate> fun_templ =
1316         v8::FunctionTemplate::New(isolate, handle_callback);
1317     fun_templ->SetLength(22);
1318     Local<Function> fun = fun_templ->GetFunction();
1319     env->Global()->Set(v8_str("obj"), fun);
1320     Local<Script> script = v8_compile("obj.length");
1321     CHECK_EQ(22, script->Run()->Int32Value());
1322   }
1323   {
1324     // Without setting length it defaults to 0.
1325     Local<v8::FunctionTemplate> fun_templ =
1326         v8::FunctionTemplate::New(isolate, handle_callback);
1327     Local<Function> fun = fun_templ->GetFunction();
1328     env->Global()->Set(v8_str("obj"), fun);
1329     Local<Script> script = v8_compile("obj.length");
1330     CHECK_EQ(0, script->Run()->Int32Value());
1331   }
1332 }
1333
1334
1335 static void* expected_ptr;
1336 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1337   void* ptr = v8::External::Cast(*args.Data())->Value();
1338   CHECK_EQ(expected_ptr, ptr);
1339   args.GetReturnValue().Set(true);
1340 }
1341
1342
1343 static void TestExternalPointerWrapping() {
1344   LocalContext env;
1345   v8::Isolate* isolate = env->GetIsolate();
1346   v8::HandleScope scope(isolate);
1347
1348   v8::Handle<v8::Value> data =
1349       v8::External::New(isolate, expected_ptr);
1350
1351   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1352   obj->Set(v8_str("func"),
1353            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1354   env->Global()->Set(v8_str("obj"), obj);
1355
1356   CHECK(CompileRun(
1357         "function foo() {\n"
1358         "  for (var i = 0; i < 13; i++) obj.func();\n"
1359         "}\n"
1360         "foo(), true")->BooleanValue());
1361 }
1362
1363
1364 THREADED_TEST(ExternalWrap) {
1365   // Check heap allocated object.
1366   int* ptr = new int;
1367   expected_ptr = ptr;
1368   TestExternalPointerWrapping();
1369   delete ptr;
1370
1371   // Check stack allocated object.
1372   int foo;
1373   expected_ptr = &foo;
1374   TestExternalPointerWrapping();
1375
1376   // Check not aligned addresses.
1377   const int n = 100;
1378   char* s = new char[n];
1379   for (int i = 0; i < n; i++) {
1380     expected_ptr = s + i;
1381     TestExternalPointerWrapping();
1382   }
1383
1384   delete[] s;
1385
1386   // Check several invalid addresses.
1387   expected_ptr = reinterpret_cast<void*>(1);
1388   TestExternalPointerWrapping();
1389
1390   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1391   TestExternalPointerWrapping();
1392
1393   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1394   TestExternalPointerWrapping();
1395
1396 #if defined(V8_HOST_ARCH_X64)
1397   // Check a value with a leading 1 bit in x64 Smi encoding.
1398   expected_ptr = reinterpret_cast<void*>(0x400000000);
1399   TestExternalPointerWrapping();
1400
1401   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1402   TestExternalPointerWrapping();
1403
1404   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1405   TestExternalPointerWrapping();
1406 #endif
1407 }
1408
1409
1410 THREADED_TEST(FindInstanceInPrototypeChain) {
1411   LocalContext env;
1412   v8::Isolate* isolate = env->GetIsolate();
1413   v8::HandleScope scope(isolate);
1414
1415   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1416   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1417   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1418   derived->Inherit(base);
1419
1420   Local<v8::Function> base_function = base->GetFunction();
1421   Local<v8::Function> derived_function = derived->GetFunction();
1422   Local<v8::Function> other_function = other->GetFunction();
1423
1424   Local<v8::Object> base_instance = base_function->NewInstance();
1425   Local<v8::Object> derived_instance = derived_function->NewInstance();
1426   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1427   Local<v8::Object> other_instance = other_function->NewInstance();
1428   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1429   other_instance->Set(v8_str("__proto__"), derived_instance2);
1430
1431   // base_instance is only an instance of base.
1432   CHECK_EQ(base_instance,
1433            base_instance->FindInstanceInPrototypeChain(base));
1434   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1435   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1436
1437   // derived_instance is an instance of base and derived.
1438   CHECK_EQ(derived_instance,
1439            derived_instance->FindInstanceInPrototypeChain(base));
1440   CHECK_EQ(derived_instance,
1441            derived_instance->FindInstanceInPrototypeChain(derived));
1442   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1443
1444   // other_instance is an instance of other and its immediate
1445   // prototype derived_instance2 is an instance of base and derived.
1446   // Note, derived_instance is an instance of base and derived too,
1447   // but it comes after derived_instance2 in the prototype chain of
1448   // other_instance.
1449   CHECK_EQ(derived_instance2,
1450            other_instance->FindInstanceInPrototypeChain(base));
1451   CHECK_EQ(derived_instance2,
1452            other_instance->FindInstanceInPrototypeChain(derived));
1453   CHECK_EQ(other_instance,
1454            other_instance->FindInstanceInPrototypeChain(other));
1455 }
1456
1457
1458 THREADED_TEST(TinyInteger) {
1459   LocalContext env;
1460   v8::Isolate* isolate = env->GetIsolate();
1461   v8::HandleScope scope(isolate);
1462
1463   int32_t value = 239;
1464   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1465   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1466
1467   value_obj = v8::Integer::New(isolate, value);
1468   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1469 }
1470
1471
1472 THREADED_TEST(BigSmiInteger) {
1473   LocalContext env;
1474   v8::HandleScope scope(env->GetIsolate());
1475   v8::Isolate* isolate = CcTest::isolate();
1476
1477   int32_t value = i::Smi::kMaxValue;
1478   // We cannot add one to a Smi::kMaxValue without wrapping.
1479   if (i::SmiValuesAre31Bits()) {
1480     CHECK(i::Smi::IsValid(value));
1481     CHECK(!i::Smi::IsValid(value + 1));
1482
1483     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1484     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1485
1486     value_obj = v8::Integer::New(isolate, value);
1487     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1488   }
1489 }
1490
1491
1492 THREADED_TEST(BigInteger) {
1493   LocalContext env;
1494   v8::HandleScope scope(env->GetIsolate());
1495   v8::Isolate* isolate = CcTest::isolate();
1496
1497   // We cannot add one to a Smi::kMaxValue without wrapping.
1498   if (i::SmiValuesAre31Bits()) {
1499     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1500     // The code will not be run in that case, due to the "if" guard.
1501     int32_t value =
1502         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1503     CHECK(value > i::Smi::kMaxValue);
1504     CHECK(!i::Smi::IsValid(value));
1505
1506     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1507     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1508
1509     value_obj = v8::Integer::New(isolate, value);
1510     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1511   }
1512 }
1513
1514
1515 THREADED_TEST(TinyUnsignedInteger) {
1516   LocalContext env;
1517   v8::HandleScope scope(env->GetIsolate());
1518   v8::Isolate* isolate = CcTest::isolate();
1519
1520   uint32_t value = 239;
1521
1522   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1523   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1524
1525   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1526   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1527 }
1528
1529
1530 THREADED_TEST(BigUnsignedSmiInteger) {
1531   LocalContext env;
1532   v8::HandleScope scope(env->GetIsolate());
1533   v8::Isolate* isolate = CcTest::isolate();
1534
1535   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1536   CHECK(i::Smi::IsValid(value));
1537   CHECK(!i::Smi::IsValid(value + 1));
1538
1539   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1540   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1541
1542   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1543   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1544 }
1545
1546
1547 THREADED_TEST(BigUnsignedInteger) {
1548   LocalContext env;
1549   v8::HandleScope scope(env->GetIsolate());
1550   v8::Isolate* isolate = CcTest::isolate();
1551
1552   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1553   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1554   CHECK(!i::Smi::IsValid(value));
1555
1556   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1557   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1558
1559   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1560   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1561 }
1562
1563
1564 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1565   LocalContext env;
1566   v8::HandleScope scope(env->GetIsolate());
1567   v8::Isolate* isolate = CcTest::isolate();
1568
1569   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1570   uint32_t value = INT32_MAX_AS_UINT + 1;
1571   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1572
1573   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1574   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1575
1576   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1577   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1578 }
1579
1580
1581 THREADED_TEST(IsNativeError) {
1582   LocalContext env;
1583   v8::HandleScope scope(env->GetIsolate());
1584   v8::Handle<Value> syntax_error = CompileRun(
1585       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1586   CHECK(syntax_error->IsNativeError());
1587   v8::Handle<Value> not_error = CompileRun("{a:42}");
1588   CHECK(!not_error->IsNativeError());
1589   v8::Handle<Value> not_object = CompileRun("42");
1590   CHECK(!not_object->IsNativeError());
1591 }
1592
1593
1594 THREADED_TEST(StringObject) {
1595   LocalContext env;
1596   v8::HandleScope scope(env->GetIsolate());
1597   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1598   CHECK(boxed_string->IsStringObject());
1599   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1600   CHECK(!unboxed_string->IsStringObject());
1601   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1602   CHECK(!boxed_not_string->IsStringObject());
1603   v8::Handle<Value> not_object = CompileRun("0");
1604   CHECK(!not_object->IsStringObject());
1605   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1606   CHECK(!as_boxed.IsEmpty());
1607   Local<v8::String> the_string = as_boxed->ValueOf();
1608   CHECK(!the_string.IsEmpty());
1609   ExpectObject("\"test\"", the_string);
1610   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1611   CHECK(new_boxed_string->IsStringObject());
1612   as_boxed = new_boxed_string.As<v8::StringObject>();
1613   the_string = as_boxed->ValueOf();
1614   CHECK(!the_string.IsEmpty());
1615   ExpectObject("\"test\"", the_string);
1616 }
1617
1618
1619 THREADED_TEST(NumberObject) {
1620   LocalContext env;
1621   v8::HandleScope scope(env->GetIsolate());
1622   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1623   CHECK(boxed_number->IsNumberObject());
1624   v8::Handle<Value> unboxed_number = CompileRun("42");
1625   CHECK(!unboxed_number->IsNumberObject());
1626   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1627   CHECK(!boxed_not_number->IsNumberObject());
1628   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1629   CHECK(!as_boxed.IsEmpty());
1630   double the_number = as_boxed->ValueOf();
1631   CHECK_EQ(42.0, the_number);
1632   v8::Handle<v8::Value> new_boxed_number =
1633       v8::NumberObject::New(env->GetIsolate(), 43);
1634   CHECK(new_boxed_number->IsNumberObject());
1635   as_boxed = new_boxed_number.As<v8::NumberObject>();
1636   the_number = as_boxed->ValueOf();
1637   CHECK_EQ(43.0, the_number);
1638 }
1639
1640
1641 THREADED_TEST(BooleanObject) {
1642   LocalContext env;
1643   v8::HandleScope scope(env->GetIsolate());
1644   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1645   CHECK(boxed_boolean->IsBooleanObject());
1646   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1647   CHECK(!unboxed_boolean->IsBooleanObject());
1648   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1649   CHECK(!boxed_not_boolean->IsBooleanObject());
1650   v8::Handle<v8::BooleanObject> as_boxed =
1651       boxed_boolean.As<v8::BooleanObject>();
1652   CHECK(!as_boxed.IsEmpty());
1653   bool the_boolean = as_boxed->ValueOf();
1654   CHECK_EQ(true, the_boolean);
1655   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1656   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1657   CHECK(boxed_true->IsBooleanObject());
1658   CHECK(boxed_false->IsBooleanObject());
1659   as_boxed = boxed_true.As<v8::BooleanObject>();
1660   CHECK_EQ(true, as_boxed->ValueOf());
1661   as_boxed = boxed_false.As<v8::BooleanObject>();
1662   CHECK_EQ(false, as_boxed->ValueOf());
1663 }
1664
1665
1666 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1667   LocalContext env;
1668   v8::HandleScope scope(env->GetIsolate());
1669
1670   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1671   CHECK(primitive_false->IsBoolean());
1672   CHECK(!primitive_false->IsBooleanObject());
1673   CHECK(!primitive_false->BooleanValue());
1674   CHECK(!primitive_false->IsTrue());
1675   CHECK(primitive_false->IsFalse());
1676
1677   Local<Value> false_value = BooleanObject::New(false);
1678   CHECK(!false_value->IsBoolean());
1679   CHECK(false_value->IsBooleanObject());
1680   CHECK(false_value->BooleanValue());
1681   CHECK(!false_value->IsTrue());
1682   CHECK(!false_value->IsFalse());
1683
1684   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1685   CHECK(!false_boolean_object->IsBoolean());
1686   CHECK(false_boolean_object->IsBooleanObject());
1687   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1688   // CHECK(false_boolean_object->BooleanValue());
1689   CHECK(!false_boolean_object->ValueOf());
1690   CHECK(!false_boolean_object->IsTrue());
1691   CHECK(!false_boolean_object->IsFalse());
1692
1693   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1694   CHECK(primitive_true->IsBoolean());
1695   CHECK(!primitive_true->IsBooleanObject());
1696   CHECK(primitive_true->BooleanValue());
1697   CHECK(primitive_true->IsTrue());
1698   CHECK(!primitive_true->IsFalse());
1699
1700   Local<Value> true_value = BooleanObject::New(true);
1701   CHECK(!true_value->IsBoolean());
1702   CHECK(true_value->IsBooleanObject());
1703   CHECK(true_value->BooleanValue());
1704   CHECK(!true_value->IsTrue());
1705   CHECK(!true_value->IsFalse());
1706
1707   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1708   CHECK(!true_boolean_object->IsBoolean());
1709   CHECK(true_boolean_object->IsBooleanObject());
1710   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1711   // CHECK(true_boolean_object->BooleanValue());
1712   CHECK(true_boolean_object->ValueOf());
1713   CHECK(!true_boolean_object->IsTrue());
1714   CHECK(!true_boolean_object->IsFalse());
1715 }
1716
1717
1718 THREADED_TEST(Number) {
1719   LocalContext env;
1720   v8::HandleScope scope(env->GetIsolate());
1721   double PI = 3.1415926;
1722   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1723   CHECK_EQ(PI, pi_obj->NumberValue());
1724 }
1725
1726
1727 THREADED_TEST(ToNumber) {
1728   LocalContext env;
1729   v8::Isolate* isolate = CcTest::isolate();
1730   v8::HandleScope scope(isolate);
1731   Local<String> str = v8_str("3.1415926");
1732   CHECK_EQ(3.1415926, str->NumberValue());
1733   v8::Handle<v8::Boolean> t = v8::True(isolate);
1734   CHECK_EQ(1.0, t->NumberValue());
1735   v8::Handle<v8::Boolean> f = v8::False(isolate);
1736   CHECK_EQ(0.0, f->NumberValue());
1737 }
1738
1739
1740 THREADED_TEST(Date) {
1741   LocalContext env;
1742   v8::HandleScope scope(env->GetIsolate());
1743   double PI = 3.1415926;
1744   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1745   CHECK_EQ(3.0, date->NumberValue());
1746   date.As<v8::Date>()->Set(v8_str("property"),
1747                            v8::Integer::New(env->GetIsolate(), 42));
1748   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1749 }
1750
1751
1752 THREADED_TEST(Boolean) {
1753   LocalContext env;
1754   v8::Isolate* isolate = env->GetIsolate();
1755   v8::HandleScope scope(isolate);
1756   v8::Handle<v8::Boolean> t = v8::True(isolate);
1757   CHECK(t->Value());
1758   v8::Handle<v8::Boolean> f = v8::False(isolate);
1759   CHECK(!f->Value());
1760   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1761   CHECK(!u->BooleanValue());
1762   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1763   CHECK(!n->BooleanValue());
1764   v8::Handle<String> str1 = v8_str("");
1765   CHECK(!str1->BooleanValue());
1766   v8::Handle<String> str2 = v8_str("x");
1767   CHECK(str2->BooleanValue());
1768   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1769   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1770   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1771   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1772   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1773 }
1774
1775
1776 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1777   ApiTestFuzzer::Fuzz();
1778   args.GetReturnValue().Set(v8_num(13.4));
1779 }
1780
1781
1782 static void GetM(Local<String> name,
1783                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1784   ApiTestFuzzer::Fuzz();
1785   info.GetReturnValue().Set(v8_num(876));
1786 }
1787
1788
1789 THREADED_TEST(GlobalPrototype) {
1790   v8::Isolate* isolate = CcTest::isolate();
1791   v8::HandleScope scope(isolate);
1792   v8::Handle<v8::FunctionTemplate> func_templ =
1793       v8::FunctionTemplate::New(isolate);
1794   func_templ->PrototypeTemplate()->Set(
1795       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1796   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1797   templ->Set(isolate, "x", v8_num(200));
1798   templ->SetAccessor(v8_str("m"), GetM);
1799   LocalContext env(0, templ);
1800   v8::Handle<Script> script(v8_compile("dummy()"));
1801   v8::Handle<Value> result(script->Run());
1802   CHECK_EQ(13.4, result->NumberValue());
1803   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1804   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1805 }
1806
1807
1808 THREADED_TEST(ObjectTemplate) {
1809   v8::Isolate* isolate = CcTest::isolate();
1810   v8::HandleScope scope(isolate);
1811   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1812   templ1->Set(isolate, "x", v8_num(10));
1813   templ1->Set(isolate, "y", v8_num(13));
1814   LocalContext env;
1815   Local<v8::Object> instance1 = templ1->NewInstance();
1816   env->Global()->Set(v8_str("p"), instance1);
1817   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1818   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1819   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1820   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1821   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1822   templ2->Set(isolate, "a", v8_num(12));
1823   templ2->Set(isolate, "b", templ1);
1824   Local<v8::Object> instance2 = templ2->NewInstance();
1825   env->Global()->Set(v8_str("q"), instance2);
1826   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1827   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1828   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1829   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1830 }
1831
1832
1833 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1834   ApiTestFuzzer::Fuzz();
1835   args.GetReturnValue().Set(v8_num(17.2));
1836 }
1837
1838
1839 static void GetKnurd(Local<String> property,
1840                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1841   ApiTestFuzzer::Fuzz();
1842   info.GetReturnValue().Set(v8_num(15.2));
1843 }
1844
1845
1846 THREADED_TEST(DescriptorInheritance) {
1847   v8::Isolate* isolate = CcTest::isolate();
1848   v8::HandleScope scope(isolate);
1849   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1850   super->PrototypeTemplate()->Set(isolate, "flabby",
1851                                   v8::FunctionTemplate::New(isolate,
1852                                                             GetFlabby));
1853   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1854
1855   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1856
1857   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1858   base1->Inherit(super);
1859   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1860
1861   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1862   base2->Inherit(super);
1863   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1864
1865   LocalContext env;
1866
1867   env->Global()->Set(v8_str("s"), super->GetFunction());
1868   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1869   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1870
1871   // Checks right __proto__ chain.
1872   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1873   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1874
1875   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1876
1877   // Instance accessor should not be visible on function object or its prototype
1878   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1879   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1880   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1881
1882   env->Global()->Set(v8_str("obj"),
1883                      base1->GetFunction()->NewInstance());
1884   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1885   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1886   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1887   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1888   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1889
1890   env->Global()->Set(v8_str("obj2"),
1891                      base2->GetFunction()->NewInstance());
1892   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1893   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1894   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1895   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1896   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1897
1898   // base1 and base2 cannot cross reference to each's prototype
1899   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1900   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1901 }
1902
1903
1904 int echo_named_call_count;
1905
1906
1907 static void EchoNamedProperty(Local<String> name,
1908                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1909   ApiTestFuzzer::Fuzz();
1910   CHECK_EQ(v8_str("data"), info.Data());
1911   echo_named_call_count++;
1912   info.GetReturnValue().Set(name);
1913 }
1914
1915
1916 // Helper functions for Interceptor/Accessor interaction tests
1917
1918 void SimpleAccessorGetter(Local<String> name,
1919                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1920   Handle<Object> self = Handle<Object>::Cast(info.This());
1921   info.GetReturnValue().Set(
1922       self->Get(String::Concat(v8_str("accessor_"), name)));
1923 }
1924
1925 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1926                           const v8::PropertyCallbackInfo<void>& info) {
1927   Handle<Object> self = Handle<Object>::Cast(info.This());
1928   self->Set(String::Concat(v8_str("accessor_"), name), value);
1929 }
1930
1931 void EmptyInterceptorGetter(Local<String> name,
1932                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1933 }
1934
1935 void EmptyInterceptorSetter(Local<String> name,
1936                             Local<Value> value,
1937                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1938 }
1939
1940 void InterceptorGetter(Local<String> name,
1941                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1942   // Intercept names that start with 'interceptor_'.
1943   String::Utf8Value utf8(name);
1944   char* name_str = *utf8;
1945   char prefix[] = "interceptor_";
1946   int i;
1947   for (i = 0; name_str[i] && prefix[i]; ++i) {
1948     if (name_str[i] != prefix[i]) return;
1949   }
1950   Handle<Object> self = Handle<Object>::Cast(info.This());
1951   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1952 }
1953
1954 void InterceptorSetter(Local<String> name,
1955                        Local<Value> value,
1956                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1957   // Intercept accesses that set certain integer values, for which the name does
1958   // not start with 'accessor_'.
1959   String::Utf8Value utf8(name);
1960   char* name_str = *utf8;
1961   char prefix[] = "accessor_";
1962   int i;
1963   for (i = 0; name_str[i] && prefix[i]; ++i) {
1964     if (name_str[i] != prefix[i]) break;
1965   }
1966   if (!prefix[i]) return;
1967
1968   if (value->IsInt32() && value->Int32Value() < 10000) {
1969     Handle<Object> self = Handle<Object>::Cast(info.This());
1970     self->SetHiddenValue(name, value);
1971     info.GetReturnValue().Set(value);
1972   }
1973 }
1974
1975 void AddAccessor(Handle<FunctionTemplate> templ,
1976                  Handle<String> name,
1977                  v8::AccessorGetterCallback getter,
1978                  v8::AccessorSetterCallback setter) {
1979   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1980 }
1981
1982 void AddInterceptor(Handle<FunctionTemplate> templ,
1983                     v8::NamedPropertyGetterCallback getter,
1984                     v8::NamedPropertySetterCallback setter) {
1985   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1986 }
1987
1988
1989 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1990   v8::HandleScope scope(CcTest::isolate());
1991   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1992   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1993   child->Inherit(parent);
1994   AddAccessor(parent, v8_str("age"),
1995               SimpleAccessorGetter, SimpleAccessorSetter);
1996   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1997   LocalContext env;
1998   env->Global()->Set(v8_str("Child"), child->GetFunction());
1999   CompileRun("var child = new Child;"
2000              "child.age = 10;");
2001   ExpectBoolean("child.hasOwnProperty('age')", false);
2002   ExpectInt32("child.age", 10);
2003   ExpectInt32("child.accessor_age", 10);
2004 }
2005
2006
2007 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2008   v8::HandleScope scope(CcTest::isolate());
2009   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2010   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2011   LocalContext env;
2012   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2013   CompileRun("var o1 = new Constructor;"
2014              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2015              "Object.defineProperty(o1, 'x', {value: 10});");
2016   CompileRun("var o2 = new Constructor;"
2017              "o2.a = 1;"
2018              "Object.defineProperty(o2, 'x', {value: 10});");
2019 }
2020
2021
2022 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2023   v8::Isolate* isolate = CcTest::isolate();
2024   v8::HandleScope scope(isolate);
2025   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2026   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2027   child->Inherit(parent);
2028   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2029   LocalContext env;
2030   env->Global()->Set(v8_str("Child"), child->GetFunction());
2031   CompileRun("var child = new Child;"
2032              "var parent = child.__proto__;"
2033              "Object.defineProperty(parent, 'age', "
2034              "  {get: function(){ return this.accessor_age; }, "
2035              "   set: function(v){ this.accessor_age = v; }, "
2036              "   enumerable: true, configurable: true});"
2037              "child.age = 10;");
2038   ExpectBoolean("child.hasOwnProperty('age')", false);
2039   ExpectInt32("child.age", 10);
2040   ExpectInt32("child.accessor_age", 10);
2041 }
2042
2043
2044 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2045   v8::Isolate* isolate = CcTest::isolate();
2046   v8::HandleScope scope(isolate);
2047   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2048   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2049   child->Inherit(parent);
2050   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2051   LocalContext env;
2052   env->Global()->Set(v8_str("Child"), child->GetFunction());
2053   CompileRun("var child = new Child;"
2054              "var parent = child.__proto__;"
2055              "parent.name = 'Alice';");
2056   ExpectBoolean("child.hasOwnProperty('name')", false);
2057   ExpectString("child.name", "Alice");
2058   CompileRun("child.name = 'Bob';");
2059   ExpectString("child.name", "Bob");
2060   ExpectBoolean("child.hasOwnProperty('name')", true);
2061   ExpectString("parent.name", "Alice");
2062 }
2063
2064
2065 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2066   v8::HandleScope scope(CcTest::isolate());
2067   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2068   AddAccessor(templ, v8_str("age"),
2069               SimpleAccessorGetter, SimpleAccessorSetter);
2070   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2071   LocalContext env;
2072   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2073   CompileRun("var obj = new Obj;"
2074              "function setAge(i){ obj.age = i; };"
2075              "for(var i = 0; i <= 10000; i++) setAge(i);");
2076   // All i < 10000 go to the interceptor.
2077   ExpectInt32("obj.interceptor_age", 9999);
2078   // The last i goes to the accessor.
2079   ExpectInt32("obj.accessor_age", 10000);
2080 }
2081
2082
2083 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2084   v8::HandleScope scope(CcTest::isolate());
2085   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2086   AddAccessor(templ, v8_str("age"),
2087               SimpleAccessorGetter, SimpleAccessorSetter);
2088   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2089   LocalContext env;
2090   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2091   CompileRun("var obj = new Obj;"
2092              "function setAge(i){ obj.age = i; };"
2093              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2094   // All i >= 10000 go to the accessor.
2095   ExpectInt32("obj.accessor_age", 10000);
2096   // The last i goes to the interceptor.
2097   ExpectInt32("obj.interceptor_age", 9999);
2098 }
2099
2100
2101 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2102   v8::HandleScope scope(CcTest::isolate());
2103   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2104   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2105   child->Inherit(parent);
2106   AddAccessor(parent, v8_str("age"),
2107               SimpleAccessorGetter, SimpleAccessorSetter);
2108   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2109   LocalContext env;
2110   env->Global()->Set(v8_str("Child"), child->GetFunction());
2111   CompileRun("var child = new Child;"
2112              "function setAge(i){ child.age = i; };"
2113              "for(var i = 0; i <= 10000; i++) setAge(i);");
2114   // All i < 10000 go to the interceptor.
2115   ExpectInt32("child.interceptor_age", 9999);
2116   // The last i goes to the accessor.
2117   ExpectInt32("child.accessor_age", 10000);
2118 }
2119
2120
2121 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2122   v8::HandleScope scope(CcTest::isolate());
2123   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2124   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2125   child->Inherit(parent);
2126   AddAccessor(parent, v8_str("age"),
2127               SimpleAccessorGetter, SimpleAccessorSetter);
2128   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2129   LocalContext env;
2130   env->Global()->Set(v8_str("Child"), child->GetFunction());
2131   CompileRun("var child = new Child;"
2132              "function setAge(i){ child.age = i; };"
2133              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2134   // All i >= 10000 go to the accessor.
2135   ExpectInt32("child.accessor_age", 10000);
2136   // The last i goes to the interceptor.
2137   ExpectInt32("child.interceptor_age", 9999);
2138 }
2139
2140
2141 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2142   v8::HandleScope scope(CcTest::isolate());
2143   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2144   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2145   LocalContext env;
2146   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2147   CompileRun("var obj = new Obj;"
2148              "function setter(i) { this.accessor_age = i; };"
2149              "function getter() { return this.accessor_age; };"
2150              "function setAge(i) { obj.age = i; };"
2151              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2152              "for(var i = 0; i <= 10000; i++) setAge(i);");
2153   // All i < 10000 go to the interceptor.
2154   ExpectInt32("obj.interceptor_age", 9999);
2155   // The last i goes to the JavaScript accessor.
2156   ExpectInt32("obj.accessor_age", 10000);
2157   // The installed JavaScript getter is still intact.
2158   // This last part is a regression test for issue 1651 and relies on the fact
2159   // that both interceptor and accessor are being installed on the same object.
2160   ExpectInt32("obj.age", 10000);
2161   ExpectBoolean("obj.hasOwnProperty('age')", true);
2162   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2163 }
2164
2165
2166 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2167   v8::HandleScope scope(CcTest::isolate());
2168   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2169   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2170   LocalContext env;
2171   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2172   CompileRun("var obj = new Obj;"
2173              "function setter(i) { this.accessor_age = i; };"
2174              "function getter() { return this.accessor_age; };"
2175              "function setAge(i) { obj.age = i; };"
2176              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2177              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2178   // All i >= 10000 go to the accessor.
2179   ExpectInt32("obj.accessor_age", 10000);
2180   // The last i goes to the interceptor.
2181   ExpectInt32("obj.interceptor_age", 9999);
2182   // The installed JavaScript getter is still intact.
2183   // This last part is a regression test for issue 1651 and relies on the fact
2184   // that both interceptor and accessor are being installed on the same object.
2185   ExpectInt32("obj.age", 10000);
2186   ExpectBoolean("obj.hasOwnProperty('age')", true);
2187   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2188 }
2189
2190
2191 THREADED_TEST(SwitchFromInterceptorToProperty) {
2192   v8::HandleScope scope(CcTest::isolate());
2193   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2194   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2195   child->Inherit(parent);
2196   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2197   LocalContext env;
2198   env->Global()->Set(v8_str("Child"), child->GetFunction());
2199   CompileRun("var child = new Child;"
2200              "function setAge(i){ child.age = i; };"
2201              "for(var i = 0; i <= 10000; i++) setAge(i);");
2202   // All i < 10000 go to the interceptor.
2203   ExpectInt32("child.interceptor_age", 9999);
2204   // The last i goes to child's own property.
2205   ExpectInt32("child.age", 10000);
2206 }
2207
2208
2209 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2210   v8::HandleScope scope(CcTest::isolate());
2211   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2212   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2213   child->Inherit(parent);
2214   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2215   LocalContext env;
2216   env->Global()->Set(v8_str("Child"), child->GetFunction());
2217   CompileRun("var child = new Child;"
2218              "function setAge(i){ child.age = i; };"
2219              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2220   // All i >= 10000 go to child's own property.
2221   ExpectInt32("child.age", 10000);
2222   // The last i goes to the interceptor.
2223   ExpectInt32("child.interceptor_age", 9999);
2224 }
2225
2226
2227 THREADED_TEST(NamedPropertyHandlerGetter) {
2228   echo_named_call_count = 0;
2229   v8::HandleScope scope(CcTest::isolate());
2230   v8::Handle<v8::FunctionTemplate> templ =
2231       v8::FunctionTemplate::New(CcTest::isolate());
2232   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2233                                                      0, 0, 0, 0,
2234                                                      v8_str("data"));
2235   LocalContext env;
2236   env->Global()->Set(v8_str("obj"),
2237                      templ->GetFunction()->NewInstance());
2238   CHECK_EQ(echo_named_call_count, 0);
2239   v8_compile("obj.x")->Run();
2240   CHECK_EQ(echo_named_call_count, 1);
2241   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2242   v8::Handle<Value> str = CompileRun(code);
2243   String::Utf8Value value(str);
2244   CHECK_EQ(*value, "oddlepoddle");
2245   // Check default behavior
2246   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2247   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2248   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2249 }
2250
2251
2252 int echo_indexed_call_count = 0;
2253
2254
2255 static void EchoIndexedProperty(
2256     uint32_t index,
2257     const v8::PropertyCallbackInfo<v8::Value>& info) {
2258   ApiTestFuzzer::Fuzz();
2259   CHECK_EQ(v8_num(637), info.Data());
2260   echo_indexed_call_count++;
2261   info.GetReturnValue().Set(v8_num(index));
2262 }
2263
2264
2265 THREADED_TEST(IndexedPropertyHandlerGetter) {
2266   v8::Isolate* isolate = CcTest::isolate();
2267   v8::HandleScope scope(isolate);
2268   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2269   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2270                                                        0, 0, 0, 0,
2271                                                        v8_num(637));
2272   LocalContext env;
2273   env->Global()->Set(v8_str("obj"),
2274                      templ->GetFunction()->NewInstance());
2275   Local<Script> script = v8_compile("obj[900]");
2276   CHECK_EQ(script->Run()->Int32Value(), 900);
2277 }
2278
2279
2280 v8::Handle<v8::Object> bottom;
2281
2282 static void CheckThisIndexedPropertyHandler(
2283     uint32_t index,
2284     const v8::PropertyCallbackInfo<v8::Value>& info) {
2285   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2286   ApiTestFuzzer::Fuzz();
2287   CHECK(info.This()->Equals(bottom));
2288 }
2289
2290 static void CheckThisNamedPropertyHandler(
2291     Local<String> name,
2292     const v8::PropertyCallbackInfo<v8::Value>& info) {
2293   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2294   ApiTestFuzzer::Fuzz();
2295   CHECK(info.This()->Equals(bottom));
2296 }
2297
2298 void CheckThisIndexedPropertySetter(
2299     uint32_t index,
2300     Local<Value> value,
2301     const v8::PropertyCallbackInfo<v8::Value>& info) {
2302   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2303   ApiTestFuzzer::Fuzz();
2304   CHECK(info.This()->Equals(bottom));
2305 }
2306
2307
2308 void CheckThisNamedPropertySetter(
2309     Local<String> property,
2310     Local<Value> value,
2311     const v8::PropertyCallbackInfo<v8::Value>& info) {
2312   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2313   ApiTestFuzzer::Fuzz();
2314   CHECK(info.This()->Equals(bottom));
2315 }
2316
2317 void CheckThisIndexedPropertyQuery(
2318     uint32_t index,
2319     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2320   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2321   ApiTestFuzzer::Fuzz();
2322   CHECK(info.This()->Equals(bottom));
2323 }
2324
2325
2326 void CheckThisNamedPropertyQuery(
2327     Local<String> property,
2328     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2329   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2330   ApiTestFuzzer::Fuzz();
2331   CHECK(info.This()->Equals(bottom));
2332 }
2333
2334
2335 void CheckThisIndexedPropertyDeleter(
2336     uint32_t index,
2337     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2338   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2339   ApiTestFuzzer::Fuzz();
2340   CHECK(info.This()->Equals(bottom));
2341 }
2342
2343
2344 void CheckThisNamedPropertyDeleter(
2345     Local<String> property,
2346     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2347   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2348   ApiTestFuzzer::Fuzz();
2349   CHECK(info.This()->Equals(bottom));
2350 }
2351
2352
2353 void CheckThisIndexedPropertyEnumerator(
2354     const v8::PropertyCallbackInfo<v8::Array>& info) {
2355   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2356   ApiTestFuzzer::Fuzz();
2357   CHECK(info.This()->Equals(bottom));
2358 }
2359
2360
2361 void CheckThisNamedPropertyEnumerator(
2362     const v8::PropertyCallbackInfo<v8::Array>& info) {
2363   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2364   ApiTestFuzzer::Fuzz();
2365   CHECK(info.This()->Equals(bottom));
2366 }
2367
2368
2369 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2370   LocalContext env;
2371   v8::Isolate* isolate = env->GetIsolate();
2372   v8::HandleScope scope(isolate);
2373
2374   // Set up a prototype chain with three interceptors.
2375   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2376   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2377       CheckThisIndexedPropertyHandler,
2378       CheckThisIndexedPropertySetter,
2379       CheckThisIndexedPropertyQuery,
2380       CheckThisIndexedPropertyDeleter,
2381       CheckThisIndexedPropertyEnumerator);
2382
2383   templ->InstanceTemplate()->SetNamedPropertyHandler(
2384       CheckThisNamedPropertyHandler,
2385       CheckThisNamedPropertySetter,
2386       CheckThisNamedPropertyQuery,
2387       CheckThisNamedPropertyDeleter,
2388       CheckThisNamedPropertyEnumerator);
2389
2390   bottom = templ->GetFunction()->NewInstance();
2391   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2392   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2393
2394   bottom->SetPrototype(middle);
2395   middle->SetPrototype(top);
2396   env->Global()->Set(v8_str("obj"), bottom);
2397
2398   // Indexed and named get.
2399   CompileRun("obj[0]");
2400   CompileRun("obj.x");
2401
2402   // Indexed and named set.
2403   CompileRun("obj[1] = 42");
2404   CompileRun("obj.y = 42");
2405
2406   // Indexed and named query.
2407   CompileRun("0 in obj");
2408   CompileRun("'x' in obj");
2409
2410   // Indexed and named deleter.
2411   CompileRun("delete obj[0]");
2412   CompileRun("delete obj.x");
2413
2414   // Enumerators.
2415   CompileRun("for (var p in obj) ;");
2416 }
2417
2418
2419 static void PrePropertyHandlerGet(
2420     Local<String> key,
2421     const v8::PropertyCallbackInfo<v8::Value>& info) {
2422   ApiTestFuzzer::Fuzz();
2423   if (v8_str("pre")->Equals(key)) {
2424     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2425   }
2426 }
2427
2428
2429 static void PrePropertyHandlerQuery(
2430     Local<String> key,
2431     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2432   if (v8_str("pre")->Equals(key)) {
2433     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2434   }
2435 }
2436
2437
2438 THREADED_TEST(PrePropertyHandler) {
2439   v8::Isolate* isolate = CcTest::isolate();
2440   v8::HandleScope scope(isolate);
2441   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2442   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2443                                                     0,
2444                                                     PrePropertyHandlerQuery);
2445   LocalContext env(NULL, desc->InstanceTemplate());
2446   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2447   v8::Handle<Value> result_pre = CompileRun("pre");
2448   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2449   v8::Handle<Value> result_on = CompileRun("on");
2450   CHECK_EQ(v8_str("Object: on"), result_on);
2451   v8::Handle<Value> result_post = CompileRun("post");
2452   CHECK(result_post.IsEmpty());
2453 }
2454
2455
2456 THREADED_TEST(UndefinedIsNotEnumerable) {
2457   LocalContext env;
2458   v8::HandleScope scope(env->GetIsolate());
2459   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2460   CHECK(result->IsFalse());
2461 }
2462
2463
2464 v8::Handle<Script> call_recursively_script;
2465 static const int kTargetRecursionDepth = 200;  // near maximum
2466
2467
2468 static void CallScriptRecursivelyCall(
2469     const v8::FunctionCallbackInfo<v8::Value>& args) {
2470   ApiTestFuzzer::Fuzz();
2471   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2472   if (depth == kTargetRecursionDepth) return;
2473   args.This()->Set(v8_str("depth"),
2474                    v8::Integer::New(args.GetIsolate(), depth + 1));
2475   args.GetReturnValue().Set(call_recursively_script->Run());
2476 }
2477
2478
2479 static void CallFunctionRecursivelyCall(
2480     const v8::FunctionCallbackInfo<v8::Value>& args) {
2481   ApiTestFuzzer::Fuzz();
2482   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2483   if (depth == kTargetRecursionDepth) {
2484     printf("[depth = %d]\n", depth);
2485     return;
2486   }
2487   args.This()->Set(v8_str("depth"),
2488                    v8::Integer::New(args.GetIsolate(), depth + 1));
2489   v8::Handle<Value> function =
2490       args.This()->Get(v8_str("callFunctionRecursively"));
2491   args.GetReturnValue().Set(
2492       function.As<Function>()->Call(args.This(), 0, NULL));
2493 }
2494
2495
2496 THREADED_TEST(DeepCrossLanguageRecursion) {
2497   v8::Isolate* isolate = CcTest::isolate();
2498   v8::HandleScope scope(isolate);
2499   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2500   global->Set(v8_str("callScriptRecursively"),
2501               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2502   global->Set(v8_str("callFunctionRecursively"),
2503               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2504   LocalContext env(NULL, global);
2505
2506   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2507   call_recursively_script = v8_compile("callScriptRecursively()");
2508   call_recursively_script->Run();
2509   call_recursively_script = v8::Handle<Script>();
2510
2511   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2512   CompileRun("callFunctionRecursively()");
2513 }
2514
2515
2516 static void ThrowingPropertyHandlerGet(
2517     Local<String> key,
2518     const v8::PropertyCallbackInfo<v8::Value>& info) {
2519   ApiTestFuzzer::Fuzz();
2520   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2521 }
2522
2523
2524 static void ThrowingPropertyHandlerSet(
2525     Local<String> key,
2526     Local<Value>,
2527     const v8::PropertyCallbackInfo<v8::Value>& info) {
2528   info.GetIsolate()->ThrowException(key);
2529   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2530 }
2531
2532
2533 THREADED_TEST(CallbackExceptionRegression) {
2534   v8::Isolate* isolate = CcTest::isolate();
2535   v8::HandleScope scope(isolate);
2536   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2537   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2538                                ThrowingPropertyHandlerSet);
2539   LocalContext env;
2540   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2541   v8::Handle<Value> otto = CompileRun(
2542       "try { with (obj) { otto; } } catch (e) { e; }");
2543   CHECK_EQ(v8_str("otto"), otto);
2544   v8::Handle<Value> netto = CompileRun(
2545       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2546   CHECK_EQ(v8_str("netto"), netto);
2547 }
2548
2549
2550 THREADED_TEST(FunctionPrototype) {
2551   v8::Isolate* isolate = CcTest::isolate();
2552   v8::HandleScope scope(isolate);
2553   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2554   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2555   LocalContext env;
2556   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2557   Local<Script> script = v8_compile("Foo.prototype.plak");
2558   CHECK_EQ(script->Run()->Int32Value(), 321);
2559 }
2560
2561
2562 THREADED_TEST(InternalFields) {
2563   LocalContext env;
2564   v8::Isolate* isolate = env->GetIsolate();
2565   v8::HandleScope scope(isolate);
2566
2567   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2568   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2569   instance_templ->SetInternalFieldCount(1);
2570   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2571   CHECK_EQ(1, obj->InternalFieldCount());
2572   CHECK(obj->GetInternalField(0)->IsUndefined());
2573   obj->SetInternalField(0, v8_num(17));
2574   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2575 }
2576
2577
2578 THREADED_TEST(GlobalObjectInternalFields) {
2579   v8::Isolate* isolate = CcTest::isolate();
2580   v8::HandleScope scope(isolate);
2581   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2582   global_template->SetInternalFieldCount(1);
2583   LocalContext env(NULL, global_template);
2584   v8::Handle<v8::Object> global_proxy = env->Global();
2585   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2586   CHECK_EQ(1, global->InternalFieldCount());
2587   CHECK(global->GetInternalField(0)->IsUndefined());
2588   global->SetInternalField(0, v8_num(17));
2589   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2590 }
2591
2592
2593 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2594   LocalContext env;
2595   v8::HandleScope scope(CcTest::isolate());
2596
2597   v8::Local<v8::Object> global = env->Global();
2598   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2599   CHECK(global->HasRealIndexedProperty(0));
2600 }
2601
2602
2603 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2604                                                void* value) {
2605   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2606   obj->SetAlignedPointerInInternalField(0, value);
2607   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2608   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2609 }
2610
2611
2612 THREADED_TEST(InternalFieldsAlignedPointers) {
2613   LocalContext env;
2614   v8::Isolate* isolate = env->GetIsolate();
2615   v8::HandleScope scope(isolate);
2616
2617   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2618   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2619   instance_templ->SetInternalFieldCount(1);
2620   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2621   CHECK_EQ(1, obj->InternalFieldCount());
2622
2623   CheckAlignedPointerInInternalField(obj, NULL);
2624
2625   int* heap_allocated = new int[100];
2626   CheckAlignedPointerInInternalField(obj, heap_allocated);
2627   delete[] heap_allocated;
2628
2629   int stack_allocated[100];
2630   CheckAlignedPointerInInternalField(obj, stack_allocated);
2631
2632   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2633   CheckAlignedPointerInInternalField(obj, huge);
2634
2635   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2636   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2637   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2638 }
2639
2640
2641 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2642                                               int index,
2643                                               void* value) {
2644   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2645   (*env)->SetAlignedPointerInEmbedderData(index, value);
2646   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2647   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2648 }
2649
2650
2651 static void* AlignedTestPointer(int i) {
2652   return reinterpret_cast<void*>(i * 1234);
2653 }
2654
2655
2656 THREADED_TEST(EmbedderDataAlignedPointers) {
2657   LocalContext env;
2658   v8::HandleScope scope(env->GetIsolate());
2659
2660   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2661
2662   int* heap_allocated = new int[100];
2663   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2664   delete[] heap_allocated;
2665
2666   int stack_allocated[100];
2667   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2668
2669   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2670   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2671
2672   // Test growing of the embedder data's backing store.
2673   for (int i = 0; i < 100; i++) {
2674     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2675   }
2676   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2677   for (int i = 0; i < 100; i++) {
2678     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2679   }
2680 }
2681
2682
2683 static void CheckEmbedderData(LocalContext* env,
2684                               int index,
2685                               v8::Handle<Value> data) {
2686   (*env)->SetEmbedderData(index, data);
2687   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2688 }
2689
2690
2691 THREADED_TEST(EmbedderData) {
2692   LocalContext env;
2693   v8::Isolate* isolate = env->GetIsolate();
2694   v8::HandleScope scope(isolate);
2695
2696   CheckEmbedderData(
2697       &env, 3,
2698       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2699   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2700                                                      "over the lazy dog."));
2701   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2702   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2703 }
2704
2705
2706 THREADED_TEST(IdentityHash) {
2707   LocalContext env;
2708   v8::Isolate* isolate = env->GetIsolate();
2709   v8::HandleScope scope(isolate);
2710
2711   // Ensure that the test starts with an fresh heap to test whether the hash
2712   // code is based on the address.
2713   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2714   Local<v8::Object> obj = v8::Object::New(isolate);
2715   int hash = obj->GetIdentityHash();
2716   int hash1 = obj->GetIdentityHash();
2717   CHECK_EQ(hash, hash1);
2718   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2719   // Since the identity hash is essentially a random number two consecutive
2720   // objects should not be assigned the same hash code. If the test below fails
2721   // the random number generator should be evaluated.
2722   CHECK_NE(hash, hash2);
2723   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2724   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2725   // Make sure that the identity hash is not based on the initial address of
2726   // the object alone. If the test below fails the random number generator
2727   // should be evaluated.
2728   CHECK_NE(hash, hash3);
2729   int hash4 = obj->GetIdentityHash();
2730   CHECK_EQ(hash, hash4);
2731
2732   // Check identity hashes behaviour in the presence of JS accessors.
2733   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2734   {
2735     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2736     Local<v8::Object> o1 = v8::Object::New(isolate);
2737     Local<v8::Object> o2 = v8::Object::New(isolate);
2738     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2739   }
2740   {
2741     CompileRun(
2742         "function cnst() { return 42; };\n"
2743         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2744     Local<v8::Object> o1 = v8::Object::New(isolate);
2745     Local<v8::Object> o2 = v8::Object::New(isolate);
2746     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2747   }
2748 }
2749
2750
2751 THREADED_TEST(SymbolProperties) {
2752   i::FLAG_harmony_symbols = true;
2753
2754   LocalContext env;
2755   v8::Isolate* isolate = env->GetIsolate();
2756   v8::HandleScope scope(isolate);
2757
2758   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2759   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2760   v8::Local<v8::Symbol> sym2 =
2761       v8::Symbol::New(isolate, v8_str("my-symbol"));
2762
2763   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2764
2765   // Check basic symbol functionality.
2766   CHECK(sym1->IsSymbol());
2767   CHECK(sym2->IsSymbol());
2768   CHECK(!obj->IsSymbol());
2769
2770   CHECK(sym1->Equals(sym1));
2771   CHECK(sym2->Equals(sym2));
2772   CHECK(!sym1->Equals(sym2));
2773   CHECK(!sym2->Equals(sym1));
2774   CHECK(sym1->StrictEquals(sym1));
2775   CHECK(sym2->StrictEquals(sym2));
2776   CHECK(!sym1->StrictEquals(sym2));
2777   CHECK(!sym2->StrictEquals(sym1));
2778
2779   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2780
2781   v8::Local<v8::Value> sym_val = sym2;
2782   CHECK(sym_val->IsSymbol());
2783   CHECK(sym_val->Equals(sym2));
2784   CHECK(sym_val->StrictEquals(sym2));
2785   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2786
2787   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2788   CHECK(sym_obj->IsSymbolObject());
2789   CHECK(!sym2->IsSymbolObject());
2790   CHECK(!obj->IsSymbolObject());
2791   CHECK(!sym_obj->Equals(sym2));
2792   CHECK(!sym_obj->StrictEquals(sym2));
2793   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2794   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2795
2796   // Make sure delete of a non-existent symbol property works.
2797   CHECK(obj->Delete(sym1));
2798   CHECK(!obj->Has(sym1));
2799
2800   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2801   CHECK(obj->Has(sym1));
2802   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2803   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2804   CHECK(obj->Has(sym1));
2805   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2806   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2807
2808   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2809   int num_props = obj->GetPropertyNames()->Length();
2810   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2811                  v8::Integer::New(isolate, 20)));
2812   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2813   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2814
2815   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2816
2817   // Add another property and delete it afterwards to force the object in
2818   // slow case.
2819   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2820   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2821   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2822   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2823   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2824
2825   CHECK(obj->Has(sym1));
2826   CHECK(obj->Has(sym2));
2827   CHECK(obj->Delete(sym2));
2828   CHECK(obj->Has(sym1));
2829   CHECK(!obj->Has(sym2));
2830   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2831   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2832
2833   // Symbol properties are inherited.
2834   v8::Local<v8::Object> child = v8::Object::New(isolate);
2835   child->SetPrototype(obj);
2836   CHECK(child->Has(sym1));
2837   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2838   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2839 }
2840
2841
2842 THREADED_TEST(PrivateProperties) {
2843   LocalContext env;
2844   v8::Isolate* isolate = env->GetIsolate();
2845   v8::HandleScope scope(isolate);
2846
2847   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2848   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2849   v8::Local<v8::Private> priv2 =
2850       v8::Private::New(isolate, v8_str("my-private"));
2851
2852   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2853
2854   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2855
2856   // Make sure delete of a non-existent private symbol property works.
2857   CHECK(obj->DeletePrivate(priv1));
2858   CHECK(!obj->HasPrivate(priv1));
2859
2860   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2861   CHECK(obj->HasPrivate(priv1));
2862   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2863   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2864   CHECK(obj->HasPrivate(priv1));
2865   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2866
2867   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2868   int num_props = obj->GetPropertyNames()->Length();
2869   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2870                  v8::Integer::New(isolate, 20)));
2871   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2872   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2873
2874   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2875
2876   // Add another property and delete it afterwards to force the object in
2877   // slow case.
2878   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2879   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2880   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2881   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2882   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2883
2884   CHECK(obj->HasPrivate(priv1));
2885   CHECK(obj->HasPrivate(priv2));
2886   CHECK(obj->DeletePrivate(priv2));
2887   CHECK(obj->HasPrivate(priv1));
2888   CHECK(!obj->HasPrivate(priv2));
2889   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2890   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2891
2892   // Private properties are inherited (for the time being).
2893   v8::Local<v8::Object> child = v8::Object::New(isolate);
2894   child->SetPrototype(obj);
2895   CHECK(child->HasPrivate(priv1));
2896   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2897   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2898 }
2899
2900
2901 THREADED_TEST(GlobalSymbols) {
2902   i::FLAG_harmony_symbols = true;
2903
2904   LocalContext env;
2905   v8::Isolate* isolate = env->GetIsolate();
2906   v8::HandleScope scope(isolate);
2907
2908   v8::Local<String> name = v8_str("my-symbol");
2909   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2910   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2911   CHECK(glob2->SameValue(glob));
2912
2913   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2914   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2915   CHECK(glob_api2->SameValue(glob_api));
2916   CHECK(!glob_api->SameValue(glob));
2917
2918   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2919   CHECK(!sym->SameValue(glob));
2920
2921   CompileRun("var sym2 = Symbol.for('my-symbol')");
2922   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2923   CHECK(sym2->SameValue(glob));
2924   CHECK(!sym2->SameValue(glob_api));
2925 }
2926
2927
2928 THREADED_TEST(GlobalPrivates) {
2929   LocalContext env;
2930   v8::Isolate* isolate = env->GetIsolate();
2931   v8::HandleScope scope(isolate);
2932
2933   v8::Local<String> name = v8_str("my-private");
2934   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2935   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2936   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2937
2938   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2939   CHECK(obj->HasPrivate(glob2));
2940
2941   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2942   CHECK(!obj->HasPrivate(priv));
2943
2944   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2945   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2946   CHECK(!obj->Has(intern));
2947 }
2948
2949
2950 class ScopedArrayBufferContents {
2951  public:
2952   explicit ScopedArrayBufferContents(
2953       const v8::ArrayBuffer::Contents& contents)
2954     : contents_(contents) {}
2955   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2956   void* Data() const { return contents_.Data(); }
2957   size_t ByteLength() const { return contents_.ByteLength(); }
2958  private:
2959   const v8::ArrayBuffer::Contents contents_;
2960 };
2961
2962 template <typename T>
2963 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2964   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2965   for (int i = 0; i < value->InternalFieldCount(); i++) {
2966     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2967   }
2968 }
2969
2970
2971 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2972   LocalContext env;
2973   v8::Isolate* isolate = env->GetIsolate();
2974   v8::HandleScope handle_scope(isolate);
2975
2976   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2977   CheckInternalFieldsAreZero(ab);
2978   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2979   CHECK(!ab->IsExternal());
2980   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2981
2982   ScopedArrayBufferContents ab_contents(ab->Externalize());
2983   CHECK(ab->IsExternal());
2984
2985   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2986   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2987   ASSERT(data != NULL);
2988   env->Global()->Set(v8_str("ab"), ab);
2989
2990   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2991   CHECK_EQ(1024, result->Int32Value());
2992
2993   result = CompileRun("var u8 = new Uint8Array(ab);"
2994                       "u8[0] = 0xFF;"
2995                       "u8[1] = 0xAA;"
2996                       "u8.length");
2997   CHECK_EQ(1024, result->Int32Value());
2998   CHECK_EQ(0xFF, data[0]);
2999   CHECK_EQ(0xAA, data[1]);
3000   data[0] = 0xCC;
3001   data[1] = 0x11;
3002   result = CompileRun("u8[0] + u8[1]");
3003   CHECK_EQ(0xDD, result->Int32Value());
3004 }
3005
3006
3007 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3008   LocalContext env;
3009   v8::Isolate* isolate = env->GetIsolate();
3010   v8::HandleScope handle_scope(isolate);
3011
3012
3013   v8::Local<v8::Value> result =
3014       CompileRun("var ab1 = new ArrayBuffer(2);"
3015                  "var u8_a = new Uint8Array(ab1);"
3016                  "u8_a[0] = 0xAA;"
3017                  "u8_a[1] = 0xFF; u8_a.buffer");
3018   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3019   CheckInternalFieldsAreZero(ab1);
3020   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3021   CHECK(!ab1->IsExternal());
3022   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3023   CHECK(ab1->IsExternal());
3024
3025   result = CompileRun("ab1.byteLength");
3026   CHECK_EQ(2, result->Int32Value());
3027   result = CompileRun("u8_a[0]");
3028   CHECK_EQ(0xAA, result->Int32Value());
3029   result = CompileRun("u8_a[1]");
3030   CHECK_EQ(0xFF, result->Int32Value());
3031   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3032                       "u8_b[0] = 0xBB;"
3033                       "u8_a[0]");
3034   CHECK_EQ(0xBB, result->Int32Value());
3035   result = CompileRun("u8_b[1]");
3036   CHECK_EQ(0xFF, result->Int32Value());
3037
3038   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3039   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3040   CHECK_EQ(0xBB, ab1_data[0]);
3041   CHECK_EQ(0xFF, ab1_data[1]);
3042   ab1_data[0] = 0xCC;
3043   ab1_data[1] = 0x11;
3044   result = CompileRun("u8_a[0] + u8_a[1]");
3045   CHECK_EQ(0xDD, result->Int32Value());
3046 }
3047
3048
3049 THREADED_TEST(ArrayBuffer_External) {
3050   LocalContext env;
3051   v8::Isolate* isolate = env->GetIsolate();
3052   v8::HandleScope handle_scope(isolate);
3053
3054   i::ScopedVector<uint8_t> my_data(100);
3055   memset(my_data.start(), 0, 100);
3056   Local<v8::ArrayBuffer> ab3 =
3057       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3058   CheckInternalFieldsAreZero(ab3);
3059   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3060   CHECK(ab3->IsExternal());
3061
3062   env->Global()->Set(v8_str("ab3"), ab3);
3063
3064   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3065   CHECK_EQ(100, result->Int32Value());
3066
3067   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3068                       "u8_b[0] = 0xBB;"
3069                       "u8_b[1] = 0xCC;"
3070                       "u8_b.length");
3071   CHECK_EQ(100, result->Int32Value());
3072   CHECK_EQ(0xBB, my_data[0]);
3073   CHECK_EQ(0xCC, my_data[1]);
3074   my_data[0] = 0xCC;
3075   my_data[1] = 0x11;
3076   result = CompileRun("u8_b[0] + u8_b[1]");
3077   CHECK_EQ(0xDD, result->Int32Value());
3078 }
3079
3080
3081 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3082   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3083   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3084 }
3085
3086
3087 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3088   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3089   CHECK_EQ(0, static_cast<int>(ta->Length()));
3090   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3091 }
3092
3093
3094 static void CheckIsTypedArrayVarNeutered(const char* name) {
3095   i::ScopedVector<char> source(1024);
3096   i::OS::SNPrintF(source,
3097       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3098       name, name, name);
3099   CHECK(CompileRun(source.start())->IsTrue());
3100   v8::Handle<v8::TypedArray> ta =
3101     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3102   CheckIsNeutered(ta);
3103 }
3104
3105
3106 template <typename TypedArray, int kElementSize>
3107 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3108                                          int byteOffset,
3109                                          int length) {
3110   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3111   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3112   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3113   CHECK_EQ(length, static_cast<int>(ta->Length()));
3114   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3115   return ta;
3116 }
3117
3118
3119 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3120   LocalContext env;
3121   v8::Isolate* isolate = env->GetIsolate();
3122   v8::HandleScope handle_scope(isolate);
3123
3124   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3125
3126   v8::Handle<v8::Uint8Array> u8a =
3127     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3128   v8::Handle<v8::Uint8ClampedArray> u8c =
3129     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3130   v8::Handle<v8::Int8Array> i8a =
3131     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3132
3133   v8::Handle<v8::Uint16Array> u16a =
3134     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3135   v8::Handle<v8::Int16Array> i16a =
3136     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3137
3138   v8::Handle<v8::Uint32Array> u32a =
3139     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3140   v8::Handle<v8::Int32Array> i32a =
3141     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3142
3143   v8::Handle<v8::Float32Array> f32a =
3144     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3145   v8::Handle<v8::Float64Array> f64a =
3146     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3147
3148   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3149   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3150   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3151   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3152
3153   ScopedArrayBufferContents contents(buffer->Externalize());
3154   buffer->Neuter();
3155   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3156   CheckIsNeutered(u8a);
3157   CheckIsNeutered(u8c);
3158   CheckIsNeutered(i8a);
3159   CheckIsNeutered(u16a);
3160   CheckIsNeutered(i16a);
3161   CheckIsNeutered(u32a);
3162   CheckIsNeutered(i32a);
3163   CheckIsNeutered(f32a);
3164   CheckIsNeutered(f64a);
3165   CheckDataViewIsNeutered(dv);
3166 }
3167
3168
3169 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3170   LocalContext env;
3171   v8::Isolate* isolate = env->GetIsolate();
3172   v8::HandleScope handle_scope(isolate);
3173
3174   CompileRun(
3175       "var ab = new ArrayBuffer(1024);"
3176       "var u8a = new Uint8Array(ab, 1, 1023);"
3177       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3178       "var i8a = new Int8Array(ab, 1, 1023);"
3179       "var u16a = new Uint16Array(ab, 2, 511);"
3180       "var i16a = new Int16Array(ab, 2, 511);"
3181       "var u32a = new Uint32Array(ab, 4, 255);"
3182       "var i32a = new Int32Array(ab, 4, 255);"
3183       "var f32a = new Float32Array(ab, 4, 255);"
3184       "var f64a = new Float64Array(ab, 8, 127);"
3185       "var dv = new DataView(ab, 1, 1023);");
3186
3187   v8::Handle<v8::ArrayBuffer> ab =
3188       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3189
3190   v8::Handle<v8::DataView> dv =
3191     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3192
3193   ScopedArrayBufferContents contents(ab->Externalize());
3194   ab->Neuter();
3195   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3196   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3197
3198   CheckIsTypedArrayVarNeutered("u8a");
3199   CheckIsTypedArrayVarNeutered("u8c");
3200   CheckIsTypedArrayVarNeutered("i8a");
3201   CheckIsTypedArrayVarNeutered("u16a");
3202   CheckIsTypedArrayVarNeutered("i16a");
3203   CheckIsTypedArrayVarNeutered("u32a");
3204   CheckIsTypedArrayVarNeutered("i32a");
3205   CheckIsTypedArrayVarNeutered("f32a");
3206   CheckIsTypedArrayVarNeutered("f64a");
3207
3208   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3209   CheckDataViewIsNeutered(dv);
3210 }
3211
3212
3213
3214 THREADED_TEST(HiddenProperties) {
3215   LocalContext env;
3216   v8::Isolate* isolate = env->GetIsolate();
3217   v8::HandleScope scope(isolate);
3218
3219   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3220   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3221   v8::Local<v8::String> empty = v8_str("");
3222   v8::Local<v8::String> prop_name = v8_str("prop_name");
3223
3224   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3225
3226   // Make sure delete of a non-existent hidden value works
3227   CHECK(obj->DeleteHiddenValue(key));
3228
3229   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3230   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3231   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3232   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3233
3234   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3235
3236   // Make sure we do not find the hidden property.
3237   CHECK(!obj->Has(empty));
3238   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239   CHECK(obj->Get(empty)->IsUndefined());
3240   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3241   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3242   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3243   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3244
3245   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3246
3247   // Add another property and delete it afterwards to force the object in
3248   // slow case.
3249   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3250   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3251   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3252   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3253   CHECK(obj->Delete(prop_name));
3254   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3255
3256   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3257
3258   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3259   CHECK(obj->GetHiddenValue(key).IsEmpty());
3260
3261   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3262   CHECK(obj->DeleteHiddenValue(key));
3263   CHECK(obj->GetHiddenValue(key).IsEmpty());
3264 }
3265
3266
3267 THREADED_TEST(Regress97784) {
3268   // Regression test for crbug.com/97784
3269   // Messing with the Object.prototype should not have effect on
3270   // hidden properties.
3271   LocalContext env;
3272   v8::HandleScope scope(env->GetIsolate());
3273
3274   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3275   v8::Local<v8::String> key = v8_str("hidden");
3276
3277   CompileRun(
3278       "set_called = false;"
3279       "Object.defineProperty("
3280       "    Object.prototype,"
3281       "    'hidden',"
3282       "    {get: function() { return 45; },"
3283       "     set: function() { set_called = true; }})");
3284
3285   CHECK(obj->GetHiddenValue(key).IsEmpty());
3286   // Make sure that the getter and setter from Object.prototype is not invoked.
3287   // If it did we would have full access to the hidden properties in
3288   // the accessor.
3289   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3290   ExpectFalse("set_called");
3291   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3292 }
3293
3294
3295 static bool interceptor_for_hidden_properties_called;
3296 static void InterceptorForHiddenProperties(
3297     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3298   interceptor_for_hidden_properties_called = true;
3299 }
3300
3301
3302 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3303   LocalContext context;
3304   v8::Isolate* isolate = context->GetIsolate();
3305   v8::HandleScope scope(isolate);
3306
3307   interceptor_for_hidden_properties_called = false;
3308
3309   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3310
3311   // Associate an interceptor with an object and start setting hidden values.
3312   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3313   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3314   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3315   Local<v8::Function> function = fun_templ->GetFunction();
3316   Local<v8::Object> obj = function->NewInstance();
3317   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3318   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3319   CHECK(!interceptor_for_hidden_properties_called);
3320 }
3321
3322
3323 THREADED_TEST(External) {
3324   v8::HandleScope scope(CcTest::isolate());
3325   int x = 3;
3326   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3327   LocalContext env;
3328   env->Global()->Set(v8_str("ext"), ext);
3329   Local<Value> reext_obj = CompileRun("this.ext");
3330   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3331   int* ptr = static_cast<int*>(reext->Value());
3332   CHECK_EQ(x, 3);
3333   *ptr = 10;
3334   CHECK_EQ(x, 10);
3335
3336   // Make sure unaligned pointers are wrapped properly.
3337   char* data = i::StrDup("0123456789");
3338   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3339   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3340   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3341   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3342
3343   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3344   CHECK_EQ('0', *char_ptr);
3345   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3346   CHECK_EQ('1', *char_ptr);
3347   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3348   CHECK_EQ('2', *char_ptr);
3349   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3350   CHECK_EQ('3', *char_ptr);
3351   i::DeleteArray(data);
3352 }
3353
3354
3355 THREADED_TEST(GlobalHandle) {
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   {
3363     v8::HandleScope scope(isolate);
3364     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3365   }
3366   global.Reset();
3367   {
3368     v8::HandleScope scope(isolate);
3369     global.Reset(isolate, v8_str("str"));
3370   }
3371   {
3372     v8::HandleScope scope(isolate);
3373     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3374   }
3375   global.Reset();
3376 }
3377
3378
3379 THREADED_TEST(ResettingGlobalHandle) {
3380   v8::Isolate* isolate = CcTest::isolate();
3381   v8::Persistent<String> global;
3382   {
3383     v8::HandleScope scope(isolate);
3384     global.Reset(isolate, v8_str("str"));
3385   }
3386   v8::internal::GlobalHandles* global_handles =
3387       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3388   int initial_handle_count = global_handles->global_handles_count();
3389   {
3390     v8::HandleScope scope(isolate);
3391     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3392   }
3393   {
3394     v8::HandleScope scope(isolate);
3395     global.Reset(isolate, v8_str("longer"));
3396   }
3397   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3398   {
3399     v8::HandleScope scope(isolate);
3400     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3401   }
3402   global.Reset();
3403   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3404 }
3405
3406
3407 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3408   v8::Isolate* isolate = CcTest::isolate();
3409   v8::Persistent<String> global;
3410   {
3411     v8::HandleScope scope(isolate);
3412     global.Reset(isolate, v8_str("str"));
3413   }
3414   v8::internal::GlobalHandles* global_handles =
3415       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3416   int initial_handle_count = global_handles->global_handles_count();
3417   {
3418     v8::HandleScope scope(isolate);
3419     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3420   }
3421   {
3422     v8::HandleScope scope(isolate);
3423     Local<String> empty;
3424     global.Reset(isolate, empty);
3425   }
3426   CHECK(global.IsEmpty());
3427   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3428 }
3429
3430
3431 template<class T>
3432 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3433   return unique.Pass();
3434 }
3435
3436
3437 template<class T>
3438 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3439                                             const v8::Persistent<T> & global) {
3440   v8::UniquePersistent<String> unique(isolate, global);
3441   return unique.Pass();
3442 }
3443
3444
3445 THREADED_TEST(UniquePersistent) {
3446   v8::Isolate* isolate = CcTest::isolate();
3447   v8::Persistent<String> global;
3448   {
3449     v8::HandleScope scope(isolate);
3450     global.Reset(isolate, v8_str("str"));
3451   }
3452   v8::internal::GlobalHandles* global_handles =
3453       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3454   int initial_handle_count = global_handles->global_handles_count();
3455   {
3456     v8::UniquePersistent<String> unique(isolate, global);
3457     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3458     // Test assignment via Pass
3459     {
3460       v8::UniquePersistent<String> copy = unique.Pass();
3461       CHECK(unique.IsEmpty());
3462       CHECK(copy == global);
3463       CHECK_EQ(initial_handle_count + 1,
3464                global_handles->global_handles_count());
3465       unique = copy.Pass();
3466     }
3467     // Test ctor via Pass
3468     {
3469       v8::UniquePersistent<String> copy(unique.Pass());
3470       CHECK(unique.IsEmpty());
3471       CHECK(copy == global);
3472       CHECK_EQ(initial_handle_count + 1,
3473                global_handles->global_handles_count());
3474       unique = copy.Pass();
3475     }
3476     // Test pass through function call
3477     {
3478       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3479       CHECK(unique.IsEmpty());
3480       CHECK(copy == global);
3481       CHECK_EQ(initial_handle_count + 1,
3482                global_handles->global_handles_count());
3483       unique = copy.Pass();
3484     }
3485     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3486   }
3487   // Test pass from function call
3488   {
3489     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3490     CHECK(unique == global);
3491     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3492   }
3493   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3494   global.Reset();
3495 }
3496
3497
3498 template<typename K, typename V>
3499 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3500  public:
3501   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3502       MapType;
3503   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3504   struct WeakCallbackDataType {
3505     MapType* map;
3506     K key;
3507   };
3508   static WeakCallbackDataType* WeakCallbackParameter(
3509       MapType* map, const K& key, Local<V> value) {
3510     WeakCallbackDataType* data = new WeakCallbackDataType;
3511     data->map = map;
3512     data->key = key;
3513     return data;
3514   }
3515   static MapType* MapFromWeakCallbackData(
3516       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3517     return data.GetParameter()->map;
3518   }
3519   static K KeyFromWeakCallbackData(
3520       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3521     return data.GetParameter()->key;
3522   }
3523   static void DisposeCallbackData(WeakCallbackDataType* data) {
3524     delete data;
3525   }
3526   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3527       K key) { }
3528 };
3529
3530
3531 template<typename Map>
3532 static void TestPersistentValueMap() {
3533   LocalContext env;
3534   v8::Isolate* isolate = env->GetIsolate();
3535   Map map(isolate);
3536   v8::internal::GlobalHandles* global_handles =
3537       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3538   int initial_handle_count = global_handles->global_handles_count();
3539   CHECK_EQ(0, static_cast<int>(map.Size()));
3540   {
3541     HandleScope scope(isolate);
3542     Local<v8::Object> obj = map.Get(7);
3543     CHECK(obj.IsEmpty());
3544     Local<v8::Object> expected = v8::Object::New(isolate);
3545     map.Set(7, expected);
3546     CHECK_EQ(1, static_cast<int>(map.Size()));
3547     obj = map.Get(7);
3548     CHECK_EQ(expected, obj);
3549     {
3550       typename Map::PersistentValueReference ref = map.GetReference(7);
3551       CHECK_EQ(expected, ref.NewLocal(isolate));
3552     }
3553     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3554     CHECK_EQ(0, static_cast<int>(map.Size()));
3555     CHECK(expected == removed);
3556     removed = map.Remove(7);
3557     CHECK(removed.IsEmpty());
3558     map.Set(8, expected);
3559     CHECK_EQ(1, static_cast<int>(map.Size()));
3560     map.Set(8, expected);
3561     CHECK_EQ(1, static_cast<int>(map.Size()));
3562     {
3563       typename Map::PersistentValueReference ref;
3564       Local<v8::Object> expected2 = v8::Object::New(isolate);
3565       removed = map.Set(8,
3566           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3567       CHECK_EQ(1, static_cast<int>(map.Size()));
3568       CHECK(expected == removed);
3569       CHECK_EQ(expected2, ref.NewLocal(isolate));
3570     }
3571   }
3572   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3573   if (map.IsWeak()) {
3574     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3575         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3576   } else {
3577     map.Clear();
3578   }
3579   CHECK_EQ(0, static_cast<int>(map.Size()));
3580   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3581 }
3582
3583
3584 TEST(PersistentValueMap) {
3585   // Default case, w/o weak callbacks:
3586   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3587
3588   // Custom traits with weak callbacks:
3589   typedef v8::PersistentValueMap<int, v8::Object,
3590       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3591   TestPersistentValueMap<WeakPersistentValueMap>();
3592 }
3593
3594
3595 TEST(PersistentValueVector) {
3596   LocalContext env;
3597   v8::Isolate* isolate = env->GetIsolate();
3598   v8::internal::GlobalHandles* global_handles =
3599       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3600   int handle_count = global_handles->global_handles_count();
3601   HandleScope scope(isolate);
3602
3603   v8::PersistentValueVector<v8::Object> vector(isolate);
3604
3605   Local<v8::Object> obj1 = v8::Object::New(isolate);
3606   Local<v8::Object> obj2 = v8::Object::New(isolate);
3607   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3608
3609   CHECK(vector.IsEmpty());
3610   CHECK_EQ(0, static_cast<int>(vector.Size()));
3611
3612   vector.ReserveCapacity(3);
3613   CHECK(vector.IsEmpty());
3614
3615   vector.Append(obj1);
3616   vector.Append(obj2);
3617   vector.Append(obj1);
3618   vector.Append(obj3.Pass());
3619   vector.Append(obj1);
3620
3621   CHECK(!vector.IsEmpty());
3622   CHECK_EQ(5, static_cast<int>(vector.Size()));
3623   CHECK(obj3.IsEmpty());
3624   CHECK_EQ(obj1, vector.Get(0));
3625   CHECK_EQ(obj1, vector.Get(2));
3626   CHECK_EQ(obj1, vector.Get(4));
3627   CHECK_EQ(obj2, vector.Get(1));
3628
3629   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3630
3631   vector.Clear();
3632   CHECK(vector.IsEmpty());
3633   CHECK_EQ(0, static_cast<int>(vector.Size()));
3634   CHECK_EQ(handle_count, global_handles->global_handles_count());
3635 }
3636
3637
3638 THREADED_TEST(GlobalHandleUpcast) {
3639   v8::Isolate* isolate = CcTest::isolate();
3640   v8::HandleScope scope(isolate);
3641   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3642   v8::Persistent<String> global_string(isolate, local);
3643   v8::Persistent<Value>& global_value =
3644       v8::Persistent<Value>::Cast(global_string);
3645   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3646   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3647   global_string.Reset();
3648 }
3649
3650
3651 THREADED_TEST(HandleEquality) {
3652   v8::Isolate* isolate = CcTest::isolate();
3653   v8::Persistent<String> global1;
3654   v8::Persistent<String> global2;
3655   {
3656     v8::HandleScope scope(isolate);
3657     global1.Reset(isolate, v8_str("str"));
3658     global2.Reset(isolate, v8_str("str2"));
3659   }
3660   CHECK_EQ(global1 == global1, true);
3661   CHECK_EQ(global1 != global1, false);
3662   {
3663     v8::HandleScope scope(isolate);
3664     Local<String> local1 = Local<String>::New(isolate, global1);
3665     Local<String> local2 = Local<String>::New(isolate, global2);
3666
3667     CHECK_EQ(global1 == local1, true);
3668     CHECK_EQ(global1 != local1, false);
3669     CHECK_EQ(local1 == global1, true);
3670     CHECK_EQ(local1 != global1, false);
3671
3672     CHECK_EQ(global1 == local2, false);
3673     CHECK_EQ(global1 != local2, true);
3674     CHECK_EQ(local2 == global1, false);
3675     CHECK_EQ(local2 != global1, true);
3676
3677     CHECK_EQ(local1 == local2, false);
3678     CHECK_EQ(local1 != local2, true);
3679
3680     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3681     CHECK_EQ(local1 == anotherLocal1, true);
3682     CHECK_EQ(local1 != anotherLocal1, false);
3683   }
3684   global1.Reset();
3685   global2.Reset();
3686 }
3687
3688
3689 THREADED_TEST(LocalHandle) {
3690   v8::HandleScope scope(CcTest::isolate());
3691   v8::Local<String> local =
3692       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3693   CHECK_EQ(local->Length(), 3);
3694 }
3695
3696
3697 class WeakCallCounter {
3698  public:
3699   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3700   int id() { return id_; }
3701   void increment() { number_of_weak_calls_++; }
3702   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3703  private:
3704   int id_;
3705   int number_of_weak_calls_;
3706 };
3707
3708
3709 template<typename T>
3710 struct WeakCallCounterAndPersistent {
3711   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3712       : counter(counter) {}
3713   WeakCallCounter* counter;
3714   v8::Persistent<T> handle;
3715 };
3716
3717
3718 template <typename T>
3719 static void WeakPointerCallback(
3720     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3721   CHECK_EQ(1234, data.GetParameter()->counter->id());
3722   data.GetParameter()->counter->increment();
3723   data.GetParameter()->handle.Reset();
3724 }
3725
3726
3727 template<typename T>
3728 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3729   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3730 }
3731
3732
3733 THREADED_TEST(ApiObjectGroups) {
3734   LocalContext env;
3735   v8::Isolate* iso = env->GetIsolate();
3736   HandleScope scope(iso);
3737
3738   WeakCallCounter counter(1234);
3739
3740   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3741   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3742   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3743   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3744   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3745   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3746
3747   {
3748     HandleScope scope(iso);
3749     g1s1.handle.Reset(iso, Object::New(iso));
3750     g1s2.handle.Reset(iso, Object::New(iso));
3751     g1c1.handle.Reset(iso, Object::New(iso));
3752     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3753     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3754     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3755
3756     g2s1.handle.Reset(iso, Object::New(iso));
3757     g2s2.handle.Reset(iso, Object::New(iso));
3758     g2c1.handle.Reset(iso, Object::New(iso));
3759     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3760     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3761     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3762   }
3763
3764   WeakCallCounterAndPersistent<Value> root(&counter);
3765   root.handle.Reset(iso, g1s1.handle);  // make a root.
3766
3767   // Connect group 1 and 2, make a cycle.
3768   {
3769     HandleScope scope(iso);
3770     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3771             Set(0, Local<Value>::New(iso, g2s2.handle)));
3772     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3773             Set(0, Local<Value>::New(iso, g1s1.handle)));
3774   }
3775
3776   {
3777     UniqueId id1 = MakeUniqueId(g1s1.handle);
3778     UniqueId id2 = MakeUniqueId(g2s2.handle);
3779     iso->SetObjectGroupId(g1s1.handle, id1);
3780     iso->SetObjectGroupId(g1s2.handle, id1);
3781     iso->SetReferenceFromGroup(id1, g1c1.handle);
3782     iso->SetObjectGroupId(g2s1.handle, id2);
3783     iso->SetObjectGroupId(g2s2.handle, id2);
3784     iso->SetReferenceFromGroup(id2, g2c1.handle);
3785   }
3786   // Do a single full GC, ensure incremental marking is stopped.
3787   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3788       iso)->heap();
3789   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3790
3791   // All object should be alive.
3792   CHECK_EQ(0, counter.NumberOfWeakCalls());
3793
3794   // Weaken the root.
3795   root.handle.SetWeak(&root, &WeakPointerCallback);
3796   // But make children strong roots---all the objects (except for children)
3797   // should be collectable now.
3798   g1c1.handle.ClearWeak();
3799   g2c1.handle.ClearWeak();
3800
3801   // Groups are deleted, rebuild groups.
3802   {
3803     UniqueId id1 = MakeUniqueId(g1s1.handle);
3804     UniqueId id2 = MakeUniqueId(g2s2.handle);
3805     iso->SetObjectGroupId(g1s1.handle, id1);
3806     iso->SetObjectGroupId(g1s2.handle, id1);
3807     iso->SetReferenceFromGroup(id1, g1c1.handle);
3808     iso->SetObjectGroupId(g2s1.handle, id2);
3809     iso->SetObjectGroupId(g2s2.handle, id2);
3810     iso->SetReferenceFromGroup(id2, g2c1.handle);
3811   }
3812
3813   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3814
3815   // All objects should be gone. 5 global handles in total.
3816   CHECK_EQ(5, counter.NumberOfWeakCalls());
3817
3818   // And now make children weak again and collect them.
3819   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3820   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3821
3822   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3823   CHECK_EQ(7, counter.NumberOfWeakCalls());
3824 }
3825
3826
3827 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3828   LocalContext env;
3829   v8::Isolate* iso = env->GetIsolate();
3830   HandleScope scope(iso);
3831
3832   WeakCallCounter counter(1234);
3833
3834   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3835   WeakCallCounterAndPersistent<String> g1s2(&counter);
3836   WeakCallCounterAndPersistent<String> g1c1(&counter);
3837   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3838   WeakCallCounterAndPersistent<String> g2s2(&counter);
3839   WeakCallCounterAndPersistent<String> g2c1(&counter);
3840
3841   {
3842     HandleScope scope(iso);
3843     g1s1.handle.Reset(iso, Object::New(iso));
3844     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3845     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3846     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3847     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3848     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3849
3850     g2s1.handle.Reset(iso, Object::New(iso));
3851     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3852     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3853     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3854     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3855     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3856   }
3857
3858   WeakCallCounterAndPersistent<Value> root(&counter);
3859   root.handle.Reset(iso, g1s1.handle);  // make a root.
3860
3861   // Connect group 1 and 2, make a cycle.
3862   {
3863     HandleScope scope(iso);
3864     CHECK(Local<Object>::New(iso, g1s1.handle)
3865               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3866     CHECK(Local<Object>::New(iso, g2s1.handle)
3867               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3868   }
3869
3870   {
3871     UniqueId id1 = MakeUniqueId(g1s1.handle);
3872     UniqueId id2 = MakeUniqueId(g2s2.handle);
3873     iso->SetObjectGroupId(g1s1.handle, id1);
3874     iso->SetObjectGroupId(g1s2.handle, id1);
3875     iso->SetReference(g1s1.handle, g1c1.handle);
3876     iso->SetObjectGroupId(g2s1.handle, id2);
3877     iso->SetObjectGroupId(g2s2.handle, id2);
3878     iso->SetReferenceFromGroup(id2, g2c1.handle);
3879   }
3880   // Do a single full GC, ensure incremental marking is stopped.
3881   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3882       iso)->heap();
3883   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3884
3885   // All object should be alive.
3886   CHECK_EQ(0, counter.NumberOfWeakCalls());
3887
3888   // Weaken the root.
3889   root.handle.SetWeak(&root, &WeakPointerCallback);
3890   // But make children strong roots---all the objects (except for children)
3891   // should be collectable now.
3892   g1c1.handle.ClearWeak();
3893   g2c1.handle.ClearWeak();
3894
3895   // Groups are deleted, rebuild groups.
3896   {
3897     UniqueId id1 = MakeUniqueId(g1s1.handle);
3898     UniqueId id2 = MakeUniqueId(g2s2.handle);
3899     iso->SetObjectGroupId(g1s1.handle, id1);
3900     iso->SetObjectGroupId(g1s2.handle, id1);
3901     iso->SetReference(g1s1.handle, g1c1.handle);
3902     iso->SetObjectGroupId(g2s1.handle, id2);
3903     iso->SetObjectGroupId(g2s2.handle, id2);
3904     iso->SetReferenceFromGroup(id2, g2c1.handle);
3905   }
3906
3907   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3908
3909   // All objects should be gone. 5 global handles in total.
3910   CHECK_EQ(5, counter.NumberOfWeakCalls());
3911
3912   // And now make children weak again and collect them.
3913   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3914   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3915
3916   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3917   CHECK_EQ(7, counter.NumberOfWeakCalls());
3918 }
3919
3920
3921 THREADED_TEST(ApiObjectGroupsCycle) {
3922   LocalContext env;
3923   v8::Isolate* iso = env->GetIsolate();
3924   HandleScope scope(iso);
3925
3926   WeakCallCounter counter(1234);
3927
3928   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3929   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3930   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3931   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3932   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3933   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3934   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3935   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3936
3937   {
3938     HandleScope scope(iso);
3939     g1s1.handle.Reset(iso, Object::New(iso));
3940     g1s2.handle.Reset(iso, Object::New(iso));
3941     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3942     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3943     CHECK(g1s1.handle.IsWeak());
3944     CHECK(g1s2.handle.IsWeak());
3945
3946     g2s1.handle.Reset(iso, Object::New(iso));
3947     g2s2.handle.Reset(iso, Object::New(iso));
3948     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3949     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3950     CHECK(g2s1.handle.IsWeak());
3951     CHECK(g2s2.handle.IsWeak());
3952
3953     g3s1.handle.Reset(iso, Object::New(iso));
3954     g3s2.handle.Reset(iso, Object::New(iso));
3955     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3956     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3957     CHECK(g3s1.handle.IsWeak());
3958     CHECK(g3s2.handle.IsWeak());
3959
3960     g4s1.handle.Reset(iso, Object::New(iso));
3961     g4s2.handle.Reset(iso, Object::New(iso));
3962     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3963     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3964     CHECK(g4s1.handle.IsWeak());
3965     CHECK(g4s2.handle.IsWeak());
3966   }
3967
3968   WeakCallCounterAndPersistent<Value> root(&counter);
3969   root.handle.Reset(iso, g1s1.handle);  // make a root.
3970
3971   // Connect groups.  We're building the following cycle:
3972   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3973   // groups.
3974   {
3975     UniqueId id1 = MakeUniqueId(g1s1.handle);
3976     UniqueId id2 = MakeUniqueId(g2s1.handle);
3977     UniqueId id3 = MakeUniqueId(g3s1.handle);
3978     UniqueId id4 = MakeUniqueId(g4s1.handle);
3979     iso->SetObjectGroupId(g1s1.handle, id1);
3980     iso->SetObjectGroupId(g1s2.handle, id1);
3981     iso->SetReferenceFromGroup(id1, g2s1.handle);
3982     iso->SetObjectGroupId(g2s1.handle, id2);
3983     iso->SetObjectGroupId(g2s2.handle, id2);
3984     iso->SetReferenceFromGroup(id2, g3s1.handle);
3985     iso->SetObjectGroupId(g3s1.handle, id3);
3986     iso->SetObjectGroupId(g3s2.handle, id3);
3987     iso->SetReferenceFromGroup(id3, g4s1.handle);
3988     iso->SetObjectGroupId(g4s1.handle, id4);
3989     iso->SetObjectGroupId(g4s2.handle, id4);
3990     iso->SetReferenceFromGroup(id4, g1s1.handle);
3991   }
3992   // Do a single full GC
3993   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3994       iso)->heap();
3995   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3996
3997   // All object should be alive.
3998   CHECK_EQ(0, counter.NumberOfWeakCalls());
3999
4000   // Weaken the root.
4001   root.handle.SetWeak(&root, &WeakPointerCallback);
4002
4003   // Groups are deleted, rebuild groups.
4004   {
4005     UniqueId id1 = MakeUniqueId(g1s1.handle);
4006     UniqueId id2 = MakeUniqueId(g2s1.handle);
4007     UniqueId id3 = MakeUniqueId(g3s1.handle);
4008     UniqueId id4 = MakeUniqueId(g4s1.handle);
4009     iso->SetObjectGroupId(g1s1.handle, id1);
4010     iso->SetObjectGroupId(g1s2.handle, id1);
4011     iso->SetReferenceFromGroup(id1, g2s1.handle);
4012     iso->SetObjectGroupId(g2s1.handle, id2);
4013     iso->SetObjectGroupId(g2s2.handle, id2);
4014     iso->SetReferenceFromGroup(id2, g3s1.handle);
4015     iso->SetObjectGroupId(g3s1.handle, id3);
4016     iso->SetObjectGroupId(g3s2.handle, id3);
4017     iso->SetReferenceFromGroup(id3, g4s1.handle);
4018     iso->SetObjectGroupId(g4s1.handle, id4);
4019     iso->SetObjectGroupId(g4s2.handle, id4);
4020     iso->SetReferenceFromGroup(id4, g1s1.handle);
4021   }
4022
4023   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4024
4025   // All objects should be gone. 9 global handles in total.
4026   CHECK_EQ(9, counter.NumberOfWeakCalls());
4027 }
4028
4029
4030 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4031 // on the buildbots, so was made non-threaded for the time being.
4032 TEST(ApiObjectGroupsCycleForScavenger) {
4033   i::FLAG_stress_compaction = false;
4034   i::FLAG_gc_global = false;
4035   LocalContext env;
4036   v8::Isolate* iso = env->GetIsolate();
4037   HandleScope scope(iso);
4038
4039   WeakCallCounter counter(1234);
4040
4041   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4042   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4043   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4044   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4045   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4046   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4047
4048   {
4049     HandleScope scope(iso);
4050     g1s1.handle.Reset(iso, Object::New(iso));
4051     g1s2.handle.Reset(iso, Object::New(iso));
4052     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4053     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4054
4055     g2s1.handle.Reset(iso, Object::New(iso));
4056     g2s2.handle.Reset(iso, Object::New(iso));
4057     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4058     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4059
4060     g3s1.handle.Reset(iso, Object::New(iso));
4061     g3s2.handle.Reset(iso, Object::New(iso));
4062     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4063     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4064   }
4065
4066   // Make a root.
4067   WeakCallCounterAndPersistent<Value> root(&counter);
4068   root.handle.Reset(iso, g1s1.handle);
4069   root.handle.MarkPartiallyDependent();
4070
4071   // Connect groups.  We're building the following cycle:
4072   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4073   // groups.
4074   {
4075     HandleScope handle_scope(iso);
4076     g1s1.handle.MarkPartiallyDependent();
4077     g1s2.handle.MarkPartiallyDependent();
4078     g2s1.handle.MarkPartiallyDependent();
4079     g2s2.handle.MarkPartiallyDependent();
4080     g3s1.handle.MarkPartiallyDependent();
4081     g3s2.handle.MarkPartiallyDependent();
4082     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4083     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4084     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4085         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4086     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4087     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4088     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4089         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4090     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4091     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4092     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4093         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4094   }
4095
4096   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4097       iso)->heap();
4098   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4099
4100   // All objects should be alive.
4101   CHECK_EQ(0, counter.NumberOfWeakCalls());
4102
4103   // Weaken the root.
4104   root.handle.SetWeak(&root, &WeakPointerCallback);
4105   root.handle.MarkPartiallyDependent();
4106
4107   // Groups are deleted, rebuild groups.
4108   {
4109     HandleScope handle_scope(iso);
4110     g1s1.handle.MarkPartiallyDependent();
4111     g1s2.handle.MarkPartiallyDependent();
4112     g2s1.handle.MarkPartiallyDependent();
4113     g2s2.handle.MarkPartiallyDependent();
4114     g3s1.handle.MarkPartiallyDependent();
4115     g3s2.handle.MarkPartiallyDependent();
4116     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4117     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4118     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4119         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4120     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4121     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4122     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4123         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4124     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4125     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4126     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4127         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4128   }
4129
4130   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4131
4132   // All objects should be gone. 7 global handles in total.
4133   CHECK_EQ(7, counter.NumberOfWeakCalls());
4134 }
4135
4136
4137 THREADED_TEST(ScriptException) {
4138   LocalContext env;
4139   v8::HandleScope scope(env->GetIsolate());
4140   Local<Script> script = v8_compile("throw 'panama!';");
4141   v8::TryCatch try_catch;
4142   Local<Value> result = script->Run();
4143   CHECK(result.IsEmpty());
4144   CHECK(try_catch.HasCaught());
4145   String::Utf8Value exception_value(try_catch.Exception());
4146   CHECK_EQ(*exception_value, "panama!");
4147 }
4148
4149
4150 TEST(TryCatchCustomException) {
4151   LocalContext env;
4152   v8::HandleScope scope(env->GetIsolate());
4153   v8::TryCatch try_catch;
4154   CompileRun("function CustomError() { this.a = 'b'; }"
4155              "(function f() { throw new CustomError(); })();");
4156   CHECK(try_catch.HasCaught());
4157   CHECK(try_catch.Exception()->ToObject()->
4158             Get(v8_str("a"))->Equals(v8_str("b")));
4159 }
4160
4161
4162 bool message_received;
4163
4164
4165 static void check_message_0(v8::Handle<v8::Message> message,
4166                             v8::Handle<Value> data) {
4167   CHECK_EQ(5.76, data->NumberValue());
4168   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4169   CHECK(!message->IsSharedCrossOrigin());
4170   message_received = true;
4171 }
4172
4173
4174 THREADED_TEST(MessageHandler0) {
4175   message_received = false;
4176   v8::HandleScope scope(CcTest::isolate());
4177   CHECK(!message_received);
4178   LocalContext context;
4179   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4180   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4181   script->Run();
4182   CHECK(message_received);
4183   // clear out the message listener
4184   v8::V8::RemoveMessageListeners(check_message_0);
4185 }
4186
4187
4188 static void check_message_1(v8::Handle<v8::Message> message,
4189                             v8::Handle<Value> data) {
4190   CHECK(data->IsNumber());
4191   CHECK_EQ(1337, data->Int32Value());
4192   CHECK(!message->IsSharedCrossOrigin());
4193   message_received = true;
4194 }
4195
4196
4197 TEST(MessageHandler1) {
4198   message_received = false;
4199   v8::HandleScope scope(CcTest::isolate());
4200   CHECK(!message_received);
4201   v8::V8::AddMessageListener(check_message_1);
4202   LocalContext context;
4203   CompileRun("throw 1337;");
4204   CHECK(message_received);
4205   // clear out the message listener
4206   v8::V8::RemoveMessageListeners(check_message_1);
4207 }
4208
4209
4210 static void check_message_2(v8::Handle<v8::Message> message,
4211                             v8::Handle<Value> data) {
4212   LocalContext context;
4213   CHECK(data->IsObject());
4214   v8::Local<v8::Value> hidden_property =
4215       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4216   CHECK(v8_str("hidden value")->Equals(hidden_property));
4217   CHECK(!message->IsSharedCrossOrigin());
4218   message_received = true;
4219 }
4220
4221
4222 TEST(MessageHandler2) {
4223   message_received = false;
4224   v8::HandleScope scope(CcTest::isolate());
4225   CHECK(!message_received);
4226   v8::V8::AddMessageListener(check_message_2);
4227   LocalContext context;
4228   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4229   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4230                                            v8_str("hidden value"));
4231   context->Global()->Set(v8_str("error"), error);
4232   CompileRun("throw error;");
4233   CHECK(message_received);
4234   // clear out the message listener
4235   v8::V8::RemoveMessageListeners(check_message_2);
4236 }
4237
4238
4239 static void check_message_3(v8::Handle<v8::Message> message,
4240                             v8::Handle<Value> data) {
4241   CHECK(message->IsSharedCrossOrigin());
4242   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4243   message_received = true;
4244 }
4245
4246
4247 TEST(MessageHandler3) {
4248   message_received = false;
4249   v8::Isolate* isolate = CcTest::isolate();
4250   v8::HandleScope scope(isolate);
4251   CHECK(!message_received);
4252   v8::V8::AddMessageListener(check_message_3);
4253   LocalContext context;
4254   v8::ScriptOrigin origin =
4255       v8::ScriptOrigin(v8_str("6.75"),
4256                        v8::Integer::New(isolate, 1),
4257                        v8::Integer::New(isolate, 2),
4258                        v8::True(isolate));
4259   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4260                                                   &origin);
4261   script->Run();
4262   CHECK(message_received);
4263   // clear out the message listener
4264   v8::V8::RemoveMessageListeners(check_message_3);
4265 }
4266
4267
4268 static void check_message_4(v8::Handle<v8::Message> message,
4269                             v8::Handle<Value> data) {
4270   CHECK(!message->IsSharedCrossOrigin());
4271   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4272   message_received = true;
4273 }
4274
4275
4276 TEST(MessageHandler4) {
4277   message_received = false;
4278   v8::Isolate* isolate = CcTest::isolate();
4279   v8::HandleScope scope(isolate);
4280   CHECK(!message_received);
4281   v8::V8::AddMessageListener(check_message_4);
4282   LocalContext context;
4283   v8::ScriptOrigin origin =
4284       v8::ScriptOrigin(v8_str("6.75"),
4285                        v8::Integer::New(isolate, 1),
4286                        v8::Integer::New(isolate, 2),
4287                        v8::False(isolate));
4288   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4289                                                   &origin);
4290   script->Run();
4291   CHECK(message_received);
4292   // clear out the message listener
4293   v8::V8::RemoveMessageListeners(check_message_4);
4294 }
4295
4296
4297 static void check_message_5a(v8::Handle<v8::Message> message,
4298                             v8::Handle<Value> data) {
4299   CHECK(message->IsSharedCrossOrigin());
4300   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4301   message_received = true;
4302 }
4303
4304
4305 static void check_message_5b(v8::Handle<v8::Message> message,
4306                             v8::Handle<Value> data) {
4307   CHECK(!message->IsSharedCrossOrigin());
4308   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4309   message_received = true;
4310 }
4311
4312
4313 TEST(MessageHandler5) {
4314   message_received = false;
4315   v8::Isolate* isolate = CcTest::isolate();
4316   v8::HandleScope scope(isolate);
4317   CHECK(!message_received);
4318   v8::V8::AddMessageListener(check_message_5a);
4319   LocalContext context;
4320   v8::ScriptOrigin origin =
4321       v8::ScriptOrigin(v8_str("6.75"),
4322                        v8::Integer::New(isolate, 1),
4323                        v8::Integer::New(isolate, 2),
4324                        v8::True(isolate));
4325   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4326                                                   &origin);
4327   script->Run();
4328   CHECK(message_received);
4329   // clear out the message listener
4330   v8::V8::RemoveMessageListeners(check_message_5a);
4331
4332   message_received = false;
4333   v8::V8::AddMessageListener(check_message_5b);
4334   origin =
4335       v8::ScriptOrigin(v8_str("6.75"),
4336                        v8::Integer::New(isolate, 1),
4337                        v8::Integer::New(isolate, 2),
4338                        v8::False(isolate));
4339   script = Script::Compile(v8_str("throw 'error'"),
4340                            &origin);
4341   script->Run();
4342   CHECK(message_received);
4343   // clear out the message listener
4344   v8::V8::RemoveMessageListeners(check_message_5b);
4345 }
4346
4347
4348 THREADED_TEST(GetSetProperty) {
4349   LocalContext context;
4350   v8::Isolate* isolate = context->GetIsolate();
4351   v8::HandleScope scope(isolate);
4352   context->Global()->Set(v8_str("foo"), v8_num(14));
4353   context->Global()->Set(v8_str("12"), v8_num(92));
4354   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4355   context->Global()->Set(v8_num(13), v8_num(56));
4356   Local<Value> foo = CompileRun("this.foo");
4357   CHECK_EQ(14, foo->Int32Value());
4358   Local<Value> twelve = CompileRun("this[12]");
4359   CHECK_EQ(92, twelve->Int32Value());
4360   Local<Value> sixteen = CompileRun("this[16]");
4361   CHECK_EQ(32, sixteen->Int32Value());
4362   Local<Value> thirteen = CompileRun("this[13]");
4363   CHECK_EQ(56, thirteen->Int32Value());
4364   CHECK_EQ(92,
4365            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4366   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4367   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4368   CHECK_EQ(32,
4369            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4370   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4371   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4372   CHECK_EQ(56,
4373            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4374   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4375   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4376 }
4377
4378
4379 THREADED_TEST(PropertyAttributes) {
4380   LocalContext context;
4381   v8::HandleScope scope(context->GetIsolate());
4382   // none
4383   Local<String> prop = v8_str("none");
4384   context->Global()->Set(prop, v8_num(7));
4385   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4386   // read-only
4387   prop = v8_str("read_only");
4388   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4389   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4390   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4391   CompileRun("read_only = 9");
4392   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4393   context->Global()->Set(prop, v8_num(10));
4394   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4395   // dont-delete
4396   prop = v8_str("dont_delete");
4397   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4398   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4399   CompileRun("delete dont_delete");
4400   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4401   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4402   // dont-enum
4403   prop = v8_str("dont_enum");
4404   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4405   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4406   // absent
4407   prop = v8_str("absent");
4408   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4409   Local<Value> fake_prop = v8_num(1);
4410   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4411   // exception
4412   TryCatch try_catch;
4413   Local<Value> exception =
4414       CompileRun("({ toString: function() { throw 'exception';} })");
4415   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4416   CHECK(try_catch.HasCaught());
4417   String::Utf8Value exception_value(try_catch.Exception());
4418   CHECK_EQ("exception", *exception_value);
4419   try_catch.Reset();
4420 }
4421
4422
4423 THREADED_TEST(Array) {
4424   LocalContext context;
4425   v8::HandleScope scope(context->GetIsolate());
4426   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4427   CHECK_EQ(0, array->Length());
4428   CHECK(array->Get(0)->IsUndefined());
4429   CHECK(!array->Has(0));
4430   CHECK(array->Get(100)->IsUndefined());
4431   CHECK(!array->Has(100));
4432   array->Set(2, v8_num(7));
4433   CHECK_EQ(3, array->Length());
4434   CHECK(!array->Has(0));
4435   CHECK(!array->Has(1));
4436   CHECK(array->Has(2));
4437   CHECK_EQ(7, array->Get(2)->Int32Value());
4438   Local<Value> obj = CompileRun("[1, 2, 3]");
4439   Local<v8::Array> arr = obj.As<v8::Array>();
4440   CHECK_EQ(3, arr->Length());
4441   CHECK_EQ(1, arr->Get(0)->Int32Value());
4442   CHECK_EQ(2, arr->Get(1)->Int32Value());
4443   CHECK_EQ(3, arr->Get(2)->Int32Value());
4444   array = v8::Array::New(context->GetIsolate(), 27);
4445   CHECK_EQ(27, array->Length());
4446   array = v8::Array::New(context->GetIsolate(), -27);
4447   CHECK_EQ(0, array->Length());
4448 }
4449
4450
4451 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4452   v8::EscapableHandleScope scope(args.GetIsolate());
4453   ApiTestFuzzer::Fuzz();
4454   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4455   for (int i = 0; i < args.Length(); i++)
4456     result->Set(i, args[i]);
4457   args.GetReturnValue().Set(scope.Escape(result));
4458 }
4459
4460
4461 THREADED_TEST(Vector) {
4462   v8::Isolate* isolate = CcTest::isolate();
4463   v8::HandleScope scope(isolate);
4464   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4465   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4466   LocalContext context(0, global);
4467
4468   const char* fun = "f()";
4469   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4470   CHECK_EQ(0, a0->Length());
4471
4472   const char* fun2 = "f(11)";
4473   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4474   CHECK_EQ(1, a1->Length());
4475   CHECK_EQ(11, a1->Get(0)->Int32Value());
4476
4477   const char* fun3 = "f(12, 13)";
4478   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4479   CHECK_EQ(2, a2->Length());
4480   CHECK_EQ(12, a2->Get(0)->Int32Value());
4481   CHECK_EQ(13, a2->Get(1)->Int32Value());
4482
4483   const char* fun4 = "f(14, 15, 16)";
4484   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4485   CHECK_EQ(3, a3->Length());
4486   CHECK_EQ(14, a3->Get(0)->Int32Value());
4487   CHECK_EQ(15, a3->Get(1)->Int32Value());
4488   CHECK_EQ(16, a3->Get(2)->Int32Value());
4489
4490   const char* fun5 = "f(17, 18, 19, 20)";
4491   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4492   CHECK_EQ(4, a4->Length());
4493   CHECK_EQ(17, a4->Get(0)->Int32Value());
4494   CHECK_EQ(18, a4->Get(1)->Int32Value());
4495   CHECK_EQ(19, a4->Get(2)->Int32Value());
4496   CHECK_EQ(20, a4->Get(3)->Int32Value());
4497 }
4498
4499
4500 THREADED_TEST(FunctionCall) {
4501   LocalContext context;
4502   v8::Isolate* isolate = context->GetIsolate();
4503   v8::HandleScope scope(isolate);
4504   CompileRun(
4505     "function Foo() {"
4506     "  var result = [];"
4507     "  for (var i = 0; i < arguments.length; i++) {"
4508     "    result.push(arguments[i]);"
4509     "  }"
4510     "  return result;"
4511     "}"
4512     "function ReturnThisSloppy() {"
4513     "  return this;"
4514     "}"
4515     "function ReturnThisStrict() {"
4516     "  'use strict';"
4517     "  return this;"
4518     "}");
4519   Local<Function> Foo =
4520       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4521   Local<Function> ReturnThisSloppy =
4522       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4523   Local<Function> ReturnThisStrict =
4524       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4525
4526   v8::Handle<Value>* args0 = NULL;
4527   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4528   CHECK_EQ(0, a0->Length());
4529
4530   v8::Handle<Value> args1[] = { v8_num(1.1) };
4531   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4532   CHECK_EQ(1, a1->Length());
4533   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4534
4535   v8::Handle<Value> args2[] = { v8_num(2.2),
4536                                 v8_num(3.3) };
4537   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4538   CHECK_EQ(2, a2->Length());
4539   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4540   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4541
4542   v8::Handle<Value> args3[] = { v8_num(4.4),
4543                                 v8_num(5.5),
4544                                 v8_num(6.6) };
4545   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4546   CHECK_EQ(3, a3->Length());
4547   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4548   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4549   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4550
4551   v8::Handle<Value> args4[] = { v8_num(7.7),
4552                                 v8_num(8.8),
4553                                 v8_num(9.9),
4554                                 v8_num(10.11) };
4555   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4556   CHECK_EQ(4, a4->Length());
4557   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4558   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4559   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4560   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4561
4562   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4563   CHECK(r1->StrictEquals(context->Global()));
4564   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4565   CHECK(r2->StrictEquals(context->Global()));
4566   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4567   CHECK(r3->IsNumberObject());
4568   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4569   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4570   CHECK(r4->IsStringObject());
4571   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4572   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4573   CHECK(r5->IsBooleanObject());
4574   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4575
4576   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4577   CHECK(r6->IsUndefined());
4578   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4579   CHECK(r7->IsNull());
4580   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4581   CHECK(r8->StrictEquals(v8_num(42)));
4582   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4583   CHECK(r9->StrictEquals(v8_str("hello")));
4584   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4585   CHECK(r10->StrictEquals(v8::True(isolate)));
4586 }
4587
4588
4589 THREADED_TEST(ConstructCall) {
4590   LocalContext context;
4591   v8::Isolate* isolate = context->GetIsolate();
4592   v8::HandleScope scope(isolate);
4593   CompileRun(
4594     "function Foo() {"
4595     "  var result = [];"
4596     "  for (var i = 0; i < arguments.length; i++) {"
4597     "    result.push(arguments[i]);"
4598     "  }"
4599     "  return result;"
4600     "}");
4601   Local<Function> Foo =
4602       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4603
4604   v8::Handle<Value>* args0 = NULL;
4605   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4606   CHECK_EQ(0, a0->Length());
4607
4608   v8::Handle<Value> args1[] = { v8_num(1.1) };
4609   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4610   CHECK_EQ(1, a1->Length());
4611   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4612
4613   v8::Handle<Value> args2[] = { v8_num(2.2),
4614                                 v8_num(3.3) };
4615   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4616   CHECK_EQ(2, a2->Length());
4617   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4618   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4619
4620   v8::Handle<Value> args3[] = { v8_num(4.4),
4621                                 v8_num(5.5),
4622                                 v8_num(6.6) };
4623   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4624   CHECK_EQ(3, a3->Length());
4625   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4626   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4627   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4628
4629   v8::Handle<Value> args4[] = { v8_num(7.7),
4630                                 v8_num(8.8),
4631                                 v8_num(9.9),
4632                                 v8_num(10.11) };
4633   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4634   CHECK_EQ(4, a4->Length());
4635   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4636   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4637   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4638   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4639 }
4640
4641
4642 static void CheckUncle(v8::TryCatch* try_catch) {
4643   CHECK(try_catch->HasCaught());
4644   String::Utf8Value str_value(try_catch->Exception());
4645   CHECK_EQ(*str_value, "uncle?");
4646   try_catch->Reset();
4647 }
4648
4649
4650 THREADED_TEST(ConversionNumber) {
4651   LocalContext env;
4652   v8::HandleScope scope(env->GetIsolate());
4653   // Very large number.
4654   CompileRun("var obj = Math.pow(2,32) * 1237;");
4655   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4656   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4657   CHECK_EQ(0, obj->ToInt32()->Value());
4658   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4659   // Large number.
4660   CompileRun("var obj = -1234567890123;");
4661   obj = env->Global()->Get(v8_str("obj"));
4662   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4663   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4664   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4665   // Small positive integer.
4666   CompileRun("var obj = 42;");
4667   obj = env->Global()->Get(v8_str("obj"));
4668   CHECK_EQ(42.0, obj->ToNumber()->Value());
4669   CHECK_EQ(42, obj->ToInt32()->Value());
4670   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4671   // Negative integer.
4672   CompileRun("var obj = -37;");
4673   obj = env->Global()->Get(v8_str("obj"));
4674   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4675   CHECK_EQ(-37, obj->ToInt32()->Value());
4676   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4677   // Positive non-int32 integer.
4678   CompileRun("var obj = 0x81234567;");
4679   obj = env->Global()->Get(v8_str("obj"));
4680   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4681   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4682   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4683   // Fraction.
4684   CompileRun("var obj = 42.3;");
4685   obj = env->Global()->Get(v8_str("obj"));
4686   CHECK_EQ(42.3, obj->ToNumber()->Value());
4687   CHECK_EQ(42, obj->ToInt32()->Value());
4688   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4689   // Large negative fraction.
4690   CompileRun("var obj = -5726623061.75;");
4691   obj = env->Global()->Get(v8_str("obj"));
4692   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4693   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4694   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4695 }
4696
4697
4698 THREADED_TEST(isNumberType) {
4699   LocalContext env;
4700   v8::HandleScope scope(env->GetIsolate());
4701   // Very large number.
4702   CompileRun("var obj = Math.pow(2,32) * 1237;");
4703   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4704   CHECK(!obj->IsInt32());
4705   CHECK(!obj->IsUint32());
4706   // Large negative number.
4707   CompileRun("var obj = -1234567890123;");
4708   obj = env->Global()->Get(v8_str("obj"));
4709   CHECK(!obj->IsInt32());
4710   CHECK(!obj->IsUint32());
4711   // Small positive integer.
4712   CompileRun("var obj = 42;");
4713   obj = env->Global()->Get(v8_str("obj"));
4714   CHECK(obj->IsInt32());
4715   CHECK(obj->IsUint32());
4716   // Negative integer.
4717   CompileRun("var obj = -37;");
4718   obj = env->Global()->Get(v8_str("obj"));
4719   CHECK(obj->IsInt32());
4720   CHECK(!obj->IsUint32());
4721   // Positive non-int32 integer.
4722   CompileRun("var obj = 0x81234567;");
4723   obj = env->Global()->Get(v8_str("obj"));
4724   CHECK(!obj->IsInt32());
4725   CHECK(obj->IsUint32());
4726   // Fraction.
4727   CompileRun("var obj = 42.3;");
4728   obj = env->Global()->Get(v8_str("obj"));
4729   CHECK(!obj->IsInt32());
4730   CHECK(!obj->IsUint32());
4731   // Large negative fraction.
4732   CompileRun("var obj = -5726623061.75;");
4733   obj = env->Global()->Get(v8_str("obj"));
4734   CHECK(!obj->IsInt32());
4735   CHECK(!obj->IsUint32());
4736   // Positive zero
4737   CompileRun("var obj = 0.0;");
4738   obj = env->Global()->Get(v8_str("obj"));
4739   CHECK(obj->IsInt32());
4740   CHECK(obj->IsUint32());
4741   // Positive zero
4742   CompileRun("var obj = -0.0;");
4743   obj = env->Global()->Get(v8_str("obj"));
4744   CHECK(!obj->IsInt32());
4745   CHECK(!obj->IsUint32());
4746 }
4747
4748
4749 THREADED_TEST(ConversionException) {
4750   LocalContext env;
4751   v8::Isolate* isolate = env->GetIsolate();
4752   v8::HandleScope scope(isolate);
4753   CompileRun(
4754     "function TestClass() { };"
4755     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4756     "var obj = new TestClass();");
4757   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4758
4759   v8::TryCatch try_catch;
4760
4761   Local<Value> to_string_result = obj->ToString();
4762   CHECK(to_string_result.IsEmpty());
4763   CheckUncle(&try_catch);
4764
4765   Local<Value> to_number_result = obj->ToNumber();
4766   CHECK(to_number_result.IsEmpty());
4767   CheckUncle(&try_catch);
4768
4769   Local<Value> to_integer_result = obj->ToInteger();
4770   CHECK(to_integer_result.IsEmpty());
4771   CheckUncle(&try_catch);
4772
4773   Local<Value> to_uint32_result = obj->ToUint32();
4774   CHECK(to_uint32_result.IsEmpty());
4775   CheckUncle(&try_catch);
4776
4777   Local<Value> to_int32_result = obj->ToInt32();
4778   CHECK(to_int32_result.IsEmpty());
4779   CheckUncle(&try_catch);
4780
4781   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4782   CHECK(to_object_result.IsEmpty());
4783   CHECK(try_catch.HasCaught());
4784   try_catch.Reset();
4785
4786   int32_t int32_value = obj->Int32Value();
4787   CHECK_EQ(0, int32_value);
4788   CheckUncle(&try_catch);
4789
4790   uint32_t uint32_value = obj->Uint32Value();
4791   CHECK_EQ(0, uint32_value);
4792   CheckUncle(&try_catch);
4793
4794   double number_value = obj->NumberValue();
4795   CHECK_NE(0, std::isnan(number_value));
4796   CheckUncle(&try_catch);
4797
4798   int64_t integer_value = obj->IntegerValue();
4799   CHECK_EQ(0.0, static_cast<double>(integer_value));
4800   CheckUncle(&try_catch);
4801 }
4802
4803
4804 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4805   ApiTestFuzzer::Fuzz();
4806   args.GetIsolate()->ThrowException(v8_str("konto"));
4807 }
4808
4809
4810 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4811   if (args.Length() < 1) {
4812     args.GetReturnValue().Set(false);
4813     return;
4814   }
4815   v8::HandleScope scope(args.GetIsolate());
4816   v8::TryCatch try_catch;
4817   Local<Value> result = CompileRun(args[0]->ToString());
4818   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4819   args.GetReturnValue().Set(try_catch.HasCaught());
4820 }
4821
4822
4823 THREADED_TEST(APICatch) {
4824   v8::Isolate* isolate = CcTest::isolate();
4825   v8::HandleScope scope(isolate);
4826   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4827   templ->Set(v8_str("ThrowFromC"),
4828              v8::FunctionTemplate::New(isolate, ThrowFromC));
4829   LocalContext context(0, templ);
4830   CompileRun(
4831     "var thrown = false;"
4832     "try {"
4833     "  ThrowFromC();"
4834     "} catch (e) {"
4835     "  thrown = true;"
4836     "}");
4837   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4838   CHECK(thrown->BooleanValue());
4839 }
4840
4841
4842 THREADED_TEST(APIThrowTryCatch) {
4843   v8::Isolate* isolate = CcTest::isolate();
4844   v8::HandleScope scope(isolate);
4845   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4846   templ->Set(v8_str("ThrowFromC"),
4847              v8::FunctionTemplate::New(isolate, ThrowFromC));
4848   LocalContext context(0, templ);
4849   v8::TryCatch try_catch;
4850   CompileRun("ThrowFromC();");
4851   CHECK(try_catch.HasCaught());
4852 }
4853
4854
4855 // Test that a try-finally block doesn't shadow a try-catch block
4856 // when setting up an external handler.
4857 //
4858 // BUG(271): Some of the exception propagation does not work on the
4859 // ARM simulator because the simulator separates the C++ stack and the
4860 // JS stack.  This test therefore fails on the simulator.  The test is
4861 // not threaded to allow the threading tests to run on the simulator.
4862 TEST(TryCatchInTryFinally) {
4863   v8::Isolate* isolate = CcTest::isolate();
4864   v8::HandleScope scope(isolate);
4865   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4866   templ->Set(v8_str("CCatcher"),
4867              v8::FunctionTemplate::New(isolate, CCatcher));
4868   LocalContext context(0, templ);
4869   Local<Value> result = CompileRun("try {"
4870                                    "  try {"
4871                                    "    CCatcher('throw 7;');"
4872                                    "  } finally {"
4873                                    "  }"
4874                                    "} catch (e) {"
4875                                    "}");
4876   CHECK(result->IsTrue());
4877 }
4878
4879
4880 static void check_reference_error_message(
4881     v8::Handle<v8::Message> message,
4882     v8::Handle<v8::Value> data) {
4883   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4884   CHECK(message->Get()->Equals(v8_str(reference_error)));
4885 }
4886
4887
4888 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4889   ApiTestFuzzer::Fuzz();
4890   CHECK(false);
4891 }
4892
4893
4894 // Test that overwritten methods are not invoked on uncaught exception
4895 // formatting. However, they are invoked when performing normal error
4896 // string conversions.
4897 TEST(APIThrowMessageOverwrittenToString) {
4898   v8::Isolate* isolate = CcTest::isolate();
4899   v8::HandleScope scope(isolate);
4900   v8::V8::AddMessageListener(check_reference_error_message);
4901   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4902   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4903   LocalContext context(NULL, templ);
4904   CompileRun("asdf;");
4905   CompileRun("var limit = {};"
4906              "limit.valueOf = fail;"
4907              "Error.stackTraceLimit = limit;");
4908   CompileRun("asdf");
4909   CompileRun("Array.prototype.pop = fail;");
4910   CompileRun("Object.prototype.hasOwnProperty = fail;");
4911   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4912   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4913   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4914   CompileRun("ReferenceError.prototype.toString ="
4915              "  function() { return 'Whoops' }");
4916   CompileRun("asdf;");
4917   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4918   CompileRun("asdf;");
4919   CompileRun("ReferenceError.prototype.constructor = void 0;");
4920   CompileRun("asdf;");
4921   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4922   CompileRun("asdf;");
4923   CompileRun("ReferenceError.prototype = new Object();");
4924   CompileRun("asdf;");
4925   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4926   CHECK(string->Equals(v8_str("Whoops")));
4927   CompileRun("ReferenceError.prototype.constructor = new Object();"
4928              "ReferenceError.prototype.constructor.name = 1;"
4929              "Number.prototype.toString = function() { return 'Whoops'; };"
4930              "ReferenceError.prototype.toString = Object.prototype.toString;");
4931   CompileRun("asdf;");
4932   v8::V8::RemoveMessageListeners(check_reference_error_message);
4933 }
4934
4935
4936 static void check_custom_error_tostring(
4937     v8::Handle<v8::Message> message,
4938     v8::Handle<v8::Value> data) {
4939   const char* uncaught_error = "Uncaught MyError toString";
4940   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4941 }
4942
4943
4944 TEST(CustomErrorToString) {
4945   LocalContext context;
4946   v8::HandleScope scope(context->GetIsolate());
4947   v8::V8::AddMessageListener(check_custom_error_tostring);
4948   CompileRun(
4949     "function MyError(name, message) {                   "
4950     "  this.name = name;                                 "
4951     "  this.message = message;                           "
4952     "}                                                   "
4953     "MyError.prototype = Object.create(Error.prototype); "
4954     "MyError.prototype.toString = function() {           "
4955     "  return 'MyError toString';                        "
4956     "};                                                  "
4957     "throw new MyError('my name', 'my message');         ");
4958   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4959 }
4960
4961
4962 static void check_custom_error_message(
4963     v8::Handle<v8::Message> message,
4964     v8::Handle<v8::Value> data) {
4965   const char* uncaught_error = "Uncaught MyError: my message";
4966   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4967   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4968 }
4969
4970
4971 TEST(CustomErrorMessage) {
4972   LocalContext context;
4973   v8::HandleScope scope(context->GetIsolate());
4974   v8::V8::AddMessageListener(check_custom_error_message);
4975
4976   // Handlebars.
4977   CompileRun(
4978     "function MyError(msg) {                             "
4979     "  this.name = 'MyError';                            "
4980     "  this.message = msg;                               "
4981     "}                                                   "
4982     "MyError.prototype = new Error();                    "
4983     "throw new MyError('my message');                    ");
4984
4985   // Closure.
4986   CompileRun(
4987     "function MyError(msg) {                             "
4988     "  this.name = 'MyError';                            "
4989     "  this.message = msg;                               "
4990     "}                                                   "
4991     "inherits = function(childCtor, parentCtor) {        "
4992     "    function tempCtor() {};                         "
4993     "    tempCtor.prototype = parentCtor.prototype;      "
4994     "    childCtor.superClass_ = parentCtor.prototype;   "
4995     "    childCtor.prototype = new tempCtor();           "
4996     "    childCtor.prototype.constructor = childCtor;    "
4997     "};                                                  "
4998     "inherits(MyError, Error);                           "
4999     "throw new MyError('my message');                    ");
5000
5001   // Object.create.
5002   CompileRun(
5003     "function MyError(msg) {                             "
5004     "  this.name = 'MyError';                            "
5005     "  this.message = msg;                               "
5006     "}                                                   "
5007     "MyError.prototype = Object.create(Error.prototype); "
5008     "throw new MyError('my message');                    ");
5009
5010   v8::V8::RemoveMessageListeners(check_custom_error_message);
5011 }
5012
5013
5014 static void receive_message(v8::Handle<v8::Message> message,
5015                             v8::Handle<v8::Value> data) {
5016   message->Get();
5017   message_received = true;
5018 }
5019
5020
5021 TEST(APIThrowMessage) {
5022   message_received = false;
5023   v8::Isolate* isolate = CcTest::isolate();
5024   v8::HandleScope scope(isolate);
5025   v8::V8::AddMessageListener(receive_message);
5026   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5027   templ->Set(v8_str("ThrowFromC"),
5028              v8::FunctionTemplate::New(isolate, ThrowFromC));
5029   LocalContext context(0, templ);
5030   CompileRun("ThrowFromC();");
5031   CHECK(message_received);
5032   v8::V8::RemoveMessageListeners(receive_message);
5033 }
5034
5035
5036 TEST(APIThrowMessageAndVerboseTryCatch) {
5037   message_received = false;
5038   v8::Isolate* isolate = CcTest::isolate();
5039   v8::HandleScope scope(isolate);
5040   v8::V8::AddMessageListener(receive_message);
5041   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5042   templ->Set(v8_str("ThrowFromC"),
5043              v8::FunctionTemplate::New(isolate, ThrowFromC));
5044   LocalContext context(0, templ);
5045   v8::TryCatch try_catch;
5046   try_catch.SetVerbose(true);
5047   Local<Value> result = CompileRun("ThrowFromC();");
5048   CHECK(try_catch.HasCaught());
5049   CHECK(result.IsEmpty());
5050   CHECK(message_received);
5051   v8::V8::RemoveMessageListeners(receive_message);
5052 }
5053
5054
5055 TEST(APIStackOverflowAndVerboseTryCatch) {
5056   message_received = false;
5057   LocalContext context;
5058   v8::HandleScope scope(context->GetIsolate());
5059   v8::V8::AddMessageListener(receive_message);
5060   v8::TryCatch try_catch;
5061   try_catch.SetVerbose(true);
5062   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5063   CHECK(try_catch.HasCaught());
5064   CHECK(result.IsEmpty());
5065   CHECK(message_received);
5066   v8::V8::RemoveMessageListeners(receive_message);
5067 }
5068
5069
5070 THREADED_TEST(ExternalScriptException) {
5071   v8::Isolate* isolate = CcTest::isolate();
5072   v8::HandleScope scope(isolate);
5073   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5074   templ->Set(v8_str("ThrowFromC"),
5075              v8::FunctionTemplate::New(isolate, ThrowFromC));
5076   LocalContext context(0, templ);
5077
5078   v8::TryCatch try_catch;
5079   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5080   CHECK(result.IsEmpty());
5081   CHECK(try_catch.HasCaught());
5082   String::Utf8Value exception_value(try_catch.Exception());
5083   CHECK_EQ("konto", *exception_value);
5084 }
5085
5086
5087
5088 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5089   ApiTestFuzzer::Fuzz();
5090   CHECK_EQ(4, args.Length());
5091   int count = args[0]->Int32Value();
5092   int cInterval = args[2]->Int32Value();
5093   if (count == 0) {
5094     args.GetIsolate()->ThrowException(v8_str("FromC"));
5095     return;
5096   } else {
5097     Local<v8::Object> global =
5098         args.GetIsolate()->GetCurrentContext()->Global();
5099     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5100     v8::Handle<Value> argv[] = { v8_num(count - 1),
5101                                  args[1],
5102                                  args[2],
5103                                  args[3] };
5104     if (count % cInterval == 0) {
5105       v8::TryCatch try_catch;
5106       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5107       int expected = args[3]->Int32Value();
5108       if (try_catch.HasCaught()) {
5109         CHECK_EQ(expected, count);
5110         CHECK(result.IsEmpty());
5111         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5112       } else {
5113         CHECK_NE(expected, count);
5114       }
5115       args.GetReturnValue().Set(result);
5116       return;
5117     } else {
5118       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5119       return;
5120     }
5121   }
5122 }
5123
5124
5125 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5126   ApiTestFuzzer::Fuzz();
5127   CHECK_EQ(3, args.Length());
5128   bool equality = args[0]->BooleanValue();
5129   int count = args[1]->Int32Value();
5130   int expected = args[2]->Int32Value();
5131   if (equality) {
5132     CHECK_EQ(count, expected);
5133   } else {
5134     CHECK_NE(count, expected);
5135   }
5136 }
5137
5138
5139 THREADED_TEST(EvalInTryFinally) {
5140   LocalContext context;
5141   v8::HandleScope scope(context->GetIsolate());
5142   v8::TryCatch try_catch;
5143   CompileRun("(function() {"
5144              "  try {"
5145              "    eval('asldkf (*&^&*^');"
5146              "  } finally {"
5147              "    return;"
5148              "  }"
5149              "})()");
5150   CHECK(!try_catch.HasCaught());
5151 }
5152
5153
5154 // This test works by making a stack of alternating JavaScript and C
5155 // activations.  These activations set up exception handlers with regular
5156 // intervals, one interval for C activations and another for JavaScript
5157 // activations.  When enough activations have been created an exception is
5158 // thrown and we check that the right activation catches the exception and that
5159 // no other activations do.  The right activation is always the topmost one with
5160 // a handler, regardless of whether it is in JavaScript or C.
5161 //
5162 // The notation used to describe a test case looks like this:
5163 //
5164 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5165 //
5166 // Each entry is an activation, either JS or C.  The index is the count at that
5167 // level.  Stars identify activations with exception handlers, the @ identifies
5168 // the exception handler that should catch the exception.
5169 //
5170 // BUG(271): Some of the exception propagation does not work on the
5171 // ARM simulator because the simulator separates the C++ stack and the
5172 // JS stack.  This test therefore fails on the simulator.  The test is
5173 // not threaded to allow the threading tests to run on the simulator.
5174 TEST(ExceptionOrder) {
5175   v8::Isolate* isolate = CcTest::isolate();
5176   v8::HandleScope scope(isolate);
5177   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5178   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5179   templ->Set(v8_str("CThrowCountDown"),
5180              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5181   LocalContext context(0, templ);
5182   CompileRun(
5183     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5184     "  if (count == 0) throw 'FromJS';"
5185     "  if (count % jsInterval == 0) {"
5186     "    try {"
5187     "      var value = CThrowCountDown(count - 1,"
5188     "                                  jsInterval,"
5189     "                                  cInterval,"
5190     "                                  expected);"
5191     "      check(false, count, expected);"
5192     "      return value;"
5193     "    } catch (e) {"
5194     "      check(true, count, expected);"
5195     "    }"
5196     "  } else {"
5197     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5198     "  }"
5199     "}");
5200   Local<Function> fun =
5201       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5202
5203   const int argc = 4;
5204   //                             count      jsInterval cInterval  expected
5205
5206   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5207   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5208   fun->Call(fun, argc, a0);
5209
5210   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5211   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5212   fun->Call(fun, argc, a1);
5213
5214   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5215   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5216   fun->Call(fun, argc, a2);
5217
5218   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5219   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5220   fun->Call(fun, argc, a3);
5221
5222   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5223   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5224   fun->Call(fun, argc, a4);
5225
5226   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5227   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5228   fun->Call(fun, argc, a5);
5229 }
5230
5231
5232 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5233   ApiTestFuzzer::Fuzz();
5234   CHECK_EQ(1, args.Length());
5235   args.GetIsolate()->ThrowException(args[0]);
5236 }
5237
5238
5239 THREADED_TEST(ThrowValues) {
5240   v8::Isolate* isolate = CcTest::isolate();
5241   v8::HandleScope scope(isolate);
5242   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5243   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5244   LocalContext context(0, templ);
5245   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5246     "function Run(obj) {"
5247     "  try {"
5248     "    Throw(obj);"
5249     "  } catch (e) {"
5250     "    return e;"
5251     "  }"
5252     "  return 'no exception';"
5253     "}"
5254     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5255   CHECK_EQ(5, result->Length());
5256   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5257   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5258   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5259   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5260   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5261   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5262   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5263 }
5264
5265
5266 THREADED_TEST(CatchZero) {
5267   LocalContext context;
5268   v8::HandleScope scope(context->GetIsolate());
5269   v8::TryCatch try_catch;
5270   CHECK(!try_catch.HasCaught());
5271   CompileRun("throw 10");
5272   CHECK(try_catch.HasCaught());
5273   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5274   try_catch.Reset();
5275   CHECK(!try_catch.HasCaught());
5276   CompileRun("throw 0");
5277   CHECK(try_catch.HasCaught());
5278   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5279 }
5280
5281
5282 THREADED_TEST(CatchExceptionFromWith) {
5283   LocalContext context;
5284   v8::HandleScope scope(context->GetIsolate());
5285   v8::TryCatch try_catch;
5286   CHECK(!try_catch.HasCaught());
5287   CompileRun("var o = {}; with (o) { throw 42; }");
5288   CHECK(try_catch.HasCaught());
5289 }
5290
5291
5292 THREADED_TEST(TryCatchAndFinallyHidingException) {
5293   LocalContext context;
5294   v8::HandleScope scope(context->GetIsolate());
5295   v8::TryCatch try_catch;
5296   CHECK(!try_catch.HasCaught());
5297   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5298   CompileRun("f({toString: function() { throw 42; }});");
5299   CHECK(!try_catch.HasCaught());
5300 }
5301
5302
5303 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5304   v8::TryCatch try_catch;
5305 }
5306
5307
5308 THREADED_TEST(TryCatchAndFinally) {
5309   LocalContext context;
5310   v8::Isolate* isolate = context->GetIsolate();
5311   v8::HandleScope scope(isolate);
5312   context->Global()->Set(
5313       v8_str("native_with_try_catch"),
5314       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5315   v8::TryCatch try_catch;
5316   CHECK(!try_catch.HasCaught());
5317   CompileRun(
5318       "try {\n"
5319       "  throw new Error('a');\n"
5320       "} finally {\n"
5321       "  native_with_try_catch();\n"
5322       "}\n");
5323   CHECK(try_catch.HasCaught());
5324 }
5325
5326
5327 static void TryCatchNestedHelper(int depth) {
5328   if (depth > 0) {
5329     v8::TryCatch try_catch;
5330     try_catch.SetVerbose(true);
5331     TryCatchNestedHelper(depth - 1);
5332     CHECK(try_catch.HasCaught());
5333     try_catch.ReThrow();
5334   } else {
5335     CcTest::isolate()->ThrowException(v8_str("back"));
5336   }
5337 }
5338
5339
5340 TEST(TryCatchNested) {
5341   v8::V8::Initialize();
5342   LocalContext context;
5343   v8::HandleScope scope(context->GetIsolate());
5344   v8::TryCatch try_catch;
5345   TryCatchNestedHelper(5);
5346   CHECK(try_catch.HasCaught());
5347   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5348 }
5349
5350
5351 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5352   CHECK(try_catch->HasCaught());
5353   Handle<Message> message = try_catch->Message();
5354   Handle<Value> resource = message->GetScriptResourceName();
5355   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5356   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5357                      "Uncaught Error: a"));
5358   CHECK_EQ(1, message->GetLineNumber());
5359   CHECK_EQ(6, message->GetStartColumn());
5360 }
5361
5362
5363 void TryCatchMixedNestingHelper(
5364     const v8::FunctionCallbackInfo<v8::Value>& args) {
5365   ApiTestFuzzer::Fuzz();
5366   v8::TryCatch try_catch;
5367   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5368   CHECK(try_catch.HasCaught());
5369   TryCatchMixedNestingCheck(&try_catch);
5370   try_catch.ReThrow();
5371 }
5372
5373
5374 // This test ensures that an outer TryCatch in the following situation:
5375 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5376 // does not clobber the Message object generated for the inner TryCatch.
5377 // This exercises the ability of TryCatch.ReThrow() to restore the
5378 // inner pending Message before throwing the exception again.
5379 TEST(TryCatchMixedNesting) {
5380   v8::Isolate* isolate = CcTest::isolate();
5381   v8::HandleScope scope(isolate);
5382   v8::V8::Initialize();
5383   v8::TryCatch try_catch;
5384   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5385   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5386              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5387   LocalContext context(0, templ);
5388   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5389   TryCatchMixedNestingCheck(&try_catch);
5390 }
5391
5392
5393 THREADED_TEST(Equality) {
5394   LocalContext context;
5395   v8::Isolate* isolate = context->GetIsolate();
5396   v8::HandleScope scope(context->GetIsolate());
5397   // Check that equality works at all before relying on CHECK_EQ
5398   CHECK(v8_str("a")->Equals(v8_str("a")));
5399   CHECK(!v8_str("a")->Equals(v8_str("b")));
5400
5401   CHECK_EQ(v8_str("a"), v8_str("a"));
5402   CHECK_NE(v8_str("a"), v8_str("b"));
5403   CHECK_EQ(v8_num(1), v8_num(1));
5404   CHECK_EQ(v8_num(1.00), v8_num(1));
5405   CHECK_NE(v8_num(1), v8_num(2));
5406
5407   // Assume String is not internalized.
5408   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5409   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5410   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5411   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5412   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5413   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5414   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5415   CHECK(!not_a_number->StrictEquals(not_a_number));
5416   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5417   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5418
5419   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5420   v8::Persistent<v8::Object> alias(isolate, obj);
5421   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5422   alias.Reset();
5423
5424   CHECK(v8_str("a")->SameValue(v8_str("a")));
5425   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5426   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5427   CHECK(v8_num(1)->SameValue(v8_num(1)));
5428   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5429   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5430   CHECK(not_a_number->SameValue(not_a_number));
5431   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5432   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5433 }
5434
5435
5436 THREADED_TEST(MultiRun) {
5437   LocalContext context;
5438   v8::HandleScope scope(context->GetIsolate());
5439   Local<Script> script = v8_compile("x");
5440   for (int i = 0; i < 10; i++)
5441     script->Run();
5442 }
5443
5444
5445 static void GetXValue(Local<String> name,
5446                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5447   ApiTestFuzzer::Fuzz();
5448   CHECK_EQ(info.Data(), v8_str("donut"));
5449   CHECK_EQ(name, v8_str("x"));
5450   info.GetReturnValue().Set(name);
5451 }
5452
5453
5454 THREADED_TEST(SimplePropertyRead) {
5455   LocalContext context;
5456   v8::Isolate* isolate = context->GetIsolate();
5457   v8::HandleScope scope(isolate);
5458   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5459   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5460   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5461   Local<Script> script = v8_compile("obj.x");
5462   for (int i = 0; i < 10; i++) {
5463     Local<Value> result = script->Run();
5464     CHECK_EQ(result, v8_str("x"));
5465   }
5466 }
5467
5468
5469 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5470   LocalContext context;
5471   v8::Isolate* isolate = context->GetIsolate();
5472   v8::HandleScope scope(isolate);
5473   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5474   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5475   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5476
5477   // Uses getOwnPropertyDescriptor to check the configurable status
5478   Local<Script> script_desc = v8_compile(
5479       "var prop = Object.getOwnPropertyDescriptor( "
5480       "obj, 'x');"
5481       "prop.configurable;");
5482   Local<Value> result = script_desc->Run();
5483   CHECK_EQ(result->BooleanValue(), true);
5484
5485   // Redefine get - but still configurable
5486   Local<Script> script_define = v8_compile(
5487       "var desc = { get: function(){return 42; },"
5488       "            configurable: true };"
5489       "Object.defineProperty(obj, 'x', desc);"
5490       "obj.x");
5491   result = script_define->Run();
5492   CHECK_EQ(result, v8_num(42));
5493
5494   // Check that the accessor is still configurable
5495   result = script_desc->Run();
5496   CHECK_EQ(result->BooleanValue(), true);
5497
5498   // Redefine to a non-configurable
5499   script_define = v8_compile(
5500       "var desc = { get: function(){return 43; },"
5501       "             configurable: false };"
5502       "Object.defineProperty(obj, 'x', desc);"
5503       "obj.x");
5504   result = script_define->Run();
5505   CHECK_EQ(result, v8_num(43));
5506   result = script_desc->Run();
5507   CHECK_EQ(result->BooleanValue(), false);
5508
5509   // Make sure that it is not possible to redefine again
5510   v8::TryCatch try_catch;
5511   result = script_define->Run();
5512   CHECK(try_catch.HasCaught());
5513   String::Utf8Value exception_value(try_catch.Exception());
5514   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5515 }
5516
5517
5518 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5519   v8::Isolate* isolate = CcTest::isolate();
5520   v8::HandleScope scope(isolate);
5521   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5522   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5523   LocalContext context;
5524   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5525
5526   Local<Script> script_desc = v8_compile(
5527       "var prop ="
5528       "Object.getOwnPropertyDescriptor( "
5529       "obj, 'x');"
5530       "prop.configurable;");
5531   Local<Value> result = script_desc->Run();
5532   CHECK_EQ(result->BooleanValue(), true);
5533
5534   Local<Script> script_define = v8_compile(
5535       "var desc = {get: function(){return 42; },"
5536       "            configurable: true };"
5537       "Object.defineProperty(obj, 'x', desc);"
5538       "obj.x");
5539   result = script_define->Run();
5540   CHECK_EQ(result, v8_num(42));
5541
5542
5543   result = script_desc->Run();
5544   CHECK_EQ(result->BooleanValue(), true);
5545
5546
5547   script_define = v8_compile(
5548       "var desc = {get: function(){return 43; },"
5549       "            configurable: false };"
5550       "Object.defineProperty(obj, 'x', desc);"
5551       "obj.x");
5552   result = script_define->Run();
5553   CHECK_EQ(result, v8_num(43));
5554   result = script_desc->Run();
5555
5556   CHECK_EQ(result->BooleanValue(), false);
5557
5558   v8::TryCatch try_catch;
5559   result = script_define->Run();
5560   CHECK(try_catch.HasCaught());
5561   String::Utf8Value exception_value(try_catch.Exception());
5562   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5563 }
5564
5565
5566 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5567                                                 char const* name) {
5568   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5569 }
5570
5571
5572 THREADED_TEST(DefineAPIAccessorOnObject) {
5573   v8::Isolate* isolate = CcTest::isolate();
5574   v8::HandleScope scope(isolate);
5575   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5576   LocalContext context;
5577
5578   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5579   CompileRun("var obj2 = {};");
5580
5581   CHECK(CompileRun("obj1.x")->IsUndefined());
5582   CHECK(CompileRun("obj2.x")->IsUndefined());
5583
5584   CHECK(GetGlobalProperty(&context, "obj1")->
5585       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5586
5587   ExpectString("obj1.x", "x");
5588   CHECK(CompileRun("obj2.x")->IsUndefined());
5589
5590   CHECK(GetGlobalProperty(&context, "obj2")->
5591       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5592
5593   ExpectString("obj1.x", "x");
5594   ExpectString("obj2.x", "x");
5595
5596   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5597   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5598
5599   CompileRun("Object.defineProperty(obj1, 'x',"
5600              "{ get: function() { return 'y'; }, configurable: true })");
5601
5602   ExpectString("obj1.x", "y");
5603   ExpectString("obj2.x", "x");
5604
5605   CompileRun("Object.defineProperty(obj2, 'x',"
5606              "{ get: function() { return 'y'; }, configurable: true })");
5607
5608   ExpectString("obj1.x", "y");
5609   ExpectString("obj2.x", "y");
5610
5611   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5612   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5613
5614   CHECK(GetGlobalProperty(&context, "obj1")->
5615       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5616   CHECK(GetGlobalProperty(&context, "obj2")->
5617       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5618
5619   ExpectString("obj1.x", "x");
5620   ExpectString("obj2.x", "x");
5621
5622   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5623   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5624
5625   // Define getters/setters, but now make them not configurable.
5626   CompileRun("Object.defineProperty(obj1, 'x',"
5627              "{ get: function() { return 'z'; }, configurable: false })");
5628   CompileRun("Object.defineProperty(obj2, 'x',"
5629              "{ get: function() { return 'z'; }, configurable: false })");
5630
5631   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5632   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5633
5634   ExpectString("obj1.x", "z");
5635   ExpectString("obj2.x", "z");
5636
5637   CHECK(!GetGlobalProperty(&context, "obj1")->
5638       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5639   CHECK(!GetGlobalProperty(&context, "obj2")->
5640       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5641
5642   ExpectString("obj1.x", "z");
5643   ExpectString("obj2.x", "z");
5644 }
5645
5646
5647 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5648   v8::Isolate* isolate = CcTest::isolate();
5649   v8::HandleScope scope(isolate);
5650   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5651   LocalContext context;
5652
5653   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5654   CompileRun("var obj2 = {};");
5655
5656   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5657         v8_str("x"),
5658         GetXValue, NULL,
5659         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5660   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5661         v8_str("x"),
5662         GetXValue, NULL,
5663         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5664
5665   ExpectString("obj1.x", "x");
5666   ExpectString("obj2.x", "x");
5667
5668   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5669   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5670
5671   CHECK(!GetGlobalProperty(&context, "obj1")->
5672       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5673   CHECK(!GetGlobalProperty(&context, "obj2")->
5674       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5675
5676   {
5677     v8::TryCatch try_catch;
5678     CompileRun("Object.defineProperty(obj1, 'x',"
5679         "{get: function() { return 'func'; }})");
5680     CHECK(try_catch.HasCaught());
5681     String::Utf8Value exception_value(try_catch.Exception());
5682     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5683   }
5684   {
5685     v8::TryCatch try_catch;
5686     CompileRun("Object.defineProperty(obj2, 'x',"
5687         "{get: function() { return 'func'; }})");
5688     CHECK(try_catch.HasCaught());
5689     String::Utf8Value exception_value(try_catch.Exception());
5690     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5691   }
5692 }
5693
5694
5695 static void Get239Value(Local<String> name,
5696                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5697   ApiTestFuzzer::Fuzz();
5698   CHECK_EQ(info.Data(), v8_str("donut"));
5699   CHECK_EQ(name, v8_str("239"));
5700   info.GetReturnValue().Set(name);
5701 }
5702
5703
5704 THREADED_TEST(ElementAPIAccessor) {
5705   v8::Isolate* isolate = CcTest::isolate();
5706   v8::HandleScope scope(isolate);
5707   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5708   LocalContext context;
5709
5710   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5711   CompileRun("var obj2 = {};");
5712
5713   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5714         v8_str("239"),
5715         Get239Value, NULL,
5716         v8_str("donut")));
5717   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5718         v8_str("239"),
5719         Get239Value, NULL,
5720         v8_str("donut")));
5721
5722   ExpectString("obj1[239]", "239");
5723   ExpectString("obj2[239]", "239");
5724   ExpectString("obj1['239']", "239");
5725   ExpectString("obj2['239']", "239");
5726 }
5727
5728
5729 v8::Persistent<Value> xValue;
5730
5731
5732 static void SetXValue(Local<String> name,
5733                       Local<Value> value,
5734                       const v8::PropertyCallbackInfo<void>& info) {
5735   CHECK_EQ(value, v8_num(4));
5736   CHECK_EQ(info.Data(), v8_str("donut"));
5737   CHECK_EQ(name, v8_str("x"));
5738   CHECK(xValue.IsEmpty());
5739   xValue.Reset(info.GetIsolate(), value);
5740 }
5741
5742
5743 THREADED_TEST(SimplePropertyWrite) {
5744   v8::Isolate* isolate = CcTest::isolate();
5745   v8::HandleScope scope(isolate);
5746   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5747   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5748   LocalContext context;
5749   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5750   Local<Script> script = v8_compile("obj.x = 4");
5751   for (int i = 0; i < 10; i++) {
5752     CHECK(xValue.IsEmpty());
5753     script->Run();
5754     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5755     xValue.Reset();
5756   }
5757 }
5758
5759
5760 THREADED_TEST(SetterOnly) {
5761   v8::Isolate* isolate = CcTest::isolate();
5762   v8::HandleScope scope(isolate);
5763   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5765   LocalContext context;
5766   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5767   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5768   for (int i = 0; i < 10; i++) {
5769     CHECK(xValue.IsEmpty());
5770     script->Run();
5771     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5772     xValue.Reset();
5773   }
5774 }
5775
5776
5777 THREADED_TEST(NoAccessors) {
5778   v8::Isolate* isolate = CcTest::isolate();
5779   v8::HandleScope scope(isolate);
5780   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5781   templ->SetAccessor(v8_str("x"),
5782                      static_cast<v8::AccessorGetterCallback>(NULL),
5783                      NULL,
5784                      v8_str("donut"));
5785   LocalContext context;
5786   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5787   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5788   for (int i = 0; i < 10; i++) {
5789     script->Run();
5790   }
5791 }
5792
5793
5794 static void XPropertyGetter(Local<String> property,
5795                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5796   ApiTestFuzzer::Fuzz();
5797   CHECK(info.Data()->IsUndefined());
5798   info.GetReturnValue().Set(property);
5799 }
5800
5801
5802 THREADED_TEST(NamedInterceptorPropertyRead) {
5803   v8::Isolate* isolate = CcTest::isolate();
5804   v8::HandleScope scope(isolate);
5805   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5806   templ->SetNamedPropertyHandler(XPropertyGetter);
5807   LocalContext context;
5808   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5809   Local<Script> script = v8_compile("obj.x");
5810   for (int i = 0; i < 10; i++) {
5811     Local<Value> result = script->Run();
5812     CHECK_EQ(result, v8_str("x"));
5813   }
5814 }
5815
5816
5817 THREADED_TEST(NamedInterceptorDictionaryIC) {
5818   v8::Isolate* isolate = CcTest::isolate();
5819   v8::HandleScope scope(isolate);
5820   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5821   templ->SetNamedPropertyHandler(XPropertyGetter);
5822   LocalContext context;
5823   // Create an object with a named interceptor.
5824   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5825   Local<Script> script = v8_compile("interceptor_obj.x");
5826   for (int i = 0; i < 10; i++) {
5827     Local<Value> result = script->Run();
5828     CHECK_EQ(result, v8_str("x"));
5829   }
5830   // Create a slow case object and a function accessing a property in
5831   // that slow case object (with dictionary probing in generated
5832   // code). Then force object with a named interceptor into slow-case,
5833   // pass it to the function, and check that the interceptor is called
5834   // instead of accessing the local property.
5835   Local<Value> result =
5836       CompileRun("function get_x(o) { return o.x; };"
5837                  "var obj = { x : 42, y : 0 };"
5838                  "delete obj.y;"
5839                  "for (var i = 0; i < 10; i++) get_x(obj);"
5840                  "interceptor_obj.x = 42;"
5841                  "interceptor_obj.y = 10;"
5842                  "delete interceptor_obj.y;"
5843                  "get_x(interceptor_obj)");
5844   CHECK_EQ(result, v8_str("x"));
5845 }
5846
5847
5848 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5849   v8::Isolate* isolate = CcTest::isolate();
5850   v8::HandleScope scope(isolate);
5851   v8::Local<Context> context1 = Context::New(isolate);
5852
5853   context1->Enter();
5854   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5855   templ->SetNamedPropertyHandler(XPropertyGetter);
5856   // Create an object with a named interceptor.
5857   v8::Local<v8::Object> object = templ->NewInstance();
5858   context1->Global()->Set(v8_str("interceptor_obj"), object);
5859
5860   // Force the object into the slow case.
5861   CompileRun("interceptor_obj.y = 0;"
5862              "delete interceptor_obj.y;");
5863   context1->Exit();
5864
5865   {
5866     // Introduce the object into a different context.
5867     // Repeat named loads to exercise ICs.
5868     LocalContext context2;
5869     context2->Global()->Set(v8_str("interceptor_obj"), object);
5870     Local<Value> result =
5871       CompileRun("function get_x(o) { return o.x; }"
5872                  "interceptor_obj.x = 42;"
5873                  "for (var i=0; i != 10; i++) {"
5874                  "  get_x(interceptor_obj);"
5875                  "}"
5876                  "get_x(interceptor_obj)");
5877     // Check that the interceptor was actually invoked.
5878     CHECK_EQ(result, v8_str("x"));
5879   }
5880
5881   // Return to the original context and force some object to the slow case
5882   // to cause the NormalizedMapCache to verify.
5883   context1->Enter();
5884   CompileRun("var obj = { x : 0 }; delete obj.x;");
5885   context1->Exit();
5886 }
5887
5888
5889 static void SetXOnPrototypeGetter(
5890     Local<String> property,
5891     const v8::PropertyCallbackInfo<v8::Value>& info) {
5892   // Set x on the prototype object and do not handle the get request.
5893   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5894   proto.As<v8::Object>()->Set(v8_str("x"),
5895                               v8::Integer::New(info.GetIsolate(), 23));
5896 }
5897
5898
5899 // This is a regression test for http://crbug.com/20104. Map
5900 // transitions should not interfere with post interceptor lookup.
5901 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5902   v8::Isolate* isolate = CcTest::isolate();
5903   v8::HandleScope scope(isolate);
5904   Local<v8::FunctionTemplate> function_template =
5905       v8::FunctionTemplate::New(isolate);
5906   Local<v8::ObjectTemplate> instance_template
5907       = function_template->InstanceTemplate();
5908   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5909   LocalContext context;
5910   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5911   // Create an instance of F and introduce a map transition for x.
5912   CompileRun("var o = new F(); o.x = 23;");
5913   // Create an instance of F and invoke the getter. The result should be 23.
5914   Local<Value> result = CompileRun("o = new F(); o.x");
5915   CHECK_EQ(result->Int32Value(), 23);
5916 }
5917
5918
5919 static void IndexedPropertyGetter(
5920     uint32_t index,
5921     const v8::PropertyCallbackInfo<v8::Value>& info) {
5922   ApiTestFuzzer::Fuzz();
5923   if (index == 37) {
5924     info.GetReturnValue().Set(v8_num(625));
5925   }
5926 }
5927
5928
5929 static void IndexedPropertySetter(
5930     uint32_t index,
5931     Local<Value> value,
5932     const v8::PropertyCallbackInfo<v8::Value>& info) {
5933   ApiTestFuzzer::Fuzz();
5934   if (index == 39) {
5935     info.GetReturnValue().Set(value);
5936   }
5937 }
5938
5939
5940 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5941   v8::Isolate* isolate = CcTest::isolate();
5942   v8::HandleScope scope(isolate);
5943   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5944   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5945                                    IndexedPropertySetter);
5946   LocalContext context;
5947   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5948   Local<Script> getter_script = v8_compile(
5949       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
5950   Local<Script> setter_script = v8_compile(
5951       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5952       "obj[17] = 23;"
5953       "obj.foo;");
5954   Local<Script> interceptor_setter_script = v8_compile(
5955       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5956       "obj[39] = 47;"
5957       "obj.foo;");  // This setter should not run, due to the interceptor.
5958   Local<Script> interceptor_getter_script = v8_compile(
5959       "obj[37];");
5960   Local<Value> result = getter_script->Run();
5961   CHECK_EQ(v8_num(5), result);
5962   result = setter_script->Run();
5963   CHECK_EQ(v8_num(23), result);
5964   result = interceptor_setter_script->Run();
5965   CHECK_EQ(v8_num(23), result);
5966   result = interceptor_getter_script->Run();
5967   CHECK_EQ(v8_num(625), result);
5968 }
5969
5970
5971 static void UnboxedDoubleIndexedPropertyGetter(
5972     uint32_t index,
5973     const v8::PropertyCallbackInfo<v8::Value>& info) {
5974   ApiTestFuzzer::Fuzz();
5975   if (index < 25) {
5976     info.GetReturnValue().Set(v8_num(index));
5977   }
5978 }
5979
5980
5981 static void UnboxedDoubleIndexedPropertySetter(
5982     uint32_t index,
5983     Local<Value> value,
5984     const v8::PropertyCallbackInfo<v8::Value>& info) {
5985   ApiTestFuzzer::Fuzz();
5986   if (index < 25) {
5987     info.GetReturnValue().Set(v8_num(index));
5988   }
5989 }
5990
5991
5992 void UnboxedDoubleIndexedPropertyEnumerator(
5993     const v8::PropertyCallbackInfo<v8::Array>& info) {
5994   // Force the list of returned keys to be stored in a FastDoubleArray.
5995   Local<Script> indexed_property_names_script = v8_compile(
5996       "keys = new Array(); keys[125000] = 1;"
5997       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5998       "keys.length = 25; keys;");
5999   Local<Value> result = indexed_property_names_script->Run();
6000   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6001 }
6002
6003
6004 // Make sure that the the interceptor code in the runtime properly handles
6005 // merging property name lists for double-array-backed arrays.
6006 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6007   v8::Isolate* isolate = CcTest::isolate();
6008   v8::HandleScope scope(isolate);
6009   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6010   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6011                                    UnboxedDoubleIndexedPropertySetter,
6012                                    0,
6013                                    0,
6014                                    UnboxedDoubleIndexedPropertyEnumerator);
6015   LocalContext context;
6016   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6017   // When obj is created, force it to be Stored in a FastDoubleArray.
6018   Local<Script> create_unboxed_double_script = v8_compile(
6019       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6020       "key_count = 0; "
6021       "for (x in obj) {key_count++;};"
6022       "obj;");
6023   Local<Value> result = create_unboxed_double_script->Run();
6024   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6025   Local<Script> key_count_check = v8_compile("key_count;");
6026   result = key_count_check->Run();
6027   CHECK_EQ(v8_num(40013), result);
6028 }
6029
6030
6031 void SloppyArgsIndexedPropertyEnumerator(
6032     const v8::PropertyCallbackInfo<v8::Array>& info) {
6033   // Force the list of returned keys to be stored in a Arguments object.
6034   Local<Script> indexed_property_names_script = v8_compile(
6035       "function f(w,x) {"
6036       " return arguments;"
6037       "}"
6038       "keys = f(0, 1, 2, 3);"
6039       "keys;");
6040   Local<Object> result =
6041       Local<Object>::Cast(indexed_property_names_script->Run());
6042   // Have to populate the handle manually, as it's not Cast-able.
6043   i::Handle<i::JSObject> o =
6044       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6045   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6046   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6047 }
6048
6049
6050 static void SloppyIndexedPropertyGetter(
6051     uint32_t index,
6052     const v8::PropertyCallbackInfo<v8::Value>& info) {
6053   ApiTestFuzzer::Fuzz();
6054   if (index < 4) {
6055     info.GetReturnValue().Set(v8_num(index));
6056   }
6057 }
6058
6059
6060 // Make sure that the the interceptor code in the runtime properly handles
6061 // merging property name lists for non-string arguments arrays.
6062 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6063   v8::Isolate* isolate = CcTest::isolate();
6064   v8::HandleScope scope(isolate);
6065   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6066   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6067                                    0,
6068                                    0,
6069                                    0,
6070                                    SloppyArgsIndexedPropertyEnumerator);
6071   LocalContext context;
6072   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6073   Local<Script> create_args_script = v8_compile(
6074       "var key_count = 0;"
6075       "for (x in obj) {key_count++;} key_count;");
6076   Local<Value> result = create_args_script->Run();
6077   CHECK_EQ(v8_num(4), result);
6078 }
6079
6080
6081 static void IdentityIndexedPropertyGetter(
6082     uint32_t index,
6083     const v8::PropertyCallbackInfo<v8::Value>& info) {
6084   info.GetReturnValue().Set(index);
6085 }
6086
6087
6088 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6089   v8::Isolate* isolate = CcTest::isolate();
6090   v8::HandleScope scope(isolate);
6091   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6092   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6093
6094   LocalContext context;
6095   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6096
6097   // Check fast object case.
6098   const char* fast_case_code =
6099       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6100   ExpectString(fast_case_code, "0");
6101
6102   // Check slow case.
6103   const char* slow_case_code =
6104       "obj.x = 1; delete obj.x;"
6105       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6106   ExpectString(slow_case_code, "1");
6107 }
6108
6109
6110 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6111   v8::Isolate* isolate = CcTest::isolate();
6112   v8::HandleScope scope(isolate);
6113   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6114   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6115
6116   LocalContext context;
6117   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6118
6119   const char* code =
6120       "try {"
6121       "  obj[0] = 239;"
6122       "  for (var i = 0; i < 100; i++) {"
6123       "    var v = obj[0];"
6124       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6125       "  }"
6126       "  'PASSED'"
6127       "} catch(e) {"
6128       "  e"
6129       "}";
6130   ExpectString(code, "PASSED");
6131 }
6132
6133
6134 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6135   v8::Isolate* isolate = CcTest::isolate();
6136   v8::HandleScope scope(isolate);
6137   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6138   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6139
6140   LocalContext context;
6141   Local<v8::Object> obj = templ->NewInstance();
6142   obj->TurnOnAccessCheck();
6143   context->Global()->Set(v8_str("obj"), obj);
6144
6145   const char* code =
6146       "try {"
6147       "  for (var i = 0; i < 100; i++) {"
6148       "    var v = obj[0];"
6149       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6150       "  }"
6151       "  'PASSED'"
6152       "} catch(e) {"
6153       "  e"
6154       "}";
6155   ExpectString(code, "PASSED");
6156 }
6157
6158
6159 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6160   i::FLAG_allow_natives_syntax = true;
6161   v8::Isolate* isolate = CcTest::isolate();
6162   v8::HandleScope scope(isolate);
6163   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6164   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6165
6166   LocalContext context;
6167   Local<v8::Object> obj = templ->NewInstance();
6168   context->Global()->Set(v8_str("obj"), obj);
6169
6170   const char* code =
6171       "try {"
6172       "  for (var i = 0; i < 100; i++) {"
6173       "    var expected = i;"
6174       "    if (i == 5) {"
6175       "      %EnableAccessChecks(obj);"
6176       "      expected = undefined;"
6177       "    }"
6178       "    var v = obj[i];"
6179       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6180       "    if (i == 5) %DisableAccessChecks(obj);"
6181       "  }"
6182       "  'PASSED'"
6183       "} catch(e) {"
6184       "  e"
6185       "}";
6186   ExpectString(code, "PASSED");
6187 }
6188
6189
6190 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6191   v8::Isolate* isolate = CcTest::isolate();
6192   v8::HandleScope scope(isolate);
6193   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6194   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6195
6196   LocalContext context;
6197   Local<v8::Object> obj = templ->NewInstance();
6198   context->Global()->Set(v8_str("obj"), obj);
6199
6200   const char* code =
6201       "try {"
6202       "  for (var i = 0; i < 100; i++) {"
6203       "    var v = obj[i];"
6204       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6205       "  }"
6206       "  'PASSED'"
6207       "} catch(e) {"
6208       "  e"
6209       "}";
6210   ExpectString(code, "PASSED");
6211 }
6212
6213
6214 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6215   v8::Isolate* isolate = CcTest::isolate();
6216   v8::HandleScope scope(isolate);
6217   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6218   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6219
6220   LocalContext context;
6221   Local<v8::Object> obj = templ->NewInstance();
6222   context->Global()->Set(v8_str("obj"), obj);
6223
6224   const char* code =
6225       "try {"
6226       "  for (var i = 0; i < 100; i++) {"
6227       "    var expected = i;"
6228       "    var key = i;"
6229       "    if (i == 25) {"
6230       "       key = -1;"
6231       "       expected = undefined;"
6232       "    }"
6233       "    if (i == 50) {"
6234       "       /* probe minimal Smi number on 32-bit platforms */"
6235       "       key = -(1 << 30);"
6236       "       expected = undefined;"
6237       "    }"
6238       "    if (i == 75) {"
6239       "       /* probe minimal Smi number on 64-bit platforms */"
6240       "       key = 1 << 31;"
6241       "       expected = undefined;"
6242       "    }"
6243       "    var v = obj[key];"
6244       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6245       "  }"
6246       "  'PASSED'"
6247       "} catch(e) {"
6248       "  e"
6249       "}";
6250   ExpectString(code, "PASSED");
6251 }
6252
6253
6254 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6255   v8::Isolate* isolate = CcTest::isolate();
6256   v8::HandleScope scope(isolate);
6257   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6258   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6259
6260   LocalContext context;
6261   Local<v8::Object> obj = templ->NewInstance();
6262   context->Global()->Set(v8_str("obj"), obj);
6263
6264   const char* code =
6265       "try {"
6266       "  for (var i = 0; i < 100; i++) {"
6267       "    var expected = i;"
6268       "    var key = i;"
6269       "    if (i == 50) {"
6270       "       key = 'foobar';"
6271       "       expected = undefined;"
6272       "    }"
6273       "    var v = obj[key];"
6274       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6275       "  }"
6276       "  'PASSED'"
6277       "} catch(e) {"
6278       "  e"
6279       "}";
6280   ExpectString(code, "PASSED");
6281 }
6282
6283
6284 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6285   v8::Isolate* isolate = CcTest::isolate();
6286   v8::HandleScope scope(isolate);
6287   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6288   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6289
6290   LocalContext context;
6291   Local<v8::Object> obj = templ->NewInstance();
6292   context->Global()->Set(v8_str("obj"), obj);
6293
6294   const char* code =
6295       "var original = obj;"
6296       "try {"
6297       "  for (var i = 0; i < 100; i++) {"
6298       "    var expected = i;"
6299       "    if (i == 50) {"
6300       "       obj = {50: 'foobar'};"
6301       "       expected = 'foobar';"
6302       "    }"
6303       "    var v = obj[i];"
6304       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6305       "    if (i == 50) obj = original;"
6306       "  }"
6307       "  'PASSED'"
6308       "} catch(e) {"
6309       "  e"
6310       "}";
6311   ExpectString(code, "PASSED");
6312 }
6313
6314
6315 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6316   v8::Isolate* isolate = CcTest::isolate();
6317   v8::HandleScope scope(isolate);
6318   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6319   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6320
6321   LocalContext context;
6322   Local<v8::Object> obj = templ->NewInstance();
6323   context->Global()->Set(v8_str("obj"), obj);
6324
6325   const char* code =
6326       "var original = obj;"
6327       "try {"
6328       "  for (var i = 0; i < 100; i++) {"
6329       "    var expected = i;"
6330       "    if (i == 5) {"
6331       "       obj = 239;"
6332       "       expected = undefined;"
6333       "    }"
6334       "    var v = obj[i];"
6335       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6336       "    if (i == 5) obj = original;"
6337       "  }"
6338       "  'PASSED'"
6339       "} catch(e) {"
6340       "  e"
6341       "}";
6342   ExpectString(code, "PASSED");
6343 }
6344
6345
6346 THREADED_TEST(IndexedInterceptorOnProto) {
6347   v8::Isolate* isolate = CcTest::isolate();
6348   v8::HandleScope scope(isolate);
6349   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6350   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6351
6352   LocalContext context;
6353   Local<v8::Object> obj = templ->NewInstance();
6354   context->Global()->Set(v8_str("obj"), obj);
6355
6356   const char* code =
6357       "var o = {__proto__: obj};"
6358       "try {"
6359       "  for (var i = 0; i < 100; i++) {"
6360       "    var v = o[i];"
6361       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6362       "  }"
6363       "  'PASSED'"
6364       "} catch(e) {"
6365       "  e"
6366       "}";
6367   ExpectString(code, "PASSED");
6368 }
6369
6370
6371 THREADED_TEST(MultiContexts) {
6372   v8::Isolate* isolate = CcTest::isolate();
6373   v8::HandleScope scope(isolate);
6374   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6375   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6376                                                         DummyCallHandler));
6377
6378   Local<String> password = v8_str("Password");
6379
6380   // Create an environment
6381   LocalContext context0(0, templ);
6382   context0->SetSecurityToken(password);
6383   v8::Handle<v8::Object> global0 = context0->Global();
6384   global0->Set(v8_str("custom"), v8_num(1234));
6385   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6386
6387   // Create an independent environment
6388   LocalContext context1(0, templ);
6389   context1->SetSecurityToken(password);
6390   v8::Handle<v8::Object> global1 = context1->Global();
6391   global1->Set(v8_str("custom"), v8_num(1234));
6392   CHECK_NE(global0, global1);
6393   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6394   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6395
6396   // Now create a new context with the old global
6397   LocalContext context2(0, templ, global1);
6398   context2->SetSecurityToken(password);
6399   v8::Handle<v8::Object> global2 = context2->Global();
6400   CHECK_EQ(global1, global2);
6401   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6402   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6403 }
6404
6405
6406 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6407   // Make sure that functions created by cloning boilerplates cannot
6408   // communicate through their __proto__ field.
6409
6410   v8::HandleScope scope(CcTest::isolate());
6411
6412   LocalContext env0;
6413   v8::Handle<v8::Object> global0 =
6414       env0->Global();
6415   v8::Handle<v8::Object> object0 =
6416       global0->Get(v8_str("Object")).As<v8::Object>();
6417   v8::Handle<v8::Object> tostring0 =
6418       object0->Get(v8_str("toString")).As<v8::Object>();
6419   v8::Handle<v8::Object> proto0 =
6420       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6421   proto0->Set(v8_str("custom"), v8_num(1234));
6422
6423   LocalContext env1;
6424   v8::Handle<v8::Object> global1 =
6425       env1->Global();
6426   v8::Handle<v8::Object> object1 =
6427       global1->Get(v8_str("Object")).As<v8::Object>();
6428   v8::Handle<v8::Object> tostring1 =
6429       object1->Get(v8_str("toString")).As<v8::Object>();
6430   v8::Handle<v8::Object> proto1 =
6431       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6432   CHECK(!proto1->Has(v8_str("custom")));
6433 }
6434
6435
6436 THREADED_TEST(Regress892105) {
6437   // Make sure that object and array literals created by cloning
6438   // boilerplates cannot communicate through their __proto__
6439   // field. This is rather difficult to check, but we try to add stuff
6440   // to Object.prototype and Array.prototype and create a new
6441   // environment. This should succeed.
6442
6443   v8::HandleScope scope(CcTest::isolate());
6444
6445   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6446                                 "Array.prototype.arr = 4567;"
6447                                 "8901");
6448
6449   LocalContext env0;
6450   Local<Script> script0 = v8_compile(source);
6451   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6452
6453   LocalContext env1;
6454   Local<Script> script1 = v8_compile(source);
6455   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6456 }
6457
6458
6459 THREADED_TEST(UndetectableObject) {
6460   LocalContext env;
6461   v8::HandleScope scope(env->GetIsolate());
6462
6463   Local<v8::FunctionTemplate> desc =
6464       v8::FunctionTemplate::New(env->GetIsolate());
6465   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6466
6467   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6468   env->Global()->Set(v8_str("undetectable"), obj);
6469
6470   ExpectString("undetectable.toString()", "[object Object]");
6471   ExpectString("typeof undetectable", "undefined");
6472   ExpectString("typeof(undetectable)", "undefined");
6473   ExpectBoolean("typeof undetectable == 'undefined'", true);
6474   ExpectBoolean("typeof undetectable == 'object'", false);
6475   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6476   ExpectBoolean("!undetectable", true);
6477
6478   ExpectObject("true&&undetectable", obj);
6479   ExpectBoolean("false&&undetectable", false);
6480   ExpectBoolean("true||undetectable", true);
6481   ExpectObject("false||undetectable", obj);
6482
6483   ExpectObject("undetectable&&true", obj);
6484   ExpectObject("undetectable&&false", obj);
6485   ExpectBoolean("undetectable||true", true);
6486   ExpectBoolean("undetectable||false", false);
6487
6488   ExpectBoolean("undetectable==null", true);
6489   ExpectBoolean("null==undetectable", true);
6490   ExpectBoolean("undetectable==undefined", true);
6491   ExpectBoolean("undefined==undetectable", true);
6492   ExpectBoolean("undetectable==undetectable", true);
6493
6494
6495   ExpectBoolean("undetectable===null", false);
6496   ExpectBoolean("null===undetectable", false);
6497   ExpectBoolean("undetectable===undefined", false);
6498   ExpectBoolean("undefined===undetectable", false);
6499   ExpectBoolean("undetectable===undetectable", true);
6500 }
6501
6502
6503 THREADED_TEST(VoidLiteral) {
6504   LocalContext env;
6505   v8::Isolate* isolate = env->GetIsolate();
6506   v8::HandleScope scope(isolate);
6507
6508   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6509   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6510
6511   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6512   env->Global()->Set(v8_str("undetectable"), obj);
6513
6514   ExpectBoolean("undefined == void 0", true);
6515   ExpectBoolean("undetectable == void 0", true);
6516   ExpectBoolean("null == void 0", true);
6517   ExpectBoolean("undefined === void 0", true);
6518   ExpectBoolean("undetectable === void 0", false);
6519   ExpectBoolean("null === void 0", false);
6520
6521   ExpectBoolean("void 0 == undefined", true);
6522   ExpectBoolean("void 0 == undetectable", true);
6523   ExpectBoolean("void 0 == null", true);
6524   ExpectBoolean("void 0 === undefined", true);
6525   ExpectBoolean("void 0 === undetectable", false);
6526   ExpectBoolean("void 0 === null", false);
6527
6528   ExpectString("(function() {"
6529                "  try {"
6530                "    return x === void 0;"
6531                "  } catch(e) {"
6532                "    return e.toString();"
6533                "  }"
6534                "})()",
6535                "ReferenceError: x is not defined");
6536   ExpectString("(function() {"
6537                "  try {"
6538                "    return void 0 === x;"
6539                "  } catch(e) {"
6540                "    return e.toString();"
6541                "  }"
6542                "})()",
6543                "ReferenceError: x is not defined");
6544 }
6545
6546
6547 THREADED_TEST(ExtensibleOnUndetectable) {
6548   LocalContext env;
6549   v8::Isolate* isolate = env->GetIsolate();
6550   v8::HandleScope scope(isolate);
6551
6552   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6553   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6554
6555   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6556   env->Global()->Set(v8_str("undetectable"), obj);
6557
6558   Local<String> source = v8_str("undetectable.x = 42;"
6559                                 "undetectable.x");
6560
6561   Local<Script> script = v8_compile(source);
6562
6563   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6564
6565   ExpectBoolean("Object.isExtensible(undetectable)", true);
6566
6567   source = v8_str("Object.preventExtensions(undetectable);");
6568   script = v8_compile(source);
6569   script->Run();
6570   ExpectBoolean("Object.isExtensible(undetectable)", false);
6571
6572   source = v8_str("undetectable.y = 2000;");
6573   script = v8_compile(source);
6574   script->Run();
6575   ExpectBoolean("undetectable.y == undefined", true);
6576 }
6577
6578
6579
6580 THREADED_TEST(UndetectableString) {
6581   LocalContext env;
6582   v8::HandleScope scope(env->GetIsolate());
6583
6584   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6585                                           String::kUndetectableString);
6586   env->Global()->Set(v8_str("undetectable"), obj);
6587
6588   ExpectString("undetectable", "foo");
6589   ExpectString("typeof undetectable", "undefined");
6590   ExpectString("typeof(undetectable)", "undefined");
6591   ExpectBoolean("typeof undetectable == 'undefined'", true);
6592   ExpectBoolean("typeof undetectable == 'string'", false);
6593   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6594   ExpectBoolean("!undetectable", true);
6595
6596   ExpectObject("true&&undetectable", obj);
6597   ExpectBoolean("false&&undetectable", false);
6598   ExpectBoolean("true||undetectable", true);
6599   ExpectObject("false||undetectable", obj);
6600
6601   ExpectObject("undetectable&&true", obj);
6602   ExpectObject("undetectable&&false", obj);
6603   ExpectBoolean("undetectable||true", true);
6604   ExpectBoolean("undetectable||false", false);
6605
6606   ExpectBoolean("undetectable==null", true);
6607   ExpectBoolean("null==undetectable", true);
6608   ExpectBoolean("undetectable==undefined", true);
6609   ExpectBoolean("undefined==undetectable", true);
6610   ExpectBoolean("undetectable==undetectable", true);
6611
6612
6613   ExpectBoolean("undetectable===null", false);
6614   ExpectBoolean("null===undetectable", false);
6615   ExpectBoolean("undetectable===undefined", false);
6616   ExpectBoolean("undefined===undetectable", false);
6617   ExpectBoolean("undetectable===undetectable", true);
6618 }
6619
6620
6621 TEST(UndetectableOptimized) {
6622   i::FLAG_allow_natives_syntax = true;
6623   LocalContext env;
6624   v8::HandleScope scope(env->GetIsolate());
6625
6626   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6627                                           String::kUndetectableString);
6628   env->Global()->Set(v8_str("undetectable"), obj);
6629   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6630
6631   ExpectString(
6632       "function testBranch() {"
6633       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6634       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6635       "}\n"
6636       "function testBool() {"
6637       "  var b1 = !%_IsUndetectableObject(undetectable);"
6638       "  var b2 = %_IsUndetectableObject(detectable);"
6639       "  if (b1) throw 3;"
6640       "  if (b2) throw 4;"
6641       "  return b1 == b2;"
6642       "}\n"
6643       "%OptimizeFunctionOnNextCall(testBranch);"
6644       "%OptimizeFunctionOnNextCall(testBool);"
6645       "for (var i = 0; i < 10; i++) {"
6646       "  testBranch();"
6647       "  testBool();"
6648       "}\n"
6649       "\"PASS\"",
6650       "PASS");
6651 }
6652
6653
6654 template <typename T> static void USE(T) { }
6655
6656
6657 // The point of this test is type checking. We run it only so compilers
6658 // don't complain about an unused function.
6659 TEST(PersistentHandles) {
6660   LocalContext env;
6661   v8::Isolate* isolate = CcTest::isolate();
6662   v8::HandleScope scope(isolate);
6663   Local<String> str = v8_str("foo");
6664   v8::Persistent<String> p_str(isolate, str);
6665   p_str.Reset();
6666   Local<Script> scr = v8_compile("");
6667   v8::Persistent<Script> p_scr(isolate, scr);
6668   p_scr.Reset();
6669   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6670   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6671   p_templ.Reset();
6672 }
6673
6674
6675 static void HandleLogDelegator(
6676     const v8::FunctionCallbackInfo<v8::Value>& args) {
6677   ApiTestFuzzer::Fuzz();
6678 }
6679
6680
6681 THREADED_TEST(GlobalObjectTemplate) {
6682   v8::Isolate* isolate = CcTest::isolate();
6683   v8::HandleScope handle_scope(isolate);
6684   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6685   global_template->Set(v8_str("JSNI_Log"),
6686                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6687   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6688   Context::Scope context_scope(context);
6689   CompileRun("JSNI_Log('LOG')");
6690 }
6691
6692
6693 static const char* kSimpleExtensionSource =
6694   "function Foo() {"
6695   "  return 4;"
6696   "}";
6697
6698
6699 TEST(SimpleExtensions) {
6700   v8::HandleScope handle_scope(CcTest::isolate());
6701   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6702   const char* extension_names[] = { "simpletest" };
6703   v8::ExtensionConfiguration extensions(1, extension_names);
6704   v8::Handle<Context> context =
6705       Context::New(CcTest::isolate(), &extensions);
6706   Context::Scope lock(context);
6707   v8::Handle<Value> result = CompileRun("Foo()");
6708   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6709 }
6710
6711
6712 TEST(NullExtensions) {
6713   v8::HandleScope handle_scope(CcTest::isolate());
6714   v8::RegisterExtension(new Extension("nulltest", NULL));
6715   const char* extension_names[] = { "nulltest" };
6716   v8::ExtensionConfiguration extensions(1, extension_names);
6717   v8::Handle<Context> context =
6718       Context::New(CcTest::isolate(), &extensions);
6719   Context::Scope lock(context);
6720   v8::Handle<Value> result = CompileRun("1+3");
6721   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6722 }
6723
6724
6725 static const char* kEmbeddedExtensionSource =
6726     "function Ret54321(){return 54321;}~~@@$"
6727     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6728 static const int kEmbeddedExtensionSourceValidLen = 34;
6729
6730
6731 TEST(ExtensionMissingSourceLength) {
6732   v8::HandleScope handle_scope(CcTest::isolate());
6733   v8::RegisterExtension(new Extension("srclentest_fail",
6734                                       kEmbeddedExtensionSource));
6735   const char* extension_names[] = { "srclentest_fail" };
6736   v8::ExtensionConfiguration extensions(1, extension_names);
6737   v8::Handle<Context> context =
6738       Context::New(CcTest::isolate(), &extensions);
6739   CHECK_EQ(0, *context);
6740 }
6741
6742
6743 TEST(ExtensionWithSourceLength) {
6744   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6745        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6746     v8::HandleScope handle_scope(CcTest::isolate());
6747     i::ScopedVector<char> extension_name(32);
6748     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6749     v8::RegisterExtension(new Extension(extension_name.start(),
6750                                         kEmbeddedExtensionSource, 0, 0,
6751                                         source_len));
6752     const char* extension_names[1] = { extension_name.start() };
6753     v8::ExtensionConfiguration extensions(1, extension_names);
6754     v8::Handle<Context> context =
6755       Context::New(CcTest::isolate(), &extensions);
6756     if (source_len == kEmbeddedExtensionSourceValidLen) {
6757       Context::Scope lock(context);
6758       v8::Handle<Value> result = CompileRun("Ret54321()");
6759       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6760     } else {
6761       // Anything but exactly the right length should fail to compile.
6762       CHECK_EQ(0, *context);
6763     }
6764   }
6765 }
6766
6767
6768 static const char* kEvalExtensionSource1 =
6769   "function UseEval1() {"
6770   "  var x = 42;"
6771   "  return eval('x');"
6772   "}";
6773
6774
6775 static const char* kEvalExtensionSource2 =
6776   "(function() {"
6777   "  var x = 42;"
6778   "  function e() {"
6779   "    return eval('x');"
6780   "  }"
6781   "  this.UseEval2 = e;"
6782   "})()";
6783
6784
6785 TEST(UseEvalFromExtension) {
6786   v8::HandleScope handle_scope(CcTest::isolate());
6787   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6788   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6789   const char* extension_names[] = { "evaltest1", "evaltest2" };
6790   v8::ExtensionConfiguration extensions(2, extension_names);
6791   v8::Handle<Context> context =
6792       Context::New(CcTest::isolate(), &extensions);
6793   Context::Scope lock(context);
6794   v8::Handle<Value> result = CompileRun("UseEval1()");
6795   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6796   result = CompileRun("UseEval2()");
6797   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6798 }
6799
6800
6801 static const char* kWithExtensionSource1 =
6802   "function UseWith1() {"
6803   "  var x = 42;"
6804   "  with({x:87}) { return x; }"
6805   "}";
6806
6807
6808
6809 static const char* kWithExtensionSource2 =
6810   "(function() {"
6811   "  var x = 42;"
6812   "  function e() {"
6813   "    with ({x:87}) { return x; }"
6814   "  }"
6815   "  this.UseWith2 = e;"
6816   "})()";
6817
6818
6819 TEST(UseWithFromExtension) {
6820   v8::HandleScope handle_scope(CcTest::isolate());
6821   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6822   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6823   const char* extension_names[] = { "withtest1", "withtest2" };
6824   v8::ExtensionConfiguration extensions(2, extension_names);
6825   v8::Handle<Context> context =
6826       Context::New(CcTest::isolate(), &extensions);
6827   Context::Scope lock(context);
6828   v8::Handle<Value> result = CompileRun("UseWith1()");
6829   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6830   result = CompileRun("UseWith2()");
6831   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6832 }
6833
6834
6835 TEST(AutoExtensions) {
6836   v8::HandleScope handle_scope(CcTest::isolate());
6837   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6838   extension->set_auto_enable(true);
6839   v8::RegisterExtension(extension);
6840   v8::Handle<Context> context =
6841       Context::New(CcTest::isolate());
6842   Context::Scope lock(context);
6843   v8::Handle<Value> result = CompileRun("Foo()");
6844   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6845 }
6846
6847
6848 static const char* kSyntaxErrorInExtensionSource =
6849     "[";
6850
6851
6852 // Test that a syntax error in an extension does not cause a fatal
6853 // error but results in an empty context.
6854 TEST(SyntaxErrorExtensions) {
6855   v8::HandleScope handle_scope(CcTest::isolate());
6856   v8::RegisterExtension(new Extension("syntaxerror",
6857                                       kSyntaxErrorInExtensionSource));
6858   const char* extension_names[] = { "syntaxerror" };
6859   v8::ExtensionConfiguration extensions(1, extension_names);
6860   v8::Handle<Context> context =
6861       Context::New(CcTest::isolate(), &extensions);
6862   CHECK(context.IsEmpty());
6863 }
6864
6865
6866 static const char* kExceptionInExtensionSource =
6867     "throw 42";
6868
6869
6870 // Test that an exception when installing an extension does not cause
6871 // a fatal error but results in an empty context.
6872 TEST(ExceptionExtensions) {
6873   v8::HandleScope handle_scope(CcTest::isolate());
6874   v8::RegisterExtension(new Extension("exception",
6875                                       kExceptionInExtensionSource));
6876   const char* extension_names[] = { "exception" };
6877   v8::ExtensionConfiguration extensions(1, extension_names);
6878   v8::Handle<Context> context =
6879       Context::New(CcTest::isolate(), &extensions);
6880   CHECK(context.IsEmpty());
6881 }
6882
6883
6884 static const char* kNativeCallInExtensionSource =
6885     "function call_runtime_last_index_of(x) {"
6886     "  return %StringLastIndexOf(x, 'bob', 10);"
6887     "}";
6888
6889
6890 static const char* kNativeCallTest =
6891     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6892
6893 // Test that a native runtime calls are supported in extensions.
6894 TEST(NativeCallInExtensions) {
6895   v8::HandleScope handle_scope(CcTest::isolate());
6896   v8::RegisterExtension(new Extension("nativecall",
6897                                       kNativeCallInExtensionSource));
6898   const char* extension_names[] = { "nativecall" };
6899   v8::ExtensionConfiguration extensions(1, extension_names);
6900   v8::Handle<Context> context =
6901       Context::New(CcTest::isolate(), &extensions);
6902   Context::Scope lock(context);
6903   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6904   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6905 }
6906
6907
6908 class NativeFunctionExtension : public Extension {
6909  public:
6910   NativeFunctionExtension(const char* name,
6911                           const char* source,
6912                           v8::FunctionCallback fun = &Echo)
6913       : Extension(name, source),
6914         function_(fun) { }
6915
6916   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6917       v8::Isolate* isolate,
6918       v8::Handle<v8::String> name) {
6919     return v8::FunctionTemplate::New(isolate, function_);
6920   }
6921
6922   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6923     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6924   }
6925  private:
6926   v8::FunctionCallback function_;
6927 };
6928
6929
6930 TEST(NativeFunctionDeclaration) {
6931   v8::HandleScope handle_scope(CcTest::isolate());
6932   const char* name = "nativedecl";
6933   v8::RegisterExtension(new NativeFunctionExtension(name,
6934                                                     "native function foo();"));
6935   const char* extension_names[] = { name };
6936   v8::ExtensionConfiguration extensions(1, extension_names);
6937   v8::Handle<Context> context =
6938       Context::New(CcTest::isolate(), &extensions);
6939   Context::Scope lock(context);
6940   v8::Handle<Value> result = CompileRun("foo(42);");
6941   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6942 }
6943
6944
6945 TEST(NativeFunctionDeclarationError) {
6946   v8::HandleScope handle_scope(CcTest::isolate());
6947   const char* name = "nativedeclerr";
6948   // Syntax error in extension code.
6949   v8::RegisterExtension(new NativeFunctionExtension(name,
6950                                                     "native\nfunction foo();"));
6951   const char* extension_names[] = { name };
6952   v8::ExtensionConfiguration extensions(1, extension_names);
6953   v8::Handle<Context> context =
6954       Context::New(CcTest::isolate(), &extensions);
6955   CHECK(context.IsEmpty());
6956 }
6957
6958
6959 TEST(NativeFunctionDeclarationErrorEscape) {
6960   v8::HandleScope handle_scope(CcTest::isolate());
6961   const char* name = "nativedeclerresc";
6962   // Syntax error in extension code - escape code in "native" means that
6963   // it's not treated as a keyword.
6964   v8::RegisterExtension(new NativeFunctionExtension(
6965       name,
6966       "nativ\\u0065 function foo();"));
6967   const char* extension_names[] = { name };
6968   v8::ExtensionConfiguration extensions(1, extension_names);
6969   v8::Handle<Context> context =
6970       Context::New(CcTest::isolate(), &extensions);
6971   CHECK(context.IsEmpty());
6972 }
6973
6974
6975 static void CheckDependencies(const char* name, const char* expected) {
6976   v8::HandleScope handle_scope(CcTest::isolate());
6977   v8::ExtensionConfiguration config(1, &name);
6978   LocalContext context(&config);
6979   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6980            context->Global()->Get(v8_str("loaded")));
6981 }
6982
6983
6984 /*
6985  * Configuration:
6986  *
6987  *     /-- B <--\
6988  * A <-          -- D <-- E
6989  *     \-- C <--/
6990  */
6991 THREADED_TEST(ExtensionDependency) {
6992   static const char* kEDeps[] = { "D" };
6993   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6994   static const char* kDDeps[] = { "B", "C" };
6995   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6996   static const char* kBCDeps[] = { "A" };
6997   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6998   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6999   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7000   CheckDependencies("A", "undefinedA");
7001   CheckDependencies("B", "undefinedAB");
7002   CheckDependencies("C", "undefinedAC");
7003   CheckDependencies("D", "undefinedABCD");
7004   CheckDependencies("E", "undefinedABCDE");
7005   v8::HandleScope handle_scope(CcTest::isolate());
7006   static const char* exts[2] = { "C", "E" };
7007   v8::ExtensionConfiguration config(2, exts);
7008   LocalContext context(&config);
7009   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7010 }
7011
7012
7013 static const char* kExtensionTestScript =
7014   "native function A();"
7015   "native function B();"
7016   "native function C();"
7017   "function Foo(i) {"
7018   "  if (i == 0) return A();"
7019   "  if (i == 1) return B();"
7020   "  if (i == 2) return C();"
7021   "}";
7022
7023
7024 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7025   ApiTestFuzzer::Fuzz();
7026   if (args.IsConstructCall()) {
7027     args.This()->Set(v8_str("data"), args.Data());
7028     args.GetReturnValue().SetNull();
7029     return;
7030   }
7031   args.GetReturnValue().Set(args.Data());
7032 }
7033
7034
7035 class FunctionExtension : public Extension {
7036  public:
7037   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7038   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7039       v8::Isolate* isolate,
7040       v8::Handle<String> name);
7041 };
7042
7043
7044 static int lookup_count = 0;
7045 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7046     v8::Isolate* isolate, v8::Handle<String> name) {
7047   lookup_count++;
7048   if (name->Equals(v8_str("A"))) {
7049     return v8::FunctionTemplate::New(
7050         isolate, CallFun, v8::Integer::New(isolate, 8));
7051   } else if (name->Equals(v8_str("B"))) {
7052     return v8::FunctionTemplate::New(
7053         isolate, CallFun, v8::Integer::New(isolate, 7));
7054   } else if (name->Equals(v8_str("C"))) {
7055     return v8::FunctionTemplate::New(
7056         isolate, CallFun, v8::Integer::New(isolate, 6));
7057   } else {
7058     return v8::Handle<v8::FunctionTemplate>();
7059   }
7060 }
7061
7062
7063 THREADED_TEST(FunctionLookup) {
7064   v8::RegisterExtension(new FunctionExtension());
7065   v8::HandleScope handle_scope(CcTest::isolate());
7066   static const char* exts[1] = { "functiontest" };
7067   v8::ExtensionConfiguration config(1, exts);
7068   LocalContext context(&config);
7069   CHECK_EQ(3, lookup_count);
7070   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7071            CompileRun("Foo(0)"));
7072   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7073            CompileRun("Foo(1)"));
7074   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7075            CompileRun("Foo(2)"));
7076 }
7077
7078
7079 THREADED_TEST(NativeFunctionConstructCall) {
7080   v8::RegisterExtension(new FunctionExtension());
7081   v8::HandleScope handle_scope(CcTest::isolate());
7082   static const char* exts[1] = { "functiontest" };
7083   v8::ExtensionConfiguration config(1, exts);
7084   LocalContext context(&config);
7085   for (int i = 0; i < 10; i++) {
7086     // Run a few times to ensure that allocation of objects doesn't
7087     // change behavior of a constructor function.
7088     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7089              CompileRun("(new A()).data"));
7090     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7091              CompileRun("(new B()).data"));
7092     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7093              CompileRun("(new C()).data"));
7094   }
7095 }
7096
7097
7098 static const char* last_location;
7099 static const char* last_message;
7100 void StoringErrorCallback(const char* location, const char* message) {
7101   if (last_location == NULL) {
7102     last_location = location;
7103     last_message = message;
7104   }
7105 }
7106
7107
7108 // ErrorReporting creates a circular extensions configuration and
7109 // tests that the fatal error handler gets called.  This renders V8
7110 // unusable and therefore this test cannot be run in parallel.
7111 TEST(ErrorReporting) {
7112   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7113   static const char* aDeps[] = { "B" };
7114   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7115   static const char* bDeps[] = { "A" };
7116   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7117   last_location = NULL;
7118   v8::ExtensionConfiguration config(1, bDeps);
7119   v8::Handle<Context> context =
7120       Context::New(CcTest::isolate(), &config);
7121   CHECK(context.IsEmpty());
7122   CHECK_NE(last_location, NULL);
7123 }
7124
7125
7126 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7127                                              v8::Handle<Value> data) {
7128   CHECK(message->GetScriptResourceName()->IsUndefined());
7129   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7130   message->GetLineNumber();
7131   message->GetSourceLine();
7132 }
7133
7134
7135 THREADED_TEST(ErrorWithMissingScriptInfo) {
7136   LocalContext context;
7137   v8::HandleScope scope(context->GetIsolate());
7138   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7139   CompileRun("throw Error()");
7140   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7141 }
7142
7143
7144 struct FlagAndPersistent {
7145   bool flag;
7146   v8::Persistent<v8::Object> handle;
7147 };
7148
7149
7150 static void DisposeAndSetFlag(
7151     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7152   data.GetParameter()->handle.Reset();
7153   data.GetParameter()->flag = true;
7154 }
7155
7156
7157 THREADED_TEST(IndependentWeakHandle) {
7158   v8::Isolate* iso = CcTest::isolate();
7159   v8::HandleScope scope(iso);
7160   v8::Handle<Context> context = Context::New(iso);
7161   Context::Scope context_scope(context);
7162
7163   FlagAndPersistent object_a, object_b;
7164
7165   {
7166     v8::HandleScope handle_scope(iso);
7167     object_a.handle.Reset(iso, v8::Object::New(iso));
7168     object_b.handle.Reset(iso, v8::Object::New(iso));
7169   }
7170
7171   object_a.flag = false;
7172   object_b.flag = false;
7173   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7174   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7175   CHECK(!object_b.handle.IsIndependent());
7176   object_a.handle.MarkIndependent();
7177   object_b.handle.MarkIndependent();
7178   CHECK(object_b.handle.IsIndependent());
7179   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7180   CHECK(object_a.flag);
7181   CHECK(object_b.flag);
7182 }
7183
7184
7185 static void InvokeScavenge() {
7186   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7187 }
7188
7189
7190 static void InvokeMarkSweep() {
7191   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7192 }
7193
7194
7195 static void ForceScavenge(
7196     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7197   data.GetParameter()->handle.Reset();
7198   data.GetParameter()->flag = true;
7199   InvokeScavenge();
7200 }
7201
7202
7203 static void ForceMarkSweep(
7204     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7205   data.GetParameter()->handle.Reset();
7206   data.GetParameter()->flag = true;
7207   InvokeMarkSweep();
7208 }
7209
7210
7211 THREADED_TEST(GCFromWeakCallbacks) {
7212   v8::Isolate* isolate = CcTest::isolate();
7213   v8::HandleScope scope(isolate);
7214   v8::Handle<Context> context = Context::New(isolate);
7215   Context::Scope context_scope(context);
7216
7217   static const int kNumberOfGCTypes = 2;
7218   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7219       Callback;
7220   Callback gc_forcing_callback[kNumberOfGCTypes] =
7221       {&ForceScavenge, &ForceMarkSweep};
7222
7223   typedef void (*GCInvoker)();
7224   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7225
7226   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7227     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7228       FlagAndPersistent object;
7229       {
7230         v8::HandleScope handle_scope(isolate);
7231         object.handle.Reset(isolate, v8::Object::New(isolate));
7232       }
7233       object.flag = false;
7234       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7235       object.handle.MarkIndependent();
7236       invoke_gc[outer_gc]();
7237       CHECK(object.flag);
7238     }
7239   }
7240 }
7241
7242
7243 static void RevivingCallback(
7244     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7245   data.GetParameter()->handle.ClearWeak();
7246   data.GetParameter()->flag = true;
7247 }
7248
7249
7250 THREADED_TEST(IndependentHandleRevival) {
7251   v8::Isolate* isolate = CcTest::isolate();
7252   v8::HandleScope scope(isolate);
7253   v8::Handle<Context> context = Context::New(isolate);
7254   Context::Scope context_scope(context);
7255
7256   FlagAndPersistent object;
7257   {
7258     v8::HandleScope handle_scope(isolate);
7259     v8::Local<v8::Object> o = v8::Object::New(isolate);
7260     object.handle.Reset(isolate, o);
7261     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7262     v8::Local<String> y_str = v8_str("y");
7263     o->Set(y_str, y_str);
7264   }
7265   object.flag = false;
7266   object.handle.SetWeak(&object, &RevivingCallback);
7267   object.handle.MarkIndependent();
7268   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7269   CHECK(object.flag);
7270   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7271   {
7272     v8::HandleScope handle_scope(isolate);
7273     v8::Local<v8::Object> o =
7274         v8::Local<v8::Object>::New(isolate, object.handle);
7275     v8::Local<String> y_str = v8_str("y");
7276     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7277     CHECK(o->Get(y_str)->Equals(y_str));
7278   }
7279 }
7280
7281
7282 v8::Handle<Function> args_fun;
7283
7284
7285 static void ArgumentsTestCallback(
7286     const v8::FunctionCallbackInfo<v8::Value>& args) {
7287   ApiTestFuzzer::Fuzz();
7288   v8::Isolate* isolate = args.GetIsolate();
7289   CHECK_EQ(args_fun, args.Callee());
7290   CHECK_EQ(3, args.Length());
7291   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7292   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7293   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7294   CHECK_EQ(v8::Undefined(isolate), args[3]);
7295   v8::HandleScope scope(args.GetIsolate());
7296   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7297 }
7298
7299
7300 THREADED_TEST(Arguments) {
7301   v8::Isolate* isolate = CcTest::isolate();
7302   v8::HandleScope scope(isolate);
7303   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7304   global->Set(v8_str("f"),
7305               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7306   LocalContext context(NULL, global);
7307   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7308   v8_compile("f(1, 2, 3)")->Run();
7309 }
7310
7311
7312 static void NoBlockGetterX(Local<String> name,
7313                            const v8::PropertyCallbackInfo<v8::Value>&) {
7314 }
7315
7316
7317 static void NoBlockGetterI(uint32_t index,
7318                            const v8::PropertyCallbackInfo<v8::Value>&) {
7319 }
7320
7321
7322 static void PDeleter(Local<String> name,
7323                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7324   if (!name->Equals(v8_str("foo"))) {
7325     return;  // not intercepted
7326   }
7327
7328   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7329 }
7330
7331
7332 static void IDeleter(uint32_t index,
7333                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7334   if (index != 2) {
7335     return;  // not intercepted
7336   }
7337
7338   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7339 }
7340
7341
7342 THREADED_TEST(Deleter) {
7343   v8::Isolate* isolate = CcTest::isolate();
7344   v8::HandleScope scope(isolate);
7345   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7346   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7347   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7348   LocalContext context;
7349   context->Global()->Set(v8_str("k"), obj->NewInstance());
7350   CompileRun(
7351     "k.foo = 'foo';"
7352     "k.bar = 'bar';"
7353     "k[2] = 2;"
7354     "k[4] = 4;");
7355   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7356   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7357
7358   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7359   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7360
7361   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7362   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7363
7364   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7365   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7366 }
7367
7368
7369 static void GetK(Local<String> name,
7370                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7371   ApiTestFuzzer::Fuzz();
7372   if (name->Equals(v8_str("foo")) ||
7373       name->Equals(v8_str("bar")) ||
7374       name->Equals(v8_str("baz"))) {
7375     info.GetReturnValue().SetUndefined();
7376   }
7377 }
7378
7379
7380 static void IndexedGetK(uint32_t index,
7381                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7382   ApiTestFuzzer::Fuzz();
7383   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7384 }
7385
7386
7387 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7388   ApiTestFuzzer::Fuzz();
7389   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7390   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7391   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7392   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7393   info.GetReturnValue().Set(result);
7394 }
7395
7396
7397 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7398   ApiTestFuzzer::Fuzz();
7399   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7400   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7401   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7402   info.GetReturnValue().Set(result);
7403 }
7404
7405
7406 THREADED_TEST(Enumerators) {
7407   v8::Isolate* isolate = CcTest::isolate();
7408   v8::HandleScope scope(isolate);
7409   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7410   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7411   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7412   LocalContext context;
7413   context->Global()->Set(v8_str("k"), obj->NewInstance());
7414   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7415     "k[10] = 0;"
7416     "k.a = 0;"
7417     "k[5] = 0;"
7418     "k.b = 0;"
7419     "k[4294967295] = 0;"
7420     "k.c = 0;"
7421     "k[4294967296] = 0;"
7422     "k.d = 0;"
7423     "k[140000] = 0;"
7424     "k.e = 0;"
7425     "k[30000000000] = 0;"
7426     "k.f = 0;"
7427     "var result = [];"
7428     "for (var prop in k) {"
7429     "  result.push(prop);"
7430     "}"
7431     "result"));
7432   // Check that we get all the property names returned including the
7433   // ones from the enumerators in the right order: indexed properties
7434   // in numerical order, indexed interceptor properties, named
7435   // properties in insertion order, named interceptor properties.
7436   // This order is not mandated by the spec, so this test is just
7437   // documenting our behavior.
7438   CHECK_EQ(17, result->Length());
7439   // Indexed properties in numerical order.
7440   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7441   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7442   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7443   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7444   // Indexed interceptor properties in the order they are returned
7445   // from the enumerator interceptor.
7446   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7447   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7448   // Named properties in insertion order.
7449   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7450   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7451   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7452   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7453   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7454   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7455   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7456   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7457   // Named interceptor properties.
7458   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7459   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7460   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7461 }
7462
7463
7464 int p_getter_count;
7465 int p_getter_count2;
7466
7467
7468 static void PGetter(Local<String> name,
7469                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7470   ApiTestFuzzer::Fuzz();
7471   p_getter_count++;
7472   v8::Handle<v8::Object> global =
7473       info.GetIsolate()->GetCurrentContext()->Global();
7474   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7475   if (name->Equals(v8_str("p1"))) {
7476     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7477   } else if (name->Equals(v8_str("p2"))) {
7478     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7479   } else if (name->Equals(v8_str("p3"))) {
7480     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7481   } else if (name->Equals(v8_str("p4"))) {
7482     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7483   }
7484 }
7485
7486
7487 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7488   ApiTestFuzzer::Fuzz();
7489   LocalContext context;
7490   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7491   CompileRun(
7492     "o1.__proto__ = { };"
7493     "var o2 = { __proto__: o1 };"
7494     "var o3 = { __proto__: o2 };"
7495     "var o4 = { __proto__: o3 };"
7496     "for (var i = 0; i < 10; i++) o4.p4;"
7497     "for (var i = 0; i < 10; i++) o3.p3;"
7498     "for (var i = 0; i < 10; i++) o2.p2;"
7499     "for (var i = 0; i < 10; i++) o1.p1;");
7500 }
7501
7502
7503 static void PGetter2(Local<String> name,
7504                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7505   ApiTestFuzzer::Fuzz();
7506   p_getter_count2++;
7507   v8::Handle<v8::Object> global =
7508       info.GetIsolate()->GetCurrentContext()->Global();
7509   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7510   if (name->Equals(v8_str("p1"))) {
7511     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7512   } else if (name->Equals(v8_str("p2"))) {
7513     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7514   } else if (name->Equals(v8_str("p3"))) {
7515     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7516   } else if (name->Equals(v8_str("p4"))) {
7517     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7518   }
7519 }
7520
7521
7522 THREADED_TEST(GetterHolders) {
7523   v8::Isolate* isolate = CcTest::isolate();
7524   v8::HandleScope scope(isolate);
7525   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7526   obj->SetAccessor(v8_str("p1"), PGetter);
7527   obj->SetAccessor(v8_str("p2"), PGetter);
7528   obj->SetAccessor(v8_str("p3"), PGetter);
7529   obj->SetAccessor(v8_str("p4"), PGetter);
7530   p_getter_count = 0;
7531   RunHolderTest(obj);
7532   CHECK_EQ(40, p_getter_count);
7533 }
7534
7535
7536 THREADED_TEST(PreInterceptorHolders) {
7537   v8::Isolate* isolate = CcTest::isolate();
7538   v8::HandleScope scope(isolate);
7539   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7540   obj->SetNamedPropertyHandler(PGetter2);
7541   p_getter_count2 = 0;
7542   RunHolderTest(obj);
7543   CHECK_EQ(40, p_getter_count2);
7544 }
7545
7546
7547 THREADED_TEST(ObjectInstantiation) {
7548   v8::Isolate* isolate = CcTest::isolate();
7549   v8::HandleScope scope(isolate);
7550   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7551   templ->SetAccessor(v8_str("t"), PGetter2);
7552   LocalContext context;
7553   context->Global()->Set(v8_str("o"), templ->NewInstance());
7554   for (int i = 0; i < 100; i++) {
7555     v8::HandleScope inner_scope(CcTest::isolate());
7556     v8::Handle<v8::Object> obj = templ->NewInstance();
7557     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7558     context->Global()->Set(v8_str("o2"), obj);
7559     v8::Handle<Value> value =
7560         CompileRun("o.__proto__ === o2.__proto__");
7561     CHECK_EQ(v8::True(isolate), value);
7562     context->Global()->Set(v8_str("o"), obj);
7563   }
7564 }
7565
7566
7567 static int StrCmp16(uint16_t* a, uint16_t* b) {
7568   while (true) {
7569     if (*a == 0 && *b == 0) return 0;
7570     if (*a != *b) return 0 + *a - *b;
7571     a++;
7572     b++;
7573   }
7574 }
7575
7576
7577 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7578   while (true) {
7579     if (n-- == 0) return 0;
7580     if (*a == 0 && *b == 0) return 0;
7581     if (*a != *b) return 0 + *a - *b;
7582     a++;
7583     b++;
7584   }
7585 }
7586
7587
7588 int GetUtf8Length(Handle<String> str) {
7589   int len = str->Utf8Length();
7590   if (len < 0) {
7591     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7592     i::String::Flatten(istr);
7593     len = str->Utf8Length();
7594   }
7595   return len;
7596 }
7597
7598
7599 THREADED_TEST(StringWrite) {
7600   LocalContext context;
7601   v8::HandleScope scope(context->GetIsolate());
7602   v8::Handle<String> str = v8_str("abcde");
7603   // abc<Icelandic eth><Unicode snowman>.
7604   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7605   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7606       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7607   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7608   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7609   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7610       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7611   // single lead surrogate
7612   uint16_t lead[1] = { 0xd800 };
7613   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7614       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7615   // single trail surrogate
7616   uint16_t trail[1] = { 0xdc00 };
7617   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7618       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7619   // surrogate pair
7620   uint16_t pair[2] = { 0xd800,  0xdc00 };
7621   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7622       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7623   const int kStride = 4;  // Must match stride in for loops in JS below.
7624   CompileRun(
7625       "var left = '';"
7626       "for (var i = 0; i < 0xd800; i += 4) {"
7627       "  left = left + String.fromCharCode(i);"
7628       "}");
7629   CompileRun(
7630       "var right = '';"
7631       "for (var i = 0; i < 0xd800; i += 4) {"
7632       "  right = String.fromCharCode(i) + right;"
7633       "}");
7634   v8::Handle<v8::Object> global = context->Global();
7635   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7636   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7637
7638   CHECK_EQ(5, str2->Length());
7639   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7640   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7641
7642   char buf[100];
7643   char utf8buf[0xd800 * 3];
7644   uint16_t wbuf[100];
7645   int len;
7646   int charlen;
7647
7648   memset(utf8buf, 0x1, 1000);
7649   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7650   CHECK_EQ(9, len);
7651   CHECK_EQ(5, charlen);
7652   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7653
7654   memset(utf8buf, 0x1, 1000);
7655   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7656   CHECK_EQ(8, len);
7657   CHECK_EQ(5, charlen);
7658   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7659
7660   memset(utf8buf, 0x1, 1000);
7661   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7662   CHECK_EQ(5, len);
7663   CHECK_EQ(4, charlen);
7664   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7665
7666   memset(utf8buf, 0x1, 1000);
7667   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7668   CHECK_EQ(5, len);
7669   CHECK_EQ(4, charlen);
7670   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7671
7672   memset(utf8buf, 0x1, 1000);
7673   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7674   CHECK_EQ(5, len);
7675   CHECK_EQ(4, charlen);
7676   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7677
7678   memset(utf8buf, 0x1, 1000);
7679   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7680   CHECK_EQ(3, len);
7681   CHECK_EQ(3, charlen);
7682   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7683
7684   memset(utf8buf, 0x1, 1000);
7685   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7686   CHECK_EQ(3, len);
7687   CHECK_EQ(3, charlen);
7688   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7689
7690   memset(utf8buf, 0x1, 1000);
7691   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7692   CHECK_EQ(2, len);
7693   CHECK_EQ(2, charlen);
7694   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7695
7696   // allow orphan surrogates by default
7697   memset(utf8buf, 0x1, 1000);
7698   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7699   CHECK_EQ(13, len);
7700   CHECK_EQ(8, charlen);
7701   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7702
7703   // replace orphan surrogates with unicode replacement character
7704   memset(utf8buf, 0x1, 1000);
7705   len = orphans_str->WriteUtf8(utf8buf,
7706                                sizeof(utf8buf),
7707                                &charlen,
7708                                String::REPLACE_INVALID_UTF8);
7709   CHECK_EQ(13, len);
7710   CHECK_EQ(8, charlen);
7711   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7712
7713   // replace single lead surrogate with unicode replacement character
7714   memset(utf8buf, 0x1, 1000);
7715   len = lead_str->WriteUtf8(utf8buf,
7716                             sizeof(utf8buf),
7717                             &charlen,
7718                             String::REPLACE_INVALID_UTF8);
7719   CHECK_EQ(4, len);
7720   CHECK_EQ(1, charlen);
7721   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7722
7723   // replace single trail surrogate with unicode replacement character
7724   memset(utf8buf, 0x1, 1000);
7725   len = trail_str->WriteUtf8(utf8buf,
7726                              sizeof(utf8buf),
7727                              &charlen,
7728                              String::REPLACE_INVALID_UTF8);
7729   CHECK_EQ(4, len);
7730   CHECK_EQ(1, charlen);
7731   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7732
7733   // do not replace / write anything if surrogate pair does not fit the buffer
7734   // space
7735   memset(utf8buf, 0x1, 1000);
7736   len = pair_str->WriteUtf8(utf8buf,
7737                              3,
7738                              &charlen,
7739                              String::REPLACE_INVALID_UTF8);
7740   CHECK_EQ(0, len);
7741   CHECK_EQ(0, charlen);
7742
7743   memset(utf8buf, 0x1, sizeof(utf8buf));
7744   len = GetUtf8Length(left_tree);
7745   int utf8_expected =
7746       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7747   CHECK_EQ(utf8_expected, len);
7748   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7749   CHECK_EQ(utf8_expected, len);
7750   CHECK_EQ(0xd800 / kStride, charlen);
7751   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7752   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7753   CHECK_EQ(0xc0 - kStride,
7754            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7755   CHECK_EQ(1, utf8buf[utf8_expected]);
7756
7757   memset(utf8buf, 0x1, sizeof(utf8buf));
7758   len = GetUtf8Length(right_tree);
7759   CHECK_EQ(utf8_expected, len);
7760   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7761   CHECK_EQ(utf8_expected, len);
7762   CHECK_EQ(0xd800 / kStride, charlen);
7763   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7764   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7765   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7766   CHECK_EQ(1, utf8buf[utf8_expected]);
7767
7768   memset(buf, 0x1, sizeof(buf));
7769   memset(wbuf, 0x1, sizeof(wbuf));
7770   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7771   CHECK_EQ(5, len);
7772   len = str->Write(wbuf);
7773   CHECK_EQ(5, len);
7774   CHECK_EQ(0, strcmp("abcde", buf));
7775   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7776   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7777
7778   memset(buf, 0x1, sizeof(buf));
7779   memset(wbuf, 0x1, sizeof(wbuf));
7780   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7781   CHECK_EQ(4, len);
7782   len = str->Write(wbuf, 0, 4);
7783   CHECK_EQ(4, len);
7784   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7785   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7786   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7787
7788   memset(buf, 0x1, sizeof(buf));
7789   memset(wbuf, 0x1, sizeof(wbuf));
7790   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7791   CHECK_EQ(5, len);
7792   len = str->Write(wbuf, 0, 5);
7793   CHECK_EQ(5, len);
7794   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7795   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7796   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7797
7798   memset(buf, 0x1, sizeof(buf));
7799   memset(wbuf, 0x1, sizeof(wbuf));
7800   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7801   CHECK_EQ(5, len);
7802   len = str->Write(wbuf, 0, 6);
7803   CHECK_EQ(5, len);
7804   CHECK_EQ(0, strcmp("abcde", buf));
7805   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7806   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7807
7808   memset(buf, 0x1, sizeof(buf));
7809   memset(wbuf, 0x1, sizeof(wbuf));
7810   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7811   CHECK_EQ(1, len);
7812   len = str->Write(wbuf, 4, -1);
7813   CHECK_EQ(1, len);
7814   CHECK_EQ(0, strcmp("e", buf));
7815   uint16_t answer5[] = {'e', '\0'};
7816   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7817
7818   memset(buf, 0x1, sizeof(buf));
7819   memset(wbuf, 0x1, sizeof(wbuf));
7820   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7821   CHECK_EQ(1, len);
7822   len = str->Write(wbuf, 4, 6);
7823   CHECK_EQ(1, len);
7824   CHECK_EQ(0, strcmp("e", buf));
7825   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7826
7827   memset(buf, 0x1, sizeof(buf));
7828   memset(wbuf, 0x1, sizeof(wbuf));
7829   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7830   CHECK_EQ(1, len);
7831   len = str->Write(wbuf, 4, 1);
7832   CHECK_EQ(1, len);
7833   CHECK_EQ(0, strncmp("e\1", buf, 2));
7834   uint16_t answer6[] = {'e', 0x101};
7835   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7836
7837   memset(buf, 0x1, sizeof(buf));
7838   memset(wbuf, 0x1, sizeof(wbuf));
7839   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7840   CHECK_EQ(1, len);
7841   len = str->Write(wbuf, 3, 1);
7842   CHECK_EQ(1, len);
7843   CHECK_EQ(0, strncmp("d\1", buf, 2));
7844   uint16_t answer7[] = {'d', 0x101};
7845   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7846
7847   memset(wbuf, 0x1, sizeof(wbuf));
7848   wbuf[5] = 'X';
7849   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7850   CHECK_EQ(5, len);
7851   CHECK_EQ('X', wbuf[5]);
7852   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7853   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7854   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7855   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7856   wbuf[5] = '\0';
7857   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7858
7859   memset(buf, 0x1, sizeof(buf));
7860   buf[5] = 'X';
7861   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7862                           0,
7863                           6,
7864                           String::NO_NULL_TERMINATION);
7865   CHECK_EQ(5, len);
7866   CHECK_EQ('X', buf[5]);
7867   CHECK_EQ(0, strncmp("abcde", buf, 5));
7868   CHECK_NE(0, strcmp("abcde", buf));
7869   buf[5] = '\0';
7870   CHECK_EQ(0, strcmp("abcde", buf));
7871
7872   memset(utf8buf, 0x1, sizeof(utf8buf));
7873   utf8buf[8] = 'X';
7874   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7875                         String::NO_NULL_TERMINATION);
7876   CHECK_EQ(8, len);
7877   CHECK_EQ('X', utf8buf[8]);
7878   CHECK_EQ(5, charlen);
7879   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7880   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7881   utf8buf[8] = '\0';
7882   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7883
7884   memset(utf8buf, 0x1, sizeof(utf8buf));
7885   utf8buf[5] = 'X';
7886   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7887                         String::NO_NULL_TERMINATION);
7888   CHECK_EQ(5, len);
7889   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7890   CHECK_EQ(5, charlen);
7891   utf8buf[5] = '\0';
7892   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7893
7894   memset(buf, 0x1, sizeof(buf));
7895   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7896   CHECK_EQ(7, len);
7897   CHECK_EQ(0, strcmp("abc", buf));
7898   CHECK_EQ(0, buf[3]);
7899   CHECK_EQ(0, strcmp("def", buf + 4));
7900
7901   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7902   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7903   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7904 }
7905
7906
7907 static void Utf16Helper(
7908     LocalContext& context,
7909     const char* name,
7910     const char* lengths_name,
7911     int len) {
7912   Local<v8::Array> a =
7913       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7914   Local<v8::Array> alens =
7915       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7916   for (int i = 0; i < len; i++) {
7917     Local<v8::String> string =
7918       Local<v8::String>::Cast(a->Get(i));
7919     Local<v8::Number> expected_len =
7920       Local<v8::Number>::Cast(alens->Get(i));
7921     int length = GetUtf8Length(string);
7922     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7923   }
7924 }
7925
7926
7927 static uint16_t StringGet(Handle<String> str, int index) {
7928   i::Handle<i::String> istring =
7929       v8::Utils::OpenHandle(String::Cast(*str));
7930   return istring->Get(index);
7931 }
7932
7933
7934 static void WriteUtf8Helper(
7935     LocalContext& context,
7936     const char* name,
7937     const char* lengths_name,
7938     int len) {
7939   Local<v8::Array> b =
7940       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7941   Local<v8::Array> alens =
7942       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7943   char buffer[1000];
7944   char buffer2[1000];
7945   for (int i = 0; i < len; i++) {
7946     Local<v8::String> string =
7947       Local<v8::String>::Cast(b->Get(i));
7948     Local<v8::Number> expected_len =
7949       Local<v8::Number>::Cast(alens->Get(i));
7950     int utf8_length = static_cast<int>(expected_len->Value());
7951     for (int j = utf8_length + 1; j >= 0; j--) {
7952       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7953       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7954       int nchars;
7955       int utf8_written =
7956           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7957       int utf8_written2 =
7958           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7959       CHECK_GE(utf8_length + 1, utf8_written);
7960       CHECK_GE(utf8_length, utf8_written2);
7961       for (int k = 0; k < utf8_written2; k++) {
7962         CHECK_EQ(buffer[k], buffer2[k]);
7963       }
7964       CHECK(nchars * 3 >= utf8_written - 1);
7965       CHECK(nchars <= utf8_written);
7966       if (j == utf8_length + 1) {
7967         CHECK_EQ(utf8_written2, utf8_length);
7968         CHECK_EQ(utf8_written2 + 1, utf8_written);
7969       }
7970       CHECK_EQ(buffer[utf8_written], 42);
7971       if (j > utf8_length) {
7972         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7973         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7974         Handle<String> roundtrip = v8_str(buffer);
7975         CHECK(roundtrip->Equals(string));
7976       } else {
7977         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7978       }
7979       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7980       if (nchars >= 2) {
7981         uint16_t trail = StringGet(string, nchars - 1);
7982         uint16_t lead = StringGet(string, nchars - 2);
7983         if (((lead & 0xfc00) == 0xd800) &&
7984             ((trail & 0xfc00) == 0xdc00)) {
7985           unsigned char u1 = buffer2[utf8_written2 - 4];
7986           unsigned char u2 = buffer2[utf8_written2 - 3];
7987           unsigned char u3 = buffer2[utf8_written2 - 2];
7988           unsigned char u4 = buffer2[utf8_written2 - 1];
7989           CHECK_EQ((u1 & 0xf8), 0xf0);
7990           CHECK_EQ((u2 & 0xc0), 0x80);
7991           CHECK_EQ((u3 & 0xc0), 0x80);
7992           CHECK_EQ((u4 & 0xc0), 0x80);
7993           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7994           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7995           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7996           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7997           CHECK_EQ((u1 & 0x3), c >> 18);
7998         }
7999       }
8000     }
8001   }
8002 }
8003
8004
8005 THREADED_TEST(Utf16) {
8006   LocalContext context;
8007   v8::HandleScope scope(context->GetIsolate());
8008   CompileRun(
8009       "var pad = '01234567890123456789';"
8010       "var p = [];"
8011       "var plens = [20, 3, 3];"
8012       "p.push('01234567890123456789');"
8013       "var lead = 0xd800;"
8014       "var trail = 0xdc00;"
8015       "p.push(String.fromCharCode(0xd800));"
8016       "p.push(String.fromCharCode(0xdc00));"
8017       "var a = [];"
8018       "var b = [];"
8019       "var c = [];"
8020       "var alens = [];"
8021       "for (var i = 0; i < 3; i++) {"
8022       "  p[1] = String.fromCharCode(lead++);"
8023       "  for (var j = 0; j < 3; j++) {"
8024       "    p[2] = String.fromCharCode(trail++);"
8025       "    a.push(p[i] + p[j]);"
8026       "    b.push(p[i] + p[j]);"
8027       "    c.push(p[i] + p[j]);"
8028       "    alens.push(plens[i] + plens[j]);"
8029       "  }"
8030       "}"
8031       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8032       "var a2 = [];"
8033       "var b2 = [];"
8034       "var c2 = [];"
8035       "var a2lens = [];"
8036       "for (var m = 0; m < 9; m++) {"
8037       "  for (var n = 0; n < 9; n++) {"
8038       "    a2.push(a[m] + a[n]);"
8039       "    b2.push(b[m] + b[n]);"
8040       "    var newc = 'x' + c[m] + c[n] + 'y';"
8041       "    c2.push(newc.substring(1, newc.length - 1));"
8042       "    var utf = alens[m] + alens[n];"  // And here.
8043            // The 'n's that start with 0xdc.. are 6-8
8044            // The 'm's that end with 0xd8.. are 1, 4 and 7
8045       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8046       "    a2lens.push(utf);"
8047       "  }"
8048       "}");
8049   Utf16Helper(context, "a", "alens", 9);
8050   Utf16Helper(context, "a2", "a2lens", 81);
8051   WriteUtf8Helper(context, "b", "alens", 9);
8052   WriteUtf8Helper(context, "b2", "a2lens", 81);
8053   WriteUtf8Helper(context, "c2", "a2lens", 81);
8054 }
8055
8056
8057 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8058   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8059   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8060   return *is1 == *is2;
8061 }
8062
8063 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8064                              const char* b) {
8065   Handle<String> symbol1 =
8066       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8067   Handle<String> symbol2 =
8068       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8069   CHECK(SameSymbol(symbol1, symbol2));
8070 }
8071
8072
8073 THREADED_TEST(Utf16Symbol) {
8074   LocalContext context;
8075   v8::HandleScope scope(context->GetIsolate());
8076
8077   Handle<String> symbol1 = v8::String::NewFromUtf8(
8078       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8079   Handle<String> symbol2 = v8::String::NewFromUtf8(
8080       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8081   CHECK(SameSymbol(symbol1, symbol2));
8082
8083   SameSymbolHelper(context->GetIsolate(),
8084                    "\360\220\220\205",  // 4 byte encoding.
8085                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8086   SameSymbolHelper(context->GetIsolate(),
8087                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8088                    "\360\220\220\206");  // 4 byte encoding.
8089   SameSymbolHelper(context->GetIsolate(),
8090                    "x\360\220\220\205",  // 4 byte encoding.
8091                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8092   SameSymbolHelper(context->GetIsolate(),
8093                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8094                    "x\360\220\220\206");  // 4 byte encoding.
8095   CompileRun(
8096       "var sym0 = 'benedictus';"
8097       "var sym0b = 'S\303\270ren';"
8098       "var sym1 = '\355\240\201\355\260\207';"
8099       "var sym2 = '\360\220\220\210';"
8100       "var sym3 = 'x\355\240\201\355\260\207';"
8101       "var sym4 = 'x\360\220\220\210';"
8102       "if (sym1.length != 2) throw sym1;"
8103       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8104       "if (sym2.length != 2) throw sym2;"
8105       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8106       "if (sym3.length != 3) throw sym3;"
8107       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8108       "if (sym4.length != 3) throw sym4;"
8109       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8110   Handle<String> sym0 = v8::String::NewFromUtf8(
8111       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8112   Handle<String> sym0b = v8::String::NewFromUtf8(
8113       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8114   Handle<String> sym1 =
8115       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8116                               v8::String::kInternalizedString);
8117   Handle<String> sym2 =
8118       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8119                               v8::String::kInternalizedString);
8120   Handle<String> sym3 = v8::String::NewFromUtf8(
8121       context->GetIsolate(), "x\355\240\201\355\260\207",
8122       v8::String::kInternalizedString);
8123   Handle<String> sym4 =
8124       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8125                               v8::String::kInternalizedString);
8126   v8::Local<v8::Object> global = context->Global();
8127   Local<Value> s0 = global->Get(v8_str("sym0"));
8128   Local<Value> s0b = global->Get(v8_str("sym0b"));
8129   Local<Value> s1 = global->Get(v8_str("sym1"));
8130   Local<Value> s2 = global->Get(v8_str("sym2"));
8131   Local<Value> s3 = global->Get(v8_str("sym3"));
8132   Local<Value> s4 = global->Get(v8_str("sym4"));
8133   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8134   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8135   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8136   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8137   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8138   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8139 }
8140
8141
8142 THREADED_TEST(ToArrayIndex) {
8143   LocalContext context;
8144   v8::Isolate* isolate = context->GetIsolate();
8145   v8::HandleScope scope(isolate);
8146
8147   v8::Handle<String> str = v8_str("42");
8148   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8149   CHECK(!index.IsEmpty());
8150   CHECK_EQ(42.0, index->Uint32Value());
8151   str = v8_str("42asdf");
8152   index = str->ToArrayIndex();
8153   CHECK(index.IsEmpty());
8154   str = v8_str("-42");
8155   index = str->ToArrayIndex();
8156   CHECK(index.IsEmpty());
8157   str = v8_str("4294967295");
8158   index = str->ToArrayIndex();
8159   CHECK(!index.IsEmpty());
8160   CHECK_EQ(4294967295.0, index->Uint32Value());
8161   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8162   index = num->ToArrayIndex();
8163   CHECK(!index.IsEmpty());
8164   CHECK_EQ(1.0, index->Uint32Value());
8165   num = v8::Number::New(isolate, -1);
8166   index = num->ToArrayIndex();
8167   CHECK(index.IsEmpty());
8168   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8169   index = obj->ToArrayIndex();
8170   CHECK(index.IsEmpty());
8171 }
8172
8173
8174 THREADED_TEST(ErrorConstruction) {
8175   LocalContext context;
8176   v8::HandleScope scope(context->GetIsolate());
8177
8178   v8::Handle<String> foo = v8_str("foo");
8179   v8::Handle<String> message = v8_str("message");
8180   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8181   CHECK(range_error->IsObject());
8182   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8183   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8184   CHECK(reference_error->IsObject());
8185   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8186   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8187   CHECK(syntax_error->IsObject());
8188   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8189   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8190   CHECK(type_error->IsObject());
8191   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8192   v8::Handle<Value> error = v8::Exception::Error(foo);
8193   CHECK(error->IsObject());
8194   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8195 }
8196
8197
8198 static void YGetter(Local<String> name,
8199                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8200   ApiTestFuzzer::Fuzz();
8201   info.GetReturnValue().Set(v8_num(10));
8202 }
8203
8204
8205 static void YSetter(Local<String> name,
8206                     Local<Value> value,
8207                     const v8::PropertyCallbackInfo<void>& info) {
8208   Local<Object> this_obj = Local<Object>::Cast(info.This());
8209   if (this_obj->Has(name)) this_obj->Delete(name);
8210   this_obj->Set(name, value);
8211 }
8212
8213
8214 THREADED_TEST(DeleteAccessor) {
8215   v8::Isolate* isolate = CcTest::isolate();
8216   v8::HandleScope scope(isolate);
8217   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8218   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8219   LocalContext context;
8220   v8::Handle<v8::Object> holder = obj->NewInstance();
8221   context->Global()->Set(v8_str("holder"), holder);
8222   v8::Handle<Value> result = CompileRun(
8223       "holder.y = 11; holder.y = 12; holder.y");
8224   CHECK_EQ(12, result->Uint32Value());
8225 }
8226
8227
8228 THREADED_TEST(TypeSwitch) {
8229   v8::Isolate* isolate = CcTest::isolate();
8230   v8::HandleScope scope(isolate);
8231   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8232   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8233   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8234   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8235   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8236   LocalContext context;
8237   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8238   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8239   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8240   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8241   for (int i = 0; i < 10; i++) {
8242     CHECK_EQ(0, type_switch->match(obj0));
8243     CHECK_EQ(1, type_switch->match(obj1));
8244     CHECK_EQ(2, type_switch->match(obj2));
8245     CHECK_EQ(3, type_switch->match(obj3));
8246     CHECK_EQ(3, type_switch->match(obj3));
8247     CHECK_EQ(2, type_switch->match(obj2));
8248     CHECK_EQ(1, type_switch->match(obj1));
8249     CHECK_EQ(0, type_switch->match(obj0));
8250   }
8251 }
8252
8253
8254 static int trouble_nesting = 0;
8255 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8256   ApiTestFuzzer::Fuzz();
8257   trouble_nesting++;
8258
8259   // Call a JS function that throws an uncaught exception.
8260   Local<v8::Object> arg_this =
8261       args.GetIsolate()->GetCurrentContext()->Global();
8262   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8263     arg_this->Get(v8_str("trouble_callee")) :
8264     arg_this->Get(v8_str("trouble_caller"));
8265   CHECK(trouble_callee->IsFunction());
8266   args.GetReturnValue().Set(
8267       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8268 }
8269
8270
8271 static int report_count = 0;
8272 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8273                                              v8::Handle<Value>) {
8274   report_count++;
8275 }
8276
8277
8278 // Counts uncaught exceptions, but other tests running in parallel
8279 // also have uncaught exceptions.
8280 TEST(ApiUncaughtException) {
8281   report_count = 0;
8282   LocalContext env;
8283   v8::Isolate* isolate = env->GetIsolate();
8284   v8::HandleScope scope(isolate);
8285   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8286
8287   Local<v8::FunctionTemplate> fun =
8288       v8::FunctionTemplate::New(isolate, TroubleCallback);
8289   v8::Local<v8::Object> global = env->Global();
8290   global->Set(v8_str("trouble"), fun->GetFunction());
8291
8292   CompileRun(
8293       "function trouble_callee() {"
8294       "  var x = null;"
8295       "  return x.foo;"
8296       "};"
8297       "function trouble_caller() {"
8298       "  trouble();"
8299       "};");
8300   Local<Value> trouble = global->Get(v8_str("trouble"));
8301   CHECK(trouble->IsFunction());
8302   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8303   CHECK(trouble_callee->IsFunction());
8304   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8305   CHECK(trouble_caller->IsFunction());
8306   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8307   CHECK_EQ(1, report_count);
8308   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8309 }
8310
8311 static const char* script_resource_name = "ExceptionInNativeScript.js";
8312 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8313                                                 v8::Handle<Value>) {
8314   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8315   CHECK(!name_val.IsEmpty() && name_val->IsString());
8316   v8::String::Utf8Value name(message->GetScriptResourceName());
8317   CHECK_EQ(script_resource_name, *name);
8318   CHECK_EQ(3, message->GetLineNumber());
8319   v8::String::Utf8Value source_line(message->GetSourceLine());
8320   CHECK_EQ("  new o.foo();", *source_line);
8321 }
8322
8323
8324 TEST(ExceptionInNativeScript) {
8325   LocalContext env;
8326   v8::Isolate* isolate = env->GetIsolate();
8327   v8::HandleScope scope(isolate);
8328   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8329
8330   Local<v8::FunctionTemplate> fun =
8331       v8::FunctionTemplate::New(isolate, TroubleCallback);
8332   v8::Local<v8::Object> global = env->Global();
8333   global->Set(v8_str("trouble"), fun->GetFunction());
8334
8335   CompileRunWithOrigin(
8336       "function trouble() {\n"
8337       "  var o = {};\n"
8338       "  new o.foo();\n"
8339       "};",
8340       script_resource_name);
8341   Local<Value> trouble = global->Get(v8_str("trouble"));
8342   CHECK(trouble->IsFunction());
8343   Function::Cast(*trouble)->Call(global, 0, NULL);
8344   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8345 }
8346
8347
8348 TEST(CompilationErrorUsingTryCatchHandler) {
8349   LocalContext env;
8350   v8::HandleScope scope(env->GetIsolate());
8351   v8::TryCatch try_catch;
8352   v8_compile("This doesn't &*&@#$&*^ compile.");
8353   CHECK_NE(NULL, *try_catch.Exception());
8354   CHECK(try_catch.HasCaught());
8355 }
8356
8357
8358 TEST(TryCatchFinallyUsingTryCatchHandler) {
8359   LocalContext env;
8360   v8::HandleScope scope(env->GetIsolate());
8361   v8::TryCatch try_catch;
8362   CompileRun("try { throw ''; } catch (e) {}");
8363   CHECK(!try_catch.HasCaught());
8364   CompileRun("try { throw ''; } finally {}");
8365   CHECK(try_catch.HasCaught());
8366   try_catch.Reset();
8367   CompileRun(
8368       "(function() {"
8369       "try { throw ''; } finally { return; }"
8370       "})()");
8371   CHECK(!try_catch.HasCaught());
8372   CompileRun(
8373       "(function()"
8374       "  { try { throw ''; } finally { throw 0; }"
8375       "})()");
8376   CHECK(try_catch.HasCaught());
8377 }
8378
8379
8380 // For use within the TestSecurityHandler() test.
8381 static bool g_security_callback_result = false;
8382 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8383                                       Local<Value> name,
8384                                       v8::AccessType type,
8385                                       Local<Value> data) {
8386   printf("a\n");
8387   // Always allow read access.
8388   if (type == v8::ACCESS_GET)
8389     return true;
8390
8391   // Sometimes allow other access.
8392   return g_security_callback_result;
8393 }
8394
8395
8396 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8397                                         uint32_t key,
8398                                         v8::AccessType type,
8399                                         Local<Value> data) {
8400   printf("b\n");
8401   // Always allow read access.
8402   if (type == v8::ACCESS_GET)
8403     return true;
8404
8405   // Sometimes allow other access.
8406   return g_security_callback_result;
8407 }
8408
8409
8410 // SecurityHandler can't be run twice
8411 TEST(SecurityHandler) {
8412   v8::Isolate* isolate = CcTest::isolate();
8413   v8::HandleScope scope0(isolate);
8414   v8::Handle<v8::ObjectTemplate> global_template =
8415       v8::ObjectTemplate::New(isolate);
8416   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8417                                            IndexedSecurityTestCallback);
8418   // Create an environment
8419   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8420   context0->Enter();
8421
8422   v8::Handle<v8::Object> global0 = context0->Global();
8423   v8::Handle<Script> script0 = v8_compile("foo = 111");
8424   script0->Run();
8425   global0->Set(v8_str("0"), v8_num(999));
8426   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8427   CHECK_EQ(111, foo0->Int32Value());
8428   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8429   CHECK_EQ(999, z0->Int32Value());
8430
8431   // Create another environment, should fail security checks.
8432   v8::HandleScope scope1(isolate);
8433
8434   v8::Handle<Context> context1 =
8435     Context::New(isolate, NULL, global_template);
8436   context1->Enter();
8437
8438   v8::Handle<v8::Object> global1 = context1->Global();
8439   global1->Set(v8_str("othercontext"), global0);
8440   // This set will fail the security check.
8441   v8::Handle<Script> script1 =
8442     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8443   script1->Run();
8444   // This read will pass the security check.
8445   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8446   CHECK_EQ(111, foo1->Int32Value());
8447   // This read will pass the security check.
8448   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8449   CHECK_EQ(999, z1->Int32Value());
8450
8451   // Create another environment, should pass security checks.
8452   { g_security_callback_result = true;  // allow security handler to pass.
8453     v8::HandleScope scope2(isolate);
8454     LocalContext context2;
8455     v8::Handle<v8::Object> global2 = context2->Global();
8456     global2->Set(v8_str("othercontext"), global0);
8457     v8::Handle<Script> script2 =
8458         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8459     script2->Run();
8460     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8461     CHECK_EQ(333, foo2->Int32Value());
8462     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8463     CHECK_EQ(888, z2->Int32Value());
8464   }
8465
8466   context1->Exit();
8467   context0->Exit();
8468 }
8469
8470
8471 THREADED_TEST(SecurityChecks) {
8472   LocalContext env1;
8473   v8::HandleScope handle_scope(env1->GetIsolate());
8474   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8475
8476   Local<Value> foo = v8_str("foo");
8477   Local<Value> bar = v8_str("bar");
8478
8479   // Set to the same domain.
8480   env1->SetSecurityToken(foo);
8481
8482   // Create a function in env1.
8483   CompileRun("spy=function(){return spy;}");
8484   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8485   CHECK(spy->IsFunction());
8486
8487   // Create another function accessing global objects.
8488   CompileRun("spy2=function(){return new this.Array();}");
8489   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8490   CHECK(spy2->IsFunction());
8491
8492   // Switch to env2 in the same domain and invoke spy on env2.
8493   {
8494     env2->SetSecurityToken(foo);
8495     // Enter env2
8496     Context::Scope scope_env2(env2);
8497     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8498     CHECK(result->IsFunction());
8499   }
8500
8501   {
8502     env2->SetSecurityToken(bar);
8503     Context::Scope scope_env2(env2);
8504
8505     // Call cross_domain_call, it should throw an exception
8506     v8::TryCatch try_catch;
8507     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8508     CHECK(try_catch.HasCaught());
8509   }
8510 }
8511
8512
8513 // Regression test case for issue 1183439.
8514 THREADED_TEST(SecurityChecksForPrototypeChain) {
8515   LocalContext current;
8516   v8::HandleScope scope(current->GetIsolate());
8517   v8::Handle<Context> other = Context::New(current->GetIsolate());
8518
8519   // Change context to be able to get to the Object function in the
8520   // other context without hitting the security checks.
8521   v8::Local<Value> other_object;
8522   { Context::Scope scope(other);
8523     other_object = other->Global()->Get(v8_str("Object"));
8524     other->Global()->Set(v8_num(42), v8_num(87));
8525   }
8526
8527   current->Global()->Set(v8_str("other"), other->Global());
8528   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8529
8530   // Make sure the security check fails here and we get an undefined
8531   // result instead of getting the Object function. Repeat in a loop
8532   // to make sure to exercise the IC code.
8533   v8::Local<Script> access_other0 = v8_compile("other.Object");
8534   v8::Local<Script> access_other1 = v8_compile("other[42]");
8535   for (int i = 0; i < 5; i++) {
8536     CHECK(!access_other0->Run()->Equals(other_object));
8537     CHECK(access_other0->Run()->IsUndefined());
8538     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8539     CHECK(access_other1->Run()->IsUndefined());
8540   }
8541
8542   // Create an object that has 'other' in its prototype chain and make
8543   // sure we cannot access the Object function indirectly through
8544   // that. Repeat in a loop to make sure to exercise the IC code.
8545   v8_compile("function F() { };"
8546              "F.prototype = other;"
8547              "var f = new F();")->Run();
8548   v8::Local<Script> access_f0 = v8_compile("f.Object");
8549   v8::Local<Script> access_f1 = v8_compile("f[42]");
8550   for (int j = 0; j < 5; j++) {
8551     CHECK(!access_f0->Run()->Equals(other_object));
8552     CHECK(access_f0->Run()->IsUndefined());
8553     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8554     CHECK(access_f1->Run()->IsUndefined());
8555   }
8556
8557   // Now it gets hairy: Set the prototype for the other global object
8558   // to be the current global object. The prototype chain for 'f' now
8559   // goes through 'other' but ends up in the current global object.
8560   { Context::Scope scope(other);
8561     other->Global()->Set(v8_str("__proto__"), current->Global());
8562   }
8563   // Set a named and an index property on the current global
8564   // object. To force the lookup to go through the other global object,
8565   // the properties must not exist in the other global object.
8566   current->Global()->Set(v8_str("foo"), v8_num(100));
8567   current->Global()->Set(v8_num(99), v8_num(101));
8568   // Try to read the properties from f and make sure that the access
8569   // gets stopped by the security checks on the other global object.
8570   Local<Script> access_f2 = v8_compile("f.foo");
8571   Local<Script> access_f3 = v8_compile("f[99]");
8572   for (int k = 0; k < 5; k++) {
8573     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8574     CHECK(access_f2->Run()->IsUndefined());
8575     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8576     CHECK(access_f3->Run()->IsUndefined());
8577   }
8578 }
8579
8580
8581 static bool named_security_check_with_gc_called;
8582
8583 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8584                                         Local<Value> name,
8585                                         v8::AccessType type,
8586                                         Local<Value> data) {
8587   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8588   named_security_check_with_gc_called = true;
8589   return true;
8590 }
8591
8592
8593 static bool indexed_security_check_with_gc_called;
8594
8595 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8596                                               uint32_t key,
8597                                               v8::AccessType type,
8598                                               Local<Value> data) {
8599   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8600   indexed_security_check_with_gc_called = true;
8601   return true;
8602 }
8603
8604
8605 TEST(SecurityTestGCAllowed) {
8606   v8::Isolate* isolate = CcTest::isolate();
8607   v8::HandleScope handle_scope(isolate);
8608   v8::Handle<v8::ObjectTemplate> object_template =
8609       v8::ObjectTemplate::New(isolate);
8610   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8611                                            IndexedSecurityTestCallbackWithGC);
8612
8613   v8::Handle<Context> context = Context::New(isolate);
8614   v8::Context::Scope context_scope(context);
8615
8616   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8617
8618   named_security_check_with_gc_called = false;
8619   CompileRun("obj.foo = new String(1001);");
8620   CHECK(named_security_check_with_gc_called);
8621
8622   indexed_security_check_with_gc_called = false;
8623   CompileRun("obj[0] = new String(1002);");
8624   CHECK(indexed_security_check_with_gc_called);
8625
8626   named_security_check_with_gc_called = false;
8627   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8628   CHECK(named_security_check_with_gc_called);
8629
8630   indexed_security_check_with_gc_called = false;
8631   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8632   CHECK(indexed_security_check_with_gc_called);
8633 }
8634
8635
8636 THREADED_TEST(CrossDomainDelete) {
8637   LocalContext env1;
8638   v8::HandleScope handle_scope(env1->GetIsolate());
8639   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8640
8641   Local<Value> foo = v8_str("foo");
8642   Local<Value> bar = v8_str("bar");
8643
8644   // Set to the same domain.
8645   env1->SetSecurityToken(foo);
8646   env2->SetSecurityToken(foo);
8647
8648   env1->Global()->Set(v8_str("prop"), v8_num(3));
8649   env2->Global()->Set(v8_str("env1"), env1->Global());
8650
8651   // Change env2 to a different domain and delete env1.prop.
8652   env2->SetSecurityToken(bar);
8653   {
8654     Context::Scope scope_env2(env2);
8655     Local<Value> result =
8656         CompileRun("delete env1.prop");
8657     CHECK(result->IsFalse());
8658   }
8659
8660   // Check that env1.prop still exists.
8661   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8662   CHECK(v->IsNumber());
8663   CHECK_EQ(3, v->Int32Value());
8664 }
8665
8666
8667 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8668   LocalContext env1;
8669   v8::HandleScope handle_scope(env1->GetIsolate());
8670   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8671
8672   Local<Value> foo = v8_str("foo");
8673   Local<Value> bar = v8_str("bar");
8674
8675   // Set to the same domain.
8676   env1->SetSecurityToken(foo);
8677   env2->SetSecurityToken(foo);
8678
8679   env1->Global()->Set(v8_str("prop"), v8_num(3));
8680   env2->Global()->Set(v8_str("env1"), env1->Global());
8681
8682   // env1.prop is enumerable in env2.
8683   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8684   {
8685     Context::Scope scope_env2(env2);
8686     Local<Value> result = CompileRun(test);
8687     CHECK(result->IsTrue());
8688   }
8689
8690   // Change env2 to a different domain and test again.
8691   env2->SetSecurityToken(bar);
8692   {
8693     Context::Scope scope_env2(env2);
8694     Local<Value> result = CompileRun(test);
8695     CHECK(result->IsFalse());
8696   }
8697 }
8698
8699
8700 THREADED_TEST(CrossDomainForIn) {
8701   LocalContext env1;
8702   v8::HandleScope handle_scope(env1->GetIsolate());
8703   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8704
8705   Local<Value> foo = v8_str("foo");
8706   Local<Value> bar = v8_str("bar");
8707
8708   // Set to the same domain.
8709   env1->SetSecurityToken(foo);
8710   env2->SetSecurityToken(foo);
8711
8712   env1->Global()->Set(v8_str("prop"), v8_num(3));
8713   env2->Global()->Set(v8_str("env1"), env1->Global());
8714
8715   // Change env2 to a different domain and set env1's global object
8716   // as the __proto__ of an object in env2 and enumerate properties
8717   // in for-in. It shouldn't enumerate properties on env1's global
8718   // object.
8719   env2->SetSecurityToken(bar);
8720   {
8721     Context::Scope scope_env2(env2);
8722     Local<Value> result =
8723         CompileRun("(function(){var obj = {'__proto__':env1};"
8724                    "for (var p in obj)"
8725                    "   if (p == 'prop') return false;"
8726                    "return true;})()");
8727     CHECK(result->IsTrue());
8728   }
8729 }
8730
8731
8732 TEST(ContextDetachGlobal) {
8733   LocalContext env1;
8734   v8::HandleScope handle_scope(env1->GetIsolate());
8735   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8736
8737   Local<v8::Object> global1 = env1->Global();
8738
8739   Local<Value> foo = v8_str("foo");
8740
8741   // Set to the same domain.
8742   env1->SetSecurityToken(foo);
8743   env2->SetSecurityToken(foo);
8744
8745   // Enter env2
8746   env2->Enter();
8747
8748   // Create a function in env2 and add a reference to it in env1.
8749   Local<v8::Object> global2 = env2->Global();
8750   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8751   CompileRun("function getProp() {return prop;}");
8752
8753   env1->Global()->Set(v8_str("getProp"),
8754                       global2->Get(v8_str("getProp")));
8755
8756   // Detach env2's global, and reuse the global object of env2
8757   env2->Exit();
8758   env2->DetachGlobal();
8759
8760   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8761                                           0,
8762                                           v8::Handle<v8::ObjectTemplate>(),
8763                                           global2);
8764   env3->SetSecurityToken(v8_str("bar"));
8765   env3->Enter();
8766
8767   Local<v8::Object> global3 = env3->Global();
8768   CHECK_EQ(global2, global3);
8769   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8770   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8771   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8772   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8773   env3->Exit();
8774
8775   // Call getProp in env1, and it should return the value 1
8776   {
8777     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8778     CHECK(get_prop->IsFunction());
8779     v8::TryCatch try_catch;
8780     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8781     CHECK(!try_catch.HasCaught());
8782     CHECK_EQ(1, r->Int32Value());
8783   }
8784
8785   // Check that env3 is not accessible from env1
8786   {
8787     Local<Value> r = global3->Get(v8_str("prop2"));
8788     CHECK(r->IsUndefined());
8789   }
8790 }
8791
8792
8793 TEST(DetachGlobal) {
8794   LocalContext env1;
8795   v8::HandleScope scope(env1->GetIsolate());
8796
8797   // Create second environment.
8798   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8799
8800   Local<Value> foo = v8_str("foo");
8801
8802   // Set same security token for env1 and env2.
8803   env1->SetSecurityToken(foo);
8804   env2->SetSecurityToken(foo);
8805
8806   // Create a property on the global object in env2.
8807   {
8808     v8::Context::Scope scope(env2);
8809     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8810   }
8811
8812   // Create a reference to env2 global from env1 global.
8813   env1->Global()->Set(v8_str("other"), env2->Global());
8814
8815   // Check that we have access to other.p in env2 from env1.
8816   Local<Value> result = CompileRun("other.p");
8817   CHECK(result->IsInt32());
8818   CHECK_EQ(42, result->Int32Value());
8819
8820   // Hold on to global from env2 and detach global from env2.
8821   Local<v8::Object> global2 = env2->Global();
8822   env2->DetachGlobal();
8823
8824   // Check that the global has been detached. No other.p property can
8825   // be found.
8826   result = CompileRun("other.p");
8827   CHECK(result->IsUndefined());
8828
8829   // Reuse global2 for env3.
8830   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8831                                           0,
8832                                           v8::Handle<v8::ObjectTemplate>(),
8833                                           global2);
8834   CHECK_EQ(global2, env3->Global());
8835
8836   // Start by using the same security token for env3 as for env1 and env2.
8837   env3->SetSecurityToken(foo);
8838
8839   // Create a property on the global object in env3.
8840   {
8841     v8::Context::Scope scope(env3);
8842     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8843   }
8844
8845   // Check that other.p is now the property in env3 and that we have access.
8846   result = CompileRun("other.p");
8847   CHECK(result->IsInt32());
8848   CHECK_EQ(24, result->Int32Value());
8849
8850   // Change security token for env3 to something different from env1 and env2.
8851   env3->SetSecurityToken(v8_str("bar"));
8852
8853   // Check that we do not have access to other.p in env1. |other| is now
8854   // the global object for env3 which has a different security token,
8855   // so access should be blocked.
8856   result = CompileRun("other.p");
8857   CHECK(result->IsUndefined());
8858 }
8859
8860
8861 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8862   info.GetReturnValue().Set(
8863       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8864 }
8865
8866
8867 TEST(DetachedAccesses) {
8868   LocalContext env1;
8869   v8::HandleScope scope(env1->GetIsolate());
8870
8871   // Create second environment.
8872   Local<ObjectTemplate> inner_global_template =
8873       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8874   inner_global_template ->SetAccessorProperty(
8875       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8876   v8::Local<Context> env2 =
8877       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8878
8879   Local<Value> foo = v8_str("foo");
8880
8881   // Set same security token for env1 and env2.
8882   env1->SetSecurityToken(foo);
8883   env2->SetSecurityToken(foo);
8884
8885   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8886
8887   {
8888     v8::Context::Scope scope(env2);
8889     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8890     CompileRun(
8891         "function bound_x() { return x; }"
8892         "function get_x()   { return this.x; }"
8893         "function get_x_w() { return (function() {return this.x;})(); }");
8894     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8895     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8896     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8897     env1->Global()->Set(
8898         v8_str("this_x"),
8899         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8900   }
8901
8902   Local<Object> env2_global = env2->Global();
8903   env2_global->TurnOnAccessCheck();
8904   env2->DetachGlobal();
8905
8906   Local<Value> result;
8907   result = CompileRun("bound_x()");
8908   CHECK_EQ(v8_str("env2_x"), result);
8909   result = CompileRun("get_x()");
8910   CHECK(result->IsUndefined());
8911   result = CompileRun("get_x_w()");
8912   CHECK(result->IsUndefined());
8913   result = CompileRun("this_x()");
8914   CHECK_EQ(v8_str("env2_x"), result);
8915
8916   // Reattach env2's proxy
8917   env2 = Context::New(env1->GetIsolate(),
8918                       0,
8919                       v8::Handle<v8::ObjectTemplate>(),
8920                       env2_global);
8921   env2->SetSecurityToken(foo);
8922   {
8923     v8::Context::Scope scope(env2);
8924     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8925     env2->Global()->Set(v8_str("env1"), env1->Global());
8926     result = CompileRun(
8927         "results = [];"
8928         "for (var i = 0; i < 4; i++ ) {"
8929         "  results.push(env1.bound_x());"
8930         "  results.push(env1.get_x());"
8931         "  results.push(env1.get_x_w());"
8932         "  results.push(env1.this_x());"
8933         "}"
8934         "results");
8935     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8936     CHECK_EQ(16, results->Length());
8937     for (int i = 0; i < 16; i += 4) {
8938       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8939       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8940       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8941       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8942     }
8943   }
8944
8945   result = CompileRun(
8946       "results = [];"
8947       "for (var i = 0; i < 4; i++ ) {"
8948       "  results.push(bound_x());"
8949       "  results.push(get_x());"
8950       "  results.push(get_x_w());"
8951       "  results.push(this_x());"
8952       "}"
8953       "results");
8954   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8955   CHECK_EQ(16, results->Length());
8956   for (int i = 0; i < 16; i += 4) {
8957     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8958     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8959     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8960     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8961   }
8962
8963   result = CompileRun(
8964       "results = [];"
8965       "for (var i = 0; i < 4; i++ ) {"
8966       "  results.push(this.bound_x());"
8967       "  results.push(this.get_x());"
8968       "  results.push(this.get_x_w());"
8969       "  results.push(this.this_x());"
8970       "}"
8971       "results");
8972   results = Local<v8::Array>::Cast(result);
8973   CHECK_EQ(16, results->Length());
8974   for (int i = 0; i < 16; i += 4) {
8975     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8976     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8977     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8978     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8979   }
8980 }
8981
8982
8983 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8984 static bool NamedAccessBlocker(Local<v8::Object> global,
8985                                Local<Value> name,
8986                                v8::AccessType type,
8987                                Local<Value> data) {
8988   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8989       allowed_access_type[type];
8990 }
8991
8992
8993 static bool IndexedAccessBlocker(Local<v8::Object> global,
8994                                  uint32_t key,
8995                                  v8::AccessType type,
8996                                  Local<Value> data) {
8997   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8998       allowed_access_type[type];
8999 }
9000
9001
9002 static int g_echo_value_1 = -1;
9003 static int g_echo_value_2 = -1;
9004
9005
9006 static void EchoGetter(
9007     Local<String> name,
9008     const v8::PropertyCallbackInfo<v8::Value>& info) {
9009   info.GetReturnValue().Set(v8_num(g_echo_value_1));
9010 }
9011
9012
9013 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9014   info.GetReturnValue().Set(v8_num(g_echo_value_2));
9015 }
9016
9017
9018 static void EchoSetter(Local<String> name,
9019                        Local<Value> value,
9020                        const v8::PropertyCallbackInfo<void>&) {
9021   if (value->IsNumber())
9022     g_echo_value_1 = value->Int32Value();
9023 }
9024
9025
9026 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
9027   v8::Handle<v8::Value> value = info[0];
9028   if (value->IsNumber())
9029     g_echo_value_2 = value->Int32Value();
9030 }
9031
9032
9033 static void UnreachableGetter(
9034     Local<String> name,
9035     const v8::PropertyCallbackInfo<v8::Value>& info) {
9036   CHECK(false);  // This function should not be called..
9037 }
9038
9039
9040 static void UnreachableSetter(Local<String>,
9041                               Local<Value>,
9042                               const v8::PropertyCallbackInfo<void>&) {
9043   CHECK(false);  // This function should nto be called.
9044 }
9045
9046
9047 static void UnreachableFunction(
9048     const v8::FunctionCallbackInfo<v8::Value>& info) {
9049   CHECK(false);  // This function should not be called..
9050 }
9051
9052
9053 TEST(AccessControl) {
9054   v8::Isolate* isolate = CcTest::isolate();
9055   v8::HandleScope handle_scope(isolate);
9056   v8::Handle<v8::ObjectTemplate> global_template =
9057       v8::ObjectTemplate::New(isolate);
9058
9059   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9060                                            IndexedAccessBlocker);
9061
9062   // Add an accessor accessible by cross-domain JS code.
9063   global_template->SetAccessor(
9064       v8_str("accessible_prop"),
9065       EchoGetter, EchoSetter,
9066       v8::Handle<Value>(),
9067       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9068
9069
9070   global_template->SetAccessorProperty(
9071       v8_str("accessible_js_prop"),
9072       v8::FunctionTemplate::New(isolate, EchoGetter),
9073       v8::FunctionTemplate::New(isolate, EchoSetter),
9074       v8::None,
9075       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9076
9077   // Add an accessor that is not accessible by cross-domain JS code.
9078   global_template->SetAccessor(v8_str("blocked_prop"),
9079                                UnreachableGetter, UnreachableSetter,
9080                                v8::Handle<Value>(),
9081                                v8::DEFAULT);
9082
9083   global_template->SetAccessorProperty(
9084       v8_str("blocked_js_prop"),
9085       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9086       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9087       v8::None,
9088       v8::DEFAULT);
9089
9090   // Create an environment
9091   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9092   context0->Enter();
9093
9094   v8::Handle<v8::Object> global0 = context0->Global();
9095
9096   // Define a property with JS getter and setter.
9097   CompileRun(
9098       "function getter() { return 'getter'; };\n"
9099       "function setter() { return 'setter'; }\n"
9100       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9101
9102   Local<Value> getter = global0->Get(v8_str("getter"));
9103   Local<Value> setter = global0->Get(v8_str("setter"));
9104
9105   // And define normal element.
9106   global0->Set(239, v8_str("239"));
9107
9108   // Define an element with JS getter and setter.
9109   CompileRun(
9110       "function el_getter() { return 'el_getter'; };\n"
9111       "function el_setter() { return 'el_setter'; };\n"
9112       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9113
9114   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9115   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9116
9117   v8::HandleScope scope1(isolate);
9118
9119   v8::Local<Context> context1 = Context::New(isolate);
9120   context1->Enter();
9121
9122   v8::Handle<v8::Object> global1 = context1->Global();
9123   global1->Set(v8_str("other"), global0);
9124
9125   // Access blocked property.
9126   CompileRun("other.blocked_prop = 1");
9127
9128   ExpectUndefined("other.blocked_prop");
9129   ExpectUndefined(
9130       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9131   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9132
9133   // Enable ACCESS_HAS
9134   allowed_access_type[v8::ACCESS_HAS] = true;
9135   ExpectUndefined("other.blocked_prop");
9136   // ... and now we can get the descriptor...
9137   ExpectUndefined(
9138       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9139   // ... and enumerate the property.
9140   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9141   allowed_access_type[v8::ACCESS_HAS] = false;
9142
9143   // Access blocked element.
9144   CompileRun("other[239] = 1");
9145
9146   ExpectUndefined("other[239]");
9147   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9148   ExpectFalse("propertyIsEnumerable.call(other, '239')");
9149
9150   // Enable ACCESS_HAS
9151   allowed_access_type[v8::ACCESS_HAS] = true;
9152   ExpectUndefined("other[239]");
9153   // ... and now we can get the descriptor...
9154   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9155   // ... and enumerate the property.
9156   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9157   allowed_access_type[v8::ACCESS_HAS] = false;
9158
9159   // Access a property with JS accessor.
9160   CompileRun("other.js_accessor_p = 2");
9161
9162   ExpectUndefined("other.js_accessor_p");
9163   ExpectUndefined(
9164       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9165
9166   // Enable ACCESS_HAS.
9167   allowed_access_type[v8::ACCESS_HAS] = true;
9168   ExpectUndefined("other.js_accessor_p");
9169   ExpectUndefined(
9170       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9171   ExpectUndefined(
9172       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9173   ExpectUndefined(
9174       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9175   allowed_access_type[v8::ACCESS_HAS] = false;
9176
9177   // Enable both ACCESS_HAS and ACCESS_GET.
9178   allowed_access_type[v8::ACCESS_HAS] = true;
9179   allowed_access_type[v8::ACCESS_GET] = true;
9180
9181   ExpectString("other.js_accessor_p", "getter");
9182   ExpectObject(
9183       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9184   ExpectUndefined(
9185       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9186   ExpectUndefined(
9187       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9188
9189   allowed_access_type[v8::ACCESS_GET] = false;
9190   allowed_access_type[v8::ACCESS_HAS] = false;
9191
9192   // Enable both ACCESS_HAS and ACCESS_SET.
9193   allowed_access_type[v8::ACCESS_HAS] = true;
9194   allowed_access_type[v8::ACCESS_SET] = true;
9195
9196   ExpectUndefined("other.js_accessor_p");
9197   ExpectUndefined(
9198       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9199   ExpectObject(
9200       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9201   ExpectUndefined(
9202       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9203
9204   allowed_access_type[v8::ACCESS_SET] = false;
9205   allowed_access_type[v8::ACCESS_HAS] = false;
9206
9207   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9208   allowed_access_type[v8::ACCESS_HAS] = true;
9209   allowed_access_type[v8::ACCESS_GET] = true;
9210   allowed_access_type[v8::ACCESS_SET] = true;
9211
9212   ExpectString("other.js_accessor_p", "getter");
9213   ExpectObject(
9214       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9215   ExpectObject(
9216       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9217   ExpectUndefined(
9218       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9219
9220   allowed_access_type[v8::ACCESS_SET] = false;
9221   allowed_access_type[v8::ACCESS_GET] = false;
9222   allowed_access_type[v8::ACCESS_HAS] = false;
9223
9224   // Access an element with JS accessor.
9225   CompileRun("other[42] = 2");
9226
9227   ExpectUndefined("other[42]");
9228   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9229
9230   // Enable ACCESS_HAS.
9231   allowed_access_type[v8::ACCESS_HAS] = true;
9232   ExpectUndefined("other[42]");
9233   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9234   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9235   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9236   allowed_access_type[v8::ACCESS_HAS] = false;
9237
9238   // Enable both ACCESS_HAS and ACCESS_GET.
9239   allowed_access_type[v8::ACCESS_HAS] = true;
9240   allowed_access_type[v8::ACCESS_GET] = true;
9241
9242   ExpectString("other[42]", "el_getter");
9243   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9244   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9245   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9246
9247   allowed_access_type[v8::ACCESS_GET] = false;
9248   allowed_access_type[v8::ACCESS_HAS] = false;
9249
9250   // Enable both ACCESS_HAS and ACCESS_SET.
9251   allowed_access_type[v8::ACCESS_HAS] = true;
9252   allowed_access_type[v8::ACCESS_SET] = true;
9253
9254   ExpectUndefined("other[42]");
9255   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9256   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9257   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9258
9259   allowed_access_type[v8::ACCESS_SET] = false;
9260   allowed_access_type[v8::ACCESS_HAS] = false;
9261
9262   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9263   allowed_access_type[v8::ACCESS_HAS] = true;
9264   allowed_access_type[v8::ACCESS_GET] = true;
9265   allowed_access_type[v8::ACCESS_SET] = true;
9266
9267   ExpectString("other[42]", "el_getter");
9268   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9269   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9270   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9271
9272   allowed_access_type[v8::ACCESS_SET] = false;
9273   allowed_access_type[v8::ACCESS_GET] = false;
9274   allowed_access_type[v8::ACCESS_HAS] = false;
9275
9276   v8::Handle<Value> value;
9277
9278   // Access accessible property
9279   value = CompileRun("other.accessible_prop = 3");
9280   CHECK(value->IsNumber());
9281   CHECK_EQ(3, value->Int32Value());
9282   CHECK_EQ(3, g_echo_value_1);
9283
9284   // Access accessible js property
9285   value = CompileRun("other.accessible_js_prop = 3");
9286   CHECK(value->IsNumber());
9287   CHECK_EQ(3, value->Int32Value());
9288   CHECK_EQ(3, g_echo_value_2);
9289
9290   value = CompileRun("other.accessible_prop");
9291   CHECK(value->IsNumber());
9292   CHECK_EQ(3, value->Int32Value());
9293
9294   value = CompileRun("other.accessible_js_prop");
9295   CHECK(value->IsNumber());
9296   CHECK_EQ(3, value->Int32Value());
9297
9298   value = CompileRun(
9299       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9300   CHECK(value->IsNumber());
9301   CHECK_EQ(3, value->Int32Value());
9302
9303   value = CompileRun(
9304       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9305   CHECK(value->IsNumber());
9306   CHECK_EQ(3, value->Int32Value());
9307
9308   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9309   CHECK(value->IsTrue());
9310
9311   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9312   CHECK(value->IsTrue());
9313
9314   // Enumeration doesn't enumerate accessors from inaccessible objects in
9315   // the prototype chain even if the accessors are in themselves accessible.
9316   value =
9317       CompileRun("(function(){var obj = {'__proto__':other};"
9318                  "for (var p in obj)"
9319                  "   if (p == 'accessible_prop' ||"
9320                  "       p == 'accessible_js_prop' ||"
9321                  "       p == 'blocked_js_prop' ||"
9322                  "       p == 'blocked_js_prop') {"
9323                  "     return false;"
9324                  "   }"
9325                  "return true;})()");
9326   CHECK(value->IsTrue());
9327
9328   context1->Exit();
9329   context0->Exit();
9330 }
9331
9332
9333 TEST(AccessControlES5) {
9334   v8::Isolate* isolate = CcTest::isolate();
9335   v8::HandleScope handle_scope(isolate);
9336   v8::Handle<v8::ObjectTemplate> global_template =
9337       v8::ObjectTemplate::New(isolate);
9338
9339   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9340                                            IndexedAccessBlocker);
9341
9342   // Add accessible accessor.
9343   global_template->SetAccessor(
9344       v8_str("accessible_prop"),
9345       EchoGetter, EchoSetter,
9346       v8::Handle<Value>(),
9347       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9348
9349
9350   // Add an accessor that is not accessible by cross-domain JS code.
9351   global_template->SetAccessor(v8_str("blocked_prop"),
9352                                UnreachableGetter, UnreachableSetter,
9353                                v8::Handle<Value>(),
9354                                v8::DEFAULT);
9355
9356   // Create an environment
9357   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9358   context0->Enter();
9359
9360   v8::Handle<v8::Object> global0 = context0->Global();
9361
9362   v8::Local<Context> context1 = Context::New(isolate);
9363   context1->Enter();
9364   v8::Handle<v8::Object> global1 = context1->Global();
9365   global1->Set(v8_str("other"), global0);
9366
9367   // Regression test for issue 1154.
9368   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9369
9370   ExpectUndefined("other.blocked_prop");
9371
9372   // Regression test for issue 1027.
9373   CompileRun("Object.defineProperty(\n"
9374              "  other, 'blocked_prop', {configurable: false})");
9375   ExpectUndefined("other.blocked_prop");
9376   ExpectUndefined(
9377       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9378
9379   // Regression test for issue 1171.
9380   ExpectTrue("Object.isExtensible(other)");
9381   CompileRun("Object.preventExtensions(other)");
9382   ExpectTrue("Object.isExtensible(other)");
9383
9384   // Object.seal and Object.freeze.
9385   CompileRun("Object.freeze(other)");
9386   ExpectTrue("Object.isExtensible(other)");
9387
9388   CompileRun("Object.seal(other)");
9389   ExpectTrue("Object.isExtensible(other)");
9390
9391   // Regression test for issue 1250.
9392   // Make sure that we can set the accessible accessors value using normal
9393   // assignment.
9394   CompileRun("other.accessible_prop = 42");
9395   CHECK_EQ(42, g_echo_value_1);
9396
9397   v8::Handle<Value> value;
9398   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9399   value = CompileRun("other.accessible_prop == 42");
9400   CHECK(value->IsTrue());
9401 }
9402
9403
9404 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9405                                             Local<Value> name,
9406                                             v8::AccessType type,
9407                                             Local<Value> data) {
9408   return false;
9409 }
9410
9411
9412 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9413                                               uint32_t key,
9414                                               v8::AccessType type,
9415                                               Local<Value> data) {
9416   return false;
9417 }
9418
9419
9420 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9421   v8::Isolate* isolate = CcTest::isolate();
9422   v8::HandleScope handle_scope(isolate);
9423   v8::Handle<v8::ObjectTemplate> obj_template =
9424       v8::ObjectTemplate::New(isolate);
9425
9426   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9427   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9428                                         GetOwnPropertyNamesIndexedBlocker);
9429
9430   // Create an environment
9431   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9432   context0->Enter();
9433
9434   v8::Handle<v8::Object> global0 = context0->Global();
9435
9436   v8::HandleScope scope1(CcTest::isolate());
9437
9438   v8::Local<Context> context1 = Context::New(isolate);
9439   context1->Enter();
9440
9441   v8::Handle<v8::Object> global1 = context1->Global();
9442   global1->Set(v8_str("other"), global0);
9443   global1->Set(v8_str("object"), obj_template->NewInstance());
9444
9445   v8::Handle<Value> value;
9446
9447   // Attempt to get the property names of the other global object and
9448   // of an object that requires access checks.  Accessing the other
9449   // global object should be blocked by access checks on the global
9450   // proxy object.  Accessing the object that requires access checks
9451   // is blocked by the access checks on the object itself.
9452   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9453   CHECK(value->IsTrue());
9454
9455   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9456   CHECK(value->IsTrue());
9457
9458   context1->Exit();
9459   context0->Exit();
9460 }
9461
9462
9463 static void IndexedPropertyEnumerator(
9464     const v8::PropertyCallbackInfo<v8::Array>& info) {
9465   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9466   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9467   result->Set(1, v8::Object::New(info.GetIsolate()));
9468   info.GetReturnValue().Set(result);
9469 }
9470
9471
9472 static void NamedPropertyEnumerator(
9473     const v8::PropertyCallbackInfo<v8::Array>& info) {
9474   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9475   result->Set(0, v8_str("x"));
9476   result->Set(1, v8::Object::New(info.GetIsolate()));
9477   info.GetReturnValue().Set(result);
9478 }
9479
9480
9481 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9482   v8::Isolate* isolate = CcTest::isolate();
9483   v8::HandleScope handle_scope(isolate);
9484   v8::Handle<v8::ObjectTemplate> obj_template =
9485       v8::ObjectTemplate::New(isolate);
9486
9487   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9488   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9489   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9490                                           IndexedPropertyEnumerator);
9491   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9492                                         NamedPropertyEnumerator);
9493
9494   LocalContext context;
9495   v8::Handle<v8::Object> global = context->Global();
9496   global->Set(v8_str("object"), obj_template->NewInstance());
9497
9498   v8::Handle<v8::Value> result =
9499       CompileRun("Object.getOwnPropertyNames(object)");
9500   CHECK(result->IsArray());
9501   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9502   CHECK_EQ(3, result_array->Length());
9503   CHECK(result_array->Get(0)->IsString());
9504   CHECK(result_array->Get(1)->IsString());
9505   CHECK(result_array->Get(2)->IsString());
9506   CHECK_EQ(v8_str("7"), result_array->Get(0));
9507   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9508   CHECK_EQ(v8_str("x"), result_array->Get(2));
9509 }
9510
9511
9512 static void ConstTenGetter(Local<String> name,
9513                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9514   info.GetReturnValue().Set(v8_num(10));
9515 }
9516
9517
9518 THREADED_TEST(CrossDomainAccessors) {
9519   v8::Isolate* isolate = CcTest::isolate();
9520   v8::HandleScope handle_scope(isolate);
9521
9522   v8::Handle<v8::FunctionTemplate> func_template =
9523       v8::FunctionTemplate::New(isolate);
9524
9525   v8::Handle<v8::ObjectTemplate> global_template =
9526       func_template->InstanceTemplate();
9527
9528   v8::Handle<v8::ObjectTemplate> proto_template =
9529       func_template->PrototypeTemplate();
9530
9531   // Add an accessor to proto that's accessible by cross-domain JS code.
9532   proto_template->SetAccessor(v8_str("accessible"),
9533                               ConstTenGetter, 0,
9534                               v8::Handle<Value>(),
9535                               v8::ALL_CAN_READ);
9536
9537   // Add an accessor that is not accessible by cross-domain JS code.
9538   global_template->SetAccessor(v8_str("unreachable"),
9539                                UnreachableGetter, 0,
9540                                v8::Handle<Value>(),
9541                                v8::DEFAULT);
9542
9543   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9544   context0->Enter();
9545
9546   Local<v8::Object> global = context0->Global();
9547   // Add a normal property that shadows 'accessible'
9548   global->Set(v8_str("accessible"), v8_num(11));
9549
9550   // Enter a new context.
9551   v8::HandleScope scope1(CcTest::isolate());
9552   v8::Local<Context> context1 = Context::New(isolate);
9553   context1->Enter();
9554
9555   v8::Handle<v8::Object> global1 = context1->Global();
9556   global1->Set(v8_str("other"), global);
9557
9558   // Should return 10, instead of 11
9559   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9560   CHECK(value->IsNumber());
9561   CHECK_EQ(10, value->Int32Value());
9562
9563   value = v8_compile("other.unreachable")->Run();
9564   CHECK(value->IsUndefined());
9565
9566   context1->Exit();
9567   context0->Exit();
9568 }
9569
9570
9571 static int named_access_count = 0;
9572 static int indexed_access_count = 0;
9573
9574 static bool NamedAccessCounter(Local<v8::Object> global,
9575                                Local<Value> name,
9576                                v8::AccessType type,
9577                                Local<Value> data) {
9578   named_access_count++;
9579   return true;
9580 }
9581
9582
9583 static bool IndexedAccessCounter(Local<v8::Object> global,
9584                                  uint32_t key,
9585                                  v8::AccessType type,
9586                                  Local<Value> data) {
9587   indexed_access_count++;
9588   return true;
9589 }
9590
9591
9592 // This one is too easily disturbed by other tests.
9593 TEST(AccessControlIC) {
9594   named_access_count = 0;
9595   indexed_access_count = 0;
9596
9597   v8::Isolate* isolate = CcTest::isolate();
9598   v8::HandleScope handle_scope(isolate);
9599
9600   // Create an environment.
9601   v8::Local<Context> context0 = Context::New(isolate);
9602   context0->Enter();
9603
9604   // Create an object that requires access-check functions to be
9605   // called for cross-domain access.
9606   v8::Handle<v8::ObjectTemplate> object_template =
9607       v8::ObjectTemplate::New(isolate);
9608   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9609                                            IndexedAccessCounter);
9610   Local<v8::Object> object = object_template->NewInstance();
9611
9612   v8::HandleScope scope1(isolate);
9613
9614   // Create another environment.
9615   v8::Local<Context> context1 = Context::New(isolate);
9616   context1->Enter();
9617
9618   // Make easy access to the object from the other environment.
9619   v8::Handle<v8::Object> global1 = context1->Global();
9620   global1->Set(v8_str("obj"), object);
9621
9622   v8::Handle<Value> value;
9623
9624   // Check that the named access-control function is called every time.
9625   CompileRun("function testProp(obj) {"
9626              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9627              "  for (var j = 0; j < 10; j++) obj.prop;"
9628              "  return obj.prop"
9629              "}");
9630   value = CompileRun("testProp(obj)");
9631   CHECK(value->IsNumber());
9632   CHECK_EQ(1, value->Int32Value());
9633   CHECK_EQ(21, named_access_count);
9634
9635   // Check that the named access-control function is called every time.
9636   CompileRun("var p = 'prop';"
9637              "function testKeyed(obj) {"
9638              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9639              "  for (var j = 0; j < 10; j++) obj[p];"
9640              "  return obj[p];"
9641              "}");
9642   // Use obj which requires access checks.  No inline caching is used
9643   // in that case.
9644   value = CompileRun("testKeyed(obj)");
9645   CHECK(value->IsNumber());
9646   CHECK_EQ(1, value->Int32Value());
9647   CHECK_EQ(42, named_access_count);
9648   // Force the inline caches into generic state and try again.
9649   CompileRun("testKeyed({ a: 0 })");
9650   CompileRun("testKeyed({ b: 0 })");
9651   value = CompileRun("testKeyed(obj)");
9652   CHECK(value->IsNumber());
9653   CHECK_EQ(1, value->Int32Value());
9654   CHECK_EQ(63, named_access_count);
9655
9656   // Check that the indexed access-control function is called every time.
9657   CompileRun("function testIndexed(obj) {"
9658              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9659              "  for (var j = 0; j < 10; j++) obj[0];"
9660              "  return obj[0]"
9661              "}");
9662   value = CompileRun("testIndexed(obj)");
9663   CHECK(value->IsNumber());
9664   CHECK_EQ(1, value->Int32Value());
9665   CHECK_EQ(21, indexed_access_count);
9666   // Force the inline caches into generic state.
9667   CompileRun("testIndexed(new Array(1))");
9668   // Test that the indexed access check is called.
9669   value = CompileRun("testIndexed(obj)");
9670   CHECK(value->IsNumber());
9671   CHECK_EQ(1, value->Int32Value());
9672   CHECK_EQ(42, indexed_access_count);
9673
9674   // Check that the named access check is called when invoking
9675   // functions on an object that requires access checks.
9676   CompileRun("obj.f = function() {}");
9677   CompileRun("function testCallNormal(obj) {"
9678              "  for (var i = 0; i < 10; i++) obj.f();"
9679              "}");
9680   CompileRun("testCallNormal(obj)");
9681   CHECK_EQ(74, named_access_count);
9682
9683   // Force obj into slow case.
9684   value = CompileRun("delete obj.prop");
9685   CHECK(value->BooleanValue());
9686   // Force inline caches into dictionary probing mode.
9687   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9688   // Test that the named access check is called.
9689   value = CompileRun("testProp(obj);");
9690   CHECK(value->IsNumber());
9691   CHECK_EQ(1, value->Int32Value());
9692   CHECK_EQ(96, named_access_count);
9693
9694   // Force the call inline cache into dictionary probing mode.
9695   CompileRun("o.f = function() {}; testCallNormal(o)");
9696   // Test that the named access check is still called for each
9697   // invocation of the function.
9698   value = CompileRun("testCallNormal(obj)");
9699   CHECK_EQ(106, named_access_count);
9700
9701   context1->Exit();
9702   context0->Exit();
9703 }
9704
9705
9706 static bool NamedAccessFlatten(Local<v8::Object> global,
9707                                Local<Value> name,
9708                                v8::AccessType type,
9709                                Local<Value> data) {
9710   char buf[100];
9711   int len;
9712
9713   CHECK(name->IsString());
9714
9715   memset(buf, 0x1, sizeof(buf));
9716   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9717   CHECK_EQ(4, len);
9718
9719   uint16_t buf2[100];
9720
9721   memset(buf, 0x1, sizeof(buf));
9722   len = name.As<String>()->Write(buf2);
9723   CHECK_EQ(4, len);
9724
9725   return true;
9726 }
9727
9728
9729 static bool IndexedAccessFlatten(Local<v8::Object> global,
9730                                  uint32_t key,
9731                                  v8::AccessType type,
9732                                  Local<Value> data) {
9733   return true;
9734 }
9735
9736
9737 // Regression test.  In access checks, operations that may cause
9738 // garbage collection are not allowed.  It used to be the case that
9739 // using the Write operation on a string could cause a garbage
9740 // collection due to flattening of the string.  This is no longer the
9741 // case.
9742 THREADED_TEST(AccessControlFlatten) {
9743   named_access_count = 0;
9744   indexed_access_count = 0;
9745
9746   v8::Isolate* isolate = CcTest::isolate();
9747   v8::HandleScope handle_scope(isolate);
9748
9749   // Create an environment.
9750   v8::Local<Context> context0 = Context::New(isolate);
9751   context0->Enter();
9752
9753   // Create an object that requires access-check functions to be
9754   // called for cross-domain access.
9755   v8::Handle<v8::ObjectTemplate> object_template =
9756       v8::ObjectTemplate::New(isolate);
9757   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9758                                            IndexedAccessFlatten);
9759   Local<v8::Object> object = object_template->NewInstance();
9760
9761   v8::HandleScope scope1(isolate);
9762
9763   // Create another environment.
9764   v8::Local<Context> context1 = Context::New(isolate);
9765   context1->Enter();
9766
9767   // Make easy access to the object from the other environment.
9768   v8::Handle<v8::Object> global1 = context1->Global();
9769   global1->Set(v8_str("obj"), object);
9770
9771   v8::Handle<Value> value;
9772
9773   value = v8_compile("var p = 'as' + 'df';")->Run();
9774   value = v8_compile("obj[p];")->Run();
9775
9776   context1->Exit();
9777   context0->Exit();
9778 }
9779
9780
9781 static void AccessControlNamedGetter(
9782     Local<String>,
9783     const v8::PropertyCallbackInfo<v8::Value>& info) {
9784   info.GetReturnValue().Set(42);
9785 }
9786
9787
9788 static void AccessControlNamedSetter(
9789     Local<String>,
9790     Local<Value> value,
9791     const v8::PropertyCallbackInfo<v8::Value>& info) {
9792   info.GetReturnValue().Set(value);
9793 }
9794
9795
9796 static void AccessControlIndexedGetter(
9797       uint32_t index,
9798       const v8::PropertyCallbackInfo<v8::Value>& info) {
9799   info.GetReturnValue().Set(v8_num(42));
9800 }
9801
9802
9803 static void AccessControlIndexedSetter(
9804     uint32_t,
9805     Local<Value> value,
9806     const v8::PropertyCallbackInfo<v8::Value>& info) {
9807   info.GetReturnValue().Set(value);
9808 }
9809
9810
9811 THREADED_TEST(AccessControlInterceptorIC) {
9812   named_access_count = 0;
9813   indexed_access_count = 0;
9814
9815   v8::Isolate* isolate = CcTest::isolate();
9816   v8::HandleScope handle_scope(isolate);
9817
9818   // Create an environment.
9819   v8::Local<Context> context0 = Context::New(isolate);
9820   context0->Enter();
9821
9822   // Create an object that requires access-check functions to be
9823   // called for cross-domain access.  The object also has interceptors
9824   // interceptor.
9825   v8::Handle<v8::ObjectTemplate> object_template =
9826       v8::ObjectTemplate::New(isolate);
9827   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9828                                            IndexedAccessCounter);
9829   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9830                                            AccessControlNamedSetter);
9831   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9832                                              AccessControlIndexedSetter);
9833   Local<v8::Object> object = object_template->NewInstance();
9834
9835   v8::HandleScope scope1(isolate);
9836
9837   // Create another environment.
9838   v8::Local<Context> context1 = Context::New(isolate);
9839   context1->Enter();
9840
9841   // Make easy access to the object from the other environment.
9842   v8::Handle<v8::Object> global1 = context1->Global();
9843   global1->Set(v8_str("obj"), object);
9844
9845   v8::Handle<Value> value;
9846
9847   // Check that the named access-control function is called every time
9848   // eventhough there is an interceptor on the object.
9849   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9850   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9851                      "obj.x")->Run();
9852   CHECK(value->IsNumber());
9853   CHECK_EQ(42, value->Int32Value());
9854   CHECK_EQ(21, named_access_count);
9855
9856   value = v8_compile("var p = 'x';")->Run();
9857   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9858   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9859                      "obj[p]")->Run();
9860   CHECK(value->IsNumber());
9861   CHECK_EQ(42, value->Int32Value());
9862   CHECK_EQ(42, named_access_count);
9863
9864   // Check that the indexed access-control function is called every
9865   // time eventhough there is an interceptor on the object.
9866   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9867   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9868                      "obj[0]")->Run();
9869   CHECK(value->IsNumber());
9870   CHECK_EQ(42, value->Int32Value());
9871   CHECK_EQ(21, indexed_access_count);
9872
9873   context1->Exit();
9874   context0->Exit();
9875 }
9876
9877
9878 THREADED_TEST(Version) {
9879   v8::V8::GetVersion();
9880 }
9881
9882
9883 static void InstanceFunctionCallback(
9884     const v8::FunctionCallbackInfo<v8::Value>& args) {
9885   ApiTestFuzzer::Fuzz();
9886   args.GetReturnValue().Set(v8_num(12));
9887 }
9888
9889
9890 THREADED_TEST(InstanceProperties) {
9891   LocalContext context;
9892   v8::Isolate* isolate = context->GetIsolate();
9893   v8::HandleScope handle_scope(isolate);
9894
9895   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9896   Local<ObjectTemplate> instance = t->InstanceTemplate();
9897
9898   instance->Set(v8_str("x"), v8_num(42));
9899   instance->Set(v8_str("f"),
9900                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9901
9902   Local<Value> o = t->GetFunction()->NewInstance();
9903
9904   context->Global()->Set(v8_str("i"), o);
9905   Local<Value> value = CompileRun("i.x");
9906   CHECK_EQ(42, value->Int32Value());
9907
9908   value = CompileRun("i.f()");
9909   CHECK_EQ(12, value->Int32Value());
9910 }
9911
9912
9913 static void GlobalObjectInstancePropertiesGet(
9914     Local<String> key,
9915     const v8::PropertyCallbackInfo<v8::Value>&) {
9916   ApiTestFuzzer::Fuzz();
9917 }
9918
9919
9920 THREADED_TEST(GlobalObjectInstanceProperties) {
9921   v8::Isolate* isolate = CcTest::isolate();
9922   v8::HandleScope handle_scope(isolate);
9923
9924   Local<Value> global_object;
9925
9926   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9927   t->InstanceTemplate()->SetNamedPropertyHandler(
9928       GlobalObjectInstancePropertiesGet);
9929   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9930   instance_template->Set(v8_str("x"), v8_num(42));
9931   instance_template->Set(v8_str("f"),
9932                          v8::FunctionTemplate::New(isolate,
9933                                                    InstanceFunctionCallback));
9934
9935   // The script to check how Crankshaft compiles missing global function
9936   // invocations.  function g is not defined and should throw on call.
9937   const char* script =
9938       "function wrapper(call) {"
9939       "  var x = 0, y = 1;"
9940       "  for (var i = 0; i < 1000; i++) {"
9941       "    x += i * 100;"
9942       "    y += i * 100;"
9943       "  }"
9944       "  if (call) g();"
9945       "}"
9946       "for (var i = 0; i < 17; i++) wrapper(false);"
9947       "var thrown = 0;"
9948       "try { wrapper(true); } catch (e) { thrown = 1; };"
9949       "thrown";
9950
9951   {
9952     LocalContext env(NULL, instance_template);
9953     // Hold on to the global object so it can be used again in another
9954     // environment initialization.
9955     global_object = env->Global();
9956
9957     Local<Value> value = CompileRun("x");
9958     CHECK_EQ(42, value->Int32Value());
9959     value = CompileRun("f()");
9960     CHECK_EQ(12, value->Int32Value());
9961     value = CompileRun(script);
9962     CHECK_EQ(1, value->Int32Value());
9963   }
9964
9965   {
9966     // Create new environment reusing the global object.
9967     LocalContext env(NULL, instance_template, global_object);
9968     Local<Value> value = CompileRun("x");
9969     CHECK_EQ(42, value->Int32Value());
9970     value = CompileRun("f()");
9971     CHECK_EQ(12, value->Int32Value());
9972     value = CompileRun(script);
9973     CHECK_EQ(1, value->Int32Value());
9974   }
9975 }
9976
9977
9978 THREADED_TEST(CallKnownGlobalReceiver) {
9979   v8::Isolate* isolate = CcTest::isolate();
9980   v8::HandleScope handle_scope(isolate);
9981
9982   Local<Value> global_object;
9983
9984   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9985   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9986
9987   // The script to check that we leave global object not
9988   // global object proxy on stack when we deoptimize from inside
9989   // arguments evaluation.
9990   // To provoke error we need to both force deoptimization
9991   // from arguments evaluation and to force CallIC to take
9992   // CallIC_Miss code path that can't cope with global proxy.
9993   const char* script =
9994       "function bar(x, y) { try { } finally { } }"
9995       "function baz(x) { try { } finally { } }"
9996       "function bom(x) { try { } finally { } }"
9997       "function foo(x) { bar([x], bom(2)); }"
9998       "for (var i = 0; i < 10000; i++) foo(1);"
9999       "foo";
10000
10001   Local<Value> foo;
10002   {
10003     LocalContext env(NULL, instance_template);
10004     // Hold on to the global object so it can be used again in another
10005     // environment initialization.
10006     global_object = env->Global();
10007     foo = CompileRun(script);
10008   }
10009
10010   {
10011     // Create new environment reusing the global object.
10012     LocalContext env(NULL, instance_template, global_object);
10013     env->Global()->Set(v8_str("foo"), foo);
10014     CompileRun("foo()");
10015   }
10016 }
10017
10018
10019 static void ShadowFunctionCallback(
10020     const v8::FunctionCallbackInfo<v8::Value>& args) {
10021   ApiTestFuzzer::Fuzz();
10022   args.GetReturnValue().Set(v8_num(42));
10023 }
10024
10025
10026 static int shadow_y;
10027 static int shadow_y_setter_call_count;
10028 static int shadow_y_getter_call_count;
10029
10030
10031 static void ShadowYSetter(Local<String>,
10032                           Local<Value>,
10033                           const v8::PropertyCallbackInfo<void>&) {
10034   shadow_y_setter_call_count++;
10035   shadow_y = 42;
10036 }
10037
10038
10039 static void ShadowYGetter(Local<String> name,
10040                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10041   ApiTestFuzzer::Fuzz();
10042   shadow_y_getter_call_count++;
10043   info.GetReturnValue().Set(v8_num(shadow_y));
10044 }
10045
10046
10047 static void ShadowIndexedGet(uint32_t index,
10048                              const v8::PropertyCallbackInfo<v8::Value>&) {
10049 }
10050
10051
10052 static void ShadowNamedGet(Local<String> key,
10053                            const v8::PropertyCallbackInfo<v8::Value>&) {
10054 }
10055
10056
10057 THREADED_TEST(ShadowObject) {
10058   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10059   v8::Isolate* isolate = CcTest::isolate();
10060   v8::HandleScope handle_scope(isolate);
10061
10062   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10063   LocalContext context(NULL, global_template);
10064
10065   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10066   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10067   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10068   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10069   Local<ObjectTemplate> instance = t->InstanceTemplate();
10070
10071   proto->Set(v8_str("f"),
10072              v8::FunctionTemplate::New(isolate,
10073                                        ShadowFunctionCallback,
10074                                        Local<Value>()));
10075   proto->Set(v8_str("x"), v8_num(12));
10076
10077   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10078
10079   Local<Value> o = t->GetFunction()->NewInstance();
10080   context->Global()->Set(v8_str("__proto__"), o);
10081
10082   Local<Value> value =
10083       CompileRun("this.propertyIsEnumerable(0)");
10084   CHECK(value->IsBoolean());
10085   CHECK(!value->BooleanValue());
10086
10087   value = CompileRun("x");
10088   CHECK_EQ(12, value->Int32Value());
10089
10090   value = CompileRun("f()");
10091   CHECK_EQ(42, value->Int32Value());
10092
10093   CompileRun("y = 43");
10094   CHECK_EQ(1, shadow_y_setter_call_count);
10095   value = CompileRun("y");
10096   CHECK_EQ(1, shadow_y_getter_call_count);
10097   CHECK_EQ(42, value->Int32Value());
10098 }
10099
10100
10101 THREADED_TEST(HiddenPrototype) {
10102   LocalContext context;
10103   v8::Isolate* isolate = context->GetIsolate();
10104   v8::HandleScope handle_scope(isolate);
10105
10106   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10107   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10108   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10109   t1->SetHiddenPrototype(true);
10110   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10111   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10112   t2->SetHiddenPrototype(true);
10113   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10114   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10115   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10116
10117   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10118   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10119   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10120   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10121
10122   // Setting the prototype on an object skips hidden prototypes.
10123   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10124   o0->Set(v8_str("__proto__"), o1);
10125   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10126   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10127   o0->Set(v8_str("__proto__"), o2);
10128   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10129   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10130   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10131   o0->Set(v8_str("__proto__"), o3);
10132   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10133   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10134   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10135   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10136
10137   // Getting the prototype of o0 should get the first visible one
10138   // which is o3.  Therefore, z should not be defined on the prototype
10139   // object.
10140   Local<Value> proto = o0->Get(v8_str("__proto__"));
10141   CHECK(proto->IsObject());
10142   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10143 }
10144
10145
10146 THREADED_TEST(HiddenPrototypeSet) {
10147   LocalContext context;
10148   v8::Isolate* isolate = context->GetIsolate();
10149   v8::HandleScope handle_scope(isolate);
10150
10151   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10152   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10153   ht->SetHiddenPrototype(true);
10154   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10155   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10156
10157   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10158   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10159   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10160   o->Set(v8_str("__proto__"), h);
10161   h->Set(v8_str("__proto__"), p);
10162
10163   // Setting a property that exists on the hidden prototype goes there.
10164   o->Set(v8_str("x"), v8_num(7));
10165   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10166   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10167   CHECK(p->Get(v8_str("x"))->IsUndefined());
10168
10169   // Setting a new property should not be forwarded to the hidden prototype.
10170   o->Set(v8_str("y"), v8_num(6));
10171   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10172   CHECK(h->Get(v8_str("y"))->IsUndefined());
10173   CHECK(p->Get(v8_str("y"))->IsUndefined());
10174
10175   // Setting a property that only exists on a prototype of the hidden prototype
10176   // is treated normally again.
10177   p->Set(v8_str("z"), v8_num(8));
10178   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10179   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10180   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10181   o->Set(v8_str("z"), v8_num(9));
10182   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10183   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10184   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10185 }
10186
10187
10188 // Regression test for issue 2457.
10189 THREADED_TEST(HiddenPrototypeIdentityHash) {
10190   LocalContext context;
10191   v8::HandleScope handle_scope(context->GetIsolate());
10192
10193   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10194   t->SetHiddenPrototype(true);
10195   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10196   Handle<Object> p = t->GetFunction()->NewInstance();
10197   Handle<Object> o = Object::New(context->GetIsolate());
10198   o->SetPrototype(p);
10199
10200   int hash = o->GetIdentityHash();
10201   USE(hash);
10202   o->Set(v8_str("foo"), v8_num(42));
10203   ASSERT_EQ(hash, o->GetIdentityHash());
10204 }
10205
10206
10207 THREADED_TEST(SetPrototype) {
10208   LocalContext context;
10209   v8::Isolate* isolate = context->GetIsolate();
10210   v8::HandleScope handle_scope(isolate);
10211
10212   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10213   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10214   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10215   t1->SetHiddenPrototype(true);
10216   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10217   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10218   t2->SetHiddenPrototype(true);
10219   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10220   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10221   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10222
10223   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10224   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10225   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10226   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10227
10228   // Setting the prototype on an object does not skip hidden prototypes.
10229   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10230   CHECK(o0->SetPrototype(o1));
10231   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10232   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10233   CHECK(o1->SetPrototype(o2));
10234   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10235   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10236   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10237   CHECK(o2->SetPrototype(o3));
10238   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10239   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10240   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10241   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10242
10243   // Getting the prototype of o0 should get the first visible one
10244   // which is o3.  Therefore, z should not be defined on the prototype
10245   // object.
10246   Local<Value> proto = o0->Get(v8_str("__proto__"));
10247   CHECK(proto->IsObject());
10248   CHECK_EQ(proto.As<v8::Object>(), o3);
10249
10250   // However, Object::GetPrototype ignores hidden prototype.
10251   Local<Value> proto0 = o0->GetPrototype();
10252   CHECK(proto0->IsObject());
10253   CHECK_EQ(proto0.As<v8::Object>(), o1);
10254
10255   Local<Value> proto1 = o1->GetPrototype();
10256   CHECK(proto1->IsObject());
10257   CHECK_EQ(proto1.As<v8::Object>(), o2);
10258
10259   Local<Value> proto2 = o2->GetPrototype();
10260   CHECK(proto2->IsObject());
10261   CHECK_EQ(proto2.As<v8::Object>(), o3);
10262 }
10263
10264
10265 // Getting property names of an object with a prototype chain that
10266 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10267 // crash the runtime.
10268 THREADED_TEST(Regress91517) {
10269   i::FLAG_allow_natives_syntax = true;
10270   LocalContext context;
10271   v8::Isolate* isolate = context->GetIsolate();
10272   v8::HandleScope handle_scope(isolate);
10273
10274   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10275   t1->SetHiddenPrototype(true);
10276   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10277   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10278   t2->SetHiddenPrototype(true);
10279   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10280   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10281   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10282   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10283   t3->SetHiddenPrototype(true);
10284   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10285   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10286   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10287
10288   // Force dictionary-based properties.
10289   i::ScopedVector<char> name_buf(1024);
10290   for (int i = 1; i <= 1000; i++) {
10291     i::OS::SNPrintF(name_buf, "sdf%d", i);
10292     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10293   }
10294
10295   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10296   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10297   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10298   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10299
10300   // Create prototype chain of hidden prototypes.
10301   CHECK(o4->SetPrototype(o3));
10302   CHECK(o3->SetPrototype(o2));
10303   CHECK(o2->SetPrototype(o1));
10304
10305   // Call the runtime version of GetLocalPropertyNames() on the natively
10306   // created object through JavaScript.
10307   context->Global()->Set(v8_str("obj"), o4);
10308   // PROPERTY_ATTRIBUTES_NONE = 0
10309   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10310
10311   ExpectInt32("names.length", 1006);
10312   ExpectTrue("names.indexOf(\"baz\") >= 0");
10313   ExpectTrue("names.indexOf(\"boo\") >= 0");
10314   ExpectTrue("names.indexOf(\"foo\") >= 0");
10315   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10316   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10317   ExpectFalse("names[1005] == undefined");
10318 }
10319
10320
10321 // Getting property names of an object with a hidden and inherited
10322 // prototype should not duplicate the accessor properties inherited.
10323 THREADED_TEST(Regress269562) {
10324   i::FLAG_allow_natives_syntax = true;
10325   LocalContext context;
10326   v8::HandleScope handle_scope(context->GetIsolate());
10327
10328   Local<v8::FunctionTemplate> t1 =
10329       v8::FunctionTemplate::New(context->GetIsolate());
10330   t1->SetHiddenPrototype(true);
10331
10332   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10333   i1->SetAccessor(v8_str("foo"),
10334                   SimpleAccessorGetter, SimpleAccessorSetter);
10335   i1->SetAccessor(v8_str("bar"),
10336                   SimpleAccessorGetter, SimpleAccessorSetter);
10337   i1->SetAccessor(v8_str("baz"),
10338                   SimpleAccessorGetter, SimpleAccessorSetter);
10339   i1->Set(v8_str("n1"), v8_num(1));
10340   i1->Set(v8_str("n2"), v8_num(2));
10341
10342   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10343   Local<v8::FunctionTemplate> t2 =
10344       v8::FunctionTemplate::New(context->GetIsolate());
10345   t2->SetHiddenPrototype(true);
10346
10347   // Inherit from t1 and mark prototype as hidden.
10348   t2->Inherit(t1);
10349   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10350
10351   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10352   CHECK(o2->SetPrototype(o1));
10353
10354   v8::Local<v8::Symbol> sym =
10355       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10356   o1->Set(sym, v8_num(3));
10357   o1->SetHiddenValue(
10358       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10359
10360   // Call the runtime version of GetLocalPropertyNames() on
10361   // the natively created object through JavaScript.
10362   context->Global()->Set(v8_str("obj"), o2);
10363   context->Global()->Set(v8_str("sym"), sym);
10364   // PROPERTY_ATTRIBUTES_NONE = 0
10365   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10366
10367   ExpectInt32("names.length", 7);
10368   ExpectTrue("names.indexOf(\"foo\") >= 0");
10369   ExpectTrue("names.indexOf(\"bar\") >= 0");
10370   ExpectTrue("names.indexOf(\"baz\") >= 0");
10371   ExpectTrue("names.indexOf(\"n1\") >= 0");
10372   ExpectTrue("names.indexOf(\"n2\") >= 0");
10373   ExpectTrue("names.indexOf(sym) >= 0");
10374   ExpectTrue("names.indexOf(\"mine\") >= 0");
10375 }
10376
10377
10378 THREADED_TEST(FunctionReadOnlyPrototype) {
10379   LocalContext context;
10380   v8::Isolate* isolate = context->GetIsolate();
10381   v8::HandleScope handle_scope(isolate);
10382
10383   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10384   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10385   t1->ReadOnlyPrototype();
10386   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10387   // Configured value of ReadOnly flag.
10388   CHECK(CompileRun(
10389       "(function() {"
10390       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10391       "  return (descriptor['writable'] == false);"
10392       "})()")->BooleanValue());
10393   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10394   CHECK_EQ(42,
10395            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10396
10397   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10398   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10399   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10400   // Default value of ReadOnly flag.
10401   CHECK(CompileRun(
10402       "(function() {"
10403       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10404       "  return (descriptor['writable'] == true);"
10405       "})()")->BooleanValue());
10406   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10407 }
10408
10409
10410 THREADED_TEST(SetPrototypeThrows) {
10411   LocalContext context;
10412   v8::Isolate* isolate = context->GetIsolate();
10413   v8::HandleScope handle_scope(isolate);
10414
10415   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10416
10417   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10418   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10419
10420   CHECK(o0->SetPrototype(o1));
10421   // If setting the prototype leads to the cycle, SetPrototype should
10422   // return false and keep VM in sane state.
10423   v8::TryCatch try_catch;
10424   CHECK(!o1->SetPrototype(o0));
10425   CHECK(!try_catch.HasCaught());
10426   ASSERT(!CcTest::i_isolate()->has_pending_exception());
10427
10428   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10429 }
10430
10431
10432 THREADED_TEST(FunctionRemovePrototype) {
10433   LocalContext context;
10434   v8::Isolate* isolate = context->GetIsolate();
10435   v8::HandleScope handle_scope(isolate);
10436
10437   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10438   t1->RemovePrototype();
10439   Local<v8::Function> fun = t1->GetFunction();
10440   context->Global()->Set(v8_str("fun"), fun);
10441   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10442
10443   v8::TryCatch try_catch;
10444   CompileRun("new fun()");
10445   CHECK(try_catch.HasCaught());
10446
10447   try_catch.Reset();
10448   fun->NewInstance();
10449   CHECK(try_catch.HasCaught());
10450 }
10451
10452
10453 THREADED_TEST(GetterSetterExceptions) {
10454   LocalContext context;
10455   v8::Isolate* isolate = context->GetIsolate();
10456   v8::HandleScope handle_scope(isolate);
10457   CompileRun(
10458     "function Foo() { };"
10459     "function Throw() { throw 5; };"
10460     "var x = { };"
10461     "x.__defineSetter__('set', Throw);"
10462     "x.__defineGetter__('get', Throw);");
10463   Local<v8::Object> x =
10464       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10465   v8::TryCatch try_catch;
10466   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10467   x->Get(v8_str("get"));
10468   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10469   x->Get(v8_str("get"));
10470   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10471   x->Get(v8_str("get"));
10472   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10473   x->Get(v8_str("get"));
10474 }
10475
10476
10477 THREADED_TEST(Constructor) {
10478   LocalContext context;
10479   v8::Isolate* isolate = context->GetIsolate();
10480   v8::HandleScope handle_scope(isolate);
10481   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10482   templ->SetClassName(v8_str("Fun"));
10483   Local<Function> cons = templ->GetFunction();
10484   context->Global()->Set(v8_str("Fun"), cons);
10485   Local<v8::Object> inst = cons->NewInstance();
10486   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10487   CHECK(obj->IsJSObject());
10488   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10489   CHECK(value->BooleanValue());
10490 }
10491
10492
10493 static void ConstructorCallback(
10494     const v8::FunctionCallbackInfo<v8::Value>& args) {
10495   ApiTestFuzzer::Fuzz();
10496   Local<Object> This;
10497
10498   if (args.IsConstructCall()) {
10499     Local<Object> Holder = args.Holder();
10500     This = Object::New(args.GetIsolate());
10501     Local<Value> proto = Holder->GetPrototype();
10502     if (proto->IsObject()) {
10503       This->SetPrototype(proto);
10504     }
10505   } else {
10506     This = args.This();
10507   }
10508
10509   This->Set(v8_str("a"), args[0]);
10510   args.GetReturnValue().Set(This);
10511 }
10512
10513
10514 static void FakeConstructorCallback(
10515     const v8::FunctionCallbackInfo<v8::Value>& args) {
10516   ApiTestFuzzer::Fuzz();
10517   args.GetReturnValue().Set(args[0]);
10518 }
10519
10520
10521 THREADED_TEST(ConstructorForObject) {
10522   LocalContext context;
10523   v8::Isolate* isolate = context->GetIsolate();
10524   v8::HandleScope handle_scope(isolate);
10525
10526   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10527     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10528     Local<Object> instance = instance_template->NewInstance();
10529     context->Global()->Set(v8_str("obj"), instance);
10530     v8::TryCatch try_catch;
10531     Local<Value> value;
10532     CHECK(!try_catch.HasCaught());
10533
10534     // Call the Object's constructor with a 32-bit signed integer.
10535     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10536     CHECK(!try_catch.HasCaught());
10537     CHECK(value->IsInt32());
10538     CHECK_EQ(28, value->Int32Value());
10539
10540     Local<Value> args1[] = { v8_num(28) };
10541     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10542     CHECK(value_obj1->IsObject());
10543     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10544     value = object1->Get(v8_str("a"));
10545     CHECK(value->IsInt32());
10546     CHECK(!try_catch.HasCaught());
10547     CHECK_EQ(28, value->Int32Value());
10548
10549     // Call the Object's constructor with a String.
10550     value = CompileRun(
10551         "(function() { var o = new obj('tipli'); return o.a; })()");
10552     CHECK(!try_catch.HasCaught());
10553     CHECK(value->IsString());
10554     String::Utf8Value string_value1(value->ToString());
10555     CHECK_EQ("tipli", *string_value1);
10556
10557     Local<Value> args2[] = { v8_str("tipli") };
10558     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10559     CHECK(value_obj2->IsObject());
10560     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10561     value = object2->Get(v8_str("a"));
10562     CHECK(!try_catch.HasCaught());
10563     CHECK(value->IsString());
10564     String::Utf8Value string_value2(value->ToString());
10565     CHECK_EQ("tipli", *string_value2);
10566
10567     // Call the Object's constructor with a Boolean.
10568     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10569     CHECK(!try_catch.HasCaught());
10570     CHECK(value->IsBoolean());
10571     CHECK_EQ(true, value->BooleanValue());
10572
10573     Handle<Value> args3[] = { v8::True(isolate) };
10574     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10575     CHECK(value_obj3->IsObject());
10576     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10577     value = object3->Get(v8_str("a"));
10578     CHECK(!try_catch.HasCaught());
10579     CHECK(value->IsBoolean());
10580     CHECK_EQ(true, value->BooleanValue());
10581
10582     // Call the Object's constructor with undefined.
10583     Handle<Value> args4[] = { v8::Undefined(isolate) };
10584     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10585     CHECK(value_obj4->IsObject());
10586     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10587     value = object4->Get(v8_str("a"));
10588     CHECK(!try_catch.HasCaught());
10589     CHECK(value->IsUndefined());
10590
10591     // Call the Object's constructor with null.
10592     Handle<Value> args5[] = { v8::Null(isolate) };
10593     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10594     CHECK(value_obj5->IsObject());
10595     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10596     value = object5->Get(v8_str("a"));
10597     CHECK(!try_catch.HasCaught());
10598     CHECK(value->IsNull());
10599   }
10600
10601   // Check exception handling when there is no constructor set for the Object.
10602   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10603     Local<Object> instance = instance_template->NewInstance();
10604     context->Global()->Set(v8_str("obj2"), instance);
10605     v8::TryCatch try_catch;
10606     Local<Value> value;
10607     CHECK(!try_catch.HasCaught());
10608
10609     value = CompileRun("new obj2(28)");
10610     CHECK(try_catch.HasCaught());
10611     String::Utf8Value exception_value1(try_catch.Exception());
10612     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10613     try_catch.Reset();
10614
10615     Local<Value> args[] = { v8_num(29) };
10616     value = instance->CallAsConstructor(1, args);
10617     CHECK(try_catch.HasCaught());
10618     String::Utf8Value exception_value2(try_catch.Exception());
10619     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10620     try_catch.Reset();
10621   }
10622
10623   // Check the case when constructor throws exception.
10624   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10625     instance_template->SetCallAsFunctionHandler(ThrowValue);
10626     Local<Object> instance = instance_template->NewInstance();
10627     context->Global()->Set(v8_str("obj3"), instance);
10628     v8::TryCatch try_catch;
10629     Local<Value> value;
10630     CHECK(!try_catch.HasCaught());
10631
10632     value = CompileRun("new obj3(22)");
10633     CHECK(try_catch.HasCaught());
10634     String::Utf8Value exception_value1(try_catch.Exception());
10635     CHECK_EQ("22", *exception_value1);
10636     try_catch.Reset();
10637
10638     Local<Value> args[] = { v8_num(23) };
10639     value = instance->CallAsConstructor(1, args);
10640     CHECK(try_catch.HasCaught());
10641     String::Utf8Value exception_value2(try_catch.Exception());
10642     CHECK_EQ("23", *exception_value2);
10643     try_catch.Reset();
10644   }
10645
10646   // Check whether constructor returns with an object or non-object.
10647   { Local<FunctionTemplate> function_template =
10648         FunctionTemplate::New(isolate, FakeConstructorCallback);
10649     Local<Function> function = function_template->GetFunction();
10650     Local<Object> instance1 = function;
10651     context->Global()->Set(v8_str("obj4"), instance1);
10652     v8::TryCatch try_catch;
10653     Local<Value> value;
10654     CHECK(!try_catch.HasCaught());
10655
10656     CHECK(instance1->IsObject());
10657     CHECK(instance1->IsFunction());
10658
10659     value = CompileRun("new obj4(28)");
10660     CHECK(!try_catch.HasCaught());
10661     CHECK(value->IsObject());
10662
10663     Local<Value> args1[] = { v8_num(28) };
10664     value = instance1->CallAsConstructor(1, args1);
10665     CHECK(!try_catch.HasCaught());
10666     CHECK(value->IsObject());
10667
10668     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10669     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10670     Local<Object> instance2 = instance_template->NewInstance();
10671     context->Global()->Set(v8_str("obj5"), instance2);
10672     CHECK(!try_catch.HasCaught());
10673
10674     CHECK(instance2->IsObject());
10675     CHECK(!instance2->IsFunction());
10676
10677     value = CompileRun("new obj5(28)");
10678     CHECK(!try_catch.HasCaught());
10679     CHECK(!value->IsObject());
10680
10681     Local<Value> args2[] = { v8_num(28) };
10682     value = instance2->CallAsConstructor(1, args2);
10683     CHECK(!try_catch.HasCaught());
10684     CHECK(!value->IsObject());
10685   }
10686 }
10687
10688
10689 THREADED_TEST(FunctionDescriptorException) {
10690   LocalContext context;
10691   v8::Isolate* isolate = context->GetIsolate();
10692   v8::HandleScope handle_scope(isolate);
10693   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10694   templ->SetClassName(v8_str("Fun"));
10695   Local<Function> cons = templ->GetFunction();
10696   context->Global()->Set(v8_str("Fun"), cons);
10697   Local<Value> value = CompileRun(
10698     "function test() {"
10699     "  try {"
10700     "    (new Fun()).blah()"
10701     "  } catch (e) {"
10702     "    var str = String(e);"
10703     // "    if (str.indexOf('TypeError') == -1) return 1;"
10704     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10705     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10706     "    return 0;"
10707     "  }"
10708     "  return 4;"
10709     "}"
10710     "test();");
10711   CHECK_EQ(0, value->Int32Value());
10712 }
10713
10714
10715 THREADED_TEST(EvalAliasedDynamic) {
10716   LocalContext current;
10717   v8::HandleScope scope(current->GetIsolate());
10718
10719   // Tests where aliased eval can only be resolved dynamically.
10720   Local<Script> script = v8_compile(
10721       "function f(x) { "
10722       "  var foo = 2;"
10723       "  with (x) { return eval('foo'); }"
10724       "}"
10725       "foo = 0;"
10726       "result1 = f(new Object());"
10727       "result2 = f(this);"
10728       "var x = new Object();"
10729       "x.eval = function(x) { return 1; };"
10730       "result3 = f(x);");
10731   script->Run();
10732   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10733   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10734   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10735
10736   v8::TryCatch try_catch;
10737   script = v8_compile(
10738       "function f(x) { "
10739       "  var bar = 2;"
10740       "  with (x) { return eval('bar'); }"
10741       "}"
10742       "result4 = f(this)");
10743   script->Run();
10744   CHECK(!try_catch.HasCaught());
10745   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10746
10747   try_catch.Reset();
10748 }
10749
10750
10751 THREADED_TEST(CrossEval) {
10752   v8::HandleScope scope(CcTest::isolate());
10753   LocalContext other;
10754   LocalContext current;
10755
10756   Local<String> token = v8_str("<security token>");
10757   other->SetSecurityToken(token);
10758   current->SetSecurityToken(token);
10759
10760   // Set up reference from current to other.
10761   current->Global()->Set(v8_str("other"), other->Global());
10762
10763   // Check that new variables are introduced in other context.
10764   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10765   script->Run();
10766   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10767   CHECK_EQ(1234, foo->Int32Value());
10768   CHECK(!current->Global()->Has(v8_str("foo")));
10769
10770   // Check that writing to non-existing properties introduces them in
10771   // the other context.
10772   script = v8_compile("other.eval('na = 1234')");
10773   script->Run();
10774   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10775   CHECK(!current->Global()->Has(v8_str("na")));
10776
10777   // Check that global variables in current context are not visible in other
10778   // context.
10779   v8::TryCatch try_catch;
10780   script = v8_compile("var bar = 42; other.eval('bar');");
10781   Local<Value> result = script->Run();
10782   CHECK(try_catch.HasCaught());
10783   try_catch.Reset();
10784
10785   // Check that local variables in current context are not visible in other
10786   // context.
10787   script = v8_compile(
10788       "(function() { "
10789       "  var baz = 87;"
10790       "  return other.eval('baz');"
10791       "})();");
10792   result = script->Run();
10793   CHECK(try_catch.HasCaught());
10794   try_catch.Reset();
10795
10796   // Check that global variables in the other environment are visible
10797   // when evaluting code.
10798   other->Global()->Set(v8_str("bis"), v8_num(1234));
10799   script = v8_compile("other.eval('bis')");
10800   CHECK_EQ(1234, script->Run()->Int32Value());
10801   CHECK(!try_catch.HasCaught());
10802
10803   // Check that the 'this' pointer points to the global object evaluating
10804   // code.
10805   other->Global()->Set(v8_str("t"), other->Global());
10806   script = v8_compile("other.eval('this == t')");
10807   result = script->Run();
10808   CHECK(result->IsTrue());
10809   CHECK(!try_catch.HasCaught());
10810
10811   // Check that variables introduced in with-statement are not visible in
10812   // other context.
10813   script = v8_compile("with({x:2}){other.eval('x')}");
10814   result = script->Run();
10815   CHECK(try_catch.HasCaught());
10816   try_catch.Reset();
10817
10818   // Check that you cannot use 'eval.call' with another object than the
10819   // current global object.
10820   script = v8_compile("other.y = 1; eval.call(other, 'y')");
10821   result = script->Run();
10822   CHECK(try_catch.HasCaught());
10823 }
10824
10825
10826 // Test that calling eval in a context which has been detached from
10827 // its global throws an exception.  This behavior is consistent with
10828 // other JavaScript implementations.
10829 THREADED_TEST(EvalInDetachedGlobal) {
10830   v8::Isolate* isolate = CcTest::isolate();
10831   v8::HandleScope scope(isolate);
10832
10833   v8::Local<Context> context0 = Context::New(isolate);
10834   v8::Local<Context> context1 = Context::New(isolate);
10835
10836   // Set up function in context0 that uses eval from context0.
10837   context0->Enter();
10838   v8::Handle<v8::Value> fun =
10839       CompileRun("var x = 42;"
10840                  "(function() {"
10841                  "  var e = eval;"
10842                  "  return function(s) { return e(s); }"
10843                  "})()");
10844   context0->Exit();
10845
10846   // Put the function into context1 and call it before and after
10847   // detaching the global.  Before detaching, the call succeeds and
10848   // after detaching and exception is thrown.
10849   context1->Enter();
10850   context1->Global()->Set(v8_str("fun"), fun);
10851   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10852   CHECK_EQ(42, x_value->Int32Value());
10853   context0->DetachGlobal();
10854   v8::TryCatch catcher;
10855   x_value = CompileRun("fun('x')");
10856   CHECK(x_value.IsEmpty());
10857   CHECK(catcher.HasCaught());
10858   context1->Exit();
10859 }
10860
10861
10862 THREADED_TEST(CrossLazyLoad) {
10863   v8::HandleScope scope(CcTest::isolate());
10864   LocalContext other;
10865   LocalContext current;
10866
10867   Local<String> token = v8_str("<security token>");
10868   other->SetSecurityToken(token);
10869   current->SetSecurityToken(token);
10870
10871   // Set up reference from current to other.
10872   current->Global()->Set(v8_str("other"), other->Global());
10873
10874   // Trigger lazy loading in other context.
10875   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10876   Local<Value> value = script->Run();
10877   CHECK_EQ(42.0, value->NumberValue());
10878 }
10879
10880
10881 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10882   ApiTestFuzzer::Fuzz();
10883   if (args.IsConstructCall()) {
10884     if (args[0]->IsInt32()) {
10885       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10886       return;
10887     }
10888   }
10889
10890   args.GetReturnValue().Set(args[0]);
10891 }
10892
10893
10894 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10895   args.GetReturnValue().Set(args.This());
10896 }
10897
10898
10899 // Test that a call handler can be set for objects which will allow
10900 // non-function objects created through the API to be called as
10901 // functions.
10902 THREADED_TEST(CallAsFunction) {
10903   LocalContext context;
10904   v8::Isolate* isolate = context->GetIsolate();
10905   v8::HandleScope scope(isolate);
10906
10907   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10908     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10909     instance_template->SetCallAsFunctionHandler(call_as_function);
10910     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10911     context->Global()->Set(v8_str("obj"), instance);
10912     v8::TryCatch try_catch;
10913     Local<Value> value;
10914     CHECK(!try_catch.HasCaught());
10915
10916     value = CompileRun("obj(42)");
10917     CHECK(!try_catch.HasCaught());
10918     CHECK_EQ(42, value->Int32Value());
10919
10920     value = CompileRun("(function(o){return o(49)})(obj)");
10921     CHECK(!try_catch.HasCaught());
10922     CHECK_EQ(49, value->Int32Value());
10923
10924     // test special case of call as function
10925     value = CompileRun("[obj]['0'](45)");
10926     CHECK(!try_catch.HasCaught());
10927     CHECK_EQ(45, value->Int32Value());
10928
10929     value = CompileRun("obj.call = Function.prototype.call;"
10930                        "obj.call(null, 87)");
10931     CHECK(!try_catch.HasCaught());
10932     CHECK_EQ(87, value->Int32Value());
10933
10934     // Regression tests for bug #1116356: Calling call through call/apply
10935     // must work for non-function receivers.
10936     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10937     value = CompileRun(apply_99);
10938     CHECK(!try_catch.HasCaught());
10939     CHECK_EQ(99, value->Int32Value());
10940
10941     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10942     value = CompileRun(call_17);
10943     CHECK(!try_catch.HasCaught());
10944     CHECK_EQ(17, value->Int32Value());
10945
10946     // Check that the call-as-function handler can be called through
10947     // new.
10948     value = CompileRun("new obj(43)");
10949     CHECK(!try_catch.HasCaught());
10950     CHECK_EQ(-43, value->Int32Value());
10951
10952     // Check that the call-as-function handler can be called through
10953     // the API.
10954     v8::Handle<Value> args[] = { v8_num(28) };
10955     value = instance->CallAsFunction(instance, 1, args);
10956     CHECK(!try_catch.HasCaught());
10957     CHECK_EQ(28, value->Int32Value());
10958   }
10959
10960   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10961     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10962     USE(instance_template);
10963     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10964     context->Global()->Set(v8_str("obj2"), instance);
10965     v8::TryCatch try_catch;
10966     Local<Value> value;
10967     CHECK(!try_catch.HasCaught());
10968
10969     // Call an object without call-as-function handler through the JS
10970     value = CompileRun("obj2(28)");
10971     CHECK(value.IsEmpty());
10972     CHECK(try_catch.HasCaught());
10973     String::Utf8Value exception_value1(try_catch.Exception());
10974     // TODO(verwaest): Better message
10975     CHECK_EQ("TypeError: object is not a function",
10976              *exception_value1);
10977     try_catch.Reset();
10978
10979     // Call an object without call-as-function handler through the API
10980     value = CompileRun("obj2(28)");
10981     v8::Handle<Value> args[] = { v8_num(28) };
10982     value = instance->CallAsFunction(instance, 1, args);
10983     CHECK(value.IsEmpty());
10984     CHECK(try_catch.HasCaught());
10985     String::Utf8Value exception_value2(try_catch.Exception());
10986     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10987     try_catch.Reset();
10988   }
10989
10990   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10991     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10992     instance_template->SetCallAsFunctionHandler(ThrowValue);
10993     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10994     context->Global()->Set(v8_str("obj3"), instance);
10995     v8::TryCatch try_catch;
10996     Local<Value> value;
10997     CHECK(!try_catch.HasCaught());
10998
10999     // Catch the exception which is thrown by call-as-function handler
11000     value = CompileRun("obj3(22)");
11001     CHECK(try_catch.HasCaught());
11002     String::Utf8Value exception_value1(try_catch.Exception());
11003     CHECK_EQ("22", *exception_value1);
11004     try_catch.Reset();
11005
11006     v8::Handle<Value> args[] = { v8_num(23) };
11007     value = instance->CallAsFunction(instance, 1, args);
11008     CHECK(try_catch.HasCaught());
11009     String::Utf8Value exception_value2(try_catch.Exception());
11010     CHECK_EQ("23", *exception_value2);
11011     try_catch.Reset();
11012   }
11013
11014   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11015     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11016     instance_template->SetCallAsFunctionHandler(ReturnThis);
11017     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11018
11019     Local<v8::Value> a1 =
11020         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11021     CHECK(a1->StrictEquals(instance));
11022     Local<v8::Value> a2 =
11023         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11024     CHECK(a2->StrictEquals(instance));
11025     Local<v8::Value> a3 =
11026         instance->CallAsFunction(v8_num(42), 0, NULL);
11027     CHECK(a3->StrictEquals(instance));
11028     Local<v8::Value> a4 =
11029         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11030     CHECK(a4->StrictEquals(instance));
11031     Local<v8::Value> a5 =
11032         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11033     CHECK(a5->StrictEquals(instance));
11034   }
11035
11036   { CompileRun(
11037       "function ReturnThisSloppy() {"
11038       "  return this;"
11039       "}"
11040       "function ReturnThisStrict() {"
11041       "  'use strict';"
11042       "  return this;"
11043       "}");
11044     Local<Function> ReturnThisSloppy =
11045         Local<Function>::Cast(
11046             context->Global()->Get(v8_str("ReturnThisSloppy")));
11047     Local<Function> ReturnThisStrict =
11048         Local<Function>::Cast(
11049             context->Global()->Get(v8_str("ReturnThisStrict")));
11050
11051     Local<v8::Value> a1 =
11052         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11053     CHECK(a1->StrictEquals(context->Global()));
11054     Local<v8::Value> a2 =
11055         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11056     CHECK(a2->StrictEquals(context->Global()));
11057     Local<v8::Value> a3 =
11058         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11059     CHECK(a3->IsNumberObject());
11060     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11061     Local<v8::Value> a4 =
11062         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11063     CHECK(a4->IsStringObject());
11064     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11065     Local<v8::Value> a5 =
11066         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11067     CHECK(a5->IsBooleanObject());
11068     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11069
11070     Local<v8::Value> a6 =
11071         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11072     CHECK(a6->IsUndefined());
11073     Local<v8::Value> a7 =
11074         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11075     CHECK(a7->IsNull());
11076     Local<v8::Value> a8 =
11077         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11078     CHECK(a8->StrictEquals(v8_num(42)));
11079     Local<v8::Value> a9 =
11080         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11081     CHECK(a9->StrictEquals(v8_str("hello")));
11082     Local<v8::Value> a10 =
11083         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11084     CHECK(a10->StrictEquals(v8::True(isolate)));
11085   }
11086 }
11087
11088
11089 // Check whether a non-function object is callable.
11090 THREADED_TEST(CallableObject) {
11091   LocalContext context;
11092   v8::Isolate* isolate = context->GetIsolate();
11093   v8::HandleScope scope(isolate);
11094
11095   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11096     instance_template->SetCallAsFunctionHandler(call_as_function);
11097     Local<Object> instance = instance_template->NewInstance();
11098     v8::TryCatch try_catch;
11099
11100     CHECK(instance->IsCallable());
11101     CHECK(!try_catch.HasCaught());
11102   }
11103
11104   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11105     Local<Object> instance = instance_template->NewInstance();
11106     v8::TryCatch try_catch;
11107
11108     CHECK(!instance->IsCallable());
11109     CHECK(!try_catch.HasCaught());
11110   }
11111
11112   { Local<FunctionTemplate> function_template =
11113         FunctionTemplate::New(isolate, call_as_function);
11114     Local<Function> function = function_template->GetFunction();
11115     Local<Object> instance = function;
11116     v8::TryCatch try_catch;
11117
11118     CHECK(instance->IsCallable());
11119     CHECK(!try_catch.HasCaught());
11120   }
11121
11122   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11123     Local<Function> function = function_template->GetFunction();
11124     Local<Object> instance = function;
11125     v8::TryCatch try_catch;
11126
11127     CHECK(instance->IsCallable());
11128     CHECK(!try_catch.HasCaught());
11129   }
11130 }
11131
11132
11133 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11134   v8::HandleScope scope(isolate);
11135   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11136   for (int i = 0; i < iterations; i++) {
11137     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11138   }
11139   return Recurse(isolate, depth - 1, iterations);
11140 }
11141
11142
11143 THREADED_TEST(HandleIteration) {
11144   static const int kIterations = 500;
11145   static const int kNesting = 200;
11146   LocalContext context;
11147   v8::Isolate* isolate = context->GetIsolate();
11148   v8::HandleScope scope0(isolate);
11149   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11150   {
11151     v8::HandleScope scope1(isolate);
11152     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11153     for (int i = 0; i < kIterations; i++) {
11154       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11155       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11156     }
11157
11158     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11159     {
11160       v8::HandleScope scope2(CcTest::isolate());
11161       for (int j = 0; j < kIterations; j++) {
11162         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11163         CHECK_EQ(j + 1 + kIterations,
11164                  v8::HandleScope::NumberOfHandles(isolate));
11165       }
11166     }
11167     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11168   }
11169   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11170   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11171 }
11172
11173
11174 static void InterceptorHasOwnPropertyGetter(
11175     Local<String> name,
11176     const v8::PropertyCallbackInfo<v8::Value>& info) {
11177   ApiTestFuzzer::Fuzz();
11178 }
11179
11180
11181 THREADED_TEST(InterceptorHasOwnProperty) {
11182   LocalContext context;
11183   v8::Isolate* isolate = context->GetIsolate();
11184   v8::HandleScope scope(isolate);
11185   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11186   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11187   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11188   Local<Function> function = fun_templ->GetFunction();
11189   context->Global()->Set(v8_str("constructor"), function);
11190   v8::Handle<Value> value = CompileRun(
11191       "var o = new constructor();"
11192       "o.hasOwnProperty('ostehaps');");
11193   CHECK_EQ(false, value->BooleanValue());
11194   value = CompileRun(
11195       "o.ostehaps = 42;"
11196       "o.hasOwnProperty('ostehaps');");
11197   CHECK_EQ(true, value->BooleanValue());
11198   value = CompileRun(
11199       "var p = new constructor();"
11200       "p.hasOwnProperty('ostehaps');");
11201   CHECK_EQ(false, value->BooleanValue());
11202 }
11203
11204
11205 static void InterceptorHasOwnPropertyGetterGC(
11206     Local<String> name,
11207     const v8::PropertyCallbackInfo<v8::Value>& info) {
11208   ApiTestFuzzer::Fuzz();
11209   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11210 }
11211
11212
11213 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11214   LocalContext context;
11215   v8::Isolate* isolate = context->GetIsolate();
11216   v8::HandleScope scope(isolate);
11217   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11218   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11219   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11220   Local<Function> function = fun_templ->GetFunction();
11221   context->Global()->Set(v8_str("constructor"), function);
11222   // Let's first make some stuff so we can be sure to get a good GC.
11223   CompileRun(
11224       "function makestr(size) {"
11225       "  switch (size) {"
11226       "    case 1: return 'f';"
11227       "    case 2: return 'fo';"
11228       "    case 3: return 'foo';"
11229       "  }"
11230       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11231       "}"
11232       "var x = makestr(12345);"
11233       "x = makestr(31415);"
11234       "x = makestr(23456);");
11235   v8::Handle<Value> value = CompileRun(
11236       "var o = new constructor();"
11237       "o.__proto__ = new String(x);"
11238       "o.hasOwnProperty('ostehaps');");
11239   CHECK_EQ(false, value->BooleanValue());
11240 }
11241
11242
11243 typedef void (*NamedPropertyGetter)(
11244     Local<String> property,
11245     const v8::PropertyCallbackInfo<v8::Value>& info);
11246
11247
11248 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11249                                    const char* source,
11250                                    int expected) {
11251   v8::Isolate* isolate = CcTest::isolate();
11252   v8::HandleScope scope(isolate);
11253   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11254   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11255   LocalContext context;
11256   context->Global()->Set(v8_str("o"), templ->NewInstance());
11257   v8::Handle<Value> value = CompileRun(source);
11258   CHECK_EQ(expected, value->Int32Value());
11259 }
11260
11261
11262 static void InterceptorLoadICGetter(
11263     Local<String> name,
11264     const v8::PropertyCallbackInfo<v8::Value>& info) {
11265   ApiTestFuzzer::Fuzz();
11266   v8::Isolate* isolate = CcTest::isolate();
11267   CHECK_EQ(isolate, info.GetIsolate());
11268   CHECK_EQ(v8_str("data"), info.Data());
11269   CHECK_EQ(v8_str("x"), name);
11270   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11271 }
11272
11273
11274 // This test should hit the load IC for the interceptor case.
11275 THREADED_TEST(InterceptorLoadIC) {
11276   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11277     "var result = 0;"
11278     "for (var i = 0; i < 1000; i++) {"
11279     "  result = o.x;"
11280     "}",
11281     42);
11282 }
11283
11284
11285 // Below go several tests which verify that JITing for various
11286 // configurations of interceptor and explicit fields works fine
11287 // (those cases are special cased to get better performance).
11288
11289 static void InterceptorLoadXICGetter(
11290     Local<String> name,
11291     const v8::PropertyCallbackInfo<v8::Value>& info) {
11292   ApiTestFuzzer::Fuzz();
11293   info.GetReturnValue().Set(
11294       v8_str("x")->Equals(name) ?
11295           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11296           v8::Handle<v8::Value>());
11297 }
11298
11299
11300 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11301   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11302     "var result = 0;"
11303     "o.y = 239;"
11304     "for (var i = 0; i < 1000; i++) {"
11305     "  result = o.y;"
11306     "}",
11307     239);
11308 }
11309
11310
11311 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11312   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11313     "var result = 0;"
11314     "o.__proto__ = { 'y': 239 };"
11315     "for (var i = 0; i < 1000; i++) {"
11316     "  result = o.y + o.x;"
11317     "}",
11318     239 + 42);
11319 }
11320
11321
11322 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11323   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11324     "var result = 0;"
11325     "o.__proto__.y = 239;"
11326     "for (var i = 0; i < 1000; i++) {"
11327     "  result = o.y + o.x;"
11328     "}",
11329     239 + 42);
11330 }
11331
11332
11333 THREADED_TEST(InterceptorLoadICUndefined) {
11334   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11335     "var result = 0;"
11336     "for (var i = 0; i < 1000; i++) {"
11337     "  result = (o.y == undefined) ? 239 : 42;"
11338     "}",
11339     239);
11340 }
11341
11342
11343 THREADED_TEST(InterceptorLoadICWithOverride) {
11344   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11345     "fst = new Object();  fst.__proto__ = o;"
11346     "snd = new Object();  snd.__proto__ = fst;"
11347     "var result1 = 0;"
11348     "for (var i = 0; i < 1000;  i++) {"
11349     "  result1 = snd.x;"
11350     "}"
11351     "fst.x = 239;"
11352     "var result = 0;"
11353     "for (var i = 0; i < 1000; i++) {"
11354     "  result = snd.x;"
11355     "}"
11356     "result + result1",
11357     239 + 42);
11358 }
11359
11360
11361 // Test the case when we stored field into
11362 // a stub, but interceptor produced value on its own.
11363 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11364   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11365     "proto = new Object();"
11366     "o.__proto__ = proto;"
11367     "proto.x = 239;"
11368     "for (var i = 0; i < 1000; i++) {"
11369     "  o.x;"
11370     // Now it should be ICed and keep a reference to x defined on proto
11371     "}"
11372     "var result = 0;"
11373     "for (var i = 0; i < 1000; i++) {"
11374     "  result += o.x;"
11375     "}"
11376     "result;",
11377     42 * 1000);
11378 }
11379
11380
11381 // Test the case when we stored field into
11382 // a stub, but it got invalidated later on.
11383 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11384   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11385     "proto1 = new Object();"
11386     "proto2 = new Object();"
11387     "o.__proto__ = proto1;"
11388     "proto1.__proto__ = proto2;"
11389     "proto2.y = 239;"
11390     "for (var i = 0; i < 1000; i++) {"
11391     "  o.y;"
11392     // Now it should be ICed and keep a reference to y defined on proto2
11393     "}"
11394     "proto1.y = 42;"
11395     "var result = 0;"
11396     "for (var i = 0; i < 1000; i++) {"
11397     "  result += o.y;"
11398     "}"
11399     "result;",
11400     42 * 1000);
11401 }
11402
11403
11404 static int interceptor_load_not_handled_calls = 0;
11405 static void InterceptorLoadNotHandled(
11406     Local<String> name,
11407     const v8::PropertyCallbackInfo<v8::Value>& info) {
11408   ++interceptor_load_not_handled_calls;
11409 }
11410
11411
11412 // Test how post-interceptor lookups are done in the non-cacheable
11413 // case: the interceptor should not be invoked during this lookup.
11414 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11415   interceptor_load_not_handled_calls = 0;
11416   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11417     "receiver = new Object();"
11418     "receiver.__proto__ = o;"
11419     "proto = new Object();"
11420     "/* Make proto a slow-case object. */"
11421     "for (var i = 0; i < 1000; i++) {"
11422     "  proto[\"xxxxxxxx\" + i] = [];"
11423     "}"
11424     "proto.x = 17;"
11425     "o.__proto__ = proto;"
11426     "var result = 0;"
11427     "for (var i = 0; i < 1000; i++) {"
11428     "  result += receiver.x;"
11429     "}"
11430     "result;",
11431     17 * 1000);
11432   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11433 }
11434
11435
11436 // Test the case when we stored field into
11437 // a stub, but it got invalidated later on due to override on
11438 // global object which is between interceptor and fields' holders.
11439 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11440   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11441     "o.__proto__ = this;"  // set a global to be a proto of o.
11442     "this.__proto__.y = 239;"
11443     "for (var i = 0; i < 10; i++) {"
11444     "  if (o.y != 239) throw 'oops: ' + o.y;"
11445     // Now it should be ICed and keep a reference to y defined on field_holder.
11446     "}"
11447     "this.y = 42;"  // Assign on a global.
11448     "var result = 0;"
11449     "for (var i = 0; i < 10; i++) {"
11450     "  result += o.y;"
11451     "}"
11452     "result;",
11453     42 * 10);
11454 }
11455
11456
11457 static void SetOnThis(Local<String> name,
11458                       Local<Value> value,
11459                       const v8::PropertyCallbackInfo<void>& info) {
11460   Local<Object>::Cast(info.This())->ForceSet(name, value);
11461 }
11462
11463
11464 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11465   v8::Isolate* isolate = CcTest::isolate();
11466   v8::HandleScope scope(isolate);
11467   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11468   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11469   templ->SetAccessor(v8_str("y"), Return239Callback);
11470   LocalContext context;
11471   context->Global()->Set(v8_str("o"), templ->NewInstance());
11472
11473   // Check the case when receiver and interceptor's holder
11474   // are the same objects.
11475   v8::Handle<Value> value = CompileRun(
11476       "var result = 0;"
11477       "for (var i = 0; i < 7; i++) {"
11478       "  result = o.y;"
11479       "}");
11480   CHECK_EQ(239, value->Int32Value());
11481
11482   // Check the case when interceptor's holder is in proto chain
11483   // of receiver.
11484   value = CompileRun(
11485       "r = { __proto__: o };"
11486       "var result = 0;"
11487       "for (var i = 0; i < 7; i++) {"
11488       "  result = r.y;"
11489       "}");
11490   CHECK_EQ(239, value->Int32Value());
11491 }
11492
11493
11494 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11495   v8::Isolate* isolate = CcTest::isolate();
11496   v8::HandleScope scope(isolate);
11497   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11498   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11499   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11500   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11501
11502   LocalContext context;
11503   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11504   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11505
11506   // Check the case when receiver and interceptor's holder
11507   // are the same objects.
11508   v8::Handle<Value> value = CompileRun(
11509       "o.__proto__ = p;"
11510       "var result = 0;"
11511       "for (var i = 0; i < 7; i++) {"
11512       "  result = o.x + o.y;"
11513       "}");
11514   CHECK_EQ(239 + 42, value->Int32Value());
11515
11516   // Check the case when interceptor's holder is in proto chain
11517   // of receiver.
11518   value = CompileRun(
11519       "r = { __proto__: o };"
11520       "var result = 0;"
11521       "for (var i = 0; i < 7; i++) {"
11522       "  result = r.x + r.y;"
11523       "}");
11524   CHECK_EQ(239 + 42, value->Int32Value());
11525 }
11526
11527
11528 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11529   v8::Isolate* isolate = CcTest::isolate();
11530   v8::HandleScope scope(isolate);
11531   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11532   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11533   templ->SetAccessor(v8_str("y"), Return239Callback);
11534
11535   LocalContext context;
11536   context->Global()->Set(v8_str("o"), templ->NewInstance());
11537
11538   v8::Handle<Value> value = CompileRun(
11539     "fst = new Object();  fst.__proto__ = o;"
11540     "snd = new Object();  snd.__proto__ = fst;"
11541     "var result1 = 0;"
11542     "for (var i = 0; i < 7;  i++) {"
11543     "  result1 = snd.x;"
11544     "}"
11545     "fst.x = 239;"
11546     "var result = 0;"
11547     "for (var i = 0; i < 7; i++) {"
11548     "  result = snd.x;"
11549     "}"
11550     "result + result1");
11551   CHECK_EQ(239 + 42, value->Int32Value());
11552 }
11553
11554
11555 // Test the case when we stored callback into
11556 // a stub, but interceptor produced value on its own.
11557 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11558   v8::Isolate* isolate = CcTest::isolate();
11559   v8::HandleScope scope(isolate);
11560   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11561   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11562   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11563   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11564
11565   LocalContext context;
11566   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11567   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11568
11569   v8::Handle<Value> value = CompileRun(
11570     "o.__proto__ = p;"
11571     "for (var i = 0; i < 7; i++) {"
11572     "  o.x;"
11573     // Now it should be ICed and keep a reference to x defined on p
11574     "}"
11575     "var result = 0;"
11576     "for (var i = 0; i < 7; i++) {"
11577     "  result += o.x;"
11578     "}"
11579     "result");
11580   CHECK_EQ(42 * 7, value->Int32Value());
11581 }
11582
11583
11584 // Test the case when we stored callback into
11585 // a stub, but it got invalidated later on.
11586 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11587   v8::Isolate* isolate = CcTest::isolate();
11588   v8::HandleScope scope(isolate);
11589   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11590   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11591   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11592   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11593
11594   LocalContext context;
11595   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11596   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11597
11598   v8::Handle<Value> value = CompileRun(
11599     "inbetween = new Object();"
11600     "o.__proto__ = inbetween;"
11601     "inbetween.__proto__ = p;"
11602     "for (var i = 0; i < 10; i++) {"
11603     "  o.y;"
11604     // Now it should be ICed and keep a reference to y defined on p
11605     "}"
11606     "inbetween.y = 42;"
11607     "var result = 0;"
11608     "for (var i = 0; i < 10; i++) {"
11609     "  result += o.y;"
11610     "}"
11611     "result");
11612   CHECK_EQ(42 * 10, value->Int32Value());
11613 }
11614
11615
11616 // Test the case when we stored callback into
11617 // a stub, but it got invalidated later on due to override on
11618 // global object which is between interceptor and callbacks' holders.
11619 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11620   v8::Isolate* isolate = CcTest::isolate();
11621   v8::HandleScope scope(isolate);
11622   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11623   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11624   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11625   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11626
11627   LocalContext context;
11628   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11629   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11630
11631   v8::Handle<Value> value = CompileRun(
11632     "o.__proto__ = this;"
11633     "this.__proto__ = p;"
11634     "for (var i = 0; i < 10; i++) {"
11635     "  if (o.y != 239) throw 'oops: ' + o.y;"
11636     // Now it should be ICed and keep a reference to y defined on p
11637     "}"
11638     "this.y = 42;"
11639     "var result = 0;"
11640     "for (var i = 0; i < 10; i++) {"
11641     "  result += o.y;"
11642     "}"
11643     "result");
11644   CHECK_EQ(42 * 10, value->Int32Value());
11645 }
11646
11647
11648 static void InterceptorLoadICGetter0(
11649     Local<String> name,
11650     const v8::PropertyCallbackInfo<v8::Value>& info) {
11651   ApiTestFuzzer::Fuzz();
11652   CHECK(v8_str("x")->Equals(name));
11653   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11654 }
11655
11656
11657 THREADED_TEST(InterceptorReturningZero) {
11658   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11659      "o.x == undefined ? 1 : 0",
11660      0);
11661 }
11662
11663
11664 static void InterceptorStoreICSetter(
11665     Local<String> key,
11666     Local<Value> value,
11667     const v8::PropertyCallbackInfo<v8::Value>& info) {
11668   CHECK(v8_str("x")->Equals(key));
11669   CHECK_EQ(42, value->Int32Value());
11670   info.GetReturnValue().Set(value);
11671 }
11672
11673
11674 // This test should hit the store IC for the interceptor case.
11675 THREADED_TEST(InterceptorStoreIC) {
11676   v8::Isolate* isolate = CcTest::isolate();
11677   v8::HandleScope scope(isolate);
11678   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11679   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11680                                  InterceptorStoreICSetter,
11681                                  0, 0, 0, v8_str("data"));
11682   LocalContext context;
11683   context->Global()->Set(v8_str("o"), templ->NewInstance());
11684   CompileRun(
11685       "for (var i = 0; i < 1000; i++) {"
11686       "  o.x = 42;"
11687       "}");
11688 }
11689
11690
11691 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11692   v8::Isolate* isolate = CcTest::isolate();
11693   v8::HandleScope scope(isolate);
11694   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11695   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11696   LocalContext context;
11697   context->Global()->Set(v8_str("o"), templ->NewInstance());
11698   v8::Handle<Value> value = CompileRun(
11699     "for (var i = 0; i < 1000; i++) {"
11700     "  o.y = 239;"
11701     "}"
11702     "42 + o.y");
11703   CHECK_EQ(239 + 42, value->Int32Value());
11704 }
11705
11706
11707
11708
11709 v8::Handle<Value> call_ic_function;
11710 v8::Handle<Value> call_ic_function2;
11711 v8::Handle<Value> call_ic_function3;
11712
11713 static void InterceptorCallICGetter(
11714     Local<String> name,
11715     const v8::PropertyCallbackInfo<v8::Value>& info) {
11716   ApiTestFuzzer::Fuzz();
11717   CHECK(v8_str("x")->Equals(name));
11718   info.GetReturnValue().Set(call_ic_function);
11719 }
11720
11721
11722 // This test should hit the call IC for the interceptor case.
11723 THREADED_TEST(InterceptorCallIC) {
11724   v8::Isolate* isolate = CcTest::isolate();
11725   v8::HandleScope scope(isolate);
11726   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11727   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11728   LocalContext context;
11729   context->Global()->Set(v8_str("o"), templ->NewInstance());
11730   call_ic_function =
11731       v8_compile("function f(x) { return x + 1; }; f")->Run();
11732   v8::Handle<Value> value = CompileRun(
11733     "var result = 0;"
11734     "for (var i = 0; i < 1000; i++) {"
11735     "  result = o.x(41);"
11736     "}");
11737   CHECK_EQ(42, value->Int32Value());
11738 }
11739
11740
11741 // This test checks that if interceptor doesn't provide
11742 // a value, we can fetch regular value.
11743 THREADED_TEST(InterceptorCallICSeesOthers) {
11744   v8::Isolate* isolate = CcTest::isolate();
11745   v8::HandleScope scope(isolate);
11746   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11747   templ->SetNamedPropertyHandler(NoBlockGetterX);
11748   LocalContext context;
11749   context->Global()->Set(v8_str("o"), templ->NewInstance());
11750   v8::Handle<Value> value = CompileRun(
11751     "o.x = function f(x) { return x + 1; };"
11752     "var result = 0;"
11753     "for (var i = 0; i < 7; i++) {"
11754     "  result = o.x(41);"
11755     "}");
11756   CHECK_EQ(42, value->Int32Value());
11757 }
11758
11759
11760 static v8::Handle<Value> call_ic_function4;
11761 static void InterceptorCallICGetter4(
11762     Local<String> name,
11763     const v8::PropertyCallbackInfo<v8::Value>& info) {
11764   ApiTestFuzzer::Fuzz();
11765   CHECK(v8_str("x")->Equals(name));
11766   info.GetReturnValue().Set(call_ic_function4);
11767 }
11768
11769
11770 // This test checks that if interceptor provides a function,
11771 // even if we cached shadowed variant, interceptor's function
11772 // is invoked
11773 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11774   v8::Isolate* isolate = CcTest::isolate();
11775   v8::HandleScope scope(isolate);
11776   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11777   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11778   LocalContext context;
11779   context->Global()->Set(v8_str("o"), templ->NewInstance());
11780   call_ic_function4 =
11781       v8_compile("function f(x) { return x - 1; }; f")->Run();
11782   v8::Handle<Value> value = CompileRun(
11783     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11784     "var result = 0;"
11785     "for (var i = 0; i < 1000; i++) {"
11786     "  result = o.x(42);"
11787     "}");
11788   CHECK_EQ(41, value->Int32Value());
11789 }
11790
11791
11792 // Test the case when we stored cacheable lookup into
11793 // a stub, but it got invalidated later on
11794 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11795   v8::Isolate* isolate = CcTest::isolate();
11796   v8::HandleScope scope(isolate);
11797   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11798   templ->SetNamedPropertyHandler(NoBlockGetterX);
11799   LocalContext context;
11800   context->Global()->Set(v8_str("o"), templ->NewInstance());
11801   v8::Handle<Value> value = CompileRun(
11802     "proto1 = new Object();"
11803     "proto2 = new Object();"
11804     "o.__proto__ = proto1;"
11805     "proto1.__proto__ = proto2;"
11806     "proto2.y = function(x) { return x + 1; };"
11807     // Invoke it many times to compile a stub
11808     "for (var i = 0; i < 7; i++) {"
11809     "  o.y(42);"
11810     "}"
11811     "proto1.y = function(x) { return x - 1; };"
11812     "var result = 0;"
11813     "for (var i = 0; i < 7; i++) {"
11814     "  result += o.y(42);"
11815     "}");
11816   CHECK_EQ(41 * 7, value->Int32Value());
11817 }
11818
11819
11820 // This test checks that if interceptor doesn't provide a function,
11821 // cached constant function is used
11822 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11823   v8::Isolate* isolate = CcTest::isolate();
11824   v8::HandleScope scope(isolate);
11825   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11826   templ->SetNamedPropertyHandler(NoBlockGetterX);
11827   LocalContext context;
11828   context->Global()->Set(v8_str("o"), templ->NewInstance());
11829   v8::Handle<Value> value = CompileRun(
11830     "function inc(x) { return x + 1; };"
11831     "inc(1);"
11832     "o.x = inc;"
11833     "var result = 0;"
11834     "for (var i = 0; i < 1000; i++) {"
11835     "  result = o.x(42);"
11836     "}");
11837   CHECK_EQ(43, value->Int32Value());
11838 }
11839
11840
11841 static v8::Handle<Value> call_ic_function5;
11842 static void InterceptorCallICGetter5(
11843     Local<String> name,
11844     const v8::PropertyCallbackInfo<v8::Value>& info) {
11845   ApiTestFuzzer::Fuzz();
11846   if (v8_str("x")->Equals(name))
11847     info.GetReturnValue().Set(call_ic_function5);
11848 }
11849
11850
11851 // This test checks that if interceptor provides a function,
11852 // even if we cached constant function, interceptor's function
11853 // is invoked
11854 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11855   v8::Isolate* isolate = CcTest::isolate();
11856   v8::HandleScope scope(isolate);
11857   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11858   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11859   LocalContext context;
11860   context->Global()->Set(v8_str("o"), templ->NewInstance());
11861   call_ic_function5 =
11862       v8_compile("function f(x) { return x - 1; }; f")->Run();
11863   v8::Handle<Value> value = CompileRun(
11864     "function inc(x) { return x + 1; };"
11865     "inc(1);"
11866     "o.x = inc;"
11867     "var result = 0;"
11868     "for (var i = 0; i < 1000; i++) {"
11869     "  result = o.x(42);"
11870     "}");
11871   CHECK_EQ(41, value->Int32Value());
11872 }
11873
11874
11875 static v8::Handle<Value> call_ic_function6;
11876 static void InterceptorCallICGetter6(
11877     Local<String> name,
11878     const v8::PropertyCallbackInfo<v8::Value>& info) {
11879   ApiTestFuzzer::Fuzz();
11880   if (v8_str("x")->Equals(name))
11881     info.GetReturnValue().Set(call_ic_function6);
11882 }
11883
11884
11885 // Same test as above, except the code is wrapped in a function
11886 // to test the optimized compiler.
11887 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11888   i::FLAG_allow_natives_syntax = true;
11889   v8::Isolate* isolate = CcTest::isolate();
11890   v8::HandleScope scope(isolate);
11891   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11892   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11893   LocalContext context;
11894   context->Global()->Set(v8_str("o"), templ->NewInstance());
11895   call_ic_function6 =
11896       v8_compile("function f(x) { return x - 1; }; f")->Run();
11897   v8::Handle<Value> value = CompileRun(
11898     "function inc(x) { return x + 1; };"
11899     "inc(1);"
11900     "o.x = inc;"
11901     "function test() {"
11902     "  var result = 0;"
11903     "  for (var i = 0; i < 1000; i++) {"
11904     "    result = o.x(42);"
11905     "  }"
11906     "  return result;"
11907     "};"
11908     "test();"
11909     "test();"
11910     "test();"
11911     "%OptimizeFunctionOnNextCall(test);"
11912     "test()");
11913   CHECK_EQ(41, value->Int32Value());
11914 }
11915
11916
11917 // Test the case when we stored constant function into
11918 // a stub, but it got invalidated later on
11919 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11920   v8::Isolate* isolate = CcTest::isolate();
11921   v8::HandleScope scope(isolate);
11922   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11923   templ->SetNamedPropertyHandler(NoBlockGetterX);
11924   LocalContext context;
11925   context->Global()->Set(v8_str("o"), templ->NewInstance());
11926   v8::Handle<Value> value = CompileRun(
11927     "function inc(x) { return x + 1; };"
11928     "inc(1);"
11929     "proto1 = new Object();"
11930     "proto2 = new Object();"
11931     "o.__proto__ = proto1;"
11932     "proto1.__proto__ = proto2;"
11933     "proto2.y = inc;"
11934     // Invoke it many times to compile a stub
11935     "for (var i = 0; i < 7; i++) {"
11936     "  o.y(42);"
11937     "}"
11938     "proto1.y = function(x) { return x - 1; };"
11939     "var result = 0;"
11940     "for (var i = 0; i < 7; i++) {"
11941     "  result += o.y(42);"
11942     "}");
11943   CHECK_EQ(41 * 7, value->Int32Value());
11944 }
11945
11946
11947 // Test the case when we stored constant function into
11948 // a stub, but it got invalidated later on due to override on
11949 // global object which is between interceptor and constant function' holders.
11950 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11951   v8::Isolate* isolate = CcTest::isolate();
11952   v8::HandleScope scope(isolate);
11953   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11954   templ->SetNamedPropertyHandler(NoBlockGetterX);
11955   LocalContext context;
11956   context->Global()->Set(v8_str("o"), templ->NewInstance());
11957   v8::Handle<Value> value = CompileRun(
11958     "function inc(x) { return x + 1; };"
11959     "inc(1);"
11960     "o.__proto__ = this;"
11961     "this.__proto__.y = inc;"
11962     // Invoke it many times to compile a stub
11963     "for (var i = 0; i < 7; i++) {"
11964     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11965     "}"
11966     "this.y = function(x) { return x - 1; };"
11967     "var result = 0;"
11968     "for (var i = 0; i < 7; i++) {"
11969     "  result += o.y(42);"
11970     "}");
11971   CHECK_EQ(41 * 7, value->Int32Value());
11972 }
11973
11974
11975 // Test the case when actual function to call sits on global object.
11976 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11977   v8::Isolate* isolate = CcTest::isolate();
11978   v8::HandleScope scope(isolate);
11979   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11980   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11981
11982   LocalContext context;
11983   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11984
11985   v8::Handle<Value> value = CompileRun(
11986     "try {"
11987     "  o.__proto__ = this;"
11988     "  for (var i = 0; i < 10; i++) {"
11989     "    var v = o.parseFloat('239');"
11990     "    if (v != 239) throw v;"
11991       // Now it should be ICed and keep a reference to parseFloat.
11992     "  }"
11993     "  var result = 0;"
11994     "  for (var i = 0; i < 10; i++) {"
11995     "    result += o.parseFloat('239');"
11996     "  }"
11997     "  result"
11998     "} catch(e) {"
11999     "  e"
12000     "};");
12001   CHECK_EQ(239 * 10, value->Int32Value());
12002 }
12003
12004 static void InterceptorCallICFastApi(
12005     Local<String> name,
12006     const v8::PropertyCallbackInfo<v8::Value>& info) {
12007   ApiTestFuzzer::Fuzz();
12008   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12009   int* call_count =
12010       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12011   ++(*call_count);
12012   if ((*call_count) % 20 == 0) {
12013     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12014   }
12015 }
12016
12017 static void FastApiCallback_TrivialSignature(
12018     const v8::FunctionCallbackInfo<v8::Value>& args) {
12019   ApiTestFuzzer::Fuzz();
12020   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12021   v8::Isolate* isolate = CcTest::isolate();
12022   CHECK_EQ(isolate, args.GetIsolate());
12023   CHECK_EQ(args.This(), args.Holder());
12024   CHECK(args.Data()->Equals(v8_str("method_data")));
12025   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12026 }
12027
12028 static void FastApiCallback_SimpleSignature(
12029     const v8::FunctionCallbackInfo<v8::Value>& args) {
12030   ApiTestFuzzer::Fuzz();
12031   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12032   v8::Isolate* isolate = CcTest::isolate();
12033   CHECK_EQ(isolate, args.GetIsolate());
12034   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12035   CHECK(args.Data()->Equals(v8_str("method_data")));
12036   // Note, we're using HasRealNamedProperty instead of Has to avoid
12037   // invoking the interceptor again.
12038   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12039   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12040 }
12041
12042
12043 // Helper to maximize the odds of object moving.
12044 static void GenerateSomeGarbage() {
12045   CompileRun(
12046       "var garbage;"
12047       "for (var i = 0; i < 1000; i++) {"
12048       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12049       "}"
12050       "garbage = undefined;");
12051 }
12052
12053
12054 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12055   static int count = 0;
12056   if (count++ % 3 == 0) {
12057     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12058         // This should move the stub
12059     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12060   }
12061 }
12062
12063
12064 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12065   LocalContext context;
12066   v8::Isolate* isolate = context->GetIsolate();
12067   v8::HandleScope scope(isolate);
12068   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12069       v8::ObjectTemplate::New(isolate);
12070   nativeobject_templ->Set(isolate, "callback",
12071                           v8::FunctionTemplate::New(isolate,
12072                                                     DirectApiCallback));
12073   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12074   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12075   // call the api function multiple times to ensure direct call stub creation.
12076   CompileRun(
12077         "function f() {"
12078         "  for (var i = 1; i <= 30; i++) {"
12079         "    nativeobject.callback();"
12080         "  }"
12081         "}"
12082         "f();");
12083 }
12084
12085
12086 void ThrowingDirectApiCallback(
12087     const v8::FunctionCallbackInfo<v8::Value>& args) {
12088   args.GetIsolate()->ThrowException(v8_str("g"));
12089 }
12090
12091
12092 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12093   LocalContext context;
12094   v8::Isolate* isolate = context->GetIsolate();
12095   v8::HandleScope scope(isolate);
12096   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12097       v8::ObjectTemplate::New(isolate);
12098   nativeobject_templ->Set(isolate, "callback",
12099                           v8::FunctionTemplate::New(isolate,
12100                                                     ThrowingDirectApiCallback));
12101   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12102   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12103   // call the api function multiple times to ensure direct call stub creation.
12104   v8::Handle<Value> result = CompileRun(
12105       "var result = '';"
12106       "function f() {"
12107       "  for (var i = 1; i <= 5; i++) {"
12108       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12109       "  }"
12110       "}"
12111       "f(); result;");
12112   CHECK_EQ(v8_str("ggggg"), result);
12113 }
12114
12115
12116 static Handle<Value> DoDirectGetter() {
12117   if (++p_getter_count % 3 == 0) {
12118     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12119     GenerateSomeGarbage();
12120   }
12121   return v8_str("Direct Getter Result");
12122 }
12123
12124 static void DirectGetterCallback(
12125     Local<String> name,
12126     const v8::PropertyCallbackInfo<v8::Value>& info) {
12127   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12128   info.GetReturnValue().Set(DoDirectGetter());
12129 }
12130
12131
12132 template<typename Accessor>
12133 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12134   LocalContext context;
12135   v8::Isolate* isolate = context->GetIsolate();
12136   v8::HandleScope scope(isolate);
12137   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12138   obj->SetAccessor(v8_str("p1"), accessor);
12139   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12140   p_getter_count = 0;
12141   v8::Handle<v8::Value> result = CompileRun(
12142       "function f() {"
12143       "  for (var i = 0; i < 30; i++) o1.p1;"
12144       "  return o1.p1"
12145       "}"
12146       "f();");
12147   CHECK_EQ(v8_str("Direct Getter Result"), result);
12148   CHECK_EQ(31, p_getter_count);
12149 }
12150
12151
12152 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12153   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12154 }
12155
12156
12157 void ThrowingDirectGetterCallback(
12158     Local<String> name,
12159     const v8::PropertyCallbackInfo<v8::Value>& info) {
12160   info.GetIsolate()->ThrowException(v8_str("g"));
12161 }
12162
12163
12164 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12165   LocalContext context;
12166   v8::Isolate* isolate = context->GetIsolate();
12167   v8::HandleScope scope(isolate);
12168   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12169   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12170   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12171   v8::Handle<Value> result = CompileRun(
12172       "var result = '';"
12173       "for (var i = 0; i < 5; i++) {"
12174       "    try { o1.p1; } catch (e) { result += e; }"
12175       "}"
12176       "result;");
12177   CHECK_EQ(v8_str("ggggg"), result);
12178 }
12179
12180
12181 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12182   int interceptor_call_count = 0;
12183   v8::Isolate* isolate = CcTest::isolate();
12184   v8::HandleScope scope(isolate);
12185   v8::Handle<v8::FunctionTemplate> fun_templ =
12186       v8::FunctionTemplate::New(isolate);
12187   v8::Handle<v8::FunctionTemplate> method_templ =
12188       v8::FunctionTemplate::New(isolate,
12189                                 FastApiCallback_TrivialSignature,
12190                                 v8_str("method_data"),
12191                                 v8::Handle<v8::Signature>());
12192   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12193   proto_templ->Set(v8_str("method"), method_templ);
12194   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12195   templ->SetNamedPropertyHandler(
12196       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12197       v8::External::New(isolate, &interceptor_call_count));
12198   LocalContext context;
12199   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12200   GenerateSomeGarbage();
12201   context->Global()->Set(v8_str("o"), fun->NewInstance());
12202   CompileRun(
12203       "var result = 0;"
12204       "for (var i = 0; i < 100; i++) {"
12205       "  result = o.method(41);"
12206       "}");
12207   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12208   CHECK_EQ(100, interceptor_call_count);
12209 }
12210
12211
12212 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12213   int interceptor_call_count = 0;
12214   v8::Isolate* isolate = CcTest::isolate();
12215   v8::HandleScope scope(isolate);
12216   v8::Handle<v8::FunctionTemplate> fun_templ =
12217       v8::FunctionTemplate::New(isolate);
12218   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12219       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12220       v8::Signature::New(isolate, fun_templ));
12221   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12222   proto_templ->Set(v8_str("method"), method_templ);
12223   fun_templ->SetHiddenPrototype(true);
12224   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12225   templ->SetNamedPropertyHandler(
12226       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12227       v8::External::New(isolate, &interceptor_call_count));
12228   LocalContext context;
12229   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12230   GenerateSomeGarbage();
12231   context->Global()->Set(v8_str("o"), fun->NewInstance());
12232   CompileRun(
12233       "o.foo = 17;"
12234       "var receiver = {};"
12235       "receiver.__proto__ = o;"
12236       "var result = 0;"
12237       "for (var i = 0; i < 100; i++) {"
12238       "  result = receiver.method(41);"
12239       "}");
12240   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12241   CHECK_EQ(100, interceptor_call_count);
12242 }
12243
12244
12245 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12246   int interceptor_call_count = 0;
12247   v8::Isolate* isolate = CcTest::isolate();
12248   v8::HandleScope scope(isolate);
12249   v8::Handle<v8::FunctionTemplate> fun_templ =
12250       v8::FunctionTemplate::New(isolate);
12251   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12252       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12253       v8::Signature::New(isolate, fun_templ));
12254   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12255   proto_templ->Set(v8_str("method"), method_templ);
12256   fun_templ->SetHiddenPrototype(true);
12257   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12258   templ->SetNamedPropertyHandler(
12259       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12260       v8::External::New(isolate, &interceptor_call_count));
12261   LocalContext context;
12262   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12263   GenerateSomeGarbage();
12264   context->Global()->Set(v8_str("o"), fun->NewInstance());
12265   CompileRun(
12266       "o.foo = 17;"
12267       "var receiver = {};"
12268       "receiver.__proto__ = o;"
12269       "var result = 0;"
12270       "var saved_result = 0;"
12271       "for (var i = 0; i < 100; i++) {"
12272       "  result = receiver.method(41);"
12273       "  if (i == 50) {"
12274       "    saved_result = result;"
12275       "    receiver = {method: function(x) { return x - 1 }};"
12276       "  }"
12277       "}");
12278   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12279   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12280   CHECK_GE(interceptor_call_count, 50);
12281 }
12282
12283
12284 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12285   int interceptor_call_count = 0;
12286   v8::Isolate* isolate = CcTest::isolate();
12287   v8::HandleScope scope(isolate);
12288   v8::Handle<v8::FunctionTemplate> fun_templ =
12289       v8::FunctionTemplate::New(isolate);
12290   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12291       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12292       v8::Signature::New(isolate, fun_templ));
12293   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12294   proto_templ->Set(v8_str("method"), method_templ);
12295   fun_templ->SetHiddenPrototype(true);
12296   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12297   templ->SetNamedPropertyHandler(
12298       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12299       v8::External::New(isolate, &interceptor_call_count));
12300   LocalContext context;
12301   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12302   GenerateSomeGarbage();
12303   context->Global()->Set(v8_str("o"), fun->NewInstance());
12304   CompileRun(
12305       "o.foo = 17;"
12306       "var receiver = {};"
12307       "receiver.__proto__ = o;"
12308       "var result = 0;"
12309       "var saved_result = 0;"
12310       "for (var i = 0; i < 100; i++) {"
12311       "  result = receiver.method(41);"
12312       "  if (i == 50) {"
12313       "    saved_result = result;"
12314       "    o.method = function(x) { return x - 1 };"
12315       "  }"
12316       "}");
12317   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12318   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12319   CHECK_GE(interceptor_call_count, 50);
12320 }
12321
12322
12323 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12324   int interceptor_call_count = 0;
12325   v8::Isolate* isolate = CcTest::isolate();
12326   v8::HandleScope scope(isolate);
12327   v8::Handle<v8::FunctionTemplate> fun_templ =
12328       v8::FunctionTemplate::New(isolate);
12329   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12330       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12331       v8::Signature::New(isolate, fun_templ));
12332   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12333   proto_templ->Set(v8_str("method"), method_templ);
12334   fun_templ->SetHiddenPrototype(true);
12335   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12336   templ->SetNamedPropertyHandler(
12337       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12338       v8::External::New(isolate, &interceptor_call_count));
12339   LocalContext context;
12340   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12341   GenerateSomeGarbage();
12342   context->Global()->Set(v8_str("o"), fun->NewInstance());
12343   v8::TryCatch try_catch;
12344   CompileRun(
12345       "o.foo = 17;"
12346       "var receiver = {};"
12347       "receiver.__proto__ = o;"
12348       "var result = 0;"
12349       "var saved_result = 0;"
12350       "for (var i = 0; i < 100; i++) {"
12351       "  result = receiver.method(41);"
12352       "  if (i == 50) {"
12353       "    saved_result = result;"
12354       "    receiver = 333;"
12355       "  }"
12356       "}");
12357   CHECK(try_catch.HasCaught());
12358   // TODO(verwaest): Adjust message.
12359   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12360            try_catch.Exception()->ToString());
12361   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12362   CHECK_GE(interceptor_call_count, 50);
12363 }
12364
12365
12366 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12367   int interceptor_call_count = 0;
12368   v8::Isolate* isolate = CcTest::isolate();
12369   v8::HandleScope scope(isolate);
12370   v8::Handle<v8::FunctionTemplate> fun_templ =
12371       v8::FunctionTemplate::New(isolate);
12372   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12373       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12374       v8::Signature::New(isolate, fun_templ));
12375   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12376   proto_templ->Set(v8_str("method"), method_templ);
12377   fun_templ->SetHiddenPrototype(true);
12378   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12379   templ->SetNamedPropertyHandler(
12380       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12381       v8::External::New(isolate, &interceptor_call_count));
12382   LocalContext context;
12383   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12384   GenerateSomeGarbage();
12385   context->Global()->Set(v8_str("o"), fun->NewInstance());
12386   v8::TryCatch try_catch;
12387   CompileRun(
12388       "o.foo = 17;"
12389       "var receiver = {};"
12390       "receiver.__proto__ = o;"
12391       "var result = 0;"
12392       "var saved_result = 0;"
12393       "for (var i = 0; i < 100; i++) {"
12394       "  result = receiver.method(41);"
12395       "  if (i == 50) {"
12396       "    saved_result = result;"
12397       "    receiver = {method: receiver.method};"
12398       "  }"
12399       "}");
12400   CHECK(try_catch.HasCaught());
12401   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12402            try_catch.Exception()->ToString());
12403   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12404   CHECK_GE(interceptor_call_count, 50);
12405 }
12406
12407
12408 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12409   v8::Isolate* isolate = CcTest::isolate();
12410   v8::HandleScope scope(isolate);
12411   v8::Handle<v8::FunctionTemplate> fun_templ =
12412       v8::FunctionTemplate::New(isolate);
12413   v8::Handle<v8::FunctionTemplate> method_templ =
12414       v8::FunctionTemplate::New(isolate,
12415                                 FastApiCallback_TrivialSignature,
12416                                 v8_str("method_data"),
12417                                 v8::Handle<v8::Signature>());
12418   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12419   proto_templ->Set(v8_str("method"), method_templ);
12420   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12421   USE(templ);
12422   LocalContext context;
12423   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12424   GenerateSomeGarbage();
12425   context->Global()->Set(v8_str("o"), fun->NewInstance());
12426   CompileRun(
12427       "var result = 0;"
12428       "for (var i = 0; i < 100; i++) {"
12429       "  result = o.method(41);"
12430       "}");
12431
12432   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12433 }
12434
12435
12436 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12437   v8::Isolate* isolate = CcTest::isolate();
12438   v8::HandleScope scope(isolate);
12439   v8::Handle<v8::FunctionTemplate> fun_templ =
12440       v8::FunctionTemplate::New(isolate);
12441   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12442       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12443       v8::Signature::New(isolate, fun_templ));
12444   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12445   proto_templ->Set(v8_str("method"), method_templ);
12446   fun_templ->SetHiddenPrototype(true);
12447   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12448   CHECK(!templ.IsEmpty());
12449   LocalContext context;
12450   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12451   GenerateSomeGarbage();
12452   context->Global()->Set(v8_str("o"), fun->NewInstance());
12453   CompileRun(
12454       "o.foo = 17;"
12455       "var receiver = {};"
12456       "receiver.__proto__ = o;"
12457       "var result = 0;"
12458       "for (var i = 0; i < 100; i++) {"
12459       "  result = receiver.method(41);"
12460       "}");
12461
12462   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12463 }
12464
12465
12466 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12467   v8::Isolate* isolate = CcTest::isolate();
12468   v8::HandleScope scope(isolate);
12469   v8::Handle<v8::FunctionTemplate> fun_templ =
12470       v8::FunctionTemplate::New(isolate);
12471   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12472       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12473       v8::Signature::New(isolate, fun_templ));
12474   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12475   proto_templ->Set(v8_str("method"), method_templ);
12476   fun_templ->SetHiddenPrototype(true);
12477   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12478   CHECK(!templ.IsEmpty());
12479   LocalContext context;
12480   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12481   GenerateSomeGarbage();
12482   context->Global()->Set(v8_str("o"), fun->NewInstance());
12483   CompileRun(
12484       "o.foo = 17;"
12485       "var receiver = {};"
12486       "receiver.__proto__ = o;"
12487       "var result = 0;"
12488       "var saved_result = 0;"
12489       "for (var i = 0; i < 100; i++) {"
12490       "  result = receiver.method(41);"
12491       "  if (i == 50) {"
12492       "    saved_result = result;"
12493       "    receiver = {method: function(x) { return x - 1 }};"
12494       "  }"
12495       "}");
12496   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12497   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12498 }
12499
12500
12501 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12502   v8::Isolate* isolate = CcTest::isolate();
12503   v8::HandleScope scope(isolate);
12504   v8::Handle<v8::FunctionTemplate> fun_templ =
12505       v8::FunctionTemplate::New(isolate);
12506   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12507       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12508       v8::Signature::New(isolate, fun_templ));
12509   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12510   proto_templ->Set(v8_str("method"), method_templ);
12511   fun_templ->SetHiddenPrototype(true);
12512   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12513   CHECK(!templ.IsEmpty());
12514   LocalContext context;
12515   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12516   GenerateSomeGarbage();
12517   context->Global()->Set(v8_str("o"), fun->NewInstance());
12518   v8::TryCatch try_catch;
12519   CompileRun(
12520       "o.foo = 17;"
12521       "var receiver = {};"
12522       "receiver.__proto__ = o;"
12523       "var result = 0;"
12524       "var saved_result = 0;"
12525       "for (var i = 0; i < 100; i++) {"
12526       "  result = receiver.method(41);"
12527       "  if (i == 50) {"
12528       "    saved_result = result;"
12529       "    receiver = 333;"
12530       "  }"
12531       "}");
12532   CHECK(try_catch.HasCaught());
12533   // TODO(verwaest): Adjust message.
12534   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12535            try_catch.Exception()->ToString());
12536   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12537 }
12538
12539
12540 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12541   v8::Isolate* isolate = CcTest::isolate();
12542   v8::HandleScope scope(isolate);
12543   v8::Handle<v8::FunctionTemplate> fun_templ =
12544       v8::FunctionTemplate::New(isolate);
12545   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12546       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12547       v8::Signature::New(isolate, fun_templ));
12548   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12549   proto_templ->Set(v8_str("method"), method_templ);
12550   fun_templ->SetHiddenPrototype(true);
12551   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12552   CHECK(!templ.IsEmpty());
12553   LocalContext context;
12554   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12555   GenerateSomeGarbage();
12556   context->Global()->Set(v8_str("o"), fun->NewInstance());
12557   v8::TryCatch try_catch;
12558   CompileRun(
12559       "o.foo = 17;"
12560       "var receiver = {};"
12561       "receiver.__proto__ = o;"
12562       "var result = 0;"
12563       "var saved_result = 0;"
12564       "for (var i = 0; i < 100; i++) {"
12565       "  result = receiver.method(41);"
12566       "  if (i == 50) {"
12567       "    saved_result = result;"
12568       "    receiver = Object.create(receiver);"
12569       "  }"
12570       "}");
12571   CHECK(try_catch.HasCaught());
12572   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12573            try_catch.Exception()->ToString());
12574   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12575 }
12576
12577
12578 v8::Handle<Value> keyed_call_ic_function;
12579
12580 static void InterceptorKeyedCallICGetter(
12581     Local<String> name,
12582     const v8::PropertyCallbackInfo<v8::Value>& info) {
12583   ApiTestFuzzer::Fuzz();
12584   if (v8_str("x")->Equals(name)) {
12585     info.GetReturnValue().Set(keyed_call_ic_function);
12586   }
12587 }
12588
12589
12590 // Test the case when we stored cacheable lookup into
12591 // a stub, but the function name changed (to another cacheable function).
12592 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12593   v8::Isolate* isolate = CcTest::isolate();
12594   v8::HandleScope scope(isolate);
12595   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12596   templ->SetNamedPropertyHandler(NoBlockGetterX);
12597   LocalContext context;
12598   context->Global()->Set(v8_str("o"), templ->NewInstance());
12599   CompileRun(
12600     "proto = new Object();"
12601     "proto.y = function(x) { return x + 1; };"
12602     "proto.z = function(x) { return x - 1; };"
12603     "o.__proto__ = proto;"
12604     "var result = 0;"
12605     "var method = 'y';"
12606     "for (var i = 0; i < 10; i++) {"
12607     "  if (i == 5) { method = 'z'; };"
12608     "  result += o[method](41);"
12609     "}");
12610   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12611 }
12612
12613
12614 // Test the case when we stored cacheable lookup into
12615 // a stub, but the function name changed (and the new function is present
12616 // both before and after the interceptor in the prototype chain).
12617 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12618   v8::Isolate* isolate = CcTest::isolate();
12619   v8::HandleScope scope(isolate);
12620   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12621   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12622   LocalContext context;
12623   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12624   keyed_call_ic_function =
12625       v8_compile("function f(x) { return x - 1; }; f")->Run();
12626   CompileRun(
12627     "o = new Object();"
12628     "proto2 = new Object();"
12629     "o.y = function(x) { return x + 1; };"
12630     "proto2.y = function(x) { return x + 2; };"
12631     "o.__proto__ = proto1;"
12632     "proto1.__proto__ = proto2;"
12633     "var result = 0;"
12634     "var method = 'x';"
12635     "for (var i = 0; i < 10; i++) {"
12636     "  if (i == 5) { method = 'y'; };"
12637     "  result += o[method](41);"
12638     "}");
12639   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12640 }
12641
12642
12643 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12644 // on the global object.
12645 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12646   v8::Isolate* isolate = CcTest::isolate();
12647   v8::HandleScope scope(isolate);
12648   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12649   templ->SetNamedPropertyHandler(NoBlockGetterX);
12650   LocalContext context;
12651   context->Global()->Set(v8_str("o"), templ->NewInstance());
12652   CompileRun(
12653     "function inc(x) { return x + 1; };"
12654     "inc(1);"
12655     "function dec(x) { return x - 1; };"
12656     "dec(1);"
12657     "o.__proto__ = this;"
12658     "this.__proto__.x = inc;"
12659     "this.__proto__.y = dec;"
12660     "var result = 0;"
12661     "var method = 'x';"
12662     "for (var i = 0; i < 10; i++) {"
12663     "  if (i == 5) { method = 'y'; };"
12664     "  result += o[method](41);"
12665     "}");
12666   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12667 }
12668
12669
12670 // Test the case when actual function to call sits on global object.
12671 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12672   v8::Isolate* isolate = CcTest::isolate();
12673   v8::HandleScope scope(isolate);
12674   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12675   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12676   LocalContext context;
12677   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12678
12679   CompileRun(
12680     "function len(x) { return x.length; };"
12681     "o.__proto__ = this;"
12682     "var m = 'parseFloat';"
12683     "var result = 0;"
12684     "for (var i = 0; i < 10; i++) {"
12685     "  if (i == 5) {"
12686     "    m = 'len';"
12687     "    saved_result = result;"
12688     "  };"
12689     "  result = o[m]('239');"
12690     "}");
12691   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12692   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12693 }
12694
12695
12696 // Test the map transition before the interceptor.
12697 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12698   v8::Isolate* isolate = CcTest::isolate();
12699   v8::HandleScope scope(isolate);
12700   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12701   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12702   LocalContext context;
12703   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12704
12705   CompileRun(
12706     "var o = new Object();"
12707     "o.__proto__ = proto;"
12708     "o.method = function(x) { return x + 1; };"
12709     "var m = 'method';"
12710     "var result = 0;"
12711     "for (var i = 0; i < 10; i++) {"
12712     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12713     "  result += o[m](41);"
12714     "}");
12715   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12716 }
12717
12718
12719 // Test the map transition after the interceptor.
12720 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12721   v8::Isolate* isolate = CcTest::isolate();
12722   v8::HandleScope scope(isolate);
12723   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12724   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12725   LocalContext context;
12726   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12727
12728   CompileRun(
12729     "var proto = new Object();"
12730     "o.__proto__ = proto;"
12731     "proto.method = function(x) { return x + 1; };"
12732     "var m = 'method';"
12733     "var result = 0;"
12734     "for (var i = 0; i < 10; i++) {"
12735     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12736     "  result += o[m](41);"
12737     "}");
12738   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12739 }
12740
12741
12742 static int interceptor_call_count = 0;
12743
12744 static void InterceptorICRefErrorGetter(
12745     Local<String> name,
12746     const v8::PropertyCallbackInfo<v8::Value>& info) {
12747   ApiTestFuzzer::Fuzz();
12748   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12749     info.GetReturnValue().Set(call_ic_function2);
12750   }
12751 }
12752
12753
12754 // This test should hit load and call ICs for the interceptor case.
12755 // Once in a while, the interceptor will reply that a property was not
12756 // found in which case we should get a reference error.
12757 THREADED_TEST(InterceptorICReferenceErrors) {
12758   v8::Isolate* isolate = CcTest::isolate();
12759   v8::HandleScope scope(isolate);
12760   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12761   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12762   LocalContext context(0, templ, v8::Handle<Value>());
12763   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12764   v8::Handle<Value> value = CompileRun(
12765     "function f() {"
12766     "  for (var i = 0; i < 1000; i++) {"
12767     "    try { x; } catch(e) { return true; }"
12768     "  }"
12769     "  return false;"
12770     "};"
12771     "f();");
12772   CHECK_EQ(true, value->BooleanValue());
12773   interceptor_call_count = 0;
12774   value = CompileRun(
12775     "function g() {"
12776     "  for (var i = 0; i < 1000; i++) {"
12777     "    try { x(42); } catch(e) { return true; }"
12778     "  }"
12779     "  return false;"
12780     "};"
12781     "g();");
12782   CHECK_EQ(true, value->BooleanValue());
12783 }
12784
12785
12786 static int interceptor_ic_exception_get_count = 0;
12787
12788 static void InterceptorICExceptionGetter(
12789     Local<String> name,
12790     const v8::PropertyCallbackInfo<v8::Value>& info) {
12791   ApiTestFuzzer::Fuzz();
12792   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12793     info.GetReturnValue().Set(call_ic_function3);
12794   }
12795   if (interceptor_ic_exception_get_count == 20) {
12796     info.GetIsolate()->ThrowException(v8_num(42));
12797     return;
12798   }
12799 }
12800
12801
12802 // Test interceptor load/call IC where the interceptor throws an
12803 // exception once in a while.
12804 THREADED_TEST(InterceptorICGetterExceptions) {
12805   interceptor_ic_exception_get_count = 0;
12806   v8::Isolate* isolate = CcTest::isolate();
12807   v8::HandleScope scope(isolate);
12808   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12809   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12810   LocalContext context(0, templ, v8::Handle<Value>());
12811   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12812   v8::Handle<Value> value = CompileRun(
12813     "function f() {"
12814     "  for (var i = 0; i < 100; i++) {"
12815     "    try { x; } catch(e) { return true; }"
12816     "  }"
12817     "  return false;"
12818     "};"
12819     "f();");
12820   CHECK_EQ(true, value->BooleanValue());
12821   interceptor_ic_exception_get_count = 0;
12822   value = CompileRun(
12823     "function f() {"
12824     "  for (var i = 0; i < 100; i++) {"
12825     "    try { x(42); } catch(e) { return true; }"
12826     "  }"
12827     "  return false;"
12828     "};"
12829     "f();");
12830   CHECK_EQ(true, value->BooleanValue());
12831 }
12832
12833
12834 static int interceptor_ic_exception_set_count = 0;
12835
12836 static void InterceptorICExceptionSetter(
12837       Local<String> key,
12838       Local<Value> value,
12839       const v8::PropertyCallbackInfo<v8::Value>& info) {
12840   ApiTestFuzzer::Fuzz();
12841   if (++interceptor_ic_exception_set_count > 20) {
12842     info.GetIsolate()->ThrowException(v8_num(42));
12843   }
12844 }
12845
12846
12847 // Test interceptor store IC where the interceptor throws an exception
12848 // once in a while.
12849 THREADED_TEST(InterceptorICSetterExceptions) {
12850   interceptor_ic_exception_set_count = 0;
12851   v8::Isolate* isolate = CcTest::isolate();
12852   v8::HandleScope scope(isolate);
12853   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12854   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12855   LocalContext context(0, templ, v8::Handle<Value>());
12856   v8::Handle<Value> value = CompileRun(
12857     "function f() {"
12858     "  for (var i = 0; i < 100; i++) {"
12859     "    try { x = 42; } catch(e) { return true; }"
12860     "  }"
12861     "  return false;"
12862     "};"
12863     "f();");
12864   CHECK_EQ(true, value->BooleanValue());
12865 }
12866
12867
12868 // Test that we ignore null interceptors.
12869 THREADED_TEST(NullNamedInterceptor) {
12870   v8::Isolate* isolate = CcTest::isolate();
12871   v8::HandleScope scope(isolate);
12872   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12873   templ->SetNamedPropertyHandler(
12874       static_cast<v8::NamedPropertyGetterCallback>(0));
12875   LocalContext context;
12876   templ->Set(CcTest::isolate(), "x", v8_num(42));
12877   v8::Handle<v8::Object> obj = templ->NewInstance();
12878   context->Global()->Set(v8_str("obj"), obj);
12879   v8::Handle<Value> value = CompileRun("obj.x");
12880   CHECK(value->IsInt32());
12881   CHECK_EQ(42, value->Int32Value());
12882 }
12883
12884
12885 // Test that we ignore null interceptors.
12886 THREADED_TEST(NullIndexedInterceptor) {
12887   v8::Isolate* isolate = CcTest::isolate();
12888   v8::HandleScope scope(isolate);
12889   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12890   templ->SetIndexedPropertyHandler(
12891       static_cast<v8::IndexedPropertyGetterCallback>(0));
12892   LocalContext context;
12893   templ->Set(CcTest::isolate(), "42", v8_num(42));
12894   v8::Handle<v8::Object> obj = templ->NewInstance();
12895   context->Global()->Set(v8_str("obj"), obj);
12896   v8::Handle<Value> value = CompileRun("obj[42]");
12897   CHECK(value->IsInt32());
12898   CHECK_EQ(42, value->Int32Value());
12899 }
12900
12901
12902 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12903   v8::Isolate* isolate = CcTest::isolate();
12904   v8::HandleScope scope(isolate);
12905   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12906   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12907   LocalContext env;
12908   env->Global()->Set(v8_str("obj"),
12909                      templ->GetFunction()->NewInstance());
12910   ExpectTrue("obj.x === 42");
12911   ExpectTrue("!obj.propertyIsEnumerable('x')");
12912 }
12913
12914
12915 static void ThrowingGetter(Local<String> name,
12916                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12917   ApiTestFuzzer::Fuzz();
12918   info.GetIsolate()->ThrowException(Handle<Value>());
12919   info.GetReturnValue().SetUndefined();
12920 }
12921
12922
12923 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12924   LocalContext context;
12925   HandleScope scope(context->GetIsolate());
12926
12927   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12928   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12929   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12930
12931   Local<Object> instance = templ->GetFunction()->NewInstance();
12932
12933   Local<Object> another = Object::New(context->GetIsolate());
12934   another->SetPrototype(instance);
12935
12936   Local<Object> with_js_getter = CompileRun(
12937       "o = {};\n"
12938       "o.__defineGetter__('f', function() { throw undefined; });\n"
12939       "o\n").As<Object>();
12940   CHECK(!with_js_getter.IsEmpty());
12941
12942   TryCatch try_catch;
12943
12944   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12945   CHECK(try_catch.HasCaught());
12946   try_catch.Reset();
12947   CHECK(result.IsEmpty());
12948
12949   result = another->GetRealNamedProperty(v8_str("f"));
12950   CHECK(try_catch.HasCaught());
12951   try_catch.Reset();
12952   CHECK(result.IsEmpty());
12953
12954   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12955   CHECK(try_catch.HasCaught());
12956   try_catch.Reset();
12957   CHECK(result.IsEmpty());
12958
12959   result = another->Get(v8_str("f"));
12960   CHECK(try_catch.HasCaught());
12961   try_catch.Reset();
12962   CHECK(result.IsEmpty());
12963
12964   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12965   CHECK(try_catch.HasCaught());
12966   try_catch.Reset();
12967   CHECK(result.IsEmpty());
12968
12969   result = with_js_getter->Get(v8_str("f"));
12970   CHECK(try_catch.HasCaught());
12971   try_catch.Reset();
12972   CHECK(result.IsEmpty());
12973 }
12974
12975
12976 static void ThrowingCallbackWithTryCatch(
12977     const v8::FunctionCallbackInfo<v8::Value>& args) {
12978   TryCatch try_catch;
12979   // Verboseness is important: it triggers message delivery which can call into
12980   // external code.
12981   try_catch.SetVerbose(true);
12982   CompileRun("throw 'from JS';");
12983   CHECK(try_catch.HasCaught());
12984   CHECK(!CcTest::i_isolate()->has_pending_exception());
12985   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12986 }
12987
12988
12989 static int call_depth;
12990
12991
12992 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12993   TryCatch try_catch;
12994 }
12995
12996
12997 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12998   if (--call_depth) CompileRun("throw 'ThrowInJS';");
12999 }
13000
13001
13002 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13003   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13004 }
13005
13006
13007 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13008   Handle<String> errorMessageString = message->Get();
13009   CHECK(!errorMessageString.IsEmpty());
13010   message->GetStackTrace();
13011   message->GetScriptResourceName();
13012 }
13013
13014
13015 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13016   LocalContext context;
13017   v8::Isolate* isolate = context->GetIsolate();
13018   HandleScope scope(isolate);
13019
13020   Local<Function> func =
13021       FunctionTemplate::New(isolate,
13022                             ThrowingCallbackWithTryCatch)->GetFunction();
13023   context->Global()->Set(v8_str("func"), func);
13024
13025   MessageCallback callbacks[] =
13026       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13027   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13028     MessageCallback callback = callbacks[i];
13029     if (callback != NULL) {
13030       V8::AddMessageListener(callback);
13031     }
13032     // Some small number to control number of times message handler should
13033     // throw an exception.
13034     call_depth = 5;
13035     ExpectFalse(
13036         "var thrown = false;\n"
13037         "try { func(); } catch(e) { thrown = true; }\n"
13038         "thrown\n");
13039     if (callback != NULL) {
13040       V8::RemoveMessageListeners(callback);
13041     }
13042   }
13043 }
13044
13045
13046 static void ParentGetter(Local<String> name,
13047                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13048   ApiTestFuzzer::Fuzz();
13049   info.GetReturnValue().Set(v8_num(1));
13050 }
13051
13052
13053 static void ChildGetter(Local<String> name,
13054                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13055   ApiTestFuzzer::Fuzz();
13056   info.GetReturnValue().Set(v8_num(42));
13057 }
13058
13059
13060 THREADED_TEST(Overriding) {
13061   LocalContext context;
13062   v8::Isolate* isolate = context->GetIsolate();
13063   v8::HandleScope scope(isolate);
13064
13065   // Parent template.
13066   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13067   Local<ObjectTemplate> parent_instance_templ =
13068       parent_templ->InstanceTemplate();
13069   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13070
13071   // Template that inherits from the parent template.
13072   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13073   Local<ObjectTemplate> child_instance_templ =
13074       child_templ->InstanceTemplate();
13075   child_templ->Inherit(parent_templ);
13076   // Override 'f'.  The child version of 'f' should get called for child
13077   // instances.
13078   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13079   // Add 'g' twice.  The 'g' added last should get called for instances.
13080   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13081   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13082
13083   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13084   // so 'h' can be shadowed on the instance object.
13085   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13086   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13087       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13088
13089   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13090   // but the attribute does not have effect because it is duplicated with
13091   // NULL setter.
13092   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13093       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13094
13095
13096
13097   // Instantiate the child template.
13098   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13099
13100   // Check that the child function overrides the parent one.
13101   context->Global()->Set(v8_str("o"), instance);
13102   Local<Value> value = v8_compile("o.f")->Run();
13103   // Check that the 'g' that was added last is hit.
13104   CHECK_EQ(42, value->Int32Value());
13105   value = v8_compile("o.g")->Run();
13106   CHECK_EQ(42, value->Int32Value());
13107
13108   // Check that 'h' cannot be shadowed.
13109   value = v8_compile("o.h = 3; o.h")->Run();
13110   CHECK_EQ(1, value->Int32Value());
13111
13112   // Check that 'i' cannot be shadowed or changed.
13113   value = v8_compile("o.i = 3; o.i")->Run();
13114   CHECK_EQ(42, value->Int32Value());
13115 }
13116
13117
13118 static void IsConstructHandler(
13119     const v8::FunctionCallbackInfo<v8::Value>& args) {
13120   ApiTestFuzzer::Fuzz();
13121   args.GetReturnValue().Set(args.IsConstructCall());
13122 }
13123
13124
13125 THREADED_TEST(IsConstructCall) {
13126   v8::Isolate* isolate = CcTest::isolate();
13127   v8::HandleScope scope(isolate);
13128
13129   // Function template with call handler.
13130   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13131   templ->SetCallHandler(IsConstructHandler);
13132
13133   LocalContext context;
13134
13135   context->Global()->Set(v8_str("f"), templ->GetFunction());
13136   Local<Value> value = v8_compile("f()")->Run();
13137   CHECK(!value->BooleanValue());
13138   value = v8_compile("new f()")->Run();
13139   CHECK(value->BooleanValue());
13140 }
13141
13142
13143 THREADED_TEST(ObjectProtoToString) {
13144   v8::Isolate* isolate = CcTest::isolate();
13145   v8::HandleScope scope(isolate);
13146   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13147   templ->SetClassName(v8_str("MyClass"));
13148
13149   LocalContext context;
13150
13151   Local<String> customized_tostring = v8_str("customized toString");
13152
13153   // Replace Object.prototype.toString
13154   v8_compile("Object.prototype.toString = function() {"
13155                   "  return 'customized toString';"
13156                   "}")->Run();
13157
13158   // Normal ToString call should call replaced Object.prototype.toString
13159   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13160   Local<String> value = instance->ToString();
13161   CHECK(value->IsString() && value->Equals(customized_tostring));
13162
13163   // ObjectProtoToString should not call replace toString function.
13164   value = instance->ObjectProtoToString();
13165   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13166
13167   // Check global
13168   value = context->Global()->ObjectProtoToString();
13169   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13170
13171   // Check ordinary object
13172   Local<Value> object = v8_compile("new Object()")->Run();
13173   value = object.As<v8::Object>()->ObjectProtoToString();
13174   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13175 }
13176
13177
13178 THREADED_TEST(ObjectGetConstructorName) {
13179   LocalContext context;
13180   v8::HandleScope scope(context->GetIsolate());
13181   v8_compile("function Parent() {};"
13182              "function Child() {};"
13183              "Child.prototype = new Parent();"
13184              "var outer = { inner: function() { } };"
13185              "var p = new Parent();"
13186              "var c = new Child();"
13187              "var x = new outer.inner();")->Run();
13188
13189   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13190   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13191       v8_str("Parent")));
13192
13193   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13194   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13195       v8_str("Child")));
13196
13197   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13198   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13199       v8_str("outer.inner")));
13200 }
13201
13202
13203 bool ApiTestFuzzer::fuzzing_ = false;
13204 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13205 int ApiTestFuzzer::active_tests_;
13206 int ApiTestFuzzer::tests_being_run_;
13207 int ApiTestFuzzer::current_;
13208
13209
13210 // We are in a callback and want to switch to another thread (if we
13211 // are currently running the thread fuzzing test).
13212 void ApiTestFuzzer::Fuzz() {
13213   if (!fuzzing_) return;
13214   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13215   test->ContextSwitch();
13216 }
13217
13218
13219 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13220 // not start immediately.
13221 bool ApiTestFuzzer::NextThread() {
13222   int test_position = GetNextTestNumber();
13223   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13224   if (test_position == current_) {
13225     if (kLogThreading)
13226       printf("Stay with %s\n", test_name);
13227     return false;
13228   }
13229   if (kLogThreading) {
13230     printf("Switch from %s to %s\n",
13231            test_name,
13232            RegisterThreadedTest::nth(test_position)->name());
13233   }
13234   current_ = test_position;
13235   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13236   return true;
13237 }
13238
13239
13240 void ApiTestFuzzer::Run() {
13241   // When it is our turn...
13242   gate_.Wait();
13243   {
13244     // ... get the V8 lock and start running the test.
13245     v8::Locker locker(CcTest::isolate());
13246     CallTest();
13247   }
13248   // This test finished.
13249   active_ = false;
13250   active_tests_--;
13251   // If it was the last then signal that fact.
13252   if (active_tests_ == 0) {
13253     all_tests_done_.Signal();
13254   } else {
13255     // Otherwise select a new test and start that.
13256     NextThread();
13257   }
13258 }
13259
13260
13261 static unsigned linear_congruential_generator;
13262
13263
13264 void ApiTestFuzzer::SetUp(PartOfTest part) {
13265   linear_congruential_generator = i::FLAG_testing_prng_seed;
13266   fuzzing_ = true;
13267   int count = RegisterThreadedTest::count();
13268   int start =  count * part / (LAST_PART + 1);
13269   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13270   active_tests_ = tests_being_run_ = end - start + 1;
13271   for (int i = 0; i < tests_being_run_; i++) {
13272     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13273   }
13274   for (int i = 0; i < active_tests_; i++) {
13275     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13276   }
13277 }
13278
13279
13280 static void CallTestNumber(int test_number) {
13281   (RegisterThreadedTest::nth(test_number)->callback())();
13282 }
13283
13284
13285 void ApiTestFuzzer::RunAllTests() {
13286   // Set off the first test.
13287   current_ = -1;
13288   NextThread();
13289   // Wait till they are all done.
13290   all_tests_done_.Wait();
13291 }
13292
13293
13294 int ApiTestFuzzer::GetNextTestNumber() {
13295   int next_test;
13296   do {
13297     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13298     linear_congruential_generator *= 1664525u;
13299     linear_congruential_generator += 1013904223u;
13300   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13301   return next_test;
13302 }
13303
13304
13305 void ApiTestFuzzer::ContextSwitch() {
13306   // If the new thread is the same as the current thread there is nothing to do.
13307   if (NextThread()) {
13308     // Now it can start.
13309     v8::Unlocker unlocker(CcTest::isolate());
13310     // Wait till someone starts us again.
13311     gate_.Wait();
13312     // And we're off.
13313   }
13314 }
13315
13316
13317 void ApiTestFuzzer::TearDown() {
13318   fuzzing_ = false;
13319   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13320     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13321     if (fuzzer != NULL) fuzzer->Join();
13322   }
13323 }
13324
13325
13326 // Lets not be needlessly self-referential.
13327 TEST(Threading1) {
13328   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13329   ApiTestFuzzer::RunAllTests();
13330   ApiTestFuzzer::TearDown();
13331 }
13332
13333
13334 TEST(Threading2) {
13335   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13336   ApiTestFuzzer::RunAllTests();
13337   ApiTestFuzzer::TearDown();
13338 }
13339
13340
13341 TEST(Threading3) {
13342   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13343   ApiTestFuzzer::RunAllTests();
13344   ApiTestFuzzer::TearDown();
13345 }
13346
13347
13348 TEST(Threading4) {
13349   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13350   ApiTestFuzzer::RunAllTests();
13351   ApiTestFuzzer::TearDown();
13352 }
13353
13354
13355 void ApiTestFuzzer::CallTest() {
13356   v8::Isolate::Scope scope(CcTest::isolate());
13357   if (kLogThreading)
13358     printf("Start test %d\n", test_number_);
13359   CallTestNumber(test_number_);
13360   if (kLogThreading)
13361     printf("End test %d\n", test_number_);
13362 }
13363
13364
13365 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13366   v8::Isolate* isolate = args.GetIsolate();
13367   CHECK(v8::Locker::IsLocked(isolate));
13368   ApiTestFuzzer::Fuzz();
13369   v8::Unlocker unlocker(isolate);
13370   const char* code = "throw 7;";
13371   {
13372     v8::Locker nested_locker(isolate);
13373     v8::HandleScope scope(isolate);
13374     v8::Handle<Value> exception;
13375     { v8::TryCatch try_catch;
13376       v8::Handle<Value> value = CompileRun(code);
13377       CHECK(value.IsEmpty());
13378       CHECK(try_catch.HasCaught());
13379       // Make sure to wrap the exception in a new handle because
13380       // the handle returned from the TryCatch is destroyed
13381       // when the TryCatch is destroyed.
13382       exception = Local<Value>::New(isolate, try_catch.Exception());
13383     }
13384     args.GetIsolate()->ThrowException(exception);
13385   }
13386 }
13387
13388
13389 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13390   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13391   ApiTestFuzzer::Fuzz();
13392   v8::Unlocker unlocker(CcTest::isolate());
13393   const char* code = "throw 7;";
13394   {
13395     v8::Locker nested_locker(CcTest::isolate());
13396     v8::HandleScope scope(args.GetIsolate());
13397     v8::Handle<Value> value = CompileRun(code);
13398     CHECK(value.IsEmpty());
13399     args.GetReturnValue().Set(v8_str("foo"));
13400   }
13401 }
13402
13403
13404 // These are locking tests that don't need to be run again
13405 // as part of the locking aggregation tests.
13406 TEST(NestedLockers) {
13407   v8::Isolate* isolate = CcTest::isolate();
13408   v8::Locker locker(isolate);
13409   CHECK(v8::Locker::IsLocked(isolate));
13410   LocalContext env;
13411   v8::HandleScope scope(env->GetIsolate());
13412   Local<v8::FunctionTemplate> fun_templ =
13413       v8::FunctionTemplate::New(isolate, ThrowInJS);
13414   Local<Function> fun = fun_templ->GetFunction();
13415   env->Global()->Set(v8_str("throw_in_js"), fun);
13416   Local<Script> script = v8_compile("(function () {"
13417                                     "  try {"
13418                                     "    throw_in_js();"
13419                                     "    return 42;"
13420                                     "  } catch (e) {"
13421                                     "    return e * 13;"
13422                                     "  }"
13423                                     "})();");
13424   CHECK_EQ(91, script->Run()->Int32Value());
13425 }
13426
13427
13428 // These are locking tests that don't need to be run again
13429 // as part of the locking aggregation tests.
13430 TEST(NestedLockersNoTryCatch) {
13431   v8::Locker locker(CcTest::isolate());
13432   LocalContext env;
13433   v8::HandleScope scope(env->GetIsolate());
13434   Local<v8::FunctionTemplate> fun_templ =
13435       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13436   Local<Function> fun = fun_templ->GetFunction();
13437   env->Global()->Set(v8_str("throw_in_js"), fun);
13438   Local<Script> script = v8_compile("(function () {"
13439                                     "  try {"
13440                                     "    throw_in_js();"
13441                                     "    return 42;"
13442                                     "  } catch (e) {"
13443                                     "    return e * 13;"
13444                                     "  }"
13445                                     "})();");
13446   CHECK_EQ(91, script->Run()->Int32Value());
13447 }
13448
13449
13450 THREADED_TEST(RecursiveLocking) {
13451   v8::Locker locker(CcTest::isolate());
13452   {
13453     v8::Locker locker2(CcTest::isolate());
13454     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13455   }
13456 }
13457
13458
13459 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13460   ApiTestFuzzer::Fuzz();
13461   v8::Unlocker unlocker(CcTest::isolate());
13462 }
13463
13464
13465 THREADED_TEST(LockUnlockLock) {
13466   {
13467     v8::Locker locker(CcTest::isolate());
13468     v8::HandleScope scope(CcTest::isolate());
13469     LocalContext env;
13470     Local<v8::FunctionTemplate> fun_templ =
13471         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13472     Local<Function> fun = fun_templ->GetFunction();
13473     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13474     Local<Script> script = v8_compile("(function () {"
13475                                       "  unlock_for_a_moment();"
13476                                       "  return 42;"
13477                                       "})();");
13478     CHECK_EQ(42, script->Run()->Int32Value());
13479   }
13480   {
13481     v8::Locker locker(CcTest::isolate());
13482     v8::HandleScope scope(CcTest::isolate());
13483     LocalContext env;
13484     Local<v8::FunctionTemplate> fun_templ =
13485         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13486     Local<Function> fun = fun_templ->GetFunction();
13487     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13488     Local<Script> script = v8_compile("(function () {"
13489                                       "  unlock_for_a_moment();"
13490                                       "  return 42;"
13491                                       "})();");
13492     CHECK_EQ(42, script->Run()->Int32Value());
13493   }
13494 }
13495
13496
13497 static int GetGlobalObjectsCount() {
13498   CcTest::heap()->EnsureHeapIsIterable();
13499   int count = 0;
13500   i::HeapIterator it(CcTest::heap());
13501   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13502     if (object->IsJSGlobalObject()) count++;
13503   return count;
13504 }
13505
13506
13507 static void CheckSurvivingGlobalObjectsCount(int expected) {
13508   // We need to collect all garbage twice to be sure that everything
13509   // has been collected.  This is because inline caches are cleared in
13510   // the first garbage collection but some of the maps have already
13511   // been marked at that point.  Therefore some of the maps are not
13512   // collected until the second garbage collection.
13513   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13514   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13515   int count = GetGlobalObjectsCount();
13516 #ifdef DEBUG
13517   if (count != expected) CcTest::heap()->TracePathToGlobal();
13518 #endif
13519   CHECK_EQ(expected, count);
13520 }
13521
13522
13523 TEST(DontLeakGlobalObjects) {
13524   // Regression test for issues 1139850 and 1174891.
13525
13526   i::FLAG_expose_gc = true;
13527   v8::V8::Initialize();
13528
13529   for (int i = 0; i < 5; i++) {
13530     { v8::HandleScope scope(CcTest::isolate());
13531       LocalContext context;
13532     }
13533     v8::V8::ContextDisposedNotification();
13534     CheckSurvivingGlobalObjectsCount(0);
13535
13536     { v8::HandleScope scope(CcTest::isolate());
13537       LocalContext context;
13538       v8_compile("Date")->Run();
13539     }
13540     v8::V8::ContextDisposedNotification();
13541     CheckSurvivingGlobalObjectsCount(0);
13542
13543     { v8::HandleScope scope(CcTest::isolate());
13544       LocalContext context;
13545       v8_compile("/aaa/")->Run();
13546     }
13547     v8::V8::ContextDisposedNotification();
13548     CheckSurvivingGlobalObjectsCount(0);
13549
13550     { v8::HandleScope scope(CcTest::isolate());
13551       const char* extension_list[] = { "v8/gc" };
13552       v8::ExtensionConfiguration extensions(1, extension_list);
13553       LocalContext context(&extensions);
13554       v8_compile("gc();")->Run();
13555     }
13556     v8::V8::ContextDisposedNotification();
13557     CheckSurvivingGlobalObjectsCount(0);
13558   }
13559 }
13560
13561
13562 TEST(CopyablePersistent) {
13563   LocalContext context;
13564   v8::Isolate* isolate = context->GetIsolate();
13565   i::GlobalHandles* globals =
13566       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13567   int initial_handles = globals->global_handles_count();
13568   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13569       CopyableObject;
13570   {
13571     CopyableObject handle1;
13572     {
13573       v8::HandleScope scope(isolate);
13574       handle1.Reset(isolate, v8::Object::New(isolate));
13575     }
13576     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13577     CopyableObject  handle2;
13578     handle2 = handle1;
13579     CHECK(handle1 == handle2);
13580     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13581     CopyableObject handle3(handle2);
13582     CHECK(handle1 == handle3);
13583     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13584   }
13585   // Verify autodispose
13586   CHECK_EQ(initial_handles, globals->global_handles_count());
13587 }
13588
13589
13590 static void WeakApiCallback(
13591     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13592   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13593   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13594   data.GetParameter()->Reset();
13595   delete data.GetParameter();
13596 }
13597
13598
13599 TEST(WeakCallbackApi) {
13600   LocalContext context;
13601   v8::Isolate* isolate = context->GetIsolate();
13602   i::GlobalHandles* globals =
13603       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13604   int initial_handles = globals->global_handles_count();
13605   {
13606     v8::HandleScope scope(isolate);
13607     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13608     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13609     v8::Persistent<v8::Object>* handle =
13610         new v8::Persistent<v8::Object>(isolate, obj);
13611     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13612                                                              WeakApiCallback);
13613   }
13614   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13615       CollectAllGarbage(i::Heap::kNoGCFlags);
13616   // Verify disposed.
13617   CHECK_EQ(initial_handles, globals->global_handles_count());
13618 }
13619
13620
13621 v8::Persistent<v8::Object> some_object;
13622 v8::Persistent<v8::Object> bad_handle;
13623
13624 void NewPersistentHandleCallback(
13625     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13626   v8::HandleScope scope(data.GetIsolate());
13627   bad_handle.Reset(data.GetIsolate(), some_object);
13628   data.GetParameter()->Reset();
13629 }
13630
13631
13632 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13633   LocalContext context;
13634   v8::Isolate* isolate = context->GetIsolate();
13635
13636   v8::Persistent<v8::Object> handle1, handle2;
13637   {
13638     v8::HandleScope scope(isolate);
13639     some_object.Reset(isolate, v8::Object::New(isolate));
13640     handle1.Reset(isolate, v8::Object::New(isolate));
13641     handle2.Reset(isolate, v8::Object::New(isolate));
13642   }
13643   // Note: order is implementation dependent alas: currently
13644   // global handle nodes are processed by PostGarbageCollectionProcessing
13645   // in reverse allocation order, so if second allocated handle is deleted,
13646   // weak callback of the first handle would be able to 'reallocate' it.
13647   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13648   handle2.Reset();
13649   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13650 }
13651
13652
13653 v8::Persistent<v8::Object> to_be_disposed;
13654
13655 void DisposeAndForceGcCallback(
13656     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13657   to_be_disposed.Reset();
13658   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13659   data.GetParameter()->Reset();
13660 }
13661
13662
13663 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13664   LocalContext context;
13665   v8::Isolate* isolate = context->GetIsolate();
13666
13667   v8::Persistent<v8::Object> handle1, handle2;
13668   {
13669     v8::HandleScope scope(isolate);
13670     handle1.Reset(isolate, v8::Object::New(isolate));
13671     handle2.Reset(isolate, v8::Object::New(isolate));
13672   }
13673   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13674   to_be_disposed.Reset(isolate, handle2);
13675   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13676 }
13677
13678 void DisposingCallback(
13679     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13680   data.GetParameter()->Reset();
13681 }
13682
13683 void HandleCreatingCallback(
13684     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13685   v8::HandleScope scope(data.GetIsolate());
13686   v8::Persistent<v8::Object>(data.GetIsolate(),
13687                              v8::Object::New(data.GetIsolate()));
13688   data.GetParameter()->Reset();
13689 }
13690
13691
13692 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13693   LocalContext context;
13694   v8::Isolate* isolate = context->GetIsolate();
13695
13696   v8::Persistent<v8::Object> handle1, handle2, handle3;
13697   {
13698     v8::HandleScope scope(isolate);
13699     handle3.Reset(isolate, v8::Object::New(isolate));
13700     handle2.Reset(isolate, v8::Object::New(isolate));
13701     handle1.Reset(isolate, v8::Object::New(isolate));
13702   }
13703   handle2.SetWeak(&handle2, DisposingCallback);
13704   handle3.SetWeak(&handle3, HandleCreatingCallback);
13705   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13706 }
13707
13708
13709 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13710   v8::V8::Initialize();
13711
13712   const int nof = 2;
13713   const char* sources[nof] = {
13714     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13715     "Object()"
13716   };
13717
13718   for (int i = 0; i < nof; i++) {
13719     const char* source = sources[i];
13720     { v8::HandleScope scope(CcTest::isolate());
13721       LocalContext context;
13722       CompileRun(source);
13723     }
13724     { v8::HandleScope scope(CcTest::isolate());
13725       LocalContext context;
13726       CompileRun(source);
13727     }
13728   }
13729 }
13730
13731
13732 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13733   v8::EscapableHandleScope inner(env->GetIsolate());
13734   env->Enter();
13735   v8::Local<Value> three = v8_num(3);
13736   v8::Local<Value> value = inner.Escape(three);
13737   env->Exit();
13738   return value;
13739 }
13740
13741
13742 THREADED_TEST(NestedHandleScopeAndContexts) {
13743   v8::Isolate* isolate = CcTest::isolate();
13744   v8::HandleScope outer(isolate);
13745   v8::Local<Context> env = Context::New(isolate);
13746   env->Enter();
13747   v8::Handle<Value> value = NestedScope(env);
13748   v8::Handle<String> str(value->ToString());
13749   CHECK(!str.IsEmpty());
13750   env->Exit();
13751 }
13752
13753
13754 static bool MatchPointers(void* key1, void* key2) {
13755   return key1 == key2;
13756 }
13757
13758
13759 struct SymbolInfo {
13760   size_t id;
13761   size_t size;
13762   std::string name;
13763 };
13764
13765
13766 class SetFunctionEntryHookTest {
13767  public:
13768   SetFunctionEntryHookTest() {
13769     CHECK(instance_ == NULL);
13770     instance_ = this;
13771   }
13772   ~SetFunctionEntryHookTest() {
13773     CHECK(instance_ == this);
13774     instance_ = NULL;
13775   }
13776   void Reset() {
13777     symbols_.clear();
13778     symbol_locations_.clear();
13779     invocations_.clear();
13780   }
13781   void RunTest();
13782   void OnJitEvent(const v8::JitCodeEvent* event);
13783   static void JitEvent(const v8::JitCodeEvent* event) {
13784     CHECK(instance_ != NULL);
13785     instance_->OnJitEvent(event);
13786   }
13787
13788   void OnEntryHook(uintptr_t function,
13789                    uintptr_t return_addr_location);
13790   static void EntryHook(uintptr_t function,
13791                         uintptr_t return_addr_location) {
13792     CHECK(instance_ != NULL);
13793     instance_->OnEntryHook(function, return_addr_location);
13794   }
13795
13796   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13797     CHECK(instance_ != NULL);
13798     args.GetReturnValue().Set(v8_num(42));
13799   }
13800   void RunLoopInNewEnv(v8::Isolate* isolate);
13801
13802   // Records addr as location of symbol.
13803   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13804
13805   // Finds the symbol containing addr
13806   SymbolInfo* FindSymbolForAddr(i::Address addr);
13807   // Returns the number of invocations where the caller name contains
13808   // \p caller_name and the function name contains \p function_name.
13809   int CountInvocations(const char* caller_name,
13810                        const char* function_name);
13811
13812   i::Handle<i::JSFunction> foo_func_;
13813   i::Handle<i::JSFunction> bar_func_;
13814
13815   typedef std::map<size_t, SymbolInfo> SymbolMap;
13816   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13817   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13818   SymbolMap symbols_;
13819   SymbolLocationMap symbol_locations_;
13820   InvocationMap invocations_;
13821
13822   static SetFunctionEntryHookTest* instance_;
13823 };
13824 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13825
13826
13827 // Returns true if addr is in the range [start, start+len).
13828 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13829   if (start <= addr && start + len > addr)
13830     return true;
13831
13832   return false;
13833 }
13834
13835 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13836                                               SymbolInfo* symbol) {
13837   // Insert the symbol at the new location.
13838   SymbolLocationMap::iterator it =
13839       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13840   // Now erase symbols to the left and right that overlap this one.
13841   while (it != symbol_locations_.begin()) {
13842     SymbolLocationMap::iterator left = it;
13843     --left;
13844     if (!Overlaps(left->first, left->second->size, addr))
13845       break;
13846     symbol_locations_.erase(left);
13847   }
13848
13849   // Now erase symbols to the left and right that overlap this one.
13850   while (true) {
13851     SymbolLocationMap::iterator right = it;
13852     ++right;
13853     if (right == symbol_locations_.end())
13854         break;
13855     if (!Overlaps(addr, symbol->size, right->first))
13856       break;
13857     symbol_locations_.erase(right);
13858   }
13859 }
13860
13861
13862 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13863   switch (event->type) {
13864     case v8::JitCodeEvent::CODE_ADDED: {
13865         CHECK(event->code_start != NULL);
13866         CHECK_NE(0, static_cast<int>(event->code_len));
13867         CHECK(event->name.str != NULL);
13868         size_t symbol_id = symbols_.size();
13869
13870         // Record the new symbol.
13871         SymbolInfo& info = symbols_[symbol_id];
13872         info.id = symbol_id;
13873         info.size = event->code_len;
13874         info.name.assign(event->name.str, event->name.str + event->name.len);
13875
13876         // And record it's location.
13877         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13878       }
13879       break;
13880
13881     case v8::JitCodeEvent::CODE_MOVED: {
13882         // We would like to never see code move that we haven't seen before,
13883         // but the code creation event does not happen until the line endings
13884         // have been calculated (this is so that we can report the line in the
13885         // script at which the function source is found, see
13886         // Compiler::RecordFunctionCompilation) and the line endings
13887         // calculations can cause a GC, which can move the newly created code
13888         // before its existence can be logged.
13889         SymbolLocationMap::iterator it(
13890             symbol_locations_.find(
13891                 reinterpret_cast<i::Address>(event->code_start)));
13892         if (it != symbol_locations_.end()) {
13893           // Found a symbol at this location, move it.
13894           SymbolInfo* info = it->second;
13895           symbol_locations_.erase(it);
13896           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13897                          info);
13898         }
13899       }
13900     default:
13901       break;
13902   }
13903 }
13904
13905 void SetFunctionEntryHookTest::OnEntryHook(
13906     uintptr_t function, uintptr_t return_addr_location) {
13907   // Get the function's code object.
13908   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13909       reinterpret_cast<i::Address>(function));
13910   CHECK(function_code != NULL);
13911
13912   // Then try and look up the caller's code object.
13913   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13914
13915   // Count the invocation.
13916   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13917   SymbolInfo* function_symbol =
13918       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13919   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13920
13921   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13922     // Check that we have a symbol for the "bar" function at the right location.
13923     SymbolLocationMap::iterator it(
13924         symbol_locations_.find(function_code->instruction_start()));
13925     CHECK(it != symbol_locations_.end());
13926   }
13927
13928   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13929     // Check that we have a symbol for "foo" at the right location.
13930     SymbolLocationMap::iterator it(
13931         symbol_locations_.find(function_code->instruction_start()));
13932     CHECK(it != symbol_locations_.end());
13933   }
13934 }
13935
13936
13937 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13938   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13939   // Do we have a direct hit on a symbol?
13940   if (it != symbol_locations_.end()) {
13941     if (it->first == addr)
13942       return it->second;
13943   }
13944
13945   // If not a direct hit, it'll have to be the previous symbol.
13946   if (it == symbol_locations_.begin())
13947     return NULL;
13948
13949   --it;
13950   size_t offs = addr - it->first;
13951   if (offs < it->second->size)
13952     return it->second;
13953
13954   return NULL;
13955 }
13956
13957
13958 int SetFunctionEntryHookTest::CountInvocations(
13959     const char* caller_name, const char* function_name) {
13960   InvocationMap::iterator it(invocations_.begin());
13961   int invocations = 0;
13962   for (; it != invocations_.end(); ++it) {
13963     SymbolInfo* caller = it->first.first;
13964     SymbolInfo* function = it->first.second;
13965
13966     // Filter out non-matching functions.
13967     if (function_name != NULL) {
13968       if (function->name.find(function_name) == std::string::npos)
13969         continue;
13970     }
13971
13972     // Filter out non-matching callers.
13973     if (caller_name != NULL) {
13974       if (caller == NULL)
13975         continue;
13976       if (caller->name.find(caller_name) == std::string::npos)
13977         continue;
13978     }
13979
13980     // It matches add the invocation count to the tally.
13981     invocations += it->second;
13982   }
13983
13984   return invocations;
13985 }
13986
13987
13988 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13989   v8::HandleScope outer(isolate);
13990   v8::Local<Context> env = Context::New(isolate);
13991   env->Enter();
13992
13993   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13994   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13995   env->Global()->Set(v8_str("obj"), t->NewInstance());
13996
13997   const char* script =
13998       "function bar() {\n"
13999       "  var sum = 0;\n"
14000       "  for (i = 0; i < 100; ++i)\n"
14001       "    sum = foo(i);\n"
14002       "  return sum;\n"
14003       "}\n"
14004       "function foo(i) { return i * i; }\n"
14005       "// Invoke on the runtime function.\n"
14006       "obj.asdf()";
14007   CompileRun(script);
14008   bar_func_ = i::Handle<i::JSFunction>::cast(
14009           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14010   ASSERT(!bar_func_.is_null());
14011
14012   foo_func_ =
14013       i::Handle<i::JSFunction>::cast(
14014            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14015   ASSERT(!foo_func_.is_null());
14016
14017   v8::Handle<v8::Value> value = CompileRun("bar();");
14018   CHECK(value->IsNumber());
14019   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14020
14021   // Test the optimized codegen path.
14022   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14023                      "bar();");
14024   CHECK(value->IsNumber());
14025   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14026
14027   env->Exit();
14028 }
14029
14030
14031 void SetFunctionEntryHookTest::RunTest() {
14032   // Work in a new isolate throughout.
14033   v8::Isolate* isolate = v8::Isolate::New();
14034
14035   // Test setting the entry hook on the new isolate.
14036   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14037
14038   // Replacing the hook, once set should fail.
14039   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14040
14041   {
14042     v8::Isolate::Scope scope(isolate);
14043
14044     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14045
14046     RunLoopInNewEnv(isolate);
14047
14048     // Check the exepected invocation counts.
14049     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14050     CHECK_EQ(200, CountInvocations("bar", "foo"));
14051     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14052
14053     // Verify that we have an entry hook on some specific stubs.
14054     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14055     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14056     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14057   }
14058   isolate->Dispose();
14059
14060   Reset();
14061
14062   // Make sure a second isolate is unaffected by the previous entry hook.
14063   isolate = v8::Isolate::New();
14064   {
14065     v8::Isolate::Scope scope(isolate);
14066
14067     // Reset the entry count to zero and set the entry hook.
14068     RunLoopInNewEnv(isolate);
14069
14070     // We should record no invocations in this isolate.
14071     CHECK_EQ(0, static_cast<int>(invocations_.size()));
14072   }
14073   // Since the isolate has been used, we shouldn't be able to set an entry
14074   // hook anymore.
14075   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14076
14077   isolate->Dispose();
14078 }
14079
14080
14081 TEST(SetFunctionEntryHook) {
14082   // FunctionEntryHook does not work well with experimental natives.
14083   // Experimental natives are compiled during snapshot deserialization.
14084   // This test breaks because InstallGetter (function from snapshot that
14085   // only gets called from experimental natives) is compiled with entry hooks.
14086   i::FLAG_allow_natives_syntax = true;
14087   i::FLAG_use_inlining = false;
14088
14089   SetFunctionEntryHookTest test;
14090   test.RunTest();
14091 }
14092
14093
14094 static i::HashMap* code_map = NULL;
14095 static i::HashMap* jitcode_line_info = NULL;
14096 static int saw_bar = 0;
14097 static int move_events = 0;
14098
14099
14100 static bool FunctionNameIs(const char* expected,
14101                            const v8::JitCodeEvent* event) {
14102   // Log lines for functions are of the general form:
14103   // "LazyCompile:<type><function_name>", where the type is one of
14104   // "*", "~" or "".
14105   static const char kPreamble[] = "LazyCompile:";
14106   static size_t kPreambleLen = sizeof(kPreamble) - 1;
14107
14108   if (event->name.len < sizeof(kPreamble) - 1 ||
14109       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14110     return false;
14111   }
14112
14113   const char* tail = event->name.str + kPreambleLen;
14114   size_t tail_len = event->name.len - kPreambleLen;
14115   size_t expected_len = strlen(expected);
14116   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14117     --tail_len;
14118     ++tail;
14119   }
14120
14121   // Check for tails like 'bar :1'.
14122   if (tail_len > expected_len + 2 &&
14123       tail[expected_len] == ' ' &&
14124       tail[expected_len + 1] == ':' &&
14125       tail[expected_len + 2] &&
14126       !strncmp(tail, expected, expected_len)) {
14127     return true;
14128   }
14129
14130   if (tail_len != expected_len)
14131     return false;
14132
14133   return strncmp(tail, expected, expected_len) == 0;
14134 }
14135
14136
14137 static void event_handler(const v8::JitCodeEvent* event) {
14138   CHECK(event != NULL);
14139   CHECK(code_map != NULL);
14140   CHECK(jitcode_line_info != NULL);
14141
14142   class DummyJitCodeLineInfo {
14143   };
14144
14145   switch (event->type) {
14146     case v8::JitCodeEvent::CODE_ADDED: {
14147         CHECK(event->code_start != NULL);
14148         CHECK_NE(0, static_cast<int>(event->code_len));
14149         CHECK(event->name.str != NULL);
14150         i::HashMap::Entry* entry =
14151             code_map->Lookup(event->code_start,
14152                              i::ComputePointerHash(event->code_start),
14153                              true);
14154         entry->value = reinterpret_cast<void*>(event->code_len);
14155
14156         if (FunctionNameIs("bar", event)) {
14157           ++saw_bar;
14158         }
14159       }
14160       break;
14161
14162     case v8::JitCodeEvent::CODE_MOVED: {
14163         uint32_t hash = i::ComputePointerHash(event->code_start);
14164         // We would like to never see code move that we haven't seen before,
14165         // but the code creation event does not happen until the line endings
14166         // have been calculated (this is so that we can report the line in the
14167         // script at which the function source is found, see
14168         // Compiler::RecordFunctionCompilation) and the line endings
14169         // calculations can cause a GC, which can move the newly created code
14170         // before its existence can be logged.
14171         i::HashMap::Entry* entry =
14172             code_map->Lookup(event->code_start, hash, false);
14173         if (entry != NULL) {
14174           ++move_events;
14175
14176           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14177           code_map->Remove(event->code_start, hash);
14178
14179           entry = code_map->Lookup(event->new_code_start,
14180                                    i::ComputePointerHash(event->new_code_start),
14181                                    true);
14182           CHECK(entry != NULL);
14183           entry->value = reinterpret_cast<void*>(event->code_len);
14184         }
14185       }
14186       break;
14187
14188     case v8::JitCodeEvent::CODE_REMOVED:
14189       // Object/code removal events are currently not dispatched from the GC.
14190       CHECK(false);
14191       break;
14192
14193     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14194     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14195     // record it in jitcode_line_info.
14196     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14197         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14198         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14199         temp_event->user_data = line_info;
14200         i::HashMap::Entry* entry =
14201             jitcode_line_info->Lookup(line_info,
14202                                       i::ComputePointerHash(line_info),
14203                                       true);
14204         entry->value = reinterpret_cast<void*>(line_info);
14205       }
14206       break;
14207     // For these two events, we will check whether the event->user_data
14208     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14209     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14210     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14211         CHECK(event->user_data != NULL);
14212         uint32_t hash = i::ComputePointerHash(event->user_data);
14213         i::HashMap::Entry* entry =
14214             jitcode_line_info->Lookup(event->user_data, hash, false);
14215         CHECK(entry != NULL);
14216         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14217       }
14218       break;
14219
14220     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14221         CHECK(event->user_data != NULL);
14222         uint32_t hash = i::ComputePointerHash(event->user_data);
14223         i::HashMap::Entry* entry =
14224             jitcode_line_info->Lookup(event->user_data, hash, false);
14225         CHECK(entry != NULL);
14226       }
14227       break;
14228
14229     default:
14230       // Impossible event.
14231       CHECK(false);
14232       break;
14233   }
14234 }
14235
14236
14237 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14238   i::FLAG_stress_compaction = true;
14239   i::FLAG_incremental_marking = false;
14240   if (i::FLAG_never_compact) return;
14241   const char* script =
14242     "function bar() {"
14243     "  var sum = 0;"
14244     "  for (i = 0; i < 100; ++i)"
14245     "    sum = foo(i);"
14246     "  return sum;"
14247     "}"
14248     "function foo(i) { return i * i; };"
14249     "bar();";
14250
14251   // Run this test in a new isolate to make sure we don't
14252   // have remnants of state from other code.
14253   v8::Isolate* isolate = v8::Isolate::New();
14254   isolate->Enter();
14255   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14256   i::Heap* heap = i_isolate->heap();
14257
14258   {
14259     v8::HandleScope scope(isolate);
14260     i::HashMap code(MatchPointers);
14261     code_map = &code;
14262
14263     i::HashMap lineinfo(MatchPointers);
14264     jitcode_line_info = &lineinfo;
14265
14266     saw_bar = 0;
14267     move_events = 0;
14268
14269     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14270
14271     // Generate new code objects sparsely distributed across several
14272     // different fragmented code-space pages.
14273     const int kIterations = 10;
14274     for (int i = 0; i < kIterations; ++i) {
14275       LocalContext env(isolate);
14276       i::AlwaysAllocateScope always_allocate(i_isolate);
14277       SimulateFullSpace(heap->code_space());
14278       CompileRun(script);
14279
14280       // Keep a strong reference to the code object in the handle scope.
14281       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14282           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14283       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14284           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14285
14286       // Clear the compilation cache to get more wastage.
14287       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14288     }
14289
14290     // Force code movement.
14291     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14292
14293     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14294
14295     CHECK_LE(kIterations, saw_bar);
14296     CHECK_LT(0, move_events);
14297
14298     code_map = NULL;
14299     jitcode_line_info = NULL;
14300   }
14301
14302   isolate->Exit();
14303   isolate->Dispose();
14304
14305   // Do this in a new isolate.
14306   isolate = v8::Isolate::New();
14307   isolate->Enter();
14308
14309   // Verify that we get callbacks for existing code objects when we
14310   // request enumeration of existing code.
14311   {
14312     v8::HandleScope scope(isolate);
14313     LocalContext env(isolate);
14314     CompileRun(script);
14315
14316     // Now get code through initial iteration.
14317     i::HashMap code(MatchPointers);
14318     code_map = &code;
14319
14320     i::HashMap lineinfo(MatchPointers);
14321     jitcode_line_info = &lineinfo;
14322
14323     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14324     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14325
14326     jitcode_line_info = NULL;
14327     // We expect that we got some events. Note that if we could get code removal
14328     // notifications, we could compare two collections, one created by listening
14329     // from the time of creation of an isolate, and the other by subscribing
14330     // with EnumExisting.
14331     CHECK_LT(0, code.occupancy());
14332
14333     code_map = NULL;
14334   }
14335
14336   isolate->Exit();
14337   isolate->Dispose();
14338 }
14339
14340
14341 THREADED_TEST(ExternalAllocatedMemory) {
14342   v8::Isolate* isolate = CcTest::isolate();
14343   v8::HandleScope outer(isolate);
14344   v8::Local<Context> env(Context::New(isolate));
14345   CHECK(!env.IsEmpty());
14346   const int64_t kSize = 1024*1024;
14347   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14348   CHECK_EQ(baseline + kSize,
14349            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14350   CHECK_EQ(baseline,
14351            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14352 }
14353
14354
14355 // Regression test for issue 54, object templates with internal fields
14356 // but no accessors or interceptors did not get their internal field
14357 // count set on instances.
14358 THREADED_TEST(Regress54) {
14359   LocalContext context;
14360   v8::Isolate* isolate = context->GetIsolate();
14361   v8::HandleScope outer(isolate);
14362   static v8::Persistent<v8::ObjectTemplate> templ;
14363   if (templ.IsEmpty()) {
14364     v8::EscapableHandleScope inner(isolate);
14365     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14366     local->SetInternalFieldCount(1);
14367     templ.Reset(isolate, inner.Escape(local));
14368   }
14369   v8::Handle<v8::Object> result =
14370       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14371   CHECK_EQ(1, result->InternalFieldCount());
14372 }
14373
14374
14375 // If part of the threaded tests, this test makes ThreadingTest fail
14376 // on mac.
14377 TEST(CatchStackOverflow) {
14378   LocalContext context;
14379   v8::HandleScope scope(context->GetIsolate());
14380   v8::TryCatch try_catch;
14381   v8::Handle<v8::Value> result = CompileRun(
14382     "function f() {"
14383     "  return f();"
14384     "}"
14385     ""
14386     "f();");
14387   CHECK(result.IsEmpty());
14388 }
14389
14390
14391 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14392                                     const char* resource_name,
14393                                     int line_offset) {
14394   v8::HandleScope scope(CcTest::isolate());
14395   v8::TryCatch try_catch;
14396   v8::Handle<v8::Value> result = script->Run();
14397   CHECK(result.IsEmpty());
14398   CHECK(try_catch.HasCaught());
14399   v8::Handle<v8::Message> message = try_catch.Message();
14400   CHECK(!message.IsEmpty());
14401   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14402   CHECK_EQ(91, message->GetStartPosition());
14403   CHECK_EQ(92, message->GetEndPosition());
14404   CHECK_EQ(2, message->GetStartColumn());
14405   CHECK_EQ(3, message->GetEndColumn());
14406   v8::String::Utf8Value line(message->GetSourceLine());
14407   CHECK_EQ("  throw 'nirk';", *line);
14408   v8::String::Utf8Value name(message->GetScriptResourceName());
14409   CHECK_EQ(resource_name, *name);
14410 }
14411
14412
14413 THREADED_TEST(TryCatchSourceInfo) {
14414   LocalContext context;
14415   v8::HandleScope scope(context->GetIsolate());
14416   v8::Local<v8::String> source = v8_str(
14417       "function Foo() {\n"
14418       "  return Bar();\n"
14419       "}\n"
14420       "\n"
14421       "function Bar() {\n"
14422       "  return Baz();\n"
14423       "}\n"
14424       "\n"
14425       "function Baz() {\n"
14426       "  throw 'nirk';\n"
14427       "}\n"
14428       "\n"
14429       "Foo();\n");
14430
14431   const char* resource_name;
14432   v8::Handle<v8::Script> script;
14433   resource_name = "test.js";
14434   script = CompileWithOrigin(source, resource_name);
14435   CheckTryCatchSourceInfo(script, resource_name, 0);
14436
14437   resource_name = "test1.js";
14438   v8::ScriptOrigin origin1(
14439       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14440   script = v8::Script::Compile(source, &origin1);
14441   CheckTryCatchSourceInfo(script, resource_name, 0);
14442
14443   resource_name = "test2.js";
14444   v8::ScriptOrigin origin2(
14445       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14446       v8::Integer::New(context->GetIsolate(), 7));
14447   script = v8::Script::Compile(source, &origin2);
14448   CheckTryCatchSourceInfo(script, resource_name, 7);
14449 }
14450
14451
14452 THREADED_TEST(CompilationCache) {
14453   LocalContext context;
14454   v8::HandleScope scope(context->GetIsolate());
14455   v8::Handle<v8::String> source0 =
14456       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14457   v8::Handle<v8::String> source1 =
14458       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14459   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14460   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14461   v8::Handle<v8::Script> script2 =
14462       v8::Script::Compile(source0);  // different origin
14463   CHECK_EQ(1234, script0->Run()->Int32Value());
14464   CHECK_EQ(1234, script1->Run()->Int32Value());
14465   CHECK_EQ(1234, script2->Run()->Int32Value());
14466 }
14467
14468
14469 static void FunctionNameCallback(
14470     const v8::FunctionCallbackInfo<v8::Value>& args) {
14471   ApiTestFuzzer::Fuzz();
14472   args.GetReturnValue().Set(v8_num(42));
14473 }
14474
14475
14476 THREADED_TEST(CallbackFunctionName) {
14477   LocalContext context;
14478   v8::Isolate* isolate = context->GetIsolate();
14479   v8::HandleScope scope(isolate);
14480   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14481   t->Set(v8_str("asdf"),
14482          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14483   context->Global()->Set(v8_str("obj"), t->NewInstance());
14484   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14485   CHECK(value->IsString());
14486   v8::String::Utf8Value name(value);
14487   CHECK_EQ("asdf", *name);
14488 }
14489
14490
14491 THREADED_TEST(DateAccess) {
14492   LocalContext context;
14493   v8::HandleScope scope(context->GetIsolate());
14494   v8::Handle<v8::Value> date =
14495       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14496   CHECK(date->IsDate());
14497   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14498 }
14499
14500
14501 void CheckProperties(v8::Isolate* isolate,
14502                      v8::Handle<v8::Value> val,
14503                      int elmc,
14504                      const char* elmv[]) {
14505   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14506   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14507   CHECK_EQ(elmc, props->Length());
14508   for (int i = 0; i < elmc; i++) {
14509     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14510     CHECK_EQ(elmv[i], *elm);
14511   }
14512 }
14513
14514
14515 void CheckOwnProperties(v8::Isolate* isolate,
14516                         v8::Handle<v8::Value> val,
14517                         int elmc,
14518                         const char* elmv[]) {
14519   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14520   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14521   CHECK_EQ(elmc, props->Length());
14522   for (int i = 0; i < elmc; i++) {
14523     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14524     CHECK_EQ(elmv[i], *elm);
14525   }
14526 }
14527
14528
14529 THREADED_TEST(PropertyEnumeration) {
14530   LocalContext context;
14531   v8::Isolate* isolate = context->GetIsolate();
14532   v8::HandleScope scope(isolate);
14533   v8::Handle<v8::Value> obj = CompileRun(
14534       "var result = [];"
14535       "result[0] = {};"
14536       "result[1] = {a: 1, b: 2};"
14537       "result[2] = [1, 2, 3];"
14538       "var proto = {x: 1, y: 2, z: 3};"
14539       "var x = { __proto__: proto, w: 0, z: 1 };"
14540       "result[3] = x;"
14541       "result;");
14542   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14543   CHECK_EQ(4, elms->Length());
14544   int elmc0 = 0;
14545   const char** elmv0 = NULL;
14546   CheckProperties(
14547       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14548   CheckOwnProperties(
14549       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14550   int elmc1 = 2;
14551   const char* elmv1[] = {"a", "b"};
14552   CheckProperties(
14553       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14554   CheckOwnProperties(
14555       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14556   int elmc2 = 3;
14557   const char* elmv2[] = {"0", "1", "2"};
14558   CheckProperties(
14559       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14560   CheckOwnProperties(
14561       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14562   int elmc3 = 4;
14563   const char* elmv3[] = {"w", "z", "x", "y"};
14564   CheckProperties(
14565       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14566   int elmc4 = 2;
14567   const char* elmv4[] = {"w", "z"};
14568   CheckOwnProperties(
14569       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14570 }
14571
14572
14573 THREADED_TEST(PropertyEnumeration2) {
14574   LocalContext context;
14575   v8::Isolate* isolate = context->GetIsolate();
14576   v8::HandleScope scope(isolate);
14577   v8::Handle<v8::Value> obj = CompileRun(
14578       "var result = [];"
14579       "result[0] = {};"
14580       "result[1] = {a: 1, b: 2};"
14581       "result[2] = [1, 2, 3];"
14582       "var proto = {x: 1, y: 2, z: 3};"
14583       "var x = { __proto__: proto, w: 0, z: 1 };"
14584       "result[3] = x;"
14585       "result;");
14586   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14587   CHECK_EQ(4, elms->Length());
14588   int elmc0 = 0;
14589   const char** elmv0 = NULL;
14590   CheckProperties(isolate,
14591                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14592
14593   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14594   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14595   CHECK_EQ(0, props->Length());
14596   for (uint32_t i = 0; i < props->Length(); i++) {
14597     printf("p[%d]\n", i);
14598   }
14599 }
14600
14601 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14602                                   Local<Value> name,
14603                                   v8::AccessType type,
14604                                   Local<Value> data) {
14605   return type != v8::ACCESS_SET;
14606 }
14607
14608
14609 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14610                                     uint32_t key,
14611                                     v8::AccessType type,
14612                                     Local<Value> data) {
14613   return type != v8::ACCESS_SET;
14614 }
14615
14616
14617 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14618   LocalContext context;
14619   v8::Isolate* isolate = context->GetIsolate();
14620   v8::HandleScope scope(isolate);
14621   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14622   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14623                                  IndexedSetAccessBlocker);
14624   templ->Set(v8_str("x"), v8::True(isolate));
14625   Local<v8::Object> instance = templ->NewInstance();
14626   context->Global()->Set(v8_str("obj"), instance);
14627   Local<Value> value = CompileRun("obj.x");
14628   CHECK(value->BooleanValue());
14629 }
14630
14631
14632 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14633                                   Local<Value> name,
14634                                   v8::AccessType type,
14635                                   Local<Value> data) {
14636   return false;
14637 }
14638
14639
14640 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14641                                     uint32_t key,
14642                                     v8::AccessType type,
14643                                     Local<Value> data) {
14644   return false;
14645 }
14646
14647
14648
14649 THREADED_TEST(AccessChecksReenabledCorrectly) {
14650   LocalContext context;
14651   v8::Isolate* isolate = context->GetIsolate();
14652   v8::HandleScope scope(isolate);
14653   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14654   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14655                                  IndexedGetAccessBlocker);
14656   templ->Set(v8_str("a"), v8_str("a"));
14657   // Add more than 8 (see kMaxFastProperties) properties
14658   // so that the constructor will force copying map.
14659   // Cannot sprintf, gcc complains unsafety.
14660   char buf[4];
14661   for (char i = '0'; i <= '9' ; i++) {
14662     buf[0] = i;
14663     for (char j = '0'; j <= '9'; j++) {
14664       buf[1] = j;
14665       for (char k = '0'; k <= '9'; k++) {
14666         buf[2] = k;
14667         buf[3] = 0;
14668         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14669       }
14670     }
14671   }
14672
14673   Local<v8::Object> instance_1 = templ->NewInstance();
14674   context->Global()->Set(v8_str("obj_1"), instance_1);
14675
14676   Local<Value> value_1 = CompileRun("obj_1.a");
14677   CHECK(value_1->IsUndefined());
14678
14679   Local<v8::Object> instance_2 = templ->NewInstance();
14680   context->Global()->Set(v8_str("obj_2"), instance_2);
14681
14682   Local<Value> value_2 = CompileRun("obj_2.a");
14683   CHECK(value_2->IsUndefined());
14684 }
14685
14686
14687 // This tests that access check information remains on the global
14688 // object template when creating contexts.
14689 THREADED_TEST(AccessControlRepeatedContextCreation) {
14690   v8::Isolate* isolate = CcTest::isolate();
14691   v8::HandleScope handle_scope(isolate);
14692   v8::Handle<v8::ObjectTemplate> global_template =
14693       v8::ObjectTemplate::New(isolate);
14694   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14695                                            IndexedSetAccessBlocker);
14696   i::Handle<i::ObjectTemplateInfo> internal_template =
14697       v8::Utils::OpenHandle(*global_template);
14698   CHECK(!internal_template->constructor()->IsUndefined());
14699   i::Handle<i::FunctionTemplateInfo> constructor(
14700       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14701   CHECK(!constructor->access_check_info()->IsUndefined());
14702   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14703   CHECK(!context0.IsEmpty());
14704   CHECK(!constructor->access_check_info()->IsUndefined());
14705 }
14706
14707
14708 THREADED_TEST(TurnOnAccessCheck) {
14709   v8::Isolate* isolate = CcTest::isolate();
14710   v8::HandleScope handle_scope(isolate);
14711
14712   // Create an environment with access check to the global object disabled by
14713   // default.
14714   v8::Handle<v8::ObjectTemplate> global_template =
14715       v8::ObjectTemplate::New(isolate);
14716   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14717                                            IndexedGetAccessBlocker,
14718                                            v8::Handle<v8::Value>(),
14719                                            false);
14720   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14721   Context::Scope context_scope(context);
14722
14723   // Set up a property and a number of functions.
14724   context->Global()->Set(v8_str("a"), v8_num(1));
14725   CompileRun("function f1() {return a;}"
14726              "function f2() {return a;}"
14727              "function g1() {return h();}"
14728              "function g2() {return h();}"
14729              "function h() {return 1;}");
14730   Local<Function> f1 =
14731       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14732   Local<Function> f2 =
14733       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14734   Local<Function> g1 =
14735       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14736   Local<Function> g2 =
14737       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14738   Local<Function> h =
14739       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14740
14741   // Get the global object.
14742   v8::Handle<v8::Object> global = context->Global();
14743
14744   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14745   // uses the runtime system to retreive property a whereas f2 uses global load
14746   // inline cache.
14747   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14748   for (int i = 0; i < 4; i++) {
14749     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14750   }
14751
14752   // Same for g1 and g2.
14753   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14754   for (int i = 0; i < 4; i++) {
14755     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14756   }
14757
14758   // Detach the global and turn on access check.
14759   Local<Object> hidden_global = Local<Object>::Cast(
14760       context->Global()->GetPrototype());
14761   context->DetachGlobal();
14762   hidden_global->TurnOnAccessCheck();
14763
14764   // Failing access check to property get results in undefined.
14765   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14766   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14767
14768   // Failing access check to function call results in exception.
14769   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14770   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14771
14772   // No failing access check when just returning a constant.
14773   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14774 }
14775
14776
14777 static const char* kPropertyA = "a";
14778 static const char* kPropertyH = "h";
14779
14780 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14781                                        Local<Value> name,
14782                                        v8::AccessType type,
14783                                        Local<Value> data) {
14784   if (!name->IsString()) return false;
14785   i::Handle<i::String> name_handle =
14786       v8::Utils::OpenHandle(String::Cast(*name));
14787   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14788       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14789 }
14790
14791
14792 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14793   v8::Isolate* isolate = CcTest::isolate();
14794   v8::HandleScope handle_scope(isolate);
14795
14796   // Create an environment with access check to the global object disabled by
14797   // default. When the registered access checker will block access to properties
14798   // a and h.
14799   v8::Handle<v8::ObjectTemplate> global_template =
14800      v8::ObjectTemplate::New(isolate);
14801   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14802                                            IndexedGetAccessBlocker,
14803                                            v8::Handle<v8::Value>(),
14804                                            false);
14805   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14806   Context::Scope context_scope(context);
14807
14808   // Set up a property and a number of functions.
14809   context->Global()->Set(v8_str("a"), v8_num(1));
14810   static const char* source = "function f1() {return a;}"
14811                               "function f2() {return a;}"
14812                               "function g1() {return h();}"
14813                               "function g2() {return h();}"
14814                               "function h() {return 1;}";
14815
14816   CompileRun(source);
14817   Local<Function> f1;
14818   Local<Function> f2;
14819   Local<Function> g1;
14820   Local<Function> g2;
14821   Local<Function> h;
14822   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14823   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14824   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14825   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14826   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14827
14828   // Get the global object.
14829   v8::Handle<v8::Object> global = context->Global();
14830
14831   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14832   // uses the runtime system to retreive property a whereas f2 uses global load
14833   // inline cache.
14834   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14835   for (int i = 0; i < 4; i++) {
14836     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14837   }
14838
14839   // Same for g1 and g2.
14840   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14841   for (int i = 0; i < 4; i++) {
14842     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14843   }
14844
14845   // Detach the global and turn on access check now blocking access to property
14846   // a and function h.
14847   Local<Object> hidden_global = Local<Object>::Cast(
14848       context->Global()->GetPrototype());
14849   context->DetachGlobal();
14850   hidden_global->TurnOnAccessCheck();
14851
14852   // Failing access check to property get results in undefined.
14853   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14854   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14855
14856   // Failing access check to function call results in exception.
14857   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14858   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14859
14860   // No failing access check when just returning a constant.
14861   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14862
14863   // Now compile the source again. And get the newly compiled functions, except
14864   // for h for which access is blocked.
14865   CompileRun(source);
14866   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14867   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14868   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14869   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14870   CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14871
14872   // Failing access check to property get results in undefined.
14873   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14874   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14875
14876   // Failing access check to function call results in exception.
14877   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14878   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14879 }
14880
14881
14882 // Tests that ScriptData can be serialized and deserialized.
14883 TEST(PreCompileSerialization) {
14884   v8::V8::Initialize();
14885   LocalContext env;
14886   v8::Isolate* isolate = env->GetIsolate();
14887   HandleScope handle_scope(isolate);
14888
14889   i::FLAG_min_preparse_length = 0;
14890   const char* script = "function foo(a) { return a+1; }";
14891   v8::ScriptCompiler::Source source(v8_str(script));
14892   v8::ScriptCompiler::Compile(isolate, &source,
14893                               v8::ScriptCompiler::kProduceDataToCache);
14894   // Serialize.
14895   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14896   char* serialized_data = i::NewArray<char>(cd->length);
14897   i::OS::MemCopy(serialized_data, cd->data, cd->length);
14898
14899   // Deserialize.
14900   i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
14901
14902   // Verify that the original is the same as the deserialized.
14903   CHECK_EQ(cd->length, deserialized->Length());
14904   CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
14905
14906   delete deserialized;
14907   i::DeleteArray(serialized_data);
14908 }
14909
14910
14911 // Attempts to deserialize bad data.
14912 TEST(PreCompileDeserializationError) {
14913   v8::V8::Initialize();
14914   const char* data = "DONT CARE";
14915   int invalid_size = 3;
14916   i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
14917   CHECK_EQ(NULL, sd);
14918 }
14919
14920
14921 TEST(CompileWithInvalidCachedData) {
14922   v8::V8::Initialize();
14923   v8::Isolate* isolate = CcTest::isolate();
14924   LocalContext context;
14925   v8::HandleScope scope(context->GetIsolate());
14926   i::FLAG_min_preparse_length = 0;
14927
14928   const char* script = "function foo(){ return 5;}\n"
14929       "function bar(){ return 6 + 7;}  foo();";
14930   v8::ScriptCompiler::Source source(v8_str(script));
14931   v8::ScriptCompiler::Compile(isolate, &source,
14932                               v8::ScriptCompiler::kProduceDataToCache);
14933   // source owns its cached data. Create a ScriptData based on it. The user
14934   // never needs to create ScriptDatas any more; we only need it here because we
14935   // want to modify the data before passing it back.
14936   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14937   // ScriptData does not take ownership of the buffers passed to it.
14938   i::ScriptData* sd =
14939       i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
14940   CHECK(!sd->HasError());
14941   // ScriptData private implementation details
14942   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14943   const int kFunctionEntrySize = i::FunctionEntry::kSize;
14944   const int kFunctionEntryStartOffset = 0;
14945   const int kFunctionEntryEndOffset = 1;
14946   unsigned* sd_data =
14947       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14948
14949   // Overwrite function bar's end position with 0.
14950   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14951   v8::TryCatch try_catch;
14952
14953   // Make the script slightly different so that we don't hit the compilation
14954   // cache. Don't change the lenghts of tokens.
14955   const char* script2 = "function foo(){ return 6;}\n"
14956       "function bar(){ return 6 + 7;}  foo();";
14957   v8::ScriptCompiler::Source source2(
14958       v8_str(script2),
14959       // CachedData doesn't take ownership of the buffers, Source takes
14960       // ownership of CachedData.
14961       new v8::ScriptCompiler::CachedData(
14962           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14963   Local<v8::UnboundScript> compiled_script =
14964       v8::ScriptCompiler::CompileUnbound(isolate, &source2);
14965
14966   CHECK(try_catch.HasCaught());
14967   {
14968     String::Utf8Value exception_value(try_catch.Message()->Get());
14969     CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
14970              *exception_value);
14971   }
14972
14973   try_catch.Reset();
14974   delete sd;
14975
14976   // Overwrite function bar's start position with 200. The function entry will
14977   // not be found when searching for it by position, and the compilation fails.
14978
14979   // ScriptData does not take ownership of the buffers passed to it.
14980   sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
14981   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14982   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14983       200;
14984   const char* script3 = "function foo(){ return 7;}\n"
14985       "function bar(){ return 6 + 7;}  foo();";
14986   v8::ScriptCompiler::Source source3(
14987       v8_str(script3),
14988       new v8::ScriptCompiler::CachedData(
14989           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
14990   compiled_script =
14991       v8::ScriptCompiler::CompileUnbound(isolate, &source3);
14992   CHECK(try_catch.HasCaught());
14993   {
14994     String::Utf8Value exception_value(try_catch.Message()->Get());
14995     CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
14996              *exception_value);
14997   }
14998   CHECK(compiled_script.IsEmpty());
14999   try_catch.Reset();
15000   delete sd;
15001
15002   // Try passing in cached data which is obviously invalid (wrong length).
15003   sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
15004   const char* script4 =
15005       "function foo(){ return 8;}\n"
15006       "function bar(){ return 6 + 7;}  foo();";
15007   v8::ScriptCompiler::Source source4(
15008       v8_str(script4),
15009       new v8::ScriptCompiler::CachedData(
15010           reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
15011   compiled_script =
15012       v8::ScriptCompiler::CompileUnbound(isolate, &source4);
15013   CHECK(try_catch.HasCaught());
15014   {
15015     String::Utf8Value exception_value(try_catch.Message()->Get());
15016     CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
15017              *exception_value);
15018   }
15019   CHECK(compiled_script.IsEmpty());
15020   delete sd;
15021 }
15022
15023
15024 // This tests that we do not allow dictionary load/call inline caches
15025 // to use functions that have not yet been compiled.  The potential
15026 // problem of loading a function that has not yet been compiled can
15027 // arise because we share code between contexts via the compilation
15028 // cache.
15029 THREADED_TEST(DictionaryICLoadedFunction) {
15030   v8::HandleScope scope(CcTest::isolate());
15031   // Test LoadIC.
15032   for (int i = 0; i < 2; i++) {
15033     LocalContext context;
15034     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15035     context->Global()->Delete(v8_str("tmp"));
15036     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15037   }
15038   // Test CallIC.
15039   for (int i = 0; i < 2; i++) {
15040     LocalContext context;
15041     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15042     context->Global()->Delete(v8_str("tmp"));
15043     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15044   }
15045 }
15046
15047
15048 // Test that cross-context new calls use the context of the callee to
15049 // create the new JavaScript object.
15050 THREADED_TEST(CrossContextNew) {
15051   v8::Isolate* isolate = CcTest::isolate();
15052   v8::HandleScope scope(isolate);
15053   v8::Local<Context> context0 = Context::New(isolate);
15054   v8::Local<Context> context1 = Context::New(isolate);
15055
15056   // Allow cross-domain access.
15057   Local<String> token = v8_str("<security token>");
15058   context0->SetSecurityToken(token);
15059   context1->SetSecurityToken(token);
15060
15061   // Set an 'x' property on the Object prototype and define a
15062   // constructor function in context0.
15063   context0->Enter();
15064   CompileRun("Object.prototype.x = 42; function C() {};");
15065   context0->Exit();
15066
15067   // Call the constructor function from context0 and check that the
15068   // result has the 'x' property.
15069   context1->Enter();
15070   context1->Global()->Set(v8_str("other"), context0->Global());
15071   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15072   CHECK(value->IsInt32());
15073   CHECK_EQ(42, value->Int32Value());
15074   context1->Exit();
15075 }
15076
15077
15078 // Verify that we can clone an object
15079 TEST(ObjectClone) {
15080   LocalContext env;
15081   v8::Isolate* isolate = env->GetIsolate();
15082   v8::HandleScope scope(isolate);
15083
15084   const char* sample =
15085     "var rv = {};"      \
15086     "rv.alpha = 'hello';" \
15087     "rv.beta = 123;"     \
15088     "rv;";
15089
15090   // Create an object, verify basics.
15091   Local<Value> val = CompileRun(sample);
15092   CHECK(val->IsObject());
15093   Local<v8::Object> obj = val.As<v8::Object>();
15094   obj->Set(v8_str("gamma"), v8_str("cloneme"));
15095
15096   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15097   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15098   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15099
15100   // Clone it.
15101   Local<v8::Object> clone = obj->Clone();
15102   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15103   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15104   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15105
15106   // Set a property on the clone, verify each object.
15107   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15108   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15109   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15110 }
15111
15112
15113 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15114  public:
15115   explicit AsciiVectorResource(i::Vector<const char> vector)
15116       : data_(vector) {}
15117   virtual ~AsciiVectorResource() {}
15118   virtual size_t length() const { return data_.length(); }
15119   virtual const char* data() const { return data_.start(); }
15120  private:
15121   i::Vector<const char> data_;
15122 };
15123
15124
15125 class UC16VectorResource : public v8::String::ExternalStringResource {
15126  public:
15127   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15128       : data_(vector) {}
15129   virtual ~UC16VectorResource() {}
15130   virtual size_t length() const { return data_.length(); }
15131   virtual const i::uc16* data() const { return data_.start(); }
15132  private:
15133   i::Vector<const i::uc16> data_;
15134 };
15135
15136
15137 static void MorphAString(i::String* string,
15138                          AsciiVectorResource* ascii_resource,
15139                          UC16VectorResource* uc16_resource) {
15140   CHECK(i::StringShape(string).IsExternal());
15141   if (string->IsOneByteRepresentation()) {
15142     // Check old map is not internalized or long.
15143     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15144     // Morph external string to be TwoByte string.
15145     string->set_map(CcTest::heap()->external_string_map());
15146     i::ExternalTwoByteString* morphed =
15147          i::ExternalTwoByteString::cast(string);
15148     morphed->set_resource(uc16_resource);
15149   } else {
15150     // Check old map is not internalized or long.
15151     CHECK(string->map() == CcTest::heap()->external_string_map());
15152     // Morph external string to be ASCII string.
15153     string->set_map(CcTest::heap()->external_ascii_string_map());
15154     i::ExternalAsciiString* morphed =
15155          i::ExternalAsciiString::cast(string);
15156     morphed->set_resource(ascii_resource);
15157   }
15158 }
15159
15160
15161 // Test that we can still flatten a string if the components it is built up
15162 // from have been turned into 16 bit strings in the mean time.
15163 THREADED_TEST(MorphCompositeStringTest) {
15164   char utf_buffer[129];
15165   const char* c_string = "Now is the time for all good men"
15166                          " to come to the aid of the party";
15167   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15168   {
15169     LocalContext env;
15170     i::Factory* factory = CcTest::i_isolate()->factory();
15171     v8::HandleScope scope(env->GetIsolate());
15172     AsciiVectorResource ascii_resource(
15173         i::Vector<const char>(c_string, i::StrLength(c_string)));
15174     UC16VectorResource uc16_resource(
15175         i::Vector<const uint16_t>(two_byte_string,
15176                                   i::StrLength(c_string)));
15177
15178     Local<String> lhs(v8::Utils::ToLocal(
15179         factory->NewExternalStringFromAscii(&ascii_resource)
15180             .ToHandleChecked()));
15181     Local<String> rhs(v8::Utils::ToLocal(
15182         factory->NewExternalStringFromAscii(&ascii_resource)
15183             .ToHandleChecked()));
15184
15185     env->Global()->Set(v8_str("lhs"), lhs);
15186     env->Global()->Set(v8_str("rhs"), rhs);
15187
15188     CompileRun(
15189         "var cons = lhs + rhs;"
15190         "var slice = lhs.substring(1, lhs.length - 1);"
15191         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15192
15193     CHECK(lhs->IsOneByte());
15194     CHECK(rhs->IsOneByte());
15195
15196     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15197     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15198
15199     // This should UTF-8 without flattening, since everything is ASCII.
15200     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15201     CHECK_EQ(128, cons->Utf8Length());
15202     int nchars = -1;
15203     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15204     CHECK_EQ(128, nchars);
15205     CHECK_EQ(0, strcmp(
15206         utf_buffer,
15207         "Now is the time for all good men to come to the aid of the party"
15208         "Now is the time for all good men to come to the aid of the party"));
15209
15210     // Now do some stuff to make sure the strings are flattened, etc.
15211     CompileRun(
15212         "/[^a-z]/.test(cons);"
15213         "/[^a-z]/.test(slice);"
15214         "/[^a-z]/.test(slice_on_cons);");
15215     const char* expected_cons =
15216         "Now is the time for all good men to come to the aid of the party"
15217         "Now is the time for all good men to come to the aid of the party";
15218     const char* expected_slice =
15219         "ow is the time for all good men to come to the aid of the part";
15220     const char* expected_slice_on_cons =
15221         "ow is the time for all good men to come to the aid of the party"
15222         "Now is the time for all good men to come to the aid of the part";
15223     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15224              env->Global()->Get(v8_str("cons")));
15225     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15226              env->Global()->Get(v8_str("slice")));
15227     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15228              env->Global()->Get(v8_str("slice_on_cons")));
15229   }
15230   i::DeleteArray(two_byte_string);
15231 }
15232
15233
15234 TEST(CompileExternalTwoByteSource) {
15235   LocalContext context;
15236   v8::HandleScope scope(context->GetIsolate());
15237
15238   // This is a very short list of sources, which currently is to check for a
15239   // regression caused by r2703.
15240   const char* ascii_sources[] = {
15241     "0.5",
15242     "-0.5",   // This mainly testes PushBack in the Scanner.
15243     "--0.5",  // This mainly testes PushBack in the Scanner.
15244     NULL
15245   };
15246
15247   // Compile the sources as external two byte strings.
15248   for (int i = 0; ascii_sources[i] != NULL; i++) {
15249     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15250     TestResource* uc16_resource = new TestResource(two_byte_string);
15251     v8::Local<v8::String> source =
15252         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15253     v8::Script::Compile(source);
15254   }
15255 }
15256
15257
15258 #ifndef V8_INTERPRETED_REGEXP
15259
15260 struct RegExpInterruptionData {
15261   int loop_count;
15262   UC16VectorResource* string_resource;
15263   v8::Persistent<v8::String> string;
15264 } regexp_interruption_data;
15265
15266
15267 class RegExpInterruptionThread : public i::Thread {
15268  public:
15269   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15270       : Thread("TimeoutThread"), isolate_(isolate) {}
15271
15272   virtual void Run() {
15273     for (regexp_interruption_data.loop_count = 0;
15274          regexp_interruption_data.loop_count < 7;
15275          regexp_interruption_data.loop_count++) {
15276       i::OS::Sleep(50);  // Wait a bit before requesting GC.
15277       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15278     }
15279     i::OS::Sleep(50);  // Wait a bit before terminating.
15280     v8::V8::TerminateExecution(isolate_);
15281   }
15282
15283  private:
15284   v8::Isolate* isolate_;
15285 };
15286
15287
15288 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15289   if (regexp_interruption_data.loop_count != 2) return;
15290   v8::HandleScope scope(CcTest::isolate());
15291   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15292       CcTest::isolate(), regexp_interruption_data.string);
15293   string->MakeExternal(regexp_interruption_data.string_resource);
15294 }
15295
15296
15297 // Test that RegExp execution can be interrupted.  Specifically, we test
15298 // * interrupting with GC
15299 // * turn the subject string from one-byte internal to two-byte external string
15300 // * force termination
15301 TEST(RegExpInterruption) {
15302   v8::HandleScope scope(CcTest::isolate());
15303   LocalContext env;
15304
15305   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15306
15307   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15308   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15309   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15310   v8::Local<v8::String> string = v8_str(ascii_content);
15311
15312   CcTest::global()->Set(v8_str("a"), string);
15313   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15314   regexp_interruption_data.string_resource = new UC16VectorResource(
15315       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15316
15317   v8::TryCatch try_catch;
15318   timeout_thread.Start();
15319
15320   CompileRun("/((a*)*)*b/.exec(a)");
15321   CHECK(try_catch.HasTerminated());
15322
15323   timeout_thread.Join();
15324
15325   regexp_interruption_data.string.Reset();
15326   i::DeleteArray(uc16_content);
15327 }
15328
15329 #endif  // V8_INTERPRETED_REGEXP
15330
15331
15332 // Test that we cannot set a property on the global object if there
15333 // is a read-only property in the prototype chain.
15334 TEST(ReadOnlyPropertyInGlobalProto) {
15335   v8::Isolate* isolate = CcTest::isolate();
15336   v8::HandleScope scope(isolate);
15337   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15338   LocalContext context(0, templ);
15339   v8::Handle<v8::Object> global = context->Global();
15340   v8::Handle<v8::Object> global_proto =
15341       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15342   global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15343   global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15344   // Check without 'eval' or 'with'.
15345   v8::Handle<v8::Value> res =
15346       CompileRun("function f() { x = 42; return x; }; f()");
15347   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15348   // Check with 'eval'.
15349   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15350   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15351   // Check with 'with'.
15352   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15353   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15354 }
15355
15356 static int force_set_set_count = 0;
15357 static int force_set_get_count = 0;
15358 bool pass_on_get = false;
15359
15360 static void ForceSetGetter(v8::Local<v8::String> name,
15361                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15362   force_set_get_count++;
15363   if (pass_on_get) {
15364     return;
15365   }
15366   info.GetReturnValue().Set(3);
15367 }
15368
15369 static void ForceSetSetter(v8::Local<v8::String> name,
15370                            v8::Local<v8::Value> value,
15371                            const v8::PropertyCallbackInfo<void>& info) {
15372   force_set_set_count++;
15373 }
15374
15375 static void ForceSetInterceptSetter(
15376     v8::Local<v8::String> name,
15377     v8::Local<v8::Value> value,
15378     const v8::PropertyCallbackInfo<v8::Value>& info) {
15379   force_set_set_count++;
15380   info.GetReturnValue().SetUndefined();
15381 }
15382
15383
15384 TEST(ForceSet) {
15385   force_set_get_count = 0;
15386   force_set_set_count = 0;
15387   pass_on_get = false;
15388
15389   v8::Isolate* isolate = CcTest::isolate();
15390   v8::HandleScope scope(isolate);
15391   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15392   v8::Handle<v8::String> access_property =
15393       v8::String::NewFromUtf8(isolate, "a");
15394   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15395   LocalContext context(NULL, templ);
15396   v8::Handle<v8::Object> global = context->Global();
15397
15398   // Ordinary properties
15399   v8::Handle<v8::String> simple_property =
15400       v8::String::NewFromUtf8(isolate, "p");
15401   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15402   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15403   // This should fail because the property is read-only
15404   global->Set(simple_property, v8::Int32::New(isolate, 5));
15405   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15406   // This should succeed even though the property is read-only
15407   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15408   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15409
15410   // Accessors
15411   CHECK_EQ(0, force_set_set_count);
15412   CHECK_EQ(0, force_set_get_count);
15413   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15414   // CHECK_EQ the property shouldn't override it, just call the setter
15415   // which in this case does nothing.
15416   global->Set(access_property, v8::Int32::New(isolate, 7));
15417   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15418   CHECK_EQ(1, force_set_set_count);
15419   CHECK_EQ(2, force_set_get_count);
15420   // Forcing the property to be set should override the accessor without
15421   // calling it
15422   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15423   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15424   CHECK_EQ(1, force_set_set_count);
15425   CHECK_EQ(2, force_set_get_count);
15426 }
15427
15428
15429 TEST(ForceSetWithInterceptor) {
15430   force_set_get_count = 0;
15431   force_set_set_count = 0;
15432   pass_on_get = false;
15433
15434   v8::Isolate* isolate = CcTest::isolate();
15435   v8::HandleScope scope(isolate);
15436   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15437   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15438   LocalContext context(NULL, templ);
15439   v8::Handle<v8::Object> global = context->Global();
15440
15441   v8::Handle<v8::String> some_property =
15442       v8::String::NewFromUtf8(isolate, "a");
15443   CHECK_EQ(0, force_set_set_count);
15444   CHECK_EQ(0, force_set_get_count);
15445   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15446   // Setting the property shouldn't override it, just call the setter
15447   // which in this case does nothing.
15448   global->Set(some_property, v8::Int32::New(isolate, 7));
15449   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15450   CHECK_EQ(1, force_set_set_count);
15451   CHECK_EQ(2, force_set_get_count);
15452   // Getting the property when the interceptor returns an empty handle
15453   // should yield undefined, since the property isn't present on the
15454   // object itself yet.
15455   pass_on_get = true;
15456   CHECK(global->Get(some_property)->IsUndefined());
15457   CHECK_EQ(1, force_set_set_count);
15458   CHECK_EQ(3, force_set_get_count);
15459   // Forcing the property to be set should cause the value to be
15460   // set locally without calling the interceptor.
15461   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15462   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15463   CHECK_EQ(1, force_set_set_count);
15464   CHECK_EQ(4, force_set_get_count);
15465   // Reenabling the interceptor should cause it to take precedence over
15466   // the property
15467   pass_on_get = false;
15468   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15469   CHECK_EQ(1, force_set_set_count);
15470   CHECK_EQ(5, force_set_get_count);
15471   // The interceptor should also work for other properties
15472   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15473                   ->Int32Value());
15474   CHECK_EQ(1, force_set_set_count);
15475   CHECK_EQ(6, force_set_get_count);
15476 }
15477
15478
15479 THREADED_TEST(ForceDelete) {
15480   v8::Isolate* isolate = CcTest::isolate();
15481   v8::HandleScope scope(isolate);
15482   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15483   LocalContext context(NULL, templ);
15484   v8::Handle<v8::Object> global = context->Global();
15485
15486   // Ordinary properties
15487   v8::Handle<v8::String> simple_property =
15488       v8::String::NewFromUtf8(isolate, "p");
15489   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15490   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15491   // This should fail because the property is dont-delete.
15492   CHECK(!global->Delete(simple_property));
15493   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15494   // This should succeed even though the property is dont-delete.
15495   CHECK(global->ForceDelete(simple_property));
15496   CHECK(global->Get(simple_property)->IsUndefined());
15497 }
15498
15499
15500 static int force_delete_interceptor_count = 0;
15501 static bool pass_on_delete = false;
15502
15503
15504 static void ForceDeleteDeleter(
15505     v8::Local<v8::String> name,
15506     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15507   force_delete_interceptor_count++;
15508   if (pass_on_delete) return;
15509   info.GetReturnValue().Set(true);
15510 }
15511
15512
15513 THREADED_TEST(ForceDeleteWithInterceptor) {
15514   force_delete_interceptor_count = 0;
15515   pass_on_delete = false;
15516
15517   v8::Isolate* isolate = CcTest::isolate();
15518   v8::HandleScope scope(isolate);
15519   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15520   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15521   LocalContext context(NULL, templ);
15522   v8::Handle<v8::Object> global = context->Global();
15523
15524   v8::Handle<v8::String> some_property =
15525       v8::String::NewFromUtf8(isolate, "a");
15526   global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15527
15528   // Deleting a property should get intercepted and nothing should
15529   // happen.
15530   CHECK_EQ(0, force_delete_interceptor_count);
15531   CHECK(global->Delete(some_property));
15532   CHECK_EQ(1, force_delete_interceptor_count);
15533   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15534   // Deleting the property when the interceptor returns an empty
15535   // handle should not delete the property since it is DontDelete.
15536   pass_on_delete = true;
15537   CHECK(!global->Delete(some_property));
15538   CHECK_EQ(2, force_delete_interceptor_count);
15539   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15540   // Forcing the property to be deleted should delete the value
15541   // without calling the interceptor.
15542   CHECK(global->ForceDelete(some_property));
15543   CHECK(global->Get(some_property)->IsUndefined());
15544   CHECK_EQ(2, force_delete_interceptor_count);
15545 }
15546
15547
15548 // Make sure that forcing a delete invalidates any IC stubs, so we
15549 // don't read the hole value.
15550 THREADED_TEST(ForceDeleteIC) {
15551   LocalContext context;
15552   v8::HandleScope scope(context->GetIsolate());
15553   // Create a DontDelete variable on the global object.
15554   CompileRun("this.__proto__ = { foo: 'horse' };"
15555              "var foo = 'fish';"
15556              "function f() { return foo.length; }");
15557   // Initialize the IC for foo in f.
15558   CompileRun("for (var i = 0; i < 4; i++) f();");
15559   // Make sure the value of foo is correct before the deletion.
15560   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15561   // Force the deletion of foo.
15562   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15563   // Make sure the value for foo is read from the prototype, and that
15564   // we don't get in trouble with reading the deleted cell value
15565   // sentinel.
15566   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15567 }
15568
15569
15570 TEST(InlinedFunctionAcrossContexts) {
15571   i::FLAG_allow_natives_syntax = true;
15572   v8::Isolate* isolate = CcTest::isolate();
15573   v8::HandleScope outer_scope(isolate);
15574   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15575   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15576   ctx1->Enter();
15577
15578   {
15579     v8::HandleScope inner_scope(CcTest::isolate());
15580     CompileRun("var G = 42; function foo() { return G; }");
15581     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15582     ctx2->Enter();
15583     ctx2->Global()->Set(v8_str("o"), foo);
15584     v8::Local<v8::Value> res = CompileRun(
15585         "function f() { return o(); }"
15586         "for (var i = 0; i < 10; ++i) f();"
15587         "%OptimizeFunctionOnNextCall(f);"
15588         "f();");
15589     CHECK_EQ(42, res->Int32Value());
15590     ctx2->Exit();
15591     v8::Handle<v8::String> G_property =
15592         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15593     CHECK(ctx1->Global()->ForceDelete(G_property));
15594     ctx2->Enter();
15595     ExpectString(
15596         "(function() {"
15597         "  try {"
15598         "    return f();"
15599         "  } catch(e) {"
15600         "    return e.toString();"
15601         "  }"
15602         " })()",
15603         "ReferenceError: G is not defined");
15604     ctx2->Exit();
15605     ctx1->Exit();
15606   }
15607 }
15608
15609
15610 static v8::Local<Context> calling_context0;
15611 static v8::Local<Context> calling_context1;
15612 static v8::Local<Context> calling_context2;
15613
15614
15615 // Check that the call to the callback is initiated in
15616 // calling_context2, the directly calling context is calling_context1
15617 // and the callback itself is in calling_context0.
15618 static void GetCallingContextCallback(
15619     const v8::FunctionCallbackInfo<v8::Value>& args) {
15620   ApiTestFuzzer::Fuzz();
15621   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15622   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15623   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15624   args.GetReturnValue().Set(42);
15625 }
15626
15627
15628 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15629   i::Isolate* isolate = CcTest::i_isolate();
15630   CHECK(isolate != NULL);
15631   CHECK(isolate->context() == NULL);
15632   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15633   v8::HandleScope scope(v8_isolate);
15634   // The following should not crash, but return an empty handle.
15635   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15636   CHECK(current.IsEmpty());
15637 }
15638
15639
15640 THREADED_TEST(GetCallingContext) {
15641   v8::Isolate* isolate = CcTest::isolate();
15642   v8::HandleScope scope(isolate);
15643
15644   Local<Context> calling_context0(Context::New(isolate));
15645   Local<Context> calling_context1(Context::New(isolate));
15646   Local<Context> calling_context2(Context::New(isolate));
15647   ::calling_context0 = calling_context0;
15648   ::calling_context1 = calling_context1;
15649   ::calling_context2 = calling_context2;
15650
15651   // Allow cross-domain access.
15652   Local<String> token = v8_str("<security token>");
15653   calling_context0->SetSecurityToken(token);
15654   calling_context1->SetSecurityToken(token);
15655   calling_context2->SetSecurityToken(token);
15656
15657   // Create an object with a C++ callback in context0.
15658   calling_context0->Enter();
15659   Local<v8::FunctionTemplate> callback_templ =
15660       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15661   calling_context0->Global()->Set(v8_str("callback"),
15662                                   callback_templ->GetFunction());
15663   calling_context0->Exit();
15664
15665   // Expose context0 in context1 and set up a function that calls the
15666   // callback function.
15667   calling_context1->Enter();
15668   calling_context1->Global()->Set(v8_str("context0"),
15669                                   calling_context0->Global());
15670   CompileRun("function f() { context0.callback() }");
15671   calling_context1->Exit();
15672
15673   // Expose context1 in context2 and call the callback function in
15674   // context0 indirectly through f in context1.
15675   calling_context2->Enter();
15676   calling_context2->Global()->Set(v8_str("context1"),
15677                                   calling_context1->Global());
15678   CompileRun("context1.f()");
15679   calling_context2->Exit();
15680   ::calling_context0.Clear();
15681   ::calling_context1.Clear();
15682   ::calling_context2.Clear();
15683 }
15684
15685
15686 // Check that a variable declaration with no explicit initialization
15687 // value does shadow an existing property in the prototype chain.
15688 THREADED_TEST(InitGlobalVarInProtoChain) {
15689   LocalContext context;
15690   v8::HandleScope scope(context->GetIsolate());
15691   // Introduce a variable in the prototype chain.
15692   CompileRun("__proto__.x = 42");
15693   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15694   CHECK(!result->IsUndefined());
15695   CHECK_EQ(43, result->Int32Value());
15696 }
15697
15698
15699 // Regression test for issue 398.
15700 // If a function is added to an object, creating a constant function
15701 // field, and the result is cloned, replacing the constant function on the
15702 // original should not affect the clone.
15703 // See http://code.google.com/p/v8/issues/detail?id=398
15704 THREADED_TEST(ReplaceConstantFunction) {
15705   LocalContext context;
15706   v8::Isolate* isolate = context->GetIsolate();
15707   v8::HandleScope scope(isolate);
15708   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15709   v8::Handle<v8::FunctionTemplate> func_templ =
15710       v8::FunctionTemplate::New(isolate);
15711   v8::Handle<v8::String> foo_string =
15712       v8::String::NewFromUtf8(isolate, "foo");
15713   obj->Set(foo_string, func_templ->GetFunction());
15714   v8::Handle<v8::Object> obj_clone = obj->Clone();
15715   obj_clone->Set(foo_string,
15716                  v8::String::NewFromUtf8(isolate, "Hello"));
15717   CHECK(!obj->Get(foo_string)->IsUndefined());
15718 }
15719
15720
15721 static void CheckElementValue(i::Isolate* isolate,
15722                               int expected,
15723                               i::Handle<i::Object> obj,
15724                               int offset) {
15725   i::Object* element =
15726       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15727   CHECK_EQ(expected, i::Smi::cast(element)->value());
15728 }
15729
15730
15731 THREADED_TEST(PixelArray) {
15732   LocalContext context;
15733   i::Isolate* isolate = CcTest::i_isolate();
15734   i::Factory* factory = isolate->factory();
15735   v8::HandleScope scope(context->GetIsolate());
15736   const int kElementCount = 260;
15737   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15738   i::Handle<i::ExternalUint8ClampedArray> pixels =
15739       i::Handle<i::ExternalUint8ClampedArray>::cast(
15740           factory->NewExternalArray(kElementCount,
15741                                     v8::kExternalUint8ClampedArray,
15742                                     pixel_data));
15743   // Force GC to trigger verification.
15744   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15745   for (int i = 0; i < kElementCount; i++) {
15746     pixels->set(i, i % 256);
15747   }
15748   // Force GC to trigger verification.
15749   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15750   for (int i = 0; i < kElementCount; i++) {
15751     CHECK_EQ(i % 256, pixels->get_scalar(i));
15752     CHECK_EQ(i % 256, pixel_data[i]);
15753   }
15754
15755   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15756   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15757   // Set the elements to be the pixels.
15758   // jsobj->set_elements(*pixels);
15759   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15760   CheckElementValue(isolate, 1, jsobj, 1);
15761   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15762   context->Global()->Set(v8_str("pixels"), obj);
15763   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15764   CHECK_EQ(1503, result->Int32Value());
15765   result = CompileRun("pixels[1]");
15766   CHECK_EQ(1, result->Int32Value());
15767
15768   result = CompileRun("var sum = 0;"
15769                       "for (var i = 0; i < 8; i++) {"
15770                       "  sum += pixels[i] = pixels[i] = -i;"
15771                       "}"
15772                       "sum;");
15773   CHECK_EQ(-28, result->Int32Value());
15774
15775   result = CompileRun("var sum = 0;"
15776                       "for (var i = 0; i < 8; i++) {"
15777                       "  sum += pixels[i] = pixels[i] = 0;"
15778                       "}"
15779                       "sum;");
15780   CHECK_EQ(0, result->Int32Value());
15781
15782   result = CompileRun("var sum = 0;"
15783                       "for (var i = 0; i < 8; i++) {"
15784                       "  sum += pixels[i] = pixels[i] = 255;"
15785                       "}"
15786                       "sum;");
15787   CHECK_EQ(8 * 255, result->Int32Value());
15788
15789   result = CompileRun("var sum = 0;"
15790                       "for (var i = 0; i < 8; i++) {"
15791                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15792                       "}"
15793                       "sum;");
15794   CHECK_EQ(2076, result->Int32Value());
15795
15796   result = CompileRun("var sum = 0;"
15797                       "for (var i = 0; i < 8; i++) {"
15798                       "  sum += pixels[i] = pixels[i] = i;"
15799                       "}"
15800                       "sum;");
15801   CHECK_EQ(28, result->Int32Value());
15802
15803   result = CompileRun("var sum = 0;"
15804                       "for (var i = 0; i < 8; i++) {"
15805                       "  sum += pixels[i];"
15806                       "}"
15807                       "sum;");
15808   CHECK_EQ(28, result->Int32Value());
15809
15810   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15811                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15812   i::Handle<i::Object> no_failure;
15813   no_failure = i::JSObject::SetElement(
15814       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15815   ASSERT(!no_failure.is_null());
15816   i::USE(no_failure);
15817   CheckElementValue(isolate, 2, jsobj, 1);
15818   *value.location() = i::Smi::FromInt(256);
15819   no_failure = i::JSObject::SetElement(
15820       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15821   ASSERT(!no_failure.is_null());
15822   i::USE(no_failure);
15823   CheckElementValue(isolate, 255, jsobj, 1);
15824   *value.location() = i::Smi::FromInt(-1);
15825   no_failure = i::JSObject::SetElement(
15826       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15827   ASSERT(!no_failure.is_null());
15828   i::USE(no_failure);
15829   CheckElementValue(isolate, 0, jsobj, 1);
15830
15831   result = CompileRun("for (var i = 0; i < 8; i++) {"
15832                       "  pixels[i] = (i * 65) - 109;"
15833                       "}"
15834                       "pixels[1] + pixels[6];");
15835   CHECK_EQ(255, result->Int32Value());
15836   CheckElementValue(isolate, 0, jsobj, 0);
15837   CheckElementValue(isolate, 0, jsobj, 1);
15838   CheckElementValue(isolate, 21, jsobj, 2);
15839   CheckElementValue(isolate, 86, jsobj, 3);
15840   CheckElementValue(isolate, 151, jsobj, 4);
15841   CheckElementValue(isolate, 216, jsobj, 5);
15842   CheckElementValue(isolate, 255, jsobj, 6);
15843   CheckElementValue(isolate, 255, jsobj, 7);
15844   result = CompileRun("var sum = 0;"
15845                       "for (var i = 0; i < 8; i++) {"
15846                       "  sum += pixels[i];"
15847                       "}"
15848                       "sum;");
15849   CHECK_EQ(984, result->Int32Value());
15850
15851   result = CompileRun("for (var i = 0; i < 8; i++) {"
15852                       "  pixels[i] = (i * 1.1);"
15853                       "}"
15854                       "pixels[1] + pixels[6];");
15855   CHECK_EQ(8, result->Int32Value());
15856   CheckElementValue(isolate, 0, jsobj, 0);
15857   CheckElementValue(isolate, 1, jsobj, 1);
15858   CheckElementValue(isolate, 2, jsobj, 2);
15859   CheckElementValue(isolate, 3, jsobj, 3);
15860   CheckElementValue(isolate, 4, jsobj, 4);
15861   CheckElementValue(isolate, 6, jsobj, 5);
15862   CheckElementValue(isolate, 7, jsobj, 6);
15863   CheckElementValue(isolate, 8, jsobj, 7);
15864
15865   result = CompileRun("for (var i = 0; i < 8; i++) {"
15866                       "  pixels[7] = undefined;"
15867                       "}"
15868                       "pixels[7];");
15869   CHECK_EQ(0, result->Int32Value());
15870   CheckElementValue(isolate, 0, jsobj, 7);
15871
15872   result = CompileRun("for (var i = 0; i < 8; i++) {"
15873                       "  pixels[6] = '2.3';"
15874                       "}"
15875                       "pixels[6];");
15876   CHECK_EQ(2, result->Int32Value());
15877   CheckElementValue(isolate, 2, jsobj, 6);
15878
15879   result = CompileRun("for (var i = 0; i < 8; i++) {"
15880                       "  pixels[5] = NaN;"
15881                       "}"
15882                       "pixels[5];");
15883   CHECK_EQ(0, result->Int32Value());
15884   CheckElementValue(isolate, 0, jsobj, 5);
15885
15886   result = CompileRun("for (var i = 0; i < 8; i++) {"
15887                       "  pixels[8] = Infinity;"
15888                       "}"
15889                       "pixels[8];");
15890   CHECK_EQ(255, result->Int32Value());
15891   CheckElementValue(isolate, 255, jsobj, 8);
15892
15893   result = CompileRun("for (var i = 0; i < 8; i++) {"
15894                       "  pixels[9] = -Infinity;"
15895                       "}"
15896                       "pixels[9];");
15897   CHECK_EQ(0, result->Int32Value());
15898   CheckElementValue(isolate, 0, jsobj, 9);
15899
15900   result = CompileRun("pixels[3] = 33;"
15901                       "delete pixels[3];"
15902                       "pixels[3];");
15903   CHECK_EQ(33, result->Int32Value());
15904
15905   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15906                       "pixels[2] = 12; pixels[3] = 13;"
15907                       "pixels.__defineGetter__('2',"
15908                       "function() { return 120; });"
15909                       "pixels[2];");
15910   CHECK_EQ(12, result->Int32Value());
15911
15912   result = CompileRun("var js_array = new Array(40);"
15913                       "js_array[0] = 77;"
15914                       "js_array;");
15915   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15916
15917   result = CompileRun("pixels[1] = 23;"
15918                       "pixels.__proto__ = [];"
15919                       "js_array.__proto__ = pixels;"
15920                       "js_array.concat(pixels);");
15921   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15922   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15923
15924   result = CompileRun("pixels[1] = 23;");
15925   CHECK_EQ(23, result->Int32Value());
15926
15927   // Test for index greater than 255.  Regression test for:
15928   // http://code.google.com/p/chromium/issues/detail?id=26337.
15929   result = CompileRun("pixels[256] = 255;");
15930   CHECK_EQ(255, result->Int32Value());
15931   result = CompileRun("var i = 0;"
15932                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15933                       "i");
15934   CHECK_EQ(255, result->Int32Value());
15935
15936   // Make sure that pixel array ICs recognize when a non-pixel array
15937   // is passed to it.
15938   result = CompileRun("function pa_load(p) {"
15939                       "  var sum = 0;"
15940                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15941                       "  return sum;"
15942                       "}"
15943                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15944                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15945                       "just_ints = new Object();"
15946                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15947                       "for (var i = 0; i < 10; ++i) {"
15948                       "  result = pa_load(just_ints);"
15949                       "}"
15950                       "result");
15951   CHECK_EQ(32640, result->Int32Value());
15952
15953   // Make sure that pixel array ICs recognize out-of-bound accesses.
15954   result = CompileRun("function pa_load(p, start) {"
15955                       "  var sum = 0;"
15956                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15957                       "  return sum;"
15958                       "}"
15959                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15960                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15961                       "for (var i = 0; i < 10; ++i) {"
15962                       "  result = pa_load(pixels,-10);"
15963                       "}"
15964                       "result");
15965   CHECK_EQ(0, result->Int32Value());
15966
15967   // Make sure that generic ICs properly handles a pixel array.
15968   result = CompileRun("function pa_load(p) {"
15969                       "  var sum = 0;"
15970                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15971                       "  return sum;"
15972                       "}"
15973                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15974                       "just_ints = new Object();"
15975                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15976                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15977                       "for (var i = 0; i < 10; ++i) {"
15978                       "  result = pa_load(pixels);"
15979                       "}"
15980                       "result");
15981   CHECK_EQ(32640, result->Int32Value());
15982
15983   // Make sure that generic load ICs recognize out-of-bound accesses in
15984   // pixel arrays.
15985   result = CompileRun("function pa_load(p, start) {"
15986                       "  var sum = 0;"
15987                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15988                       "  return sum;"
15989                       "}"
15990                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15991                       "just_ints = new Object();"
15992                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15993                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15994                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15995                       "for (var i = 0; i < 10; ++i) {"
15996                       "  result = pa_load(pixels,-10);"
15997                       "}"
15998                       "result");
15999   CHECK_EQ(0, result->Int32Value());
16000
16001   // Make sure that generic ICs properly handles other types than pixel
16002   // arrays (that the inlined fast pixel array test leaves the right information
16003   // in the right registers).
16004   result = CompileRun("function pa_load(p) {"
16005                       "  var sum = 0;"
16006                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16007                       "  return sum;"
16008                       "}"
16009                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16010                       "just_ints = new Object();"
16011                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16012                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16013                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16014                       "sparse_array = new Object();"
16015                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16016                       "sparse_array[1000000] = 3;"
16017                       "for (var i = 0; i < 10; ++i) {"
16018                       "  result = pa_load(sparse_array);"
16019                       "}"
16020                       "result");
16021   CHECK_EQ(32640, result->Int32Value());
16022
16023   // Make sure that pixel array store ICs clamp values correctly.
16024   result = CompileRun("function pa_store(p) {"
16025                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16026                       "}"
16027                       "pa_store(pixels);"
16028                       "var sum = 0;"
16029                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16030                       "sum");
16031   CHECK_EQ(48896, result->Int32Value());
16032
16033   // Make sure that pixel array stores correctly handle accesses outside
16034   // of the pixel array..
16035   result = CompileRun("function pa_store(p,start) {"
16036                       "  for (var j = 0; j < 256; j++) {"
16037                       "    p[j+start] = j * 2;"
16038                       "  }"
16039                       "}"
16040                       "pa_store(pixels,0);"
16041                       "pa_store(pixels,-128);"
16042                       "var sum = 0;"
16043                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16044                       "sum");
16045   CHECK_EQ(65280, result->Int32Value());
16046
16047   // Make sure that the generic store stub correctly handle accesses outside
16048   // of the pixel array..
16049   result = CompileRun("function pa_store(p,start) {"
16050                       "  for (var j = 0; j < 256; j++) {"
16051                       "    p[j+start] = j * 2;"
16052                       "  }"
16053                       "}"
16054                       "pa_store(pixels,0);"
16055                       "just_ints = new Object();"
16056                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16057                       "pa_store(just_ints, 0);"
16058                       "pa_store(pixels,-128);"
16059                       "var sum = 0;"
16060                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16061                       "sum");
16062   CHECK_EQ(65280, result->Int32Value());
16063
16064   // Make sure that the generic keyed store stub clamps pixel array values
16065   // correctly.
16066   result = CompileRun("function pa_store(p) {"
16067                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16068                       "}"
16069                       "pa_store(pixels);"
16070                       "just_ints = new Object();"
16071                       "pa_store(just_ints);"
16072                       "pa_store(pixels);"
16073                       "var sum = 0;"
16074                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16075                       "sum");
16076   CHECK_EQ(48896, result->Int32Value());
16077
16078   // Make sure that pixel array loads are optimized by crankshaft.
16079   result = CompileRun("function pa_load(p) {"
16080                       "  var sum = 0;"
16081                       "  for (var i=0; i<256; ++i) {"
16082                       "    sum += p[i];"
16083                       "  }"
16084                       "  return sum; "
16085                       "}"
16086                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16087                       "for (var i = 0; i < 5000; ++i) {"
16088                       "  result = pa_load(pixels);"
16089                       "}"
16090                       "result");
16091   CHECK_EQ(32640, result->Int32Value());
16092
16093   // Make sure that pixel array stores are optimized by crankshaft.
16094   result = CompileRun("function pa_init(p) {"
16095                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16096                       "}"
16097                       "function pa_load(p) {"
16098                       "  var sum = 0;"
16099                       "  for (var i=0; i<256; ++i) {"
16100                       "    sum += p[i];"
16101                       "  }"
16102                       "  return sum; "
16103                       "}"
16104                       "for (var i = 0; i < 5000; ++i) {"
16105                       "  pa_init(pixels);"
16106                       "}"
16107                       "result = pa_load(pixels);"
16108                       "result");
16109   CHECK_EQ(32640, result->Int32Value());
16110
16111   free(pixel_data);
16112 }
16113
16114
16115 THREADED_TEST(PixelArrayInfo) {
16116   LocalContext context;
16117   v8::HandleScope scope(context->GetIsolate());
16118   for (int size = 0; size < 100; size += 10) {
16119     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16120     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16121     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16122     CHECK(obj->HasIndexedPropertiesInPixelData());
16123     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16124     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16125     free(pixel_data);
16126   }
16127 }
16128
16129
16130 static void NotHandledIndexedPropertyGetter(
16131     uint32_t index,
16132     const v8::PropertyCallbackInfo<v8::Value>& info) {
16133   ApiTestFuzzer::Fuzz();
16134 }
16135
16136
16137 static void NotHandledIndexedPropertySetter(
16138     uint32_t index,
16139     Local<Value> value,
16140     const v8::PropertyCallbackInfo<v8::Value>& info) {
16141   ApiTestFuzzer::Fuzz();
16142 }
16143
16144
16145 THREADED_TEST(PixelArrayWithInterceptor) {
16146   LocalContext context;
16147   i::Factory* factory = CcTest::i_isolate()->factory();
16148   v8::Isolate* isolate = context->GetIsolate();
16149   v8::HandleScope scope(isolate);
16150   const int kElementCount = 260;
16151   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16152   i::Handle<i::ExternalUint8ClampedArray> pixels =
16153       i::Handle<i::ExternalUint8ClampedArray>::cast(
16154           factory->NewExternalArray(kElementCount,
16155                                     v8::kExternalUint8ClampedArray,
16156                                     pixel_data));
16157   for (int i = 0; i < kElementCount; i++) {
16158     pixels->set(i, i % 256);
16159   }
16160   v8::Handle<v8::ObjectTemplate> templ =
16161       v8::ObjectTemplate::New(context->GetIsolate());
16162   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16163                                    NotHandledIndexedPropertySetter);
16164   v8::Handle<v8::Object> obj = templ->NewInstance();
16165   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16166   context->Global()->Set(v8_str("pixels"), obj);
16167   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16168   CHECK_EQ(1, result->Int32Value());
16169   result = CompileRun("var sum = 0;"
16170                       "for (var i = 0; i < 8; i++) {"
16171                       "  sum += pixels[i] = pixels[i] = -i;"
16172                       "}"
16173                       "sum;");
16174   CHECK_EQ(-28, result->Int32Value());
16175   result = CompileRun("pixels.hasOwnProperty('1')");
16176   CHECK(result->BooleanValue());
16177   free(pixel_data);
16178 }
16179
16180
16181 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16182   switch (array_type) {
16183     case v8::kExternalInt8Array:
16184     case v8::kExternalUint8Array:
16185     case v8::kExternalUint8ClampedArray:
16186       return 1;
16187       break;
16188     case v8::kExternalInt16Array:
16189     case v8::kExternalUint16Array:
16190       return 2;
16191       break;
16192     case v8::kExternalInt32Array:
16193     case v8::kExternalUint32Array:
16194     case v8::kExternalFloat32Array:
16195       return 4;
16196       break;
16197     case v8::kExternalFloat64Array:
16198       return 8;
16199       break;
16200     default:
16201       UNREACHABLE();
16202       return -1;
16203   }
16204   UNREACHABLE();
16205   return -1;
16206 }
16207
16208
16209 template <class ExternalArrayClass, class ElementType>
16210 static void ObjectWithExternalArrayTestHelper(
16211     Handle<Context> context,
16212     v8::Handle<Object> obj,
16213     int element_count,
16214     v8::ExternalArrayType array_type,
16215     int64_t low, int64_t high) {
16216   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16217   i::Isolate* isolate = jsobj->GetIsolate();
16218   obj->Set(v8_str("field"),
16219            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16220   context->Global()->Set(v8_str("ext_array"), obj);
16221   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16222   CHECK_EQ(1503, result->Int32Value());
16223   result = CompileRun("ext_array[1]");
16224   CHECK_EQ(1, result->Int32Value());
16225
16226   // Check assigned smis
16227   result = CompileRun("for (var i = 0; i < 8; i++) {"
16228                       "  ext_array[i] = i;"
16229                       "}"
16230                       "var sum = 0;"
16231                       "for (var i = 0; i < 8; i++) {"
16232                       "  sum += ext_array[i];"
16233                       "}"
16234                       "sum;");
16235
16236   CHECK_EQ(28, result->Int32Value());
16237   // Check pass through of assigned smis
16238   result = CompileRun("var sum = 0;"
16239                       "for (var i = 0; i < 8; i++) {"
16240                       "  sum += ext_array[i] = ext_array[i] = -i;"
16241                       "}"
16242                       "sum;");
16243   CHECK_EQ(-28, result->Int32Value());
16244
16245
16246   // Check assigned smis in reverse order
16247   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16248                       "  ext_array[i] = i;"
16249                       "}"
16250                       "var sum = 0;"
16251                       "for (var i = 0; i < 8; i++) {"
16252                       "  sum += ext_array[i];"
16253                       "}"
16254                       "sum;");
16255   CHECK_EQ(28, result->Int32Value());
16256
16257   // Check pass through of assigned HeapNumbers
16258   result = CompileRun("var sum = 0;"
16259                       "for (var i = 0; i < 16; i+=2) {"
16260                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16261                       "}"
16262                       "sum;");
16263   CHECK_EQ(-28, result->Int32Value());
16264
16265   // Check assigned HeapNumbers
16266   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16267                       "  ext_array[i] = (i * 0.5);"
16268                       "}"
16269                       "var sum = 0;"
16270                       "for (var i = 0; i < 16; i+=2) {"
16271                       "  sum += ext_array[i];"
16272                       "}"
16273                       "sum;");
16274   CHECK_EQ(28, result->Int32Value());
16275
16276   // Check assigned HeapNumbers in reverse order
16277   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16278                       "  ext_array[i] = (i * 0.5);"
16279                       "}"
16280                       "var sum = 0;"
16281                       "for (var i = 0; i < 16; i+=2) {"
16282                       "  sum += ext_array[i];"
16283                       "}"
16284                       "sum;");
16285   CHECK_EQ(28, result->Int32Value());
16286
16287   i::ScopedVector<char> test_buf(1024);
16288
16289   // Check legal boundary conditions.
16290   // The repeated loads and stores ensure the ICs are exercised.
16291   const char* boundary_program =
16292       "var res = 0;"
16293       "for (var i = 0; i < 16; i++) {"
16294       "  ext_array[i] = %lld;"
16295       "  if (i > 8) {"
16296       "    res = ext_array[i];"
16297       "  }"
16298       "}"
16299       "res;";
16300   i::OS::SNPrintF(test_buf,
16301                   boundary_program,
16302                   low);
16303   result = CompileRun(test_buf.start());
16304   CHECK_EQ(low, result->IntegerValue());
16305
16306   i::OS::SNPrintF(test_buf,
16307                   boundary_program,
16308                   high);
16309   result = CompileRun(test_buf.start());
16310   CHECK_EQ(high, result->IntegerValue());
16311
16312   // Check misprediction of type in IC.
16313   result = CompileRun("var tmp_array = ext_array;"
16314                       "var sum = 0;"
16315                       "for (var i = 0; i < 8; i++) {"
16316                       "  tmp_array[i] = i;"
16317                       "  sum += tmp_array[i];"
16318                       "  if (i == 4) {"
16319                       "    tmp_array = {};"
16320                       "  }"
16321                       "}"
16322                       "sum;");
16323   // Force GC to trigger verification.
16324   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16325   CHECK_EQ(28, result->Int32Value());
16326
16327   // Make sure out-of-range loads do not throw.
16328   i::OS::SNPrintF(test_buf,
16329                   "var caught_exception = false;"
16330                   "try {"
16331                   "  ext_array[%d];"
16332                   "} catch (e) {"
16333                   "  caught_exception = true;"
16334                   "}"
16335                   "caught_exception;",
16336                   element_count);
16337   result = CompileRun(test_buf.start());
16338   CHECK_EQ(false, result->BooleanValue());
16339
16340   // Make sure out-of-range stores do not throw.
16341   i::OS::SNPrintF(test_buf,
16342                   "var caught_exception = false;"
16343                   "try {"
16344                   "  ext_array[%d] = 1;"
16345                   "} catch (e) {"
16346                   "  caught_exception = true;"
16347                   "}"
16348                   "caught_exception;",
16349                   element_count);
16350   result = CompileRun(test_buf.start());
16351   CHECK_EQ(false, result->BooleanValue());
16352
16353   // Check other boundary conditions, values and operations.
16354   result = CompileRun("for (var i = 0; i < 8; i++) {"
16355                       "  ext_array[7] = undefined;"
16356                       "}"
16357                       "ext_array[7];");
16358   CHECK_EQ(0, result->Int32Value());
16359   if (array_type == v8::kExternalFloat64Array ||
16360       array_type == v8::kExternalFloat32Array) {
16361     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16362              static_cast<int>(
16363                  i::Object::GetElement(
16364                      isolate, jsobj, 7).ToHandleChecked()->Number()));
16365   } else {
16366     CheckElementValue(isolate, 0, jsobj, 7);
16367   }
16368
16369   result = CompileRun("for (var i = 0; i < 8; i++) {"
16370                       "  ext_array[6] = '2.3';"
16371                       "}"
16372                       "ext_array[6];");
16373   CHECK_EQ(2, result->Int32Value());
16374   CHECK_EQ(2,
16375            static_cast<int>(
16376                i::Object::GetElement(
16377                    isolate, jsobj, 6).ToHandleChecked()->Number()));
16378
16379   if (array_type != v8::kExternalFloat32Array &&
16380       array_type != v8::kExternalFloat64Array) {
16381     // Though the specification doesn't state it, be explicit about
16382     // converting NaNs and +/-Infinity to zero.
16383     result = CompileRun("for (var i = 0; i < 8; i++) {"
16384                         "  ext_array[i] = 5;"
16385                         "}"
16386                         "for (var i = 0; i < 8; i++) {"
16387                         "  ext_array[i] = NaN;"
16388                         "}"
16389                         "ext_array[5];");
16390     CHECK_EQ(0, result->Int32Value());
16391     CheckElementValue(isolate, 0, jsobj, 5);
16392
16393     result = CompileRun("for (var i = 0; i < 8; i++) {"
16394                         "  ext_array[i] = 5;"
16395                         "}"
16396                         "for (var i = 0; i < 8; i++) {"
16397                         "  ext_array[i] = Infinity;"
16398                         "}"
16399                         "ext_array[5];");
16400     int expected_value =
16401         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16402     CHECK_EQ(expected_value, result->Int32Value());
16403     CheckElementValue(isolate, expected_value, jsobj, 5);
16404
16405     result = CompileRun("for (var i = 0; i < 8; i++) {"
16406                         "  ext_array[i] = 5;"
16407                         "}"
16408                         "for (var i = 0; i < 8; i++) {"
16409                         "  ext_array[i] = -Infinity;"
16410                         "}"
16411                         "ext_array[5];");
16412     CHECK_EQ(0, result->Int32Value());
16413     CheckElementValue(isolate, 0, jsobj, 5);
16414
16415     // Check truncation behavior of integral arrays.
16416     const char* unsigned_data =
16417         "var source_data = [0.6, 10.6];"
16418         "var expected_results = [0, 10];";
16419     const char* signed_data =
16420         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16421         "var expected_results = [0, 10, 0, -10];";
16422     const char* pixel_data =
16423         "var source_data = [0.6, 10.6];"
16424         "var expected_results = [1, 11];";
16425     bool is_unsigned =
16426         (array_type == v8::kExternalUint8Array ||
16427          array_type == v8::kExternalUint16Array ||
16428          array_type == v8::kExternalUint32Array);
16429     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16430
16431     i::OS::SNPrintF(test_buf,
16432                     "%s"
16433                     "var all_passed = true;"
16434                     "for (var i = 0; i < source_data.length; i++) {"
16435                     "  for (var j = 0; j < 8; j++) {"
16436                     "    ext_array[j] = source_data[i];"
16437                     "  }"
16438                     "  all_passed = all_passed &&"
16439                     "               (ext_array[5] == expected_results[i]);"
16440                     "}"
16441                     "all_passed;",
16442                     (is_unsigned ?
16443                          unsigned_data :
16444                          (is_pixel_data ? pixel_data : signed_data)));
16445     result = CompileRun(test_buf.start());
16446     CHECK_EQ(true, result->BooleanValue());
16447   }
16448
16449   i::Handle<ExternalArrayClass> array(
16450       ExternalArrayClass::cast(jsobj->elements()));
16451   for (int i = 0; i < element_count; i++) {
16452     array->set(i, static_cast<ElementType>(i));
16453   }
16454
16455   // Test complex assignments
16456   result = CompileRun("function ee_op_test_complex_func(sum) {"
16457                       " for (var i = 0; i < 40; ++i) {"
16458                       "   sum += (ext_array[i] += 1);"
16459                       "   sum += (ext_array[i] -= 1);"
16460                       " } "
16461                       " return sum;"
16462                       "}"
16463                       "sum=0;"
16464                       "for (var i=0;i<10000;++i) {"
16465                       "  sum=ee_op_test_complex_func(sum);"
16466                       "}"
16467                       "sum;");
16468   CHECK_EQ(16000000, result->Int32Value());
16469
16470   // Test count operations
16471   result = CompileRun("function ee_op_test_count_func(sum) {"
16472                       " for (var i = 0; i < 40; ++i) {"
16473                       "   sum += (++ext_array[i]);"
16474                       "   sum += (--ext_array[i]);"
16475                       " } "
16476                       " return sum;"
16477                       "}"
16478                       "sum=0;"
16479                       "for (var i=0;i<10000;++i) {"
16480                       "  sum=ee_op_test_count_func(sum);"
16481                       "}"
16482                       "sum;");
16483   CHECK_EQ(16000000, result->Int32Value());
16484
16485   result = CompileRun("ext_array[3] = 33;"
16486                       "delete ext_array[3];"
16487                       "ext_array[3];");
16488   CHECK_EQ(33, result->Int32Value());
16489
16490   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16491                       "ext_array[2] = 12; ext_array[3] = 13;"
16492                       "ext_array.__defineGetter__('2',"
16493                       "function() { return 120; });"
16494                       "ext_array[2];");
16495   CHECK_EQ(12, result->Int32Value());
16496
16497   result = CompileRun("var js_array = new Array(40);"
16498                       "js_array[0] = 77;"
16499                       "js_array;");
16500   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16501
16502   result = CompileRun("ext_array[1] = 23;"
16503                       "ext_array.__proto__ = [];"
16504                       "js_array.__proto__ = ext_array;"
16505                       "js_array.concat(ext_array);");
16506   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16507   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16508
16509   result = CompileRun("ext_array[1] = 23;");
16510   CHECK_EQ(23, result->Int32Value());
16511 }
16512
16513
16514 template <class FixedTypedArrayClass,
16515           i::ElementsKind elements_kind,
16516           class ElementType>
16517 static void FixedTypedArrayTestHelper(
16518     v8::ExternalArrayType array_type,
16519     ElementType low,
16520     ElementType high) {
16521   i::FLAG_allow_natives_syntax = true;
16522   LocalContext context;
16523   i::Isolate* isolate = CcTest::i_isolate();
16524   i::Factory* factory = isolate->factory();
16525   v8::HandleScope scope(context->GetIsolate());
16526   const int kElementCount = 260;
16527   i::Handle<FixedTypedArrayClass> fixed_array =
16528     i::Handle<FixedTypedArrayClass>::cast(
16529         factory->NewFixedTypedArray(kElementCount, array_type));
16530   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16531            fixed_array->map()->instance_type());
16532   CHECK_EQ(kElementCount, fixed_array->length());
16533   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16534   for (int i = 0; i < kElementCount; i++) {
16535     fixed_array->set(i, static_cast<ElementType>(i));
16536   }
16537   // Force GC to trigger verification.
16538   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16539   for (int i = 0; i < kElementCount; i++) {
16540     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16541              static_cast<int64_t>(fixed_array->get_scalar(i)));
16542   }
16543   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16544   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16545   i::Handle<i::Map> fixed_array_map =
16546       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16547   jsobj->set_map(*fixed_array_map);
16548   jsobj->set_elements(*fixed_array);
16549
16550   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16551       context.local(), obj, kElementCount, array_type,
16552       static_cast<int64_t>(low),
16553       static_cast<int64_t>(high));
16554 }
16555
16556
16557 THREADED_TEST(FixedUint8Array) {
16558   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16559     v8::kExternalUint8Array,
16560     0x0, 0xFF);
16561 }
16562
16563
16564 THREADED_TEST(FixedUint8ClampedArray) {
16565   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16566                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16567     v8::kExternalUint8ClampedArray,
16568     0x0, 0xFF);
16569 }
16570
16571
16572 THREADED_TEST(FixedInt8Array) {
16573   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16574     v8::kExternalInt8Array,
16575     -0x80, 0x7F);
16576 }
16577
16578
16579 THREADED_TEST(FixedUint16Array) {
16580   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16581     v8::kExternalUint16Array,
16582     0x0, 0xFFFF);
16583 }
16584
16585
16586 THREADED_TEST(FixedInt16Array) {
16587   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16588     v8::kExternalInt16Array,
16589     -0x8000, 0x7FFF);
16590 }
16591
16592
16593 THREADED_TEST(FixedUint32Array) {
16594   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16595     v8::kExternalUint32Array,
16596     0x0, UINT_MAX);
16597 }
16598
16599
16600 THREADED_TEST(FixedInt32Array) {
16601   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16602     v8::kExternalInt32Array,
16603     INT_MIN, INT_MAX);
16604 }
16605
16606
16607 THREADED_TEST(FixedFloat32Array) {
16608   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16609     v8::kExternalFloat32Array,
16610     -500, 500);
16611 }
16612
16613
16614 THREADED_TEST(FixedFloat64Array) {
16615   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16616     v8::kExternalFloat64Array,
16617     -500, 500);
16618 }
16619
16620
16621 template <class ExternalArrayClass, class ElementType>
16622 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16623                                     int64_t low,
16624                                     int64_t high) {
16625   LocalContext context;
16626   i::Isolate* isolate = CcTest::i_isolate();
16627   i::Factory* factory = isolate->factory();
16628   v8::HandleScope scope(context->GetIsolate());
16629   const int kElementCount = 40;
16630   int element_size = ExternalArrayElementSize(array_type);
16631   ElementType* array_data =
16632       static_cast<ElementType*>(malloc(kElementCount * element_size));
16633   i::Handle<ExternalArrayClass> array =
16634       i::Handle<ExternalArrayClass>::cast(
16635           factory->NewExternalArray(kElementCount, array_type, array_data));
16636   // Force GC to trigger verification.
16637   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16638   for (int i = 0; i < kElementCount; i++) {
16639     array->set(i, static_cast<ElementType>(i));
16640   }
16641   // Force GC to trigger verification.
16642   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16643   for (int i = 0; i < kElementCount; i++) {
16644     CHECK_EQ(static_cast<int64_t>(i),
16645              static_cast<int64_t>(array->get_scalar(i)));
16646     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16647   }
16648
16649   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16650   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16651   // Set the elements to be the external array.
16652   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16653                                                array_type,
16654                                                kElementCount);
16655   CHECK_EQ(1,
16656            static_cast<int>(
16657                i::Object::GetElement(
16658                    isolate, jsobj, 1).ToHandleChecked()->Number()));
16659
16660   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16661       context.local(), obj, kElementCount, array_type, low, high);
16662
16663   v8::Handle<v8::Value> result;
16664
16665   // Test more complex manipulations which cause eax to contain values
16666   // that won't be completely overwritten by loads from the arrays.
16667   // This catches bugs in the instructions used for the KeyedLoadIC
16668   // for byte and word types.
16669   {
16670     const int kXSize = 300;
16671     const int kYSize = 300;
16672     const int kLargeElementCount = kXSize * kYSize * 4;
16673     ElementType* large_array_data =
16674         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16675     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16676     // Set the elements to be the external array.
16677     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16678                                                        array_type,
16679                                                        kLargeElementCount);
16680     context->Global()->Set(v8_str("large_array"), large_obj);
16681     // Initialize contents of a few rows.
16682     for (int x = 0; x < 300; x++) {
16683       int row = 0;
16684       int offset = row * 300 * 4;
16685       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16686       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16687       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16688       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16689       row = 150;
16690       offset = row * 300 * 4;
16691       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16692       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16693       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16694       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16695       row = 298;
16696       offset = row * 300 * 4;
16697       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16698       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16699       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16700       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16701     }
16702     // The goal of the code below is to make "offset" large enough
16703     // that the computation of the index (which goes into eax) has
16704     // high bits set which will not be overwritten by a byte or short
16705     // load.
16706     result = CompileRun("var failed = false;"
16707                         "var offset = 0;"
16708                         "for (var i = 0; i < 300; i++) {"
16709                         "  if (large_array[4 * i] != 127 ||"
16710                         "      large_array[4 * i + 1] != 0 ||"
16711                         "      large_array[4 * i + 2] != 0 ||"
16712                         "      large_array[4 * i + 3] != 127) {"
16713                         "    failed = true;"
16714                         "  }"
16715                         "}"
16716                         "offset = 150 * 300 * 4;"
16717                         "for (var i = 0; i < 300; i++) {"
16718                         "  if (large_array[offset + 4 * i] != 127 ||"
16719                         "      large_array[offset + 4 * i + 1] != 0 ||"
16720                         "      large_array[offset + 4 * i + 2] != 0 ||"
16721                         "      large_array[offset + 4 * i + 3] != 127) {"
16722                         "    failed = true;"
16723                         "  }"
16724                         "}"
16725                         "offset = 298 * 300 * 4;"
16726                         "for (var i = 0; i < 300; i++) {"
16727                         "  if (large_array[offset + 4 * i] != 127 ||"
16728                         "      large_array[offset + 4 * i + 1] != 0 ||"
16729                         "      large_array[offset + 4 * i + 2] != 0 ||"
16730                         "      large_array[offset + 4 * i + 3] != 127) {"
16731                         "    failed = true;"
16732                         "  }"
16733                         "}"
16734                         "!failed;");
16735     CHECK_EQ(true, result->BooleanValue());
16736     free(large_array_data);
16737   }
16738
16739   // The "" property descriptor is overloaded to store information about
16740   // the external array. Ensure that setting and accessing the "" property
16741   // works (it should overwrite the information cached about the external
16742   // array in the DescriptorArray) in various situations.
16743   result = CompileRun("ext_array[''] = 23; ext_array['']");
16744   CHECK_EQ(23, result->Int32Value());
16745
16746   // Property "" set after the external array is associated with the object.
16747   {
16748     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16749     obj2->Set(v8_str("ee_test_field"),
16750               v8::Int32::New(context->GetIsolate(), 256));
16751     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16752     // Set the elements to be the external array.
16753     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16754                                                   array_type,
16755                                                   kElementCount);
16756     context->Global()->Set(v8_str("ext_array"), obj2);
16757     result = CompileRun("ext_array['']");
16758     CHECK_EQ(1503, result->Int32Value());
16759   }
16760
16761   // Property "" set after the external array is associated with the object.
16762   {
16763     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16764     obj2->Set(v8_str("ee_test_field_2"),
16765               v8::Int32::New(context->GetIsolate(), 256));
16766     // Set the elements to be the external array.
16767     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16768                                                   array_type,
16769                                                   kElementCount);
16770     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16771     context->Global()->Set(v8_str("ext_array"), obj2);
16772     result = CompileRun("ext_array['']");
16773     CHECK_EQ(1503, result->Int32Value());
16774   }
16775
16776   // Should reuse the map from previous test.
16777   {
16778     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16779     obj2->Set(v8_str("ee_test_field_2"),
16780               v8::Int32::New(context->GetIsolate(), 256));
16781     // Set the elements to be the external array. Should re-use the map
16782     // from previous test.
16783     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16784                                                   array_type,
16785                                                   kElementCount);
16786     context->Global()->Set(v8_str("ext_array"), obj2);
16787     result = CompileRun("ext_array['']");
16788   }
16789
16790   // Property "" is a constant function that shouldn't not be interfered with
16791   // when an external array is set.
16792   {
16793     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16794     // Start
16795     obj2->Set(v8_str("ee_test_field3"),
16796               v8::Int32::New(context->GetIsolate(), 256));
16797
16798     // Add a constant function to an object.
16799     context->Global()->Set(v8_str("ext_array"), obj2);
16800     result = CompileRun("ext_array[''] = function() {return 1503;};"
16801                         "ext_array['']();");
16802
16803     // Add an external array transition to the same map that
16804     // has the constant transition.
16805     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16806     obj3->Set(v8_str("ee_test_field3"),
16807               v8::Int32::New(context->GetIsolate(), 256));
16808     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16809                                                   array_type,
16810                                                   kElementCount);
16811     context->Global()->Set(v8_str("ext_array"), obj3);
16812   }
16813
16814   // If a external array transition is in the map, it should get clobbered
16815   // by a constant function.
16816   {
16817     // Add an external array transition.
16818     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16819     obj3->Set(v8_str("ee_test_field4"),
16820               v8::Int32::New(context->GetIsolate(), 256));
16821     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16822                                                   array_type,
16823                                                   kElementCount);
16824
16825     // Add a constant function to the same map that just got an external array
16826     // transition.
16827     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16828     obj2->Set(v8_str("ee_test_field4"),
16829               v8::Int32::New(context->GetIsolate(), 256));
16830     context->Global()->Set(v8_str("ext_array"), obj2);
16831     result = CompileRun("ext_array[''] = function() {return 1503;};"
16832                         "ext_array['']();");
16833   }
16834
16835   free(array_data);
16836 }
16837
16838
16839 THREADED_TEST(ExternalInt8Array) {
16840   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16841       v8::kExternalInt8Array,
16842       -128,
16843       127);
16844 }
16845
16846
16847 THREADED_TEST(ExternalUint8Array) {
16848   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16849       v8::kExternalUint8Array,
16850       0,
16851       255);
16852 }
16853
16854
16855 THREADED_TEST(ExternalUint8ClampedArray) {
16856   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16857       v8::kExternalUint8ClampedArray,
16858       0,
16859       255);
16860 }
16861
16862
16863 THREADED_TEST(ExternalInt16Array) {
16864   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16865       v8::kExternalInt16Array,
16866       -32768,
16867       32767);
16868 }
16869
16870
16871 THREADED_TEST(ExternalUint16Array) {
16872   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16873       v8::kExternalUint16Array,
16874       0,
16875       65535);
16876 }
16877
16878
16879 THREADED_TEST(ExternalInt32Array) {
16880   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16881       v8::kExternalInt32Array,
16882       INT_MIN,   // -2147483648
16883       INT_MAX);  //  2147483647
16884 }
16885
16886
16887 THREADED_TEST(ExternalUint32Array) {
16888   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16889       v8::kExternalUint32Array,
16890       0,
16891       UINT_MAX);  // 4294967295
16892 }
16893
16894
16895 THREADED_TEST(ExternalFloat32Array) {
16896   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16897       v8::kExternalFloat32Array,
16898       -500,
16899       500);
16900 }
16901
16902
16903 THREADED_TEST(ExternalFloat64Array) {
16904   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16905       v8::kExternalFloat64Array,
16906       -500,
16907       500);
16908 }
16909
16910
16911 THREADED_TEST(ExternalArrays) {
16912   TestExternalInt8Array();
16913   TestExternalUint8Array();
16914   TestExternalInt16Array();
16915   TestExternalUint16Array();
16916   TestExternalInt32Array();
16917   TestExternalUint32Array();
16918   TestExternalFloat32Array();
16919 }
16920
16921
16922 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16923   LocalContext context;
16924   v8::HandleScope scope(context->GetIsolate());
16925   for (int size = 0; size < 100; size += 10) {
16926     int element_size = ExternalArrayElementSize(array_type);
16927     void* external_data = malloc(size * element_size);
16928     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16929     obj->SetIndexedPropertiesToExternalArrayData(
16930         external_data, array_type, size);
16931     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16932     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16933     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16934     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16935     free(external_data);
16936   }
16937 }
16938
16939
16940 THREADED_TEST(ExternalArrayInfo) {
16941   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16942   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16943   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16944   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16945   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16946   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16947   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16948   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16949   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16950 }
16951
16952
16953 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16954                           v8::ExternalArrayType array_type,
16955                           int size) {
16956   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16957   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16958   last_location = last_message = NULL;
16959   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16960   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16961   CHECK_NE(NULL, last_location);
16962   CHECK_NE(NULL, last_message);
16963 }
16964
16965
16966 TEST(ExternalArrayLimits) {
16967   LocalContext context;
16968   v8::Isolate* isolate = context->GetIsolate();
16969   v8::HandleScope scope(isolate);
16970   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16971   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16972   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16973   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16974   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16975   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16976   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16977   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16978   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16979   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16980   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16981   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16982   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16983   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16984   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16985   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16986   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16987   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16988 }
16989
16990
16991 template <typename ElementType, typename TypedArray,
16992           class ExternalArrayClass>
16993 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16994                           int64_t low, int64_t high) {
16995   const int kElementCount = 50;
16996
16997   i::ScopedVector<ElementType> backing_store(kElementCount+2);
16998
16999   LocalContext env;
17000   v8::Isolate* isolate = env->GetIsolate();
17001   v8::HandleScope handle_scope(isolate);
17002
17003   Local<v8::ArrayBuffer> ab =
17004       v8::ArrayBuffer::New(isolate, backing_store.start(),
17005                            (kElementCount + 2) * sizeof(ElementType));
17006   Local<TypedArray> ta =
17007       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17008   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17009   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17010   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17011   CHECK_EQ(kElementCount*sizeof(ElementType),
17012            static_cast<int>(ta->ByteLength()));
17013   CHECK_EQ(ab, ta->Buffer());
17014
17015   ElementType* data = backing_store.start() + 2;
17016   for (int i = 0; i < kElementCount; i++) {
17017     data[i] = static_cast<ElementType>(i);
17018   }
17019
17020   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17021       env.local(), ta, kElementCount, array_type, low, high);
17022 }
17023
17024
17025 THREADED_TEST(Uint8Array) {
17026   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17027       v8::kExternalUint8Array, 0, 0xFF);
17028 }
17029
17030
17031 THREADED_TEST(Int8Array) {
17032   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17033       v8::kExternalInt8Array, -0x80, 0x7F);
17034 }
17035
17036
17037 THREADED_TEST(Uint16Array) {
17038   TypedArrayTestHelper<uint16_t,
17039                        v8::Uint16Array,
17040                        i::ExternalUint16Array>(
17041       v8::kExternalUint16Array, 0, 0xFFFF);
17042 }
17043
17044
17045 THREADED_TEST(Int16Array) {
17046   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17047       v8::kExternalInt16Array, -0x8000, 0x7FFF);
17048 }
17049
17050
17051 THREADED_TEST(Uint32Array) {
17052   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17053       v8::kExternalUint32Array, 0, UINT_MAX);
17054 }
17055
17056
17057 THREADED_TEST(Int32Array) {
17058   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17059       v8::kExternalInt32Array, INT_MIN, INT_MAX);
17060 }
17061
17062
17063 THREADED_TEST(Float32Array) {
17064   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17065       v8::kExternalFloat32Array, -500, 500);
17066 }
17067
17068
17069 THREADED_TEST(Float64Array) {
17070   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17071       v8::kExternalFloat64Array, -500, 500);
17072 }
17073
17074
17075 THREADED_TEST(Uint8ClampedArray) {
17076   TypedArrayTestHelper<uint8_t,
17077                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17078       v8::kExternalUint8ClampedArray, 0, 0xFF);
17079 }
17080
17081
17082 THREADED_TEST(DataView) {
17083   const int kSize = 50;
17084
17085   i::ScopedVector<uint8_t> backing_store(kSize+2);
17086
17087   LocalContext env;
17088   v8::Isolate* isolate = env->GetIsolate();
17089   v8::HandleScope handle_scope(isolate);
17090
17091   Local<v8::ArrayBuffer> ab =
17092       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17093   Local<v8::DataView> dv =
17094       v8::DataView::New(ab, 2, kSize);
17095   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17096   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17097   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17098   CHECK_EQ(ab, dv->Buffer());
17099 }
17100
17101
17102 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17103   THREADED_TEST(Is##View) {                                                   \
17104     LocalContext env;                                                         \
17105     v8::Isolate* isolate = env->GetIsolate();                                 \
17106     v8::HandleScope handle_scope(isolate);                                    \
17107                                                                               \
17108     Handle<Value> result = CompileRun(                                        \
17109         "var ab = new ArrayBuffer(128);"                                      \
17110         "new " #View "(ab)");                                                 \
17111     CHECK(result->IsArrayBufferView());                                       \
17112     CHECK(result->Is##View());                                                \
17113     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17114   }
17115
17116 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17117 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17118 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17119 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17120 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17121 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17122 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17123 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17124 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17125 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17126
17127 #undef IS_ARRAY_BUFFER_VIEW_TEST
17128
17129
17130
17131 THREADED_TEST(ScriptContextDependence) {
17132   LocalContext c1;
17133   v8::HandleScope scope(c1->GetIsolate());
17134   const char *source = "foo";
17135   v8::Handle<v8::Script> dep = v8_compile(source);
17136   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17137       c1->GetIsolate(), source));
17138   v8::Handle<v8::UnboundScript> indep =
17139       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17140   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17141                     v8::Integer::New(c1->GetIsolate(), 100));
17142   CHECK_EQ(dep->Run()->Int32Value(), 100);
17143   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17144   LocalContext c2;
17145   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17146                     v8::Integer::New(c2->GetIsolate(), 101));
17147   CHECK_EQ(dep->Run()->Int32Value(), 100);
17148   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17149 }
17150
17151
17152 THREADED_TEST(StackTrace) {
17153   LocalContext context;
17154   v8::HandleScope scope(context->GetIsolate());
17155   v8::TryCatch try_catch;
17156   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17157   v8::Handle<v8::String> src =
17158       v8::String::NewFromUtf8(context->GetIsolate(), source);
17159   v8::Handle<v8::String> origin =
17160       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17161   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17162   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17163       ->BindToCurrentContext()
17164       ->Run();
17165   CHECK(try_catch.HasCaught());
17166   v8::String::Utf8Value stack(try_catch.StackTrace());
17167   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17168 }
17169
17170
17171 // Checks that a StackFrame has certain expected values.
17172 void checkStackFrame(const char* expected_script_name,
17173     const char* expected_func_name, int expected_line_number,
17174     int expected_column, bool is_eval, bool is_constructor,
17175     v8::Handle<v8::StackFrame> frame) {
17176   v8::HandleScope scope(CcTest::isolate());
17177   v8::String::Utf8Value func_name(frame->GetFunctionName());
17178   v8::String::Utf8Value script_name(frame->GetScriptName());
17179   if (*script_name == NULL) {
17180     // The situation where there is no associated script, like for evals.
17181     CHECK(expected_script_name == NULL);
17182   } else {
17183     CHECK(strstr(*script_name, expected_script_name) != NULL);
17184   }
17185   CHECK(strstr(*func_name, expected_func_name) != NULL);
17186   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17187   CHECK_EQ(expected_column, frame->GetColumn());
17188   CHECK_EQ(is_eval, frame->IsEval());
17189   CHECK_EQ(is_constructor, frame->IsConstructor());
17190 }
17191
17192
17193 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17194   v8::HandleScope scope(args.GetIsolate());
17195   const char* origin = "capture-stack-trace-test";
17196   const int kOverviewTest = 1;
17197   const int kDetailedTest = 2;
17198
17199   ASSERT(args.Length() == 1);
17200
17201   int testGroup = args[0]->Int32Value();
17202   if (testGroup == kOverviewTest) {
17203     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17204         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17205     CHECK_EQ(4, stackTrace->GetFrameCount());
17206     checkStackFrame(origin, "bar", 2, 10, false, false,
17207                     stackTrace->GetFrame(0));
17208     checkStackFrame(origin, "foo", 6, 3, false, false,
17209                     stackTrace->GetFrame(1));
17210     // This is the source string inside the eval which has the call to foo.
17211     checkStackFrame(NULL, "", 1, 5, false, false,
17212                     stackTrace->GetFrame(2));
17213     // The last frame is an anonymous function which has the initial eval call.
17214     checkStackFrame(origin, "", 8, 7, false, false,
17215                     stackTrace->GetFrame(3));
17216
17217     CHECK(stackTrace->AsArray()->IsArray());
17218   } else if (testGroup == kDetailedTest) {
17219     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17220         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17221     CHECK_EQ(4, stackTrace->GetFrameCount());
17222     checkStackFrame(origin, "bat", 4, 22, false, false,
17223                     stackTrace->GetFrame(0));
17224     checkStackFrame(origin, "baz", 8, 3, false, true,
17225                     stackTrace->GetFrame(1));
17226     bool is_eval = true;
17227     // This is the source string inside the eval which has the call to baz.
17228     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17229                     stackTrace->GetFrame(2));
17230     // The last frame is an anonymous function which has the initial eval call.
17231     checkStackFrame(origin, "", 10, 1, false, false,
17232                     stackTrace->GetFrame(3));
17233
17234     CHECK(stackTrace->AsArray()->IsArray());
17235   }
17236 }
17237
17238
17239 // Tests the C++ StackTrace API.
17240 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17241 // THREADED_TEST(CaptureStackTrace) {
17242 TEST(CaptureStackTrace) {
17243   v8::Isolate* isolate = CcTest::isolate();
17244   v8::HandleScope scope(isolate);
17245   v8::Handle<v8::String> origin =
17246       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17247   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17248   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17249              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17250   LocalContext context(0, templ);
17251
17252   // Test getting OVERVIEW information. Should ignore information that is not
17253   // script name, function name, line number, and column offset.
17254   const char *overview_source =
17255     "function bar() {\n"
17256     "  var y; AnalyzeStackInNativeCode(1);\n"
17257     "}\n"
17258     "function foo() {\n"
17259     "\n"
17260     "  bar();\n"
17261     "}\n"
17262     "var x;eval('new foo();');";
17263   v8::Handle<v8::String> overview_src =
17264       v8::String::NewFromUtf8(isolate, overview_source);
17265   v8::ScriptCompiler::Source script_source(overview_src,
17266                                            v8::ScriptOrigin(origin));
17267   v8::Handle<Value> overview_result(
17268       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17269           ->BindToCurrentContext()
17270           ->Run());
17271   CHECK(!overview_result.IsEmpty());
17272   CHECK(overview_result->IsObject());
17273
17274   // Test getting DETAILED information.
17275   const char *detailed_source =
17276     "function bat() {AnalyzeStackInNativeCode(2);\n"
17277     "}\n"
17278     "\n"
17279     "function baz() {\n"
17280     "  bat();\n"
17281     "}\n"
17282     "eval('new baz();');";
17283   v8::Handle<v8::String> detailed_src =
17284       v8::String::NewFromUtf8(isolate, detailed_source);
17285   // Make the script using a non-zero line and column offset.
17286   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17287   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17288   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17289   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17290   v8::Handle<v8::UnboundScript> detailed_script(
17291       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17292   v8::Handle<Value> detailed_result(
17293       detailed_script->BindToCurrentContext()->Run());
17294   CHECK(!detailed_result.IsEmpty());
17295   CHECK(detailed_result->IsObject());
17296 }
17297
17298
17299 static void StackTraceForUncaughtExceptionListener(
17300     v8::Handle<v8::Message> message,
17301     v8::Handle<Value>) {
17302   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17303   CHECK_EQ(2, stack_trace->GetFrameCount());
17304   checkStackFrame("origin", "foo", 2, 3, false, false,
17305                   stack_trace->GetFrame(0));
17306   checkStackFrame("origin", "bar", 5, 3, false, false,
17307                   stack_trace->GetFrame(1));
17308 }
17309
17310
17311 TEST(CaptureStackTraceForUncaughtException) {
17312   report_count = 0;
17313   LocalContext env;
17314   v8::HandleScope scope(env->GetIsolate());
17315   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17316   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17317
17318   CompileRunWithOrigin(
17319       "function foo() {\n"
17320       "  throw 1;\n"
17321       "};\n"
17322       "function bar() {\n"
17323       "  foo();\n"
17324       "};",
17325       "origin");
17326   v8::Local<v8::Object> global = env->Global();
17327   Local<Value> trouble = global->Get(v8_str("bar"));
17328   CHECK(trouble->IsFunction());
17329   Function::Cast(*trouble)->Call(global, 0, NULL);
17330   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17331   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17332 }
17333
17334
17335 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17336   LocalContext env;
17337   v8::HandleScope scope(env->GetIsolate());
17338   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17339                                                     1024,
17340                                                     v8::StackTrace::kDetailed);
17341
17342   CompileRun(
17343       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17344       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17345       "    'isConstructor'];\n"
17346       "for (var i = 0; i < setters.length; i++) {\n"
17347       "  var prop = setters[i];\n"
17348       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17349       "}\n");
17350   CompileRun("throw 'exception';");
17351   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17352 }
17353
17354
17355 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17356                                      v8::Handle<v8::Value> data) {
17357   // Use the frame where JavaScript is called from.
17358   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17359   CHECK(!stack_trace.IsEmpty());
17360   int frame_count = stack_trace->GetFrameCount();
17361   CHECK_EQ(3, frame_count);
17362   int line_number[] = {1, 2, 5};
17363   for (int i = 0; i < frame_count; i++) {
17364     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17365   }
17366 }
17367
17368
17369 // Test that we only return the stack trace at the site where the exception
17370 // is first thrown (not where it is rethrown).
17371 TEST(RethrowStackTrace) {
17372   LocalContext env;
17373   v8::HandleScope scope(env->GetIsolate());
17374   // We make sure that
17375   // - the stack trace of the ReferenceError in g() is reported.
17376   // - the stack trace is not overwritten when e1 is rethrown by t().
17377   // - the stack trace of e2 does not overwrite that of e1.
17378   const char* source =
17379       "function g() { error; }          \n"
17380       "function f() { g(); }            \n"
17381       "function t(e) { throw e; }       \n"
17382       "try {                            \n"
17383       "  f();                           \n"
17384       "} catch (e1) {                   \n"
17385       "  try {                          \n"
17386       "    error;                       \n"
17387       "  } catch (e2) {                 \n"
17388       "    t(e1);                       \n"
17389       "  }                              \n"
17390       "}                                \n";
17391   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17392   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17393   CompileRun(source);
17394   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17395   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17396 }
17397
17398
17399 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17400                                               v8::Handle<v8::Value> data) {
17401   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17402   CHECK(!stack_trace.IsEmpty());
17403   int frame_count = stack_trace->GetFrameCount();
17404   CHECK_EQ(2, frame_count);
17405   int line_number[] = {3, 7};
17406   for (int i = 0; i < frame_count; i++) {
17407     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17408   }
17409 }
17410
17411
17412 // Test that we do not recognize identity for primitive exceptions.
17413 TEST(RethrowPrimitiveStackTrace) {
17414   LocalContext env;
17415   v8::HandleScope scope(env->GetIsolate());
17416   // We do not capture stack trace for non Error objects on creation time.
17417   // Instead, we capture the stack trace on last throw.
17418   const char* source =
17419       "function g() { throw 404; }      \n"
17420       "function f() { g(); }            \n"
17421       "function t(e) { throw e; }       \n"
17422       "try {                            \n"
17423       "  f();                           \n"
17424       "} catch (e1) {                   \n"
17425       "  t(e1)                          \n"
17426       "}                                \n";
17427   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17428   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17429   CompileRun(source);
17430   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17431   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17432 }
17433
17434
17435 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17436                                               v8::Handle<v8::Value> data) {
17437   // Use the frame where JavaScript is called from.
17438   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17439   CHECK(!stack_trace.IsEmpty());
17440   CHECK_EQ(1, stack_trace->GetFrameCount());
17441   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17442 }
17443
17444
17445 // Test that the stack trace is captured when the error object is created and
17446 // not where it is thrown.
17447 TEST(RethrowExistingStackTrace) {
17448   LocalContext env;
17449   v8::HandleScope scope(env->GetIsolate());
17450   const char* source =
17451       "var e = new Error();           \n"
17452       "throw e;                       \n";
17453   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17454   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17455   CompileRun(source);
17456   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17457   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17458 }
17459
17460
17461 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17462                                                v8::Handle<v8::Value> data) {
17463   // Use the frame where JavaScript is called from.
17464   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17465   CHECK(!stack_trace.IsEmpty());
17466   CHECK_EQ(1, stack_trace->GetFrameCount());
17467   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17468 }
17469
17470
17471 // Test that the stack trace is captured where the bogus Error object is thrown.
17472 TEST(RethrowBogusErrorStackTrace) {
17473   LocalContext env;
17474   v8::HandleScope scope(env->GetIsolate());
17475   const char* source =
17476       "var e = {__proto__: new Error()} \n"
17477       "throw e;                         \n";
17478   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17479   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17480   CompileRun(source);
17481   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17482   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17483 }
17484
17485
17486 void AnalyzeStackOfEvalWithSourceURL(
17487     const v8::FunctionCallbackInfo<v8::Value>& args) {
17488   v8::HandleScope scope(args.GetIsolate());
17489   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17490       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17491   CHECK_EQ(5, stackTrace->GetFrameCount());
17492   v8::Handle<v8::String> url = v8_str("eval_url");
17493   for (int i = 0; i < 3; i++) {
17494     v8::Handle<v8::String> name =
17495         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17496     CHECK(!name.IsEmpty());
17497     CHECK_EQ(url, name);
17498   }
17499 }
17500
17501
17502 TEST(SourceURLInStackTrace) {
17503   v8::Isolate* isolate = CcTest::isolate();
17504   v8::HandleScope scope(isolate);
17505   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17506   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17507              v8::FunctionTemplate::New(isolate,
17508                                        AnalyzeStackOfEvalWithSourceURL));
17509   LocalContext context(0, templ);
17510
17511   const char *source =
17512     "function outer() {\n"
17513     "function bar() {\n"
17514     "  AnalyzeStackOfEvalWithSourceURL();\n"
17515     "}\n"
17516     "function foo() {\n"
17517     "\n"
17518     "  bar();\n"
17519     "}\n"
17520     "foo();\n"
17521     "}\n"
17522     "eval('(' + outer +')()%s');";
17523
17524   i::ScopedVector<char> code(1024);
17525   i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17526   CHECK(CompileRun(code.start())->IsUndefined());
17527   i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17528   CHECK(CompileRun(code.start())->IsUndefined());
17529 }
17530
17531
17532 static int scriptIdInStack[2];
17533
17534 void AnalyzeScriptIdInStack(
17535     const v8::FunctionCallbackInfo<v8::Value>& args) {
17536   v8::HandleScope scope(args.GetIsolate());
17537   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17538       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17539   CHECK_EQ(2, stackTrace->GetFrameCount());
17540   for (int i = 0; i < 2; i++) {
17541     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17542   }
17543 }
17544
17545
17546 TEST(ScriptIdInStackTrace) {
17547   v8::Isolate* isolate = CcTest::isolate();
17548   v8::HandleScope scope(isolate);
17549   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17550   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17551              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17552   LocalContext context(0, templ);
17553
17554   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17555     isolate,
17556     "function foo() {\n"
17557     "  AnalyzeScriptIdInStack();"
17558     "}\n"
17559     "foo();\n");
17560   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17561   script->Run();
17562   for (int i = 0; i < 2; i++) {
17563     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17564     CHECK_EQ(scriptIdInStack[i], script->GetId());
17565   }
17566 }
17567
17568
17569 void AnalyzeStackOfInlineScriptWithSourceURL(
17570     const v8::FunctionCallbackInfo<v8::Value>& args) {
17571   v8::HandleScope scope(args.GetIsolate());
17572   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17573       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17574   CHECK_EQ(4, stackTrace->GetFrameCount());
17575   v8::Handle<v8::String> url = v8_str("url");
17576   for (int i = 0; i < 3; i++) {
17577     v8::Handle<v8::String> name =
17578         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17579     CHECK(!name.IsEmpty());
17580     CHECK_EQ(url, name);
17581   }
17582 }
17583
17584
17585 TEST(InlineScriptWithSourceURLInStackTrace) {
17586   v8::Isolate* isolate = CcTest::isolate();
17587   v8::HandleScope scope(isolate);
17588   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17589   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17590              v8::FunctionTemplate::New(
17591                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17592   LocalContext context(0, templ);
17593
17594   const char *source =
17595     "function outer() {\n"
17596     "function bar() {\n"
17597     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17598     "}\n"
17599     "function foo() {\n"
17600     "\n"
17601     "  bar();\n"
17602     "}\n"
17603     "foo();\n"
17604     "}\n"
17605     "outer()\n%s";
17606
17607   i::ScopedVector<char> code(1024);
17608   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17609   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17610   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17611   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17612 }
17613
17614
17615 void AnalyzeStackOfDynamicScriptWithSourceURL(
17616     const v8::FunctionCallbackInfo<v8::Value>& args) {
17617   v8::HandleScope scope(args.GetIsolate());
17618   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17619       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17620   CHECK_EQ(4, stackTrace->GetFrameCount());
17621   v8::Handle<v8::String> url = v8_str("source_url");
17622   for (int i = 0; i < 3; i++) {
17623     v8::Handle<v8::String> name =
17624         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17625     CHECK(!name.IsEmpty());
17626     CHECK_EQ(url, name);
17627   }
17628 }
17629
17630
17631 TEST(DynamicWithSourceURLInStackTrace) {
17632   v8::Isolate* isolate = CcTest::isolate();
17633   v8::HandleScope scope(isolate);
17634   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17635   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17636              v8::FunctionTemplate::New(
17637                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17638   LocalContext context(0, templ);
17639
17640   const char *source =
17641     "function outer() {\n"
17642     "function bar() {\n"
17643     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17644     "}\n"
17645     "function foo() {\n"
17646     "\n"
17647     "  bar();\n"
17648     "}\n"
17649     "foo();\n"
17650     "}\n"
17651     "outer()\n%s";
17652
17653   i::ScopedVector<char> code(1024);
17654   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17655   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17656   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17657   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17658 }
17659
17660
17661 TEST(DynamicWithSourceURLInStackTraceString) {
17662   LocalContext context;
17663   v8::HandleScope scope(context->GetIsolate());
17664
17665   const char *source =
17666     "function outer() {\n"
17667     "  function foo() {\n"
17668     "    FAIL.FAIL;\n"
17669     "  }\n"
17670     "  foo();\n"
17671     "}\n"
17672     "outer()\n%s";
17673
17674   i::ScopedVector<char> code(1024);
17675   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17676   v8::TryCatch try_catch;
17677   CompileRunWithOrigin(code.start(), "", 0, 0);
17678   CHECK(try_catch.HasCaught());
17679   v8::String::Utf8Value stack(try_catch.StackTrace());
17680   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17681 }
17682
17683
17684 static void CreateGarbageInOldSpace() {
17685   i::Factory* factory = CcTest::i_isolate()->factory();
17686   v8::HandleScope scope(CcTest::isolate());
17687   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17688   for (int i = 0; i < 1000; i++) {
17689     factory->NewFixedArray(1000, i::TENURED);
17690   }
17691 }
17692
17693
17694 // Test that idle notification can be handled and eventually returns true.
17695 TEST(IdleNotification) {
17696   const intptr_t MB = 1024 * 1024;
17697   LocalContext env;
17698   v8::HandleScope scope(env->GetIsolate());
17699   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17700   CreateGarbageInOldSpace();
17701   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17702   CHECK_GT(size_with_garbage, initial_size + MB);
17703   bool finished = false;
17704   for (int i = 0; i < 200 && !finished; i++) {
17705     finished = v8::V8::IdleNotification();
17706   }
17707   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17708   CHECK(finished);
17709   CHECK_LT(final_size, initial_size + 1);
17710 }
17711
17712
17713 // Test that idle notification can be handled and eventually collects garbage.
17714 TEST(IdleNotificationWithSmallHint) {
17715   const intptr_t MB = 1024 * 1024;
17716   const int IdlePauseInMs = 900;
17717   LocalContext env;
17718   v8::HandleScope scope(env->GetIsolate());
17719   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17720   CreateGarbageInOldSpace();
17721   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17722   CHECK_GT(size_with_garbage, initial_size + MB);
17723   bool finished = false;
17724   for (int i = 0; i < 200 && !finished; i++) {
17725     finished = v8::V8::IdleNotification(IdlePauseInMs);
17726   }
17727   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17728   CHECK(finished);
17729   CHECK_LT(final_size, initial_size + 1);
17730 }
17731
17732
17733 // Test that idle notification can be handled and eventually collects garbage.
17734 TEST(IdleNotificationWithLargeHint) {
17735   const intptr_t MB = 1024 * 1024;
17736   const int IdlePauseInMs = 900;
17737   LocalContext env;
17738   v8::HandleScope scope(env->GetIsolate());
17739   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17740   CreateGarbageInOldSpace();
17741   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17742   CHECK_GT(size_with_garbage, initial_size + MB);
17743   bool finished = false;
17744   for (int i = 0; i < 200 && !finished; i++) {
17745     finished = v8::V8::IdleNotification(IdlePauseInMs);
17746   }
17747   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17748   CHECK(finished);
17749   CHECK_LT(final_size, initial_size + 1);
17750 }
17751
17752
17753 TEST(Regress2107) {
17754   const intptr_t MB = 1024 * 1024;
17755   const int kShortIdlePauseInMs = 100;
17756   const int kLongIdlePauseInMs = 1000;
17757   LocalContext env;
17758   v8::Isolate* isolate = env->GetIsolate();
17759   v8::HandleScope scope(env->GetIsolate());
17760   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17761   // Send idle notification to start a round of incremental GCs.
17762   v8::V8::IdleNotification(kShortIdlePauseInMs);
17763   // Emulate 7 page reloads.
17764   for (int i = 0; i < 7; i++) {
17765     {
17766       v8::HandleScope inner_scope(env->GetIsolate());
17767       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17768       ctx->Enter();
17769       CreateGarbageInOldSpace();
17770       ctx->Exit();
17771     }
17772     v8::V8::ContextDisposedNotification();
17773     v8::V8::IdleNotification(kLongIdlePauseInMs);
17774   }
17775   // Create garbage and check that idle notification still collects it.
17776   CreateGarbageInOldSpace();
17777   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17778   CHECK_GT(size_with_garbage, initial_size + MB);
17779   bool finished = false;
17780   for (int i = 0; i < 200 && !finished; i++) {
17781     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17782   }
17783   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17784   CHECK_LT(final_size, initial_size + 1);
17785 }
17786
17787
17788 TEST(Regress2333) {
17789   LocalContext env;
17790   for (int i = 0; i < 3; i++) {
17791     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17792   }
17793 }
17794
17795 static uint32_t* stack_limit;
17796
17797 static void GetStackLimitCallback(
17798     const v8::FunctionCallbackInfo<v8::Value>& args) {
17799   stack_limit = reinterpret_cast<uint32_t*>(
17800       CcTest::i_isolate()->stack_guard()->real_climit());
17801 }
17802
17803
17804 // Uses the address of a local variable to determine the stack top now.
17805 // Given a size, returns an address that is that far from the current
17806 // top of stack.
17807 static uint32_t* ComputeStackLimit(uint32_t size) {
17808   uint32_t* answer = &size - (size / sizeof(size));
17809   // If the size is very large and the stack is very near the bottom of
17810   // memory then the calculation above may wrap around and give an address
17811   // that is above the (downwards-growing) stack.  In that case we return
17812   // a very low address.
17813   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17814   return answer;
17815 }
17816
17817
17818 // We need at least 165kB for an x64 debug build with clang and ASAN.
17819 static const int stack_breathing_room = 256 * i::KB;
17820
17821
17822 TEST(SetResourceConstraints) {
17823   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17824
17825   // Set stack limit.
17826   v8::ResourceConstraints constraints;
17827   constraints.set_stack_limit(set_limit);
17828   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17829
17830   // Execute a script.
17831   LocalContext env;
17832   v8::HandleScope scope(env->GetIsolate());
17833   Local<v8::FunctionTemplate> fun_templ =
17834       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17835   Local<Function> fun = fun_templ->GetFunction();
17836   env->Global()->Set(v8_str("get_stack_limit"), fun);
17837   CompileRun("get_stack_limit();");
17838
17839   CHECK(stack_limit == set_limit);
17840 }
17841
17842
17843 TEST(SetResourceConstraintsInThread) {
17844   uint32_t* set_limit;
17845   {
17846     v8::Locker locker(CcTest::isolate());
17847     set_limit = ComputeStackLimit(stack_breathing_room);
17848
17849     // Set stack limit.
17850     v8::ResourceConstraints constraints;
17851     constraints.set_stack_limit(set_limit);
17852     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17853
17854     // Execute a script.
17855     v8::HandleScope scope(CcTest::isolate());
17856     LocalContext env;
17857     Local<v8::FunctionTemplate> fun_templ =
17858         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17859     Local<Function> fun = fun_templ->GetFunction();
17860     env->Global()->Set(v8_str("get_stack_limit"), fun);
17861     CompileRun("get_stack_limit();");
17862
17863     CHECK(stack_limit == set_limit);
17864   }
17865   {
17866     v8::Locker locker(CcTest::isolate());
17867     CHECK(stack_limit == set_limit);
17868   }
17869 }
17870
17871
17872 THREADED_TEST(GetHeapStatistics) {
17873   LocalContext c1;
17874   v8::HandleScope scope(c1->GetIsolate());
17875   v8::HeapStatistics heap_statistics;
17876   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17877   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17878   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17879   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17880   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17881 }
17882
17883
17884 class VisitorImpl : public v8::ExternalResourceVisitor {
17885  public:
17886   explicit VisitorImpl(TestResource** resource) {
17887     for (int i = 0; i < 4; i++) {
17888       resource_[i] = resource[i];
17889       found_resource_[i] = false;
17890     }
17891   }
17892   virtual ~VisitorImpl() {}
17893   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17894     if (!string->IsExternal()) {
17895       CHECK(string->IsExternalAscii());
17896       return;
17897     }
17898     v8::String::ExternalStringResource* resource =
17899         string->GetExternalStringResource();
17900     CHECK(resource);
17901     for (int i = 0; i < 4; i++) {
17902       if (resource_[i] == resource) {
17903         CHECK(!found_resource_[i]);
17904         found_resource_[i] = true;
17905       }
17906     }
17907   }
17908   void CheckVisitedResources() {
17909     for (int i = 0; i < 4; i++) {
17910       CHECK(found_resource_[i]);
17911     }
17912   }
17913
17914  private:
17915   v8::String::ExternalStringResource* resource_[4];
17916   bool found_resource_[4];
17917 };
17918
17919
17920 TEST(ExternalizeOldSpaceTwoByteCons) {
17921   LocalContext env;
17922   v8::HandleScope scope(env->GetIsolate());
17923   v8::Local<v8::String> cons =
17924       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17925   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17926   CcTest::heap()->CollectAllAvailableGarbage();
17927   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17928             *v8::Utils::OpenHandle(*cons)));
17929
17930   TestResource* resource = new TestResource(
17931       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17932   cons->MakeExternal(resource);
17933
17934   CHECK(cons->IsExternal());
17935   CHECK_EQ(resource, cons->GetExternalStringResource());
17936   String::Encoding encoding;
17937   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17938   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17939 }
17940
17941
17942 TEST(ExternalizeOldSpaceOneByteCons) {
17943   LocalContext env;
17944   v8::HandleScope scope(env->GetIsolate());
17945   v8::Local<v8::String> cons =
17946       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17947   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17948   CcTest::heap()->CollectAllAvailableGarbage();
17949   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17950             *v8::Utils::OpenHandle(*cons)));
17951
17952   TestAsciiResource* resource =
17953       new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17954   cons->MakeExternal(resource);
17955
17956   CHECK(cons->IsExternalAscii());
17957   CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17958   String::Encoding encoding;
17959   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17960   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17961 }
17962
17963
17964 TEST(VisitExternalStrings) {
17965   LocalContext env;
17966   v8::HandleScope scope(env->GetIsolate());
17967   const char* string = "Some string";
17968   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17969   TestResource* resource[4];
17970   resource[0] = new TestResource(two_byte_string);
17971   v8::Local<v8::String> string0 =
17972       v8::String::NewExternal(env->GetIsolate(), resource[0]);
17973   resource[1] = new TestResource(two_byte_string, NULL, false);
17974   v8::Local<v8::String> string1 =
17975       v8::String::NewExternal(env->GetIsolate(), resource[1]);
17976
17977   // Externalized symbol.
17978   resource[2] = new TestResource(two_byte_string, NULL, false);
17979   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17980       env->GetIsolate(), string, v8::String::kInternalizedString);
17981   CHECK(string2->MakeExternal(resource[2]));
17982
17983   // Symbolized External.
17984   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17985   v8::Local<v8::String> string3 =
17986       v8::String::NewExternal(env->GetIsolate(), resource[3]);
17987   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
17988   // Turn into a symbol.
17989   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17990   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
17991       string3_i).is_null());
17992   CHECK(string3_i->IsInternalizedString());
17993
17994   // We need to add usages for string* to avoid warnings in GCC 4.7
17995   CHECK(string0->IsExternal());
17996   CHECK(string1->IsExternal());
17997   CHECK(string2->IsExternal());
17998   CHECK(string3->IsExternal());
17999
18000   VisitorImpl visitor(resource);
18001   v8::V8::VisitExternalResources(&visitor);
18002   visitor.CheckVisitedResources();
18003 }
18004
18005
18006 TEST(ExternalStringCollectedAtTearDown) {
18007   int destroyed = 0;
18008   v8::Isolate* isolate = v8::Isolate::New();
18009   { v8::Isolate::Scope isolate_scope(isolate);
18010     v8::HandleScope handle_scope(isolate);
18011     const char* s = "One string to test them all, one string to find them.";
18012     TestAsciiResource* inscription =
18013         new TestAsciiResource(i::StrDup(s), &destroyed);
18014     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18015     // Ring is still alive.  Orcs are roaming freely across our lands.
18016     CHECK_EQ(0, destroyed);
18017     USE(ring);
18018   }
18019
18020   isolate->Dispose();
18021   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18022   CHECK_EQ(1, destroyed);
18023 }
18024
18025
18026 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18027   int destroyed = 0;
18028   v8::Isolate* isolate = v8::Isolate::New();
18029   { v8::Isolate::Scope isolate_scope(isolate);
18030     LocalContext env(isolate);
18031     v8::HandleScope handle_scope(isolate);
18032     CompileRun("var ring = 'One string to test them all';");
18033     const char* s = "One string to test them all";
18034     TestAsciiResource* inscription =
18035         new TestAsciiResource(i::StrDup(s), &destroyed);
18036     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18037     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18038     ring->MakeExternal(inscription);
18039     // Ring is still alive.  Orcs are roaming freely across our lands.
18040     CHECK_EQ(0, destroyed);
18041     USE(ring);
18042   }
18043
18044   isolate->Dispose();
18045   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18046   CHECK_EQ(1, destroyed);
18047 }
18048
18049
18050 TEST(ExternalInternalizedStringCollectedAtGC) {
18051   int destroyed = 0;
18052   { LocalContext env;
18053     v8::HandleScope handle_scope(env->GetIsolate());
18054     CompileRun("var ring = 'One string to test them all';");
18055     const char* s = "One string to test them all";
18056     TestAsciiResource* inscription =
18057         new TestAsciiResource(i::StrDup(s), &destroyed);
18058     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18059     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18060     ring->MakeExternal(inscription);
18061     // Ring is still alive.  Orcs are roaming freely across our lands.
18062     CHECK_EQ(0, destroyed);
18063     USE(ring);
18064   }
18065
18066   // Garbage collector deals swift blows to evil.
18067   CcTest::i_isolate()->compilation_cache()->Clear();
18068   CcTest::heap()->CollectAllAvailableGarbage();
18069
18070   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18071   CHECK_EQ(1, destroyed);
18072 }
18073
18074
18075 static double DoubleFromBits(uint64_t value) {
18076   double target;
18077   i::OS::MemCopy(&target, &value, sizeof(target));
18078   return target;
18079 }
18080
18081
18082 static uint64_t DoubleToBits(double value) {
18083   uint64_t target;
18084   i::OS::MemCopy(&target, &value, sizeof(target));
18085   return target;
18086 }
18087
18088
18089 static double DoubleToDateTime(double input) {
18090   double date_limit = 864e13;
18091   if (std::isnan(input) || input < -date_limit || input > date_limit) {
18092     return i::OS::nan_value();
18093   }
18094   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18095 }
18096
18097
18098 // We don't have a consistent way to write 64-bit constants syntactically, so we
18099 // split them into two 32-bit constants and combine them programmatically.
18100 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18101   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18102 }
18103
18104
18105 THREADED_TEST(QuietSignalingNaNs) {
18106   LocalContext context;
18107   v8::Isolate* isolate = context->GetIsolate();
18108   v8::HandleScope scope(isolate);
18109   v8::TryCatch try_catch;
18110
18111   // Special double values.
18112   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18113   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18114   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18115   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18116   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18117   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18118   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18119
18120   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18121   // on either side of the epoch.
18122   double date_limit = 864e13;
18123
18124   double test_values[] = {
18125       snan,
18126       qnan,
18127       infinity,
18128       max_normal,
18129       date_limit + 1,
18130       date_limit,
18131       min_normal,
18132       max_denormal,
18133       min_denormal,
18134       0,
18135       -0,
18136       -min_denormal,
18137       -max_denormal,
18138       -min_normal,
18139       -date_limit,
18140       -date_limit - 1,
18141       -max_normal,
18142       -infinity,
18143       -qnan,
18144       -snan
18145   };
18146   int num_test_values = 20;
18147
18148   for (int i = 0; i < num_test_values; i++) {
18149     double test_value = test_values[i];
18150
18151     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18152     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18153     double stored_number = number->NumberValue();
18154     if (!std::isnan(test_value)) {
18155       CHECK_EQ(test_value, stored_number);
18156     } else {
18157       uint64_t stored_bits = DoubleToBits(stored_number);
18158       // Check if quiet nan (bits 51..62 all set).
18159 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18160       // Most significant fraction bit for quiet nan is set to 0
18161       // on MIPS architecture. Allowed by IEEE-754.
18162       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18163 #else
18164       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18165 #endif
18166     }
18167
18168     // Check that Date::New preserves non-NaNs in the date range and
18169     // quiets SNaNs.
18170     v8::Handle<v8::Value> date =
18171         v8::Date::New(isolate, test_value);
18172     double expected_stored_date = DoubleToDateTime(test_value);
18173     double stored_date = date->NumberValue();
18174     if (!std::isnan(expected_stored_date)) {
18175       CHECK_EQ(expected_stored_date, stored_date);
18176     } else {
18177       uint64_t stored_bits = DoubleToBits(stored_date);
18178       // Check if quiet nan (bits 51..62 all set).
18179 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18180       // Most significant fraction bit for quiet nan is set to 0
18181       // on MIPS architecture. Allowed by IEEE-754.
18182       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18183 #else
18184       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18185 #endif
18186     }
18187   }
18188 }
18189
18190
18191 static void SpaghettiIncident(
18192     const v8::FunctionCallbackInfo<v8::Value>& args) {
18193   v8::HandleScope scope(args.GetIsolate());
18194   v8::TryCatch tc;
18195   v8::Handle<v8::String> str(args[0]->ToString());
18196   USE(str);
18197   if (tc.HasCaught())
18198     tc.ReThrow();
18199 }
18200
18201
18202 // Test that an exception can be propagated down through a spaghetti
18203 // stack using ReThrow.
18204 THREADED_TEST(SpaghettiStackReThrow) {
18205   v8::Isolate* isolate = CcTest::isolate();
18206   v8::HandleScope scope(isolate);
18207   LocalContext context;
18208   context->Global()->Set(
18209       v8::String::NewFromUtf8(isolate, "s"),
18210       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18211   v8::TryCatch try_catch;
18212   CompileRun(
18213       "var i = 0;"
18214       "var o = {"
18215       "  toString: function () {"
18216       "    if (i == 10) {"
18217       "      throw 'Hey!';"
18218       "    } else {"
18219       "      i++;"
18220       "      return s(o);"
18221       "    }"
18222       "  }"
18223       "};"
18224       "s(o);");
18225   CHECK(try_catch.HasCaught());
18226   v8::String::Utf8Value value(try_catch.Exception());
18227   CHECK_EQ(0, strcmp(*value, "Hey!"));
18228 }
18229
18230
18231 TEST(Regress528) {
18232   v8::V8::Initialize();
18233   v8::Isolate* isolate = CcTest::isolate();
18234   v8::HandleScope scope(isolate);
18235   v8::Local<Context> other_context;
18236   int gc_count;
18237
18238   // Create a context used to keep the code from aging in the compilation
18239   // cache.
18240   other_context = Context::New(isolate);
18241
18242   // Context-dependent context data creates reference from the compilation
18243   // cache to the global object.
18244   const char* source_simple = "1";
18245   {
18246     v8::HandleScope scope(isolate);
18247     v8::Local<Context> context = Context::New(isolate);
18248
18249     context->Enter();
18250     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18251     context->SetEmbedderData(0, obj);
18252     CompileRun(source_simple);
18253     context->Exit();
18254   }
18255   v8::V8::ContextDisposedNotification();
18256   for (gc_count = 1; gc_count < 10; gc_count++) {
18257     other_context->Enter();
18258     CompileRun(source_simple);
18259     other_context->Exit();
18260     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18261     if (GetGlobalObjectsCount() == 1) break;
18262   }
18263   CHECK_GE(2, gc_count);
18264   CHECK_EQ(1, GetGlobalObjectsCount());
18265
18266   // Eval in a function creates reference from the compilation cache to the
18267   // global object.
18268   const char* source_eval = "function f(){eval('1')}; f()";
18269   {
18270     v8::HandleScope scope(isolate);
18271     v8::Local<Context> context = Context::New(isolate);
18272
18273     context->Enter();
18274     CompileRun(source_eval);
18275     context->Exit();
18276   }
18277   v8::V8::ContextDisposedNotification();
18278   for (gc_count = 1; gc_count < 10; gc_count++) {
18279     other_context->Enter();
18280     CompileRun(source_eval);
18281     other_context->Exit();
18282     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18283     if (GetGlobalObjectsCount() == 1) break;
18284   }
18285   CHECK_GE(2, gc_count);
18286   CHECK_EQ(1, GetGlobalObjectsCount());
18287
18288   // Looking up the line number for an exception creates reference from the
18289   // compilation cache to the global object.
18290   const char* source_exception = "function f(){throw 1;} f()";
18291   {
18292     v8::HandleScope scope(isolate);
18293     v8::Local<Context> context = Context::New(isolate);
18294
18295     context->Enter();
18296     v8::TryCatch try_catch;
18297     CompileRun(source_exception);
18298     CHECK(try_catch.HasCaught());
18299     v8::Handle<v8::Message> message = try_catch.Message();
18300     CHECK(!message.IsEmpty());
18301     CHECK_EQ(1, message->GetLineNumber());
18302     context->Exit();
18303   }
18304   v8::V8::ContextDisposedNotification();
18305   for (gc_count = 1; gc_count < 10; gc_count++) {
18306     other_context->Enter();
18307     CompileRun(source_exception);
18308     other_context->Exit();
18309     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18310     if (GetGlobalObjectsCount() == 1) break;
18311   }
18312   CHECK_GE(2, gc_count);
18313   CHECK_EQ(1, GetGlobalObjectsCount());
18314
18315   v8::V8::ContextDisposedNotification();
18316 }
18317
18318
18319 THREADED_TEST(ScriptOrigin) {
18320   LocalContext env;
18321   v8::HandleScope scope(env->GetIsolate());
18322   v8::ScriptOrigin origin =
18323       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18324   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18325       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18326   v8::Script::Compile(script, &origin)->Run();
18327   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18328       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18329   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18330       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18331
18332   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18333   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18334   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18335
18336   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18337   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18338   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18339 }
18340
18341
18342 THREADED_TEST(FunctionGetInferredName) {
18343   LocalContext env;
18344   v8::HandleScope scope(env->GetIsolate());
18345   v8::ScriptOrigin origin =
18346       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18347   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18348       env->GetIsolate(),
18349       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
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   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18354 }
18355
18356
18357 THREADED_TEST(FunctionGetDisplayName) {
18358   LocalContext env;
18359   v8::HandleScope scope(env->GetIsolate());
18360   const char* code = "var error = false;"
18361                      "function a() { this.x = 1; };"
18362                      "a.displayName = 'display_a';"
18363                      "var b = (function() {"
18364                      "  var f = function() { this.x = 2; };"
18365                      "  f.displayName = 'display_b';"
18366                      "  return f;"
18367                      "})();"
18368                      "var c = function() {};"
18369                      "c.__defineGetter__('displayName', function() {"
18370                      "  error = true;"
18371                      "  throw new Error();"
18372                      "});"
18373                      "function d() {};"
18374                      "d.__defineGetter__('displayName', function() {"
18375                      "  error = true;"
18376                      "  return 'wrong_display_name';"
18377                      "});"
18378                      "function e() {};"
18379                      "e.displayName = 'wrong_display_name';"
18380                      "e.__defineSetter__('displayName', function() {"
18381                      "  error = true;"
18382                      "  throw new Error();"
18383                      "});"
18384                      "function f() {};"
18385                      "f.displayName = { 'foo': 6, toString: function() {"
18386                      "  error = true;"
18387                      "  return 'wrong_display_name';"
18388                      "}};"
18389                      "var g = function() {"
18390                      "  arguments.callee.displayName = 'set_in_runtime';"
18391                      "}; g();"
18392                      ;
18393   v8::ScriptOrigin origin =
18394       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18395   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18396       ->Run();
18397   v8::Local<v8::Value> error =
18398       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18399   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18400       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18401   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18402       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18403   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18404       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18405   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18406       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18407   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18408       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18409   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18410       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18411   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18412       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18413   CHECK_EQ(false, error->BooleanValue());
18414   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18415   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18416   CHECK(c->GetDisplayName()->IsUndefined());
18417   CHECK(d->GetDisplayName()->IsUndefined());
18418   CHECK(e->GetDisplayName()->IsUndefined());
18419   CHECK(f->GetDisplayName()->IsUndefined());
18420   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18421 }
18422
18423
18424 THREADED_TEST(ScriptLineNumber) {
18425   LocalContext env;
18426   v8::HandleScope scope(env->GetIsolate());
18427   v8::ScriptOrigin origin =
18428       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18429   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18430       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18431   v8::Script::Compile(script, &origin)->Run();
18432   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18433       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18434   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18435       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18436   CHECK_EQ(0, f->GetScriptLineNumber());
18437   CHECK_EQ(2, g->GetScriptLineNumber());
18438 }
18439
18440
18441 THREADED_TEST(ScriptColumnNumber) {
18442   LocalContext env;
18443   v8::Isolate* isolate = env->GetIsolate();
18444   v8::HandleScope scope(isolate);
18445   v8::ScriptOrigin origin =
18446       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18447                        v8::Integer::New(isolate, 3),
18448                        v8::Integer::New(isolate, 2));
18449   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18450       isolate, "function foo() {}\n\n     function bar() {}");
18451   v8::Script::Compile(script, &origin)->Run();
18452   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18453       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18454   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18455       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18456   CHECK_EQ(14, foo->GetScriptColumnNumber());
18457   CHECK_EQ(17, bar->GetScriptColumnNumber());
18458 }
18459
18460
18461 THREADED_TEST(FunctionIsBuiltin) {
18462   LocalContext env;
18463   v8::Isolate* isolate = env->GetIsolate();
18464   v8::HandleScope scope(isolate);
18465   v8::Local<v8::Function> f;
18466   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18467   CHECK(f->IsBuiltin());
18468   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18469   CHECK(f->IsBuiltin());
18470   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18471   CHECK(f->IsBuiltin());
18472   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18473   CHECK(f->IsBuiltin());
18474   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18475   CHECK(!f->IsBuiltin());
18476 }
18477
18478
18479 THREADED_TEST(FunctionGetScriptId) {
18480   LocalContext env;
18481   v8::Isolate* isolate = env->GetIsolate();
18482   v8::HandleScope scope(isolate);
18483   v8::ScriptOrigin origin =
18484       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18485                        v8::Integer::New(isolate, 3),
18486                        v8::Integer::New(isolate, 2));
18487   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18488       isolate, "function foo() {}\n\n     function bar() {}");
18489   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18490   script->Run();
18491   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18492       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18493   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18494       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18495   CHECK_EQ(script->GetId(), foo->ScriptId());
18496   CHECK_EQ(script->GetId(), bar->ScriptId());
18497 }
18498
18499
18500 THREADED_TEST(FunctionGetBoundFunction) {
18501   LocalContext env;
18502   v8::HandleScope scope(env->GetIsolate());
18503   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18504       env->GetIsolate(), "test"));
18505   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18506       env->GetIsolate(),
18507       "var a = new Object();\n"
18508       "a.x = 1;\n"
18509       "function f () { return this.x };\n"
18510       "var g = f.bind(a);\n"
18511       "var b = g();");
18512   v8::Script::Compile(script, &origin)->Run();
18513   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18514       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18515   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18516       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18517   CHECK(g->GetBoundFunction()->IsFunction());
18518   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18519       g->GetBoundFunction());
18520   CHECK_EQ(f->GetName(), original_function->GetName());
18521   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18522   CHECK_EQ(f->GetScriptColumnNumber(),
18523            original_function->GetScriptColumnNumber());
18524 }
18525
18526
18527 static void GetterWhichReturns42(
18528     Local<String> name,
18529     const v8::PropertyCallbackInfo<v8::Value>& info) {
18530   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18531   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18532   info.GetReturnValue().Set(v8_num(42));
18533 }
18534
18535
18536 static void SetterWhichSetsYOnThisTo23(
18537     Local<String> name,
18538     Local<Value> value,
18539     const v8::PropertyCallbackInfo<void>& info) {
18540   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18541   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18542   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18543 }
18544
18545
18546 void FooGetInterceptor(Local<String> name,
18547                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18548   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18549   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18550   if (!name->Equals(v8_str("foo"))) return;
18551   info.GetReturnValue().Set(v8_num(42));
18552 }
18553
18554
18555 void FooSetInterceptor(Local<String> name,
18556                        Local<Value> value,
18557                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18558   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18559   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18560   if (!name->Equals(v8_str("foo"))) return;
18561   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18562   info.GetReturnValue().Set(v8_num(23));
18563 }
18564
18565
18566 TEST(SetterOnConstructorPrototype) {
18567   v8::Isolate* isolate = CcTest::isolate();
18568   v8::HandleScope scope(isolate);
18569   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18570   templ->SetAccessor(v8_str("x"),
18571                      GetterWhichReturns42,
18572                      SetterWhichSetsYOnThisTo23);
18573   LocalContext context;
18574   context->Global()->Set(v8_str("P"), templ->NewInstance());
18575   CompileRun("function C1() {"
18576              "  this.x = 23;"
18577              "};"
18578              "C1.prototype = P;"
18579              "function C2() {"
18580              "  this.x = 23"
18581              "};"
18582              "C2.prototype = { };"
18583              "C2.prototype.__proto__ = P;");
18584
18585   v8::Local<v8::Script> script;
18586   script = v8_compile("new C1();");
18587   for (int i = 0; i < 10; i++) {
18588     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18589     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18590     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18591   }
18592
18593 script = v8_compile("new C2();");
18594   for (int i = 0; i < 10; i++) {
18595     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18596     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18597     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18598   }
18599 }
18600
18601
18602 static void NamedPropertyGetterWhichReturns42(
18603     Local<String> name,
18604     const v8::PropertyCallbackInfo<v8::Value>& info) {
18605   info.GetReturnValue().Set(v8_num(42));
18606 }
18607
18608
18609 static void NamedPropertySetterWhichSetsYOnThisTo23(
18610     Local<String> name,
18611     Local<Value> value,
18612     const v8::PropertyCallbackInfo<v8::Value>& info) {
18613   if (name->Equals(v8_str("x"))) {
18614     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18615   }
18616 }
18617
18618
18619 THREADED_TEST(InterceptorOnConstructorPrototype) {
18620   v8::Isolate* isolate = CcTest::isolate();
18621   v8::HandleScope scope(isolate);
18622   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18623   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18624                                  NamedPropertySetterWhichSetsYOnThisTo23);
18625   LocalContext context;
18626   context->Global()->Set(v8_str("P"), templ->NewInstance());
18627   CompileRun("function C1() {"
18628              "  this.x = 23;"
18629              "};"
18630              "C1.prototype = P;"
18631              "function C2() {"
18632              "  this.x = 23"
18633              "};"
18634              "C2.prototype = { };"
18635              "C2.prototype.__proto__ = P;");
18636
18637   v8::Local<v8::Script> script;
18638   script = v8_compile("new C1();");
18639   for (int i = 0; i < 10; i++) {
18640     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18641     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18642     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18643   }
18644
18645   script = v8_compile("new C2();");
18646   for (int i = 0; i < 10; i++) {
18647     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18648     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18649     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18650   }
18651 }
18652
18653
18654 TEST(Regress618) {
18655   const char* source = "function C1() {"
18656                        "  this.x = 23;"
18657                        "};"
18658                        "C1.prototype = P;";
18659
18660   LocalContext context;
18661   v8::Isolate* isolate = context->GetIsolate();
18662   v8::HandleScope scope(isolate);
18663   v8::Local<v8::Script> script;
18664
18665   // Use a simple object as prototype.
18666   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18667   prototype->Set(v8_str("y"), v8_num(42));
18668   context->Global()->Set(v8_str("P"), prototype);
18669
18670   // This compile will add the code to the compilation cache.
18671   CompileRun(source);
18672
18673   script = v8_compile("new C1();");
18674   // Allow enough iterations for the inobject slack tracking logic
18675   // to finalize instance size and install the fast construct stub.
18676   for (int i = 0; i < 256; i++) {
18677     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18678     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18679     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18680   }
18681
18682   // Use an API object with accessors as prototype.
18683   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18684   templ->SetAccessor(v8_str("x"),
18685                      GetterWhichReturns42,
18686                      SetterWhichSetsYOnThisTo23);
18687   context->Global()->Set(v8_str("P"), templ->NewInstance());
18688
18689   // This compile will get the code from the compilation cache.
18690   CompileRun(source);
18691
18692   script = v8_compile("new C1();");
18693   for (int i = 0; i < 10; i++) {
18694     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18695     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18696     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18697   }
18698 }
18699
18700 v8::Isolate* gc_callbacks_isolate = NULL;
18701 int prologue_call_count = 0;
18702 int epilogue_call_count = 0;
18703 int prologue_call_count_second = 0;
18704 int epilogue_call_count_second = 0;
18705 int prologue_call_count_alloc = 0;
18706 int epilogue_call_count_alloc = 0;
18707
18708 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18709   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18710   ++prologue_call_count;
18711 }
18712
18713
18714 void PrologueCallback(v8::Isolate* isolate,
18715                       v8::GCType,
18716                       v8::GCCallbackFlags flags) {
18717   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18718   CHECK_EQ(gc_callbacks_isolate, isolate);
18719   ++prologue_call_count;
18720 }
18721
18722
18723 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18724   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18725   ++epilogue_call_count;
18726 }
18727
18728
18729 void EpilogueCallback(v8::Isolate* isolate,
18730                       v8::GCType,
18731                       v8::GCCallbackFlags flags) {
18732   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18733   CHECK_EQ(gc_callbacks_isolate, isolate);
18734   ++epilogue_call_count;
18735 }
18736
18737
18738 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18739   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18740   ++prologue_call_count_second;
18741 }
18742
18743
18744 void PrologueCallbackSecond(v8::Isolate* isolate,
18745                             v8::GCType,
18746                             v8::GCCallbackFlags flags) {
18747   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18748   CHECK_EQ(gc_callbacks_isolate, isolate);
18749   ++prologue_call_count_second;
18750 }
18751
18752
18753 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18754   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18755   ++epilogue_call_count_second;
18756 }
18757
18758
18759 void EpilogueCallbackSecond(v8::Isolate* isolate,
18760                             v8::GCType,
18761                             v8::GCCallbackFlags flags) {
18762   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18763   CHECK_EQ(gc_callbacks_isolate, isolate);
18764   ++epilogue_call_count_second;
18765 }
18766
18767
18768 void PrologueCallbackAlloc(v8::Isolate* isolate,
18769                            v8::GCType,
18770                            v8::GCCallbackFlags flags) {
18771   v8::HandleScope scope(isolate);
18772
18773   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18774   CHECK_EQ(gc_callbacks_isolate, isolate);
18775   ++prologue_call_count_alloc;
18776
18777   // Simulate full heap to see if we will reenter this callback
18778   SimulateFullSpace(CcTest::heap()->new_space());
18779
18780   Local<Object> obj = Object::New(isolate);
18781   CHECK(!obj.IsEmpty());
18782
18783   CcTest::heap()->CollectAllGarbage(
18784       i::Heap::kAbortIncrementalMarkingMask);
18785 }
18786
18787
18788 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18789                            v8::GCType,
18790                            v8::GCCallbackFlags flags) {
18791   v8::HandleScope scope(isolate);
18792
18793   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18794   CHECK_EQ(gc_callbacks_isolate, isolate);
18795   ++epilogue_call_count_alloc;
18796
18797   // Simulate full heap to see if we will reenter this callback
18798   SimulateFullSpace(CcTest::heap()->new_space());
18799
18800   Local<Object> obj = Object::New(isolate);
18801   CHECK(!obj.IsEmpty());
18802
18803   CcTest::heap()->CollectAllGarbage(
18804       i::Heap::kAbortIncrementalMarkingMask);
18805 }
18806
18807
18808 TEST(GCCallbacksOld) {
18809   LocalContext context;
18810
18811   v8::V8::AddGCPrologueCallback(PrologueCallback);
18812   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18813   CHECK_EQ(0, prologue_call_count);
18814   CHECK_EQ(0, epilogue_call_count);
18815   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18816   CHECK_EQ(1, prologue_call_count);
18817   CHECK_EQ(1, epilogue_call_count);
18818   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18819   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18820   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18821   CHECK_EQ(2, prologue_call_count);
18822   CHECK_EQ(2, epilogue_call_count);
18823   CHECK_EQ(1, prologue_call_count_second);
18824   CHECK_EQ(1, epilogue_call_count_second);
18825   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18826   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18827   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18828   CHECK_EQ(2, prologue_call_count);
18829   CHECK_EQ(2, epilogue_call_count);
18830   CHECK_EQ(2, prologue_call_count_second);
18831   CHECK_EQ(2, epilogue_call_count_second);
18832   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18833   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18834   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18835   CHECK_EQ(2, prologue_call_count);
18836   CHECK_EQ(2, epilogue_call_count);
18837   CHECK_EQ(2, prologue_call_count_second);
18838   CHECK_EQ(2, epilogue_call_count_second);
18839 }
18840
18841
18842 TEST(GCCallbacks) {
18843   LocalContext context;
18844   v8::Isolate* isolate = context->GetIsolate();
18845   gc_callbacks_isolate = isolate;
18846   isolate->AddGCPrologueCallback(PrologueCallback);
18847   isolate->AddGCEpilogueCallback(EpilogueCallback);
18848   CHECK_EQ(0, prologue_call_count);
18849   CHECK_EQ(0, epilogue_call_count);
18850   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18851   CHECK_EQ(1, prologue_call_count);
18852   CHECK_EQ(1, epilogue_call_count);
18853   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18854   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18855   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18856   CHECK_EQ(2, prologue_call_count);
18857   CHECK_EQ(2, epilogue_call_count);
18858   CHECK_EQ(1, prologue_call_count_second);
18859   CHECK_EQ(1, epilogue_call_count_second);
18860   isolate->RemoveGCPrologueCallback(PrologueCallback);
18861   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18862   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18863   CHECK_EQ(2, prologue_call_count);
18864   CHECK_EQ(2, epilogue_call_count);
18865   CHECK_EQ(2, prologue_call_count_second);
18866   CHECK_EQ(2, epilogue_call_count_second);
18867   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18868   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18869   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18870   CHECK_EQ(2, prologue_call_count);
18871   CHECK_EQ(2, epilogue_call_count);
18872   CHECK_EQ(2, prologue_call_count_second);
18873   CHECK_EQ(2, epilogue_call_count_second);
18874
18875   CHECK_EQ(0, prologue_call_count_alloc);
18876   CHECK_EQ(0, epilogue_call_count_alloc);
18877   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18878   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18879   CcTest::heap()->CollectAllGarbage(
18880       i::Heap::kAbortIncrementalMarkingMask);
18881   CHECK_EQ(1, prologue_call_count_alloc);
18882   CHECK_EQ(1, epilogue_call_count_alloc);
18883   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18884   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18885 }
18886
18887
18888 THREADED_TEST(AddToJSFunctionResultCache) {
18889   i::FLAG_stress_compaction = false;
18890   i::FLAG_allow_natives_syntax = true;
18891   v8::HandleScope scope(CcTest::isolate());
18892
18893   LocalContext context;
18894
18895   const char* code =
18896       "(function() {"
18897       "  var key0 = 'a';"
18898       "  var key1 = 'b';"
18899       "  var r0 = %_GetFromCache(0, key0);"
18900       "  var r1 = %_GetFromCache(0, key1);"
18901       "  var r0_ = %_GetFromCache(0, key0);"
18902       "  if (r0 !== r0_)"
18903       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18904       "  var r1_ = %_GetFromCache(0, key1);"
18905       "  if (r1 !== r1_)"
18906       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18907       "  return 'PASSED';"
18908       "})()";
18909   CcTest::heap()->ClearJSFunctionResultCaches();
18910   ExpectString(code, "PASSED");
18911 }
18912
18913
18914 THREADED_TEST(FillJSFunctionResultCache) {
18915   i::FLAG_allow_natives_syntax = true;
18916   LocalContext context;
18917   v8::HandleScope scope(context->GetIsolate());
18918
18919   const char* code =
18920       "(function() {"
18921       "  var k = 'a';"
18922       "  var r = %_GetFromCache(0, k);"
18923       "  for (var i = 0; i < 16; i++) {"
18924       "    %_GetFromCache(0, 'a' + i);"
18925       "  };"
18926       "  if (r === %_GetFromCache(0, k))"
18927       "    return 'FAILED: k0CacheSize is too small';"
18928       "  return 'PASSED';"
18929       "})()";
18930   CcTest::heap()->ClearJSFunctionResultCaches();
18931   ExpectString(code, "PASSED");
18932 }
18933
18934
18935 THREADED_TEST(RoundRobinGetFromCache) {
18936   i::FLAG_allow_natives_syntax = true;
18937   LocalContext context;
18938   v8::HandleScope scope(context->GetIsolate());
18939
18940   const char* code =
18941       "(function() {"
18942       "  var keys = [];"
18943       "  for (var i = 0; i < 16; i++) keys.push(i);"
18944       "  var values = [];"
18945       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18946       "  for (var i = 0; i < 16; i++) {"
18947       "    var v = %_GetFromCache(0, keys[i]);"
18948       "    if (v.toString() !== values[i].toString())"
18949       "      return 'Wrong value for ' + "
18950       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18951       "  };"
18952       "  return 'PASSED';"
18953       "})()";
18954   CcTest::heap()->ClearJSFunctionResultCaches();
18955   ExpectString(code, "PASSED");
18956 }
18957
18958
18959 THREADED_TEST(ReverseGetFromCache) {
18960   i::FLAG_allow_natives_syntax = true;
18961   LocalContext context;
18962   v8::HandleScope scope(context->GetIsolate());
18963
18964   const char* code =
18965       "(function() {"
18966       "  var keys = [];"
18967       "  for (var i = 0; i < 16; i++) keys.push(i);"
18968       "  var values = [];"
18969       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18970       "  for (var i = 15; i >= 16; i--) {"
18971       "    var v = %_GetFromCache(0, keys[i]);"
18972       "    if (v !== values[i])"
18973       "      return 'Wrong value for ' + "
18974       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18975       "  };"
18976       "  return 'PASSED';"
18977       "})()";
18978   CcTest::heap()->ClearJSFunctionResultCaches();
18979   ExpectString(code, "PASSED");
18980 }
18981
18982
18983 THREADED_TEST(TestEviction) {
18984   i::FLAG_allow_natives_syntax = true;
18985   LocalContext context;
18986   v8::HandleScope scope(context->GetIsolate());
18987
18988   const char* code =
18989       "(function() {"
18990       "  for (var i = 0; i < 2*16; i++) {"
18991       "    %_GetFromCache(0, 'a' + i);"
18992       "  };"
18993       "  return 'PASSED';"
18994       "})()";
18995   CcTest::heap()->ClearJSFunctionResultCaches();
18996   ExpectString(code, "PASSED");
18997 }
18998
18999
19000 THREADED_TEST(TwoByteStringInAsciiCons) {
19001   // See Chromium issue 47824.
19002   LocalContext context;
19003   v8::HandleScope scope(context->GetIsolate());
19004
19005   const char* init_code =
19006       "var str1 = 'abelspendabel';"
19007       "var str2 = str1 + str1 + str1;"
19008       "str2;";
19009   Local<Value> result = CompileRun(init_code);
19010
19011   Local<Value> indexof = CompileRun("str2.indexOf('els')");
19012   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19013
19014   CHECK(result->IsString());
19015   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19016   int length = string->length();
19017   CHECK(string->IsOneByteRepresentation());
19018
19019   i::Handle<i::String> flat_string = i::String::Flatten(string);
19020
19021   CHECK(string->IsOneByteRepresentation());
19022   CHECK(flat_string->IsOneByteRepresentation());
19023
19024   // Create external resource.
19025   uint16_t* uc16_buffer = new uint16_t[length + 1];
19026
19027   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19028   uc16_buffer[length] = 0;
19029
19030   TestResource resource(uc16_buffer);
19031
19032   flat_string->MakeExternal(&resource);
19033
19034   CHECK(flat_string->IsTwoByteRepresentation());
19035
19036   // If the cons string has been short-circuited, skip the following checks.
19037   if (!string.is_identical_to(flat_string)) {
19038     // At this point, we should have a Cons string which is flat and ASCII,
19039     // with a first half that is a two-byte string (although it only contains
19040     // ASCII characters). This is a valid sequence of steps, and it can happen
19041     // in real pages.
19042     CHECK(string->IsOneByteRepresentation());
19043     i::ConsString* cons = i::ConsString::cast(*string);
19044     CHECK_EQ(0, cons->second()->length());
19045     CHECK(cons->first()->IsTwoByteRepresentation());
19046   }
19047
19048   // Check that some string operations work.
19049
19050   // Atom RegExp.
19051   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19052   CHECK_EQ(6, reresult->Int32Value());
19053
19054   // Nonatom RegExp.
19055   reresult = CompileRun("str2.match(/abe./g).length;");
19056   CHECK_EQ(6, reresult->Int32Value());
19057
19058   reresult = CompileRun("str2.search(/bel/g);");
19059   CHECK_EQ(1, reresult->Int32Value());
19060
19061   reresult = CompileRun("str2.search(/be./g);");
19062   CHECK_EQ(1, reresult->Int32Value());
19063
19064   ExpectTrue("/bel/g.test(str2);");
19065
19066   ExpectTrue("/be./g.test(str2);");
19067
19068   reresult = CompileRun("/bel/g.exec(str2);");
19069   CHECK(!reresult->IsNull());
19070
19071   reresult = CompileRun("/be./g.exec(str2);");
19072   CHECK(!reresult->IsNull());
19073
19074   ExpectString("str2.substring(2, 10);", "elspenda");
19075
19076   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19077
19078   ExpectString("str2.charAt(2);", "e");
19079
19080   ExpectObject("str2.indexOf('els');", indexof);
19081
19082   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19083
19084   reresult = CompileRun("str2.charCodeAt(2);");
19085   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19086 }
19087
19088
19089 TEST(ContainsOnlyOneByte) {
19090   v8::V8::Initialize();
19091   v8::Isolate* isolate = CcTest::isolate();
19092   v8::HandleScope scope(isolate);
19093   // Make a buffer long enough that it won't automatically be converted.
19094   const int length = 512;
19095   // Ensure word aligned assignment.
19096   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19097   i::SmartArrayPointer<uintptr_t>
19098   aligned_contents(new uintptr_t[aligned_length]);
19099   uint16_t* string_contents =
19100       reinterpret_cast<uint16_t*>(aligned_contents.get());
19101   // Set to contain only one byte.
19102   for (int i = 0; i < length-1; i++) {
19103     string_contents[i] = 0x41;
19104   }
19105   string_contents[length-1] = 0;
19106   // Simple case.
19107   Handle<String> string =
19108       String::NewExternal(isolate,
19109                           new TestResource(string_contents, NULL, false));
19110   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19111   // Counter example.
19112   string = String::NewFromTwoByte(isolate, string_contents);
19113   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19114   // Test left right and balanced cons strings.
19115   Handle<String> base = String::NewFromUtf8(isolate, "a");
19116   Handle<String> left = base;
19117   Handle<String> right = base;
19118   for (int i = 0; i < 1000; i++) {
19119     left = String::Concat(base, left);
19120     right = String::Concat(right, base);
19121   }
19122   Handle<String> balanced = String::Concat(left, base);
19123   balanced = String::Concat(balanced, right);
19124   Handle<String> cons_strings[] = {left, balanced, right};
19125   Handle<String> two_byte =
19126       String::NewExternal(isolate,
19127                           new TestResource(string_contents, NULL, false));
19128   USE(two_byte); USE(cons_strings);
19129   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19130     // Base assumptions.
19131     string = cons_strings[i];
19132     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19133     // Test left and right concatentation.
19134     string = String::Concat(two_byte, cons_strings[i]);
19135     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19136     string = String::Concat(cons_strings[i], two_byte);
19137     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19138   }
19139   // Set bits in different positions
19140   // for strings of different lengths and alignments.
19141   for (int alignment = 0; alignment < 7; alignment++) {
19142     for (int size = 2; alignment + size < length; size *= 2) {
19143       int zero_offset = size + alignment;
19144       string_contents[zero_offset] = 0;
19145       for (int i = 0; i < size; i++) {
19146         int shift = 8 + (i % 7);
19147         string_contents[alignment + i] = 1 << shift;
19148         string = String::NewExternal(
19149             isolate,
19150             new TestResource(string_contents + alignment, NULL, false));
19151         CHECK_EQ(size, string->Length());
19152         CHECK(!string->ContainsOnlyOneByte());
19153         string_contents[alignment + i] = 0x41;
19154       }
19155       string_contents[zero_offset] = 0x41;
19156     }
19157   }
19158 }
19159
19160
19161 // Failed access check callback that performs a GC on each invocation.
19162 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19163                                  v8::AccessType type,
19164                                  Local<v8::Value> data) {
19165   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19166 }
19167
19168
19169 TEST(GCInFailedAccessCheckCallback) {
19170   // Install a failed access check callback that performs a GC on each
19171   // invocation. Then force the callback to be called from va
19172
19173   v8::V8::Initialize();
19174   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19175
19176   v8::Isolate* isolate = CcTest::isolate();
19177   v8::HandleScope scope(isolate);
19178
19179   // Create an ObjectTemplate for global objects and install access
19180   // check callbacks that will block access.
19181   v8::Handle<v8::ObjectTemplate> global_template =
19182       v8::ObjectTemplate::New(isolate);
19183   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19184                                            IndexedGetAccessBlocker,
19185                                            v8::Handle<v8::Value>(),
19186                                            false);
19187
19188   // Create a context and set an x property on it's global object.
19189   LocalContext context0(NULL, global_template);
19190   context0->Global()->Set(v8_str("x"), v8_num(42));
19191   v8::Handle<v8::Object> global0 = context0->Global();
19192
19193   // Create a context with a different security token so that the
19194   // failed access check callback will be called on each access.
19195   LocalContext context1(NULL, global_template);
19196   context1->Global()->Set(v8_str("other"), global0);
19197
19198   // Get property with failed access check.
19199   ExpectUndefined("other.x");
19200
19201   // Get element with failed access check.
19202   ExpectUndefined("other[0]");
19203
19204   // Set property with failed access check.
19205   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19206   CHECK(result->IsObject());
19207
19208   // Set element with failed access check.
19209   result = CompileRun("other[0] = new Object()");
19210   CHECK(result->IsObject());
19211
19212   // Get property attribute with failed access check.
19213   ExpectFalse("\'x\' in other");
19214
19215   // Get property attribute for element with failed access check.
19216   ExpectFalse("0 in other");
19217
19218   // Delete property.
19219   ExpectFalse("delete other.x");
19220
19221   // Delete element.
19222   CHECK_EQ(false, global0->Delete(0));
19223
19224   // DefineAccessor.
19225   CHECK_EQ(false,
19226            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19227
19228   // Define JavaScript accessor.
19229   ExpectUndefined("Object.prototype.__defineGetter__.call("
19230                   "    other, \'x\', function() { return 42; })");
19231
19232   // LookupAccessor.
19233   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19234                   "    other, \'x\')");
19235
19236   // HasLocalElement.
19237   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19238
19239   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19240   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19241   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19242
19243   // Reset the failed access check callback so it does not influence
19244   // the other tests.
19245   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19246 }
19247
19248
19249 TEST(IsolateNewDispose) {
19250   v8::Isolate* current_isolate = CcTest::isolate();
19251   v8::Isolate* isolate = v8::Isolate::New();
19252   CHECK(isolate != NULL);
19253   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19254   CHECK(current_isolate != isolate);
19255   CHECK(current_isolate == CcTest::isolate());
19256
19257   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19258   last_location = last_message = NULL;
19259   isolate->Dispose();
19260   CHECK_EQ(last_location, NULL);
19261   CHECK_EQ(last_message, NULL);
19262 }
19263
19264
19265 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19266   v8::Isolate* isolate = v8::Isolate::New();
19267   {
19268     v8::Isolate::Scope i_scope(isolate);
19269     v8::HandleScope scope(isolate);
19270     LocalContext context(isolate);
19271     // Run something in this isolate.
19272     ExpectTrue("true");
19273     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19274     last_location = last_message = NULL;
19275     // Still entered, should fail.
19276     isolate->Dispose();
19277     CHECK_NE(last_location, NULL);
19278     CHECK_NE(last_message, NULL);
19279   }
19280   isolate->Dispose();
19281 }
19282
19283
19284 TEST(RunTwoIsolatesOnSingleThread) {
19285   // Run isolate 1.
19286   v8::Isolate* isolate1 = v8::Isolate::New();
19287   isolate1->Enter();
19288   v8::Persistent<v8::Context> context1;
19289   {
19290     v8::HandleScope scope(isolate1);
19291     context1.Reset(isolate1, Context::New(isolate1));
19292   }
19293
19294   {
19295     v8::HandleScope scope(isolate1);
19296     v8::Local<v8::Context> context =
19297         v8::Local<v8::Context>::New(isolate1, context1);
19298     v8::Context::Scope context_scope(context);
19299     // Run something in new isolate.
19300     CompileRun("var foo = 'isolate 1';");
19301     ExpectString("function f() { return foo; }; f()", "isolate 1");
19302   }
19303
19304   // Run isolate 2.
19305   v8::Isolate* isolate2 = v8::Isolate::New();
19306   v8::Persistent<v8::Context> context2;
19307
19308   {
19309     v8::Isolate::Scope iscope(isolate2);
19310     v8::HandleScope scope(isolate2);
19311     context2.Reset(isolate2, Context::New(isolate2));
19312     v8::Local<v8::Context> context =
19313         v8::Local<v8::Context>::New(isolate2, context2);
19314     v8::Context::Scope context_scope(context);
19315
19316     // Run something in new isolate.
19317     CompileRun("var foo = 'isolate 2';");
19318     ExpectString("function f() { return foo; }; f()", "isolate 2");
19319   }
19320
19321   {
19322     v8::HandleScope scope(isolate1);
19323     v8::Local<v8::Context> context =
19324         v8::Local<v8::Context>::New(isolate1, context1);
19325     v8::Context::Scope context_scope(context);
19326     // Now again in isolate 1
19327     ExpectString("function f() { return foo; }; f()", "isolate 1");
19328   }
19329
19330   isolate1->Exit();
19331
19332   // Run some stuff in default isolate.
19333   v8::Persistent<v8::Context> context_default;
19334   {
19335     v8::Isolate* isolate = CcTest::isolate();
19336     v8::Isolate::Scope iscope(isolate);
19337     v8::HandleScope scope(isolate);
19338     context_default.Reset(isolate, Context::New(isolate));
19339   }
19340
19341   {
19342     v8::HandleScope scope(CcTest::isolate());
19343     v8::Local<v8::Context> context =
19344         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19345     v8::Context::Scope context_scope(context);
19346     // Variables in other isolates should be not available, verify there
19347     // is an exception.
19348     ExpectTrue("function f() {"
19349                "  try {"
19350                "    foo;"
19351                "    return false;"
19352                "  } catch(e) {"
19353                "    return true;"
19354                "  }"
19355                "};"
19356                "var isDefaultIsolate = true;"
19357                "f()");
19358   }
19359
19360   isolate1->Enter();
19361
19362   {
19363     v8::Isolate::Scope iscope(isolate2);
19364     v8::HandleScope scope(isolate2);
19365     v8::Local<v8::Context> context =
19366         v8::Local<v8::Context>::New(isolate2, context2);
19367     v8::Context::Scope context_scope(context);
19368     ExpectString("function f() { return foo; }; f()", "isolate 2");
19369   }
19370
19371   {
19372     v8::HandleScope scope(v8::Isolate::GetCurrent());
19373     v8::Local<v8::Context> context =
19374         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19375     v8::Context::Scope context_scope(context);
19376     ExpectString("function f() { return foo; }; f()", "isolate 1");
19377   }
19378
19379   {
19380     v8::Isolate::Scope iscope(isolate2);
19381     context2.Reset();
19382   }
19383
19384   context1.Reset();
19385   isolate1->Exit();
19386
19387   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19388   last_location = last_message = NULL;
19389
19390   isolate1->Dispose();
19391   CHECK_EQ(last_location, NULL);
19392   CHECK_EQ(last_message, NULL);
19393
19394   isolate2->Dispose();
19395   CHECK_EQ(last_location, NULL);
19396   CHECK_EQ(last_message, NULL);
19397
19398   // Check that default isolate still runs.
19399   {
19400     v8::HandleScope scope(CcTest::isolate());
19401     v8::Local<v8::Context> context =
19402         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19403     v8::Context::Scope context_scope(context);
19404     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19405   }
19406 }
19407
19408
19409 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19410   v8::Isolate::Scope isolate_scope(isolate);
19411   v8::HandleScope scope(isolate);
19412   LocalContext context(isolate);
19413   i::ScopedVector<char> code(1024);
19414   i::OS::SNPrintF(code, "function fib(n) {"
19415                         "  if (n <= 2) return 1;"
19416                         "  return fib(n-1) + fib(n-2);"
19417                         "}"
19418                         "fib(%d)", limit);
19419   Local<Value> value = CompileRun(code.start());
19420   CHECK(value->IsNumber());
19421   return static_cast<int>(value->NumberValue());
19422 }
19423
19424 class IsolateThread : public v8::internal::Thread {
19425  public:
19426   IsolateThread(v8::Isolate* isolate, int fib_limit)
19427       : Thread("IsolateThread"),
19428         isolate_(isolate),
19429         fib_limit_(fib_limit),
19430         result_(0) { }
19431
19432   void Run() {
19433     result_ = CalcFibonacci(isolate_, fib_limit_);
19434   }
19435
19436   int result() { return result_; }
19437
19438  private:
19439   v8::Isolate* isolate_;
19440   int fib_limit_;
19441   int result_;
19442 };
19443
19444
19445 TEST(MultipleIsolatesOnIndividualThreads) {
19446   v8::Isolate* isolate1 = v8::Isolate::New();
19447   v8::Isolate* isolate2 = v8::Isolate::New();
19448
19449   IsolateThread thread1(isolate1, 21);
19450   IsolateThread thread2(isolate2, 12);
19451
19452   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19453   thread1.Start();
19454   thread2.Start();
19455
19456   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19457   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19458
19459   thread1.Join();
19460   thread2.Join();
19461
19462   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19463   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19464   CHECK_EQ(result1, 10946);
19465   CHECK_EQ(result2, 144);
19466   CHECK_EQ(result1, thread1.result());
19467   CHECK_EQ(result2, thread2.result());
19468
19469   isolate1->Dispose();
19470   isolate2->Dispose();
19471 }
19472
19473
19474 TEST(IsolateDifferentContexts) {
19475   v8::Isolate* isolate = v8::Isolate::New();
19476   Local<v8::Context> context;
19477   {
19478     v8::Isolate::Scope isolate_scope(isolate);
19479     v8::HandleScope handle_scope(isolate);
19480     context = v8::Context::New(isolate);
19481     v8::Context::Scope context_scope(context);
19482     Local<Value> v = CompileRun("2");
19483     CHECK(v->IsNumber());
19484     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19485   }
19486   {
19487     v8::Isolate::Scope isolate_scope(isolate);
19488     v8::HandleScope handle_scope(isolate);
19489     context = v8::Context::New(isolate);
19490     v8::Context::Scope context_scope(context);
19491     Local<Value> v = CompileRun("22");
19492     CHECK(v->IsNumber());
19493     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19494   }
19495   isolate->Dispose();
19496 }
19497
19498 class InitDefaultIsolateThread : public v8::internal::Thread {
19499  public:
19500   enum TestCase {
19501     SetResourceConstraints,
19502     SetFatalHandler,
19503     SetCounterFunction,
19504     SetCreateHistogramFunction,
19505     SetAddHistogramSampleFunction
19506   };
19507
19508   explicit InitDefaultIsolateThread(TestCase testCase)
19509       : Thread("InitDefaultIsolateThread"),
19510         testCase_(testCase),
19511         result_(false) { }
19512
19513   void Run() {
19514     v8::Isolate* isolate = v8::Isolate::New();
19515     isolate->Enter();
19516     switch (testCase_) {
19517       case SetResourceConstraints: {
19518         static const int K = 1024;
19519         v8::ResourceConstraints constraints;
19520         constraints.set_max_new_space_size(256 * K);
19521         constraints.set_max_old_space_size(4 * K * K);
19522         v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19523         break;
19524       }
19525
19526       case SetFatalHandler:
19527         v8::V8::SetFatalErrorHandler(NULL);
19528         break;
19529
19530       case SetCounterFunction:
19531         v8::V8::SetCounterFunction(NULL);
19532         break;
19533
19534       case SetCreateHistogramFunction:
19535         v8::V8::SetCreateHistogramFunction(NULL);
19536         break;
19537
19538       case SetAddHistogramSampleFunction:
19539         v8::V8::SetAddHistogramSampleFunction(NULL);
19540         break;
19541     }
19542     isolate->Exit();
19543     isolate->Dispose();
19544     result_ = true;
19545   }
19546
19547   bool result() { return result_; }
19548
19549  private:
19550   TestCase testCase_;
19551   bool result_;
19552 };
19553
19554
19555 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19556   InitDefaultIsolateThread thread(testCase);
19557   thread.Start();
19558   thread.Join();
19559   CHECK_EQ(thread.result(), true);
19560 }
19561
19562
19563 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19564   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19565 }
19566
19567
19568 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19569   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19570 }
19571
19572
19573 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19574   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19575 }
19576
19577
19578 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19579   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19580 }
19581
19582
19583 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19584   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19585 }
19586
19587
19588 TEST(StringCheckMultipleContexts) {
19589   const char* code =
19590       "(function() { return \"a\".charAt(0); })()";
19591
19592   {
19593     // Run the code twice in the first context to initialize the call IC.
19594     LocalContext context1;
19595     v8::HandleScope scope(context1->GetIsolate());
19596     ExpectString(code, "a");
19597     ExpectString(code, "a");
19598   }
19599
19600   {
19601     // Change the String.prototype in the second context and check
19602     // that the right function gets called.
19603     LocalContext context2;
19604     v8::HandleScope scope(context2->GetIsolate());
19605     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19606     ExpectString(code, "not a");
19607   }
19608 }
19609
19610
19611 TEST(NumberCheckMultipleContexts) {
19612   const char* code =
19613       "(function() { return (42).toString(); })()";
19614
19615   {
19616     // Run the code twice in the first context to initialize the call IC.
19617     LocalContext context1;
19618     v8::HandleScope scope(context1->GetIsolate());
19619     ExpectString(code, "42");
19620     ExpectString(code, "42");
19621   }
19622
19623   {
19624     // Change the Number.prototype in the second context and check
19625     // that the right function gets called.
19626     LocalContext context2;
19627     v8::HandleScope scope(context2->GetIsolate());
19628     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19629     ExpectString(code, "not 42");
19630   }
19631 }
19632
19633
19634 TEST(BooleanCheckMultipleContexts) {
19635   const char* code =
19636       "(function() { return true.toString(); })()";
19637
19638   {
19639     // Run the code twice in the first context to initialize the call IC.
19640     LocalContext context1;
19641     v8::HandleScope scope(context1->GetIsolate());
19642     ExpectString(code, "true");
19643     ExpectString(code, "true");
19644   }
19645
19646   {
19647     // Change the Boolean.prototype in the second context and check
19648     // that the right function gets called.
19649     LocalContext context2;
19650     v8::HandleScope scope(context2->GetIsolate());
19651     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19652     ExpectString(code, "");
19653   }
19654 }
19655
19656
19657 TEST(DontDeleteCellLoadIC) {
19658   const char* function_code =
19659       "function readCell() { while (true) { return cell; } }";
19660
19661   {
19662     // Run the code twice in the first context to initialize the load
19663     // IC for a don't delete cell.
19664     LocalContext context1;
19665     v8::HandleScope scope(context1->GetIsolate());
19666     CompileRun("var cell = \"first\";");
19667     ExpectBoolean("delete cell", false);
19668     CompileRun(function_code);
19669     ExpectString("readCell()", "first");
19670     ExpectString("readCell()", "first");
19671   }
19672
19673   {
19674     // Use a deletable cell in the second context.
19675     LocalContext context2;
19676     v8::HandleScope scope(context2->GetIsolate());
19677     CompileRun("cell = \"second\";");
19678     CompileRun(function_code);
19679     ExpectString("readCell()", "second");
19680     ExpectBoolean("delete cell", true);
19681     ExpectString("(function() {"
19682                  "  try {"
19683                  "    return readCell();"
19684                  "  } catch(e) {"
19685                  "    return e.toString();"
19686                  "  }"
19687                  "})()",
19688                  "ReferenceError: cell is not defined");
19689     CompileRun("cell = \"new_second\";");
19690     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19691     ExpectString("readCell()", "new_second");
19692     ExpectString("readCell()", "new_second");
19693   }
19694 }
19695
19696
19697 TEST(DontDeleteCellLoadICForceDelete) {
19698   const char* function_code =
19699       "function readCell() { while (true) { return cell; } }";
19700
19701   // Run the code twice to initialize the load IC for a don't delete
19702   // cell.
19703   LocalContext context;
19704   v8::HandleScope scope(context->GetIsolate());
19705   CompileRun("var cell = \"value\";");
19706   ExpectBoolean("delete cell", false);
19707   CompileRun(function_code);
19708   ExpectString("readCell()", "value");
19709   ExpectString("readCell()", "value");
19710
19711   // Delete the cell using the API and check the inlined code works
19712   // correctly.
19713   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19714   ExpectString("(function() {"
19715                "  try {"
19716                "    return readCell();"
19717                "  } catch(e) {"
19718                "    return e.toString();"
19719                "  }"
19720                "})()",
19721                "ReferenceError: cell is not defined");
19722 }
19723
19724
19725 TEST(DontDeleteCellLoadICAPI) {
19726   const char* function_code =
19727       "function readCell() { while (true) { return cell; } }";
19728
19729   // Run the code twice to initialize the load IC for a don't delete
19730   // cell created using the API.
19731   LocalContext context;
19732   v8::HandleScope scope(context->GetIsolate());
19733   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19734   ExpectBoolean("delete cell", false);
19735   CompileRun(function_code);
19736   ExpectString("readCell()", "value");
19737   ExpectString("readCell()", "value");
19738
19739   // Delete the cell using the API and check the inlined code works
19740   // correctly.
19741   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19742   ExpectString("(function() {"
19743                "  try {"
19744                "    return readCell();"
19745                "  } catch(e) {"
19746                "    return e.toString();"
19747                "  }"
19748                "})()",
19749                "ReferenceError: cell is not defined");
19750 }
19751
19752
19753 class Visitor42 : public v8::PersistentHandleVisitor {
19754  public:
19755   explicit Visitor42(v8::Persistent<v8::Object>* object)
19756       : counter_(0), object_(object) { }
19757
19758   virtual void VisitPersistentHandle(Persistent<Value>* value,
19759                                      uint16_t class_id) {
19760     if (class_id != 42) return;
19761     CHECK_EQ(42, value->WrapperClassId());
19762     v8::Isolate* isolate = CcTest::isolate();
19763     v8::HandleScope handle_scope(isolate);
19764     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19765     v8::Handle<v8::Value> object =
19766         v8::Local<v8::Object>::New(isolate, *object_);
19767     CHECK(handle->IsObject());
19768     CHECK_EQ(Handle<Object>::Cast(handle), object);
19769     ++counter_;
19770   }
19771
19772   int counter_;
19773   v8::Persistent<v8::Object>* object_;
19774 };
19775
19776
19777 TEST(PersistentHandleVisitor) {
19778   LocalContext context;
19779   v8::Isolate* isolate = context->GetIsolate();
19780   v8::HandleScope scope(isolate);
19781   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19782   CHECK_EQ(0, object.WrapperClassId());
19783   object.SetWrapperClassId(42);
19784   CHECK_EQ(42, object.WrapperClassId());
19785
19786   Visitor42 visitor(&object);
19787   v8::V8::VisitHandlesWithClassIds(&visitor);
19788   CHECK_EQ(1, visitor.counter_);
19789
19790   object.Reset();
19791 }
19792
19793
19794 TEST(WrapperClassId) {
19795   LocalContext context;
19796   v8::Isolate* isolate = context->GetIsolate();
19797   v8::HandleScope scope(isolate);
19798   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19799   CHECK_EQ(0, object.WrapperClassId());
19800   object.SetWrapperClassId(65535);
19801   CHECK_EQ(65535, object.WrapperClassId());
19802   object.Reset();
19803 }
19804
19805
19806 TEST(PersistentHandleInNewSpaceVisitor) {
19807   LocalContext context;
19808   v8::Isolate* isolate = context->GetIsolate();
19809   v8::HandleScope scope(isolate);
19810   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19811   CHECK_EQ(0, object1.WrapperClassId());
19812   object1.SetWrapperClassId(42);
19813   CHECK_EQ(42, object1.WrapperClassId());
19814
19815   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19816
19817   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19818   CHECK_EQ(0, object2.WrapperClassId());
19819   object2.SetWrapperClassId(42);
19820   CHECK_EQ(42, object2.WrapperClassId());
19821
19822   Visitor42 visitor(&object2);
19823   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19824   CHECK_EQ(1, visitor.counter_);
19825
19826   object1.Reset();
19827   object2.Reset();
19828 }
19829
19830
19831 TEST(RegExp) {
19832   LocalContext context;
19833   v8::HandleScope scope(context->GetIsolate());
19834
19835   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19836   CHECK(re->IsRegExp());
19837   CHECK(re->GetSource()->Equals(v8_str("foo")));
19838   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19839
19840   re = v8::RegExp::New(v8_str("bar"),
19841                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19842                                                       v8::RegExp::kGlobal));
19843   CHECK(re->IsRegExp());
19844   CHECK(re->GetSource()->Equals(v8_str("bar")));
19845   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19846            static_cast<int>(re->GetFlags()));
19847
19848   re = v8::RegExp::New(v8_str("baz"),
19849                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19850                                                       v8::RegExp::kMultiline));
19851   CHECK(re->IsRegExp());
19852   CHECK(re->GetSource()->Equals(v8_str("baz")));
19853   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19854            static_cast<int>(re->GetFlags()));
19855
19856   re = CompileRun("/quux/").As<v8::RegExp>();
19857   CHECK(re->IsRegExp());
19858   CHECK(re->GetSource()->Equals(v8_str("quux")));
19859   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19860
19861   re = CompileRun("/quux/gm").As<v8::RegExp>();
19862   CHECK(re->IsRegExp());
19863   CHECK(re->GetSource()->Equals(v8_str("quux")));
19864   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19865            static_cast<int>(re->GetFlags()));
19866
19867   // Override the RegExp constructor and check the API constructor
19868   // still works.
19869   CompileRun("RegExp = function() {}");
19870
19871   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19872   CHECK(re->IsRegExp());
19873   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19874   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19875
19876   re = v8::RegExp::New(v8_str("foobarbaz"),
19877                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19878                                                       v8::RegExp::kMultiline));
19879   CHECK(re->IsRegExp());
19880   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19881   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19882            static_cast<int>(re->GetFlags()));
19883
19884   context->Global()->Set(v8_str("re"), re);
19885   ExpectTrue("re.test('FoobarbaZ')");
19886
19887   // RegExps are objects on which you can set properties.
19888   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19889   v8::Handle<v8::Value> value(CompileRun("re.property"));
19890   CHECK_EQ(32, value->Int32Value());
19891
19892   v8::TryCatch try_catch;
19893   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19894   CHECK(re.IsEmpty());
19895   CHECK(try_catch.HasCaught());
19896   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19897   ExpectTrue("ex instanceof SyntaxError");
19898 }
19899
19900
19901 THREADED_TEST(Equals) {
19902   LocalContext localContext;
19903   v8::HandleScope handleScope(localContext->GetIsolate());
19904
19905   v8::Handle<v8::Object> globalProxy = localContext->Global();
19906   v8::Handle<Value> global = globalProxy->GetPrototype();
19907
19908   CHECK(global->StrictEquals(global));
19909   CHECK(!global->StrictEquals(globalProxy));
19910   CHECK(!globalProxy->StrictEquals(global));
19911   CHECK(globalProxy->StrictEquals(globalProxy));
19912
19913   CHECK(global->Equals(global));
19914   CHECK(!global->Equals(globalProxy));
19915   CHECK(!globalProxy->Equals(global));
19916   CHECK(globalProxy->Equals(globalProxy));
19917 }
19918
19919
19920 static void Getter(v8::Local<v8::String> property,
19921                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19922   info.GetReturnValue().Set(v8_str("42!"));
19923 }
19924
19925
19926 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19927   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19928   result->Set(0, v8_str("universalAnswer"));
19929   info.GetReturnValue().Set(result);
19930 }
19931
19932
19933 TEST(NamedEnumeratorAndForIn) {
19934   LocalContext context;
19935   v8::Isolate* isolate = context->GetIsolate();
19936   v8::HandleScope handle_scope(isolate);
19937   v8::Context::Scope context_scope(context.local());
19938
19939   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19940   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19941   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19942   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19943         "var result = []; for (var k in o) result.push(k); result"));
19944   CHECK_EQ(1, result->Length());
19945   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19946 }
19947
19948
19949 TEST(DefinePropertyPostDetach) {
19950   LocalContext context;
19951   v8::HandleScope scope(context->GetIsolate());
19952   v8::Handle<v8::Object> proxy = context->Global();
19953   v8::Handle<v8::Function> define_property =
19954       CompileRun("(function() {"
19955                  "  Object.defineProperty("
19956                  "    this,"
19957                  "    1,"
19958                  "    { configurable: true, enumerable: true, value: 3 });"
19959                  "})").As<Function>();
19960   context->DetachGlobal();
19961   define_property->Call(proxy, 0, NULL);
19962 }
19963
19964
19965 static void InstallContextId(v8::Handle<Context> context, int id) {
19966   Context::Scope scope(context);
19967   CompileRun("Object.prototype").As<Object>()->
19968       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19969 }
19970
19971
19972 static void CheckContextId(v8::Handle<Object> object, int expected) {
19973   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19974 }
19975
19976
19977 THREADED_TEST(CreationContext) {
19978   v8::Isolate* isolate = CcTest::isolate();
19979   HandleScope handle_scope(isolate);
19980   Handle<Context> context1 = Context::New(isolate);
19981   InstallContextId(context1, 1);
19982   Handle<Context> context2 = Context::New(isolate);
19983   InstallContextId(context2, 2);
19984   Handle<Context> context3 = Context::New(isolate);
19985   InstallContextId(context3, 3);
19986
19987   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19988
19989   Local<Object> object1;
19990   Local<Function> func1;
19991   {
19992     Context::Scope scope(context1);
19993     object1 = Object::New(isolate);
19994     func1 = tmpl->GetFunction();
19995   }
19996
19997   Local<Object> object2;
19998   Local<Function> func2;
19999   {
20000     Context::Scope scope(context2);
20001     object2 = Object::New(isolate);
20002     func2 = tmpl->GetFunction();
20003   }
20004
20005   Local<Object> instance1;
20006   Local<Object> instance2;
20007
20008   {
20009     Context::Scope scope(context3);
20010     instance1 = func1->NewInstance();
20011     instance2 = func2->NewInstance();
20012   }
20013
20014   CHECK(object1->CreationContext() == context1);
20015   CheckContextId(object1, 1);
20016   CHECK(func1->CreationContext() == context1);
20017   CheckContextId(func1, 1);
20018   CHECK(instance1->CreationContext() == context1);
20019   CheckContextId(instance1, 1);
20020   CHECK(object2->CreationContext() == context2);
20021   CheckContextId(object2, 2);
20022   CHECK(func2->CreationContext() == context2);
20023   CheckContextId(func2, 2);
20024   CHECK(instance2->CreationContext() == context2);
20025   CheckContextId(instance2, 2);
20026
20027   {
20028     Context::Scope scope(context1);
20029     CHECK(object1->CreationContext() == context1);
20030     CheckContextId(object1, 1);
20031     CHECK(func1->CreationContext() == context1);
20032     CheckContextId(func1, 1);
20033     CHECK(instance1->CreationContext() == context1);
20034     CheckContextId(instance1, 1);
20035     CHECK(object2->CreationContext() == context2);
20036     CheckContextId(object2, 2);
20037     CHECK(func2->CreationContext() == context2);
20038     CheckContextId(func2, 2);
20039     CHECK(instance2->CreationContext() == context2);
20040     CheckContextId(instance2, 2);
20041   }
20042
20043   {
20044     Context::Scope scope(context2);
20045     CHECK(object1->CreationContext() == context1);
20046     CheckContextId(object1, 1);
20047     CHECK(func1->CreationContext() == context1);
20048     CheckContextId(func1, 1);
20049     CHECK(instance1->CreationContext() == context1);
20050     CheckContextId(instance1, 1);
20051     CHECK(object2->CreationContext() == context2);
20052     CheckContextId(object2, 2);
20053     CHECK(func2->CreationContext() == context2);
20054     CheckContextId(func2, 2);
20055     CHECK(instance2->CreationContext() == context2);
20056     CheckContextId(instance2, 2);
20057   }
20058 }
20059
20060
20061 THREADED_TEST(CreationContextOfJsFunction) {
20062   HandleScope handle_scope(CcTest::isolate());
20063   Handle<Context> context = Context::New(CcTest::isolate());
20064   InstallContextId(context, 1);
20065
20066   Local<Object> function;
20067   {
20068     Context::Scope scope(context);
20069     function = CompileRun("function foo() {}; foo").As<Object>();
20070   }
20071
20072   CHECK(function->CreationContext() == context);
20073   CheckContextId(function, 1);
20074 }
20075
20076
20077 void HasOwnPropertyIndexedPropertyGetter(
20078     uint32_t index,
20079     const v8::PropertyCallbackInfo<v8::Value>& info) {
20080   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20081 }
20082
20083
20084 void HasOwnPropertyNamedPropertyGetter(
20085     Local<String> property,
20086     const v8::PropertyCallbackInfo<v8::Value>& info) {
20087   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20088 }
20089
20090
20091 void HasOwnPropertyIndexedPropertyQuery(
20092     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20093   if (index == 42) info.GetReturnValue().Set(1);
20094 }
20095
20096
20097 void HasOwnPropertyNamedPropertyQuery(
20098     Local<String> property,
20099     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20100   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20101 }
20102
20103
20104 void HasOwnPropertyNamedPropertyQuery2(
20105     Local<String> property,
20106     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20107   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20108 }
20109
20110
20111 void HasOwnPropertyAccessorGetter(
20112     Local<String> property,
20113     const v8::PropertyCallbackInfo<v8::Value>& info) {
20114   info.GetReturnValue().Set(v8_str("yes"));
20115 }
20116
20117
20118 TEST(HasOwnProperty) {
20119   LocalContext env;
20120   v8::Isolate* isolate = env->GetIsolate();
20121   v8::HandleScope scope(isolate);
20122   { // Check normal properties and defined getters.
20123     Handle<Value> value = CompileRun(
20124         "function Foo() {"
20125         "    this.foo = 11;"
20126         "    this.__defineGetter__('baz', function() { return 1; });"
20127         "};"
20128         "function Bar() { "
20129         "    this.bar = 13;"
20130         "    this.__defineGetter__('bla', function() { return 2; });"
20131         "};"
20132         "Bar.prototype = new Foo();"
20133         "new Bar();");
20134     CHECK(value->IsObject());
20135     Handle<Object> object = value->ToObject();
20136     CHECK(object->Has(v8_str("foo")));
20137     CHECK(!object->HasOwnProperty(v8_str("foo")));
20138     CHECK(object->HasOwnProperty(v8_str("bar")));
20139     CHECK(object->Has(v8_str("baz")));
20140     CHECK(!object->HasOwnProperty(v8_str("baz")));
20141     CHECK(object->HasOwnProperty(v8_str("bla")));
20142   }
20143   { // Check named getter interceptors.
20144     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20145     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20146     Handle<Object> instance = templ->NewInstance();
20147     CHECK(!instance->HasOwnProperty(v8_str("42")));
20148     CHECK(instance->HasOwnProperty(v8_str("foo")));
20149     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20150   }
20151   { // Check indexed getter interceptors.
20152     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20153     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20154     Handle<Object> instance = templ->NewInstance();
20155     CHECK(instance->HasOwnProperty(v8_str("42")));
20156     CHECK(!instance->HasOwnProperty(v8_str("43")));
20157     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20158   }
20159   { // Check named query interceptors.
20160     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20161     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20162     Handle<Object> instance = templ->NewInstance();
20163     CHECK(instance->HasOwnProperty(v8_str("foo")));
20164     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20165   }
20166   { // Check indexed query interceptors.
20167     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20168     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20169     Handle<Object> instance = templ->NewInstance();
20170     CHECK(instance->HasOwnProperty(v8_str("42")));
20171     CHECK(!instance->HasOwnProperty(v8_str("41")));
20172   }
20173   { // Check callbacks.
20174     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20175     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20176     Handle<Object> instance = templ->NewInstance();
20177     CHECK(instance->HasOwnProperty(v8_str("foo")));
20178     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20179   }
20180   { // Check that query wins on disagreement.
20181     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20182     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20183                                    0,
20184                                    HasOwnPropertyNamedPropertyQuery2);
20185     Handle<Object> instance = templ->NewInstance();
20186     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20187     CHECK(instance->HasOwnProperty(v8_str("bar")));
20188   }
20189 }
20190
20191
20192 TEST(IndexedInterceptorWithStringProto) {
20193   v8::Isolate* isolate = CcTest::isolate();
20194   v8::HandleScope scope(isolate);
20195   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20196   templ->SetIndexedPropertyHandler(NULL,
20197                                    NULL,
20198                                    HasOwnPropertyIndexedPropertyQuery);
20199   LocalContext context;
20200   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20201   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20202   // These should be intercepted.
20203   CHECK(CompileRun("42 in obj")->BooleanValue());
20204   CHECK(CompileRun("'42' in obj")->BooleanValue());
20205   // These should fall through to the String prototype.
20206   CHECK(CompileRun("0 in obj")->BooleanValue());
20207   CHECK(CompileRun("'0' in obj")->BooleanValue());
20208   // And these should both fail.
20209   CHECK(!CompileRun("32 in obj")->BooleanValue());
20210   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20211 }
20212
20213
20214 void CheckCodeGenerationAllowed() {
20215   Handle<Value> result = CompileRun("eval('42')");
20216   CHECK_EQ(42, result->Int32Value());
20217   result = CompileRun("(function(e) { return e('42'); })(eval)");
20218   CHECK_EQ(42, result->Int32Value());
20219   result = CompileRun("var f = new Function('return 42'); f()");
20220   CHECK_EQ(42, result->Int32Value());
20221 }
20222
20223
20224 void CheckCodeGenerationDisallowed() {
20225   TryCatch try_catch;
20226
20227   Handle<Value> result = CompileRun("eval('42')");
20228   CHECK(result.IsEmpty());
20229   CHECK(try_catch.HasCaught());
20230   try_catch.Reset();
20231
20232   result = CompileRun("(function(e) { return e('42'); })(eval)");
20233   CHECK(result.IsEmpty());
20234   CHECK(try_catch.HasCaught());
20235   try_catch.Reset();
20236
20237   result = CompileRun("var f = new Function('return 42'); f()");
20238   CHECK(result.IsEmpty());
20239   CHECK(try_catch.HasCaught());
20240 }
20241
20242
20243 bool CodeGenerationAllowed(Local<Context> context) {
20244   ApiTestFuzzer::Fuzz();
20245   return true;
20246 }
20247
20248
20249 bool CodeGenerationDisallowed(Local<Context> context) {
20250   ApiTestFuzzer::Fuzz();
20251   return false;
20252 }
20253
20254
20255 THREADED_TEST(AllowCodeGenFromStrings) {
20256   LocalContext context;
20257   v8::HandleScope scope(context->GetIsolate());
20258
20259   // eval and the Function constructor allowed by default.
20260   CHECK(context->IsCodeGenerationFromStringsAllowed());
20261   CheckCodeGenerationAllowed();
20262
20263   // Disallow eval and the Function constructor.
20264   context->AllowCodeGenerationFromStrings(false);
20265   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20266   CheckCodeGenerationDisallowed();
20267
20268   // Allow again.
20269   context->AllowCodeGenerationFromStrings(true);
20270   CheckCodeGenerationAllowed();
20271
20272   // Disallow but setting a global callback that will allow the calls.
20273   context->AllowCodeGenerationFromStrings(false);
20274   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20275   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20276   CheckCodeGenerationAllowed();
20277
20278   // Set a callback that disallows the code generation.
20279   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20280   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20281   CheckCodeGenerationDisallowed();
20282 }
20283
20284
20285 TEST(SetErrorMessageForCodeGenFromStrings) {
20286   LocalContext context;
20287   v8::HandleScope scope(context->GetIsolate());
20288   TryCatch try_catch;
20289
20290   Handle<String> message = v8_str("Message") ;
20291   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20292   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20293   context->AllowCodeGenerationFromStrings(false);
20294   context->SetErrorMessageForCodeGenerationFromStrings(message);
20295   Handle<Value> result = CompileRun("eval('42')");
20296   CHECK(result.IsEmpty());
20297   CHECK(try_catch.HasCaught());
20298   Handle<String> actual_message = try_catch.Message()->Get();
20299   CHECK(expected_message->Equals(actual_message));
20300 }
20301
20302
20303 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20304 }
20305
20306
20307 THREADED_TEST(CallAPIFunctionOnNonObject) {
20308   LocalContext context;
20309   v8::Isolate* isolate = context->GetIsolate();
20310   v8::HandleScope scope(isolate);
20311   Handle<FunctionTemplate> templ =
20312       v8::FunctionTemplate::New(isolate, NonObjectThis);
20313   Handle<Function> function = templ->GetFunction();
20314   context->Global()->Set(v8_str("f"), function);
20315   TryCatch try_catch;
20316   CompileRun("f.call(2)");
20317 }
20318
20319
20320 // Regression test for issue 1470.
20321 THREADED_TEST(ReadOnlyIndexedProperties) {
20322   v8::Isolate* isolate = CcTest::isolate();
20323   v8::HandleScope scope(isolate);
20324   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20325
20326   LocalContext context;
20327   Local<v8::Object> obj = templ->NewInstance();
20328   context->Global()->Set(v8_str("obj"), obj);
20329   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20330   obj->Set(v8_str("1"), v8_str("foobar"));
20331   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20332   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20333   obj->Set(v8_num(2), v8_str("foobar"));
20334   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20335
20336   // Test non-smi case.
20337   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20338   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20339   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20340 }
20341
20342
20343 THREADED_TEST(Regress1516) {
20344   LocalContext context;
20345   v8::HandleScope scope(context->GetIsolate());
20346
20347   { v8::HandleScope temp_scope(context->GetIsolate());
20348     CompileRun("({'a': 0})");
20349   }
20350
20351   int elements;
20352   { i::MapCache* map_cache =
20353         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20354     elements = map_cache->NumberOfElements();
20355     CHECK_LE(1, elements);
20356   }
20357
20358   CcTest::heap()->CollectAllGarbage(
20359       i::Heap::kAbortIncrementalMarkingMask);
20360   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20361     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20362       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20363       CHECK_GT(elements, map_cache->NumberOfElements());
20364     }
20365   }
20366 }
20367
20368
20369 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20370                                                 Local<Value> name,
20371                                                 v8::AccessType type,
20372                                                 Local<Value> data) {
20373   // Only block read access to __proto__.
20374   if (type == v8::ACCESS_GET &&
20375       name->IsString() &&
20376       name->ToString()->Length() == 9 &&
20377       name->ToString()->Utf8Length() == 9) {
20378     char buffer[10];
20379     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20380     return strncmp(buffer, "__proto__", 9) != 0;
20381   }
20382
20383   return true;
20384 }
20385
20386
20387 THREADED_TEST(Regress93759) {
20388   v8::Isolate* isolate = CcTest::isolate();
20389   HandleScope scope(isolate);
20390
20391   // Template for object with security check.
20392   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20393   // We don't do indexing, so any callback can be used for that.
20394   no_proto_template->SetAccessCheckCallbacks(
20395       BlockProtoNamedSecurityTestCallback,
20396       IndexedSecurityTestCallback);
20397
20398   // Templates for objects with hidden prototypes and possibly security check.
20399   Local<FunctionTemplate> hidden_proto_template =
20400       v8::FunctionTemplate::New(isolate);
20401   hidden_proto_template->SetHiddenPrototype(true);
20402
20403   Local<FunctionTemplate> protected_hidden_proto_template =
20404       v8::FunctionTemplate::New(isolate);
20405   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20406       BlockProtoNamedSecurityTestCallback,
20407       IndexedSecurityTestCallback);
20408   protected_hidden_proto_template->SetHiddenPrototype(true);
20409
20410   // Context for "foreign" objects used in test.
20411   Local<Context> context = v8::Context::New(isolate);
20412   context->Enter();
20413
20414   // Plain object, no security check.
20415   Local<Object> simple_object = Object::New(isolate);
20416
20417   // Object with explicit security check.
20418   Local<Object> protected_object =
20419       no_proto_template->NewInstance();
20420
20421   // JSGlobalProxy object, always have security check.
20422   Local<Object> proxy_object =
20423       context->Global();
20424
20425   // Global object, the  prototype of proxy_object. No security checks.
20426   Local<Object> global_object =
20427       proxy_object->GetPrototype()->ToObject();
20428
20429   // Hidden prototype without security check.
20430   Local<Object> hidden_prototype =
20431       hidden_proto_template->GetFunction()->NewInstance();
20432   Local<Object> object_with_hidden =
20433     Object::New(isolate);
20434   object_with_hidden->SetPrototype(hidden_prototype);
20435
20436   // Hidden prototype with security check on the hidden prototype.
20437   Local<Object> protected_hidden_prototype =
20438       protected_hidden_proto_template->GetFunction()->NewInstance();
20439   Local<Object> object_with_protected_hidden =
20440     Object::New(isolate);
20441   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20442
20443   context->Exit();
20444
20445   // Template for object for second context. Values to test are put on it as
20446   // properties.
20447   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20448   global_template->Set(v8_str("simple"), simple_object);
20449   global_template->Set(v8_str("protected"), protected_object);
20450   global_template->Set(v8_str("global"), global_object);
20451   global_template->Set(v8_str("proxy"), proxy_object);
20452   global_template->Set(v8_str("hidden"), object_with_hidden);
20453   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20454
20455   LocalContext context2(NULL, global_template);
20456
20457   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20458   CHECK(result1->Equals(simple_object->GetPrototype()));
20459
20460   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20461   CHECK(result2->Equals(Undefined(isolate)));
20462
20463   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20464   CHECK(result3->Equals(global_object->GetPrototype()));
20465
20466   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20467   CHECK(result4->Equals(Undefined(isolate)));
20468
20469   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20470   CHECK(result5->Equals(
20471       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20472
20473   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20474   CHECK(result6->Equals(Undefined(isolate)));
20475 }
20476
20477
20478 THREADED_TEST(Regress125988) {
20479   v8::HandleScope scope(CcTest::isolate());
20480   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20481   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20482   LocalContext env;
20483   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20484   CompileRun("var a = new Object();"
20485              "var b = new Intercept();"
20486              "var c = new Object();"
20487              "c.__proto__ = b;"
20488              "b.__proto__ = a;"
20489              "a.x = 23;"
20490              "for (var i = 0; i < 3; i++) c.x;");
20491   ExpectBoolean("c.hasOwnProperty('x')", false);
20492   ExpectInt32("c.x", 23);
20493   CompileRun("a.y = 42;"
20494              "for (var i = 0; i < 3; i++) c.x;");
20495   ExpectBoolean("c.hasOwnProperty('x')", false);
20496   ExpectInt32("c.x", 23);
20497   ExpectBoolean("c.hasOwnProperty('y')", false);
20498   ExpectInt32("c.y", 42);
20499 }
20500
20501
20502 static void TestReceiver(Local<Value> expected_result,
20503                          Local<Value> expected_receiver,
20504                          const char* code) {
20505   Local<Value> result = CompileRun(code);
20506   CHECK(result->IsObject());
20507   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20508   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20509 }
20510
20511
20512 THREADED_TEST(ForeignFunctionReceiver) {
20513   v8::Isolate* isolate = CcTest::isolate();
20514   HandleScope scope(isolate);
20515
20516   // Create two contexts with different "id" properties ('i' and 'o').
20517   // Call a function both from its own context and from a the foreign
20518   // context, and see what "this" is bound to (returning both "this"
20519   // and "this.id" for comparison).
20520
20521   Local<Context> foreign_context = v8::Context::New(isolate);
20522   foreign_context->Enter();
20523   Local<Value> foreign_function =
20524     CompileRun("function func() { return { 0: this.id, "
20525                "                           1: this, "
20526                "                           toString: function() { "
20527                "                               return this[0];"
20528                "                           }"
20529                "                         };"
20530                "}"
20531                "var id = 'i';"
20532                "func;");
20533   CHECK(foreign_function->IsFunction());
20534   foreign_context->Exit();
20535
20536   LocalContext context;
20537
20538   Local<String> password = v8_str("Password");
20539   // Don't get hit by security checks when accessing foreign_context's
20540   // global receiver (aka. global proxy).
20541   context->SetSecurityToken(password);
20542   foreign_context->SetSecurityToken(password);
20543
20544   Local<String> i = v8_str("i");
20545   Local<String> o = v8_str("o");
20546   Local<String> id = v8_str("id");
20547
20548   CompileRun("function ownfunc() { return { 0: this.id, "
20549              "                              1: this, "
20550              "                              toString: function() { "
20551              "                                  return this[0];"
20552              "                              }"
20553              "                             };"
20554              "}"
20555              "var id = 'o';"
20556              "ownfunc");
20557   context->Global()->Set(v8_str("func"), foreign_function);
20558
20559   // Sanity check the contexts.
20560   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20561   CHECK(o->Equals(context->Global()->Get(id)));
20562
20563   // Checking local function's receiver.
20564   // Calling function using its call/apply methods.
20565   TestReceiver(o, context->Global(), "ownfunc.call()");
20566   TestReceiver(o, context->Global(), "ownfunc.apply()");
20567   // Making calls through built-in functions.
20568   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20569   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20570   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20571   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20572   // Calling with environment record as base.
20573   TestReceiver(o, context->Global(), "ownfunc()");
20574   // Calling with no base.
20575   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20576
20577   // Checking foreign function return value.
20578   // Calling function using its call/apply methods.
20579   TestReceiver(i, foreign_context->Global(), "func.call()");
20580   TestReceiver(i, foreign_context->Global(), "func.apply()");
20581   // Calling function using another context's call/apply methods.
20582   TestReceiver(i, foreign_context->Global(),
20583                "Function.prototype.call.call(func)");
20584   TestReceiver(i, foreign_context->Global(),
20585                "Function.prototype.call.apply(func)");
20586   TestReceiver(i, foreign_context->Global(),
20587                "Function.prototype.apply.call(func)");
20588   TestReceiver(i, foreign_context->Global(),
20589                "Function.prototype.apply.apply(func)");
20590   // Making calls through built-in functions.
20591   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20592   // ToString(func()) is func()[0], i.e., the returned this.id.
20593   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20594   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20595   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20596
20597   // Calling with environment record as base.
20598   TestReceiver(i, foreign_context->Global(), "func()");
20599   // Calling with no base.
20600   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20601 }
20602
20603
20604 uint8_t callback_fired = 0;
20605
20606
20607 void CallCompletedCallback1() {
20608   i::OS::Print("Firing callback 1.\n");
20609   callback_fired ^= 1;  // Toggle first bit.
20610 }
20611
20612
20613 void CallCompletedCallback2() {
20614   i::OS::Print("Firing callback 2.\n");
20615   callback_fired ^= 2;  // Toggle second bit.
20616 }
20617
20618
20619 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20620   int32_t level = args[0]->Int32Value();
20621   if (level < 3) {
20622     level++;
20623     i::OS::Print("Entering recursion level %d.\n", level);
20624     char script[64];
20625     i::Vector<char> script_vector(script, sizeof(script));
20626     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20627     CompileRun(script_vector.start());
20628     i::OS::Print("Leaving recursion level %d.\n", level);
20629     CHECK_EQ(0, callback_fired);
20630   } else {
20631     i::OS::Print("Recursion ends.\n");
20632     CHECK_EQ(0, callback_fired);
20633   }
20634 }
20635
20636
20637 TEST(CallCompletedCallback) {
20638   LocalContext env;
20639   v8::HandleScope scope(env->GetIsolate());
20640   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20641       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20642   env->Global()->Set(v8_str("recursion"),
20643                      recursive_runtime->GetFunction());
20644   // Adding the same callback a second time has no effect.
20645   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20646   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20647   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20648   i::OS::Print("--- Script (1) ---\n");
20649   Local<Script> script = v8::Script::Compile(
20650       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20651   script->Run();
20652   CHECK_EQ(3, callback_fired);
20653
20654   i::OS::Print("\n--- Script (2) ---\n");
20655   callback_fired = 0;
20656   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20657   script->Run();
20658   CHECK_EQ(2, callback_fired);
20659
20660   i::OS::Print("\n--- Function ---\n");
20661   callback_fired = 0;
20662   Local<Function> recursive_function =
20663       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20664   v8::Handle<Value> args[] = { v8_num(0) };
20665   recursive_function->Call(env->Global(), 1, args);
20666   CHECK_EQ(2, callback_fired);
20667 }
20668
20669
20670 void CallCompletedCallbackNoException() {
20671   v8::HandleScope scope(CcTest::isolate());
20672   CompileRun("1+1;");
20673 }
20674
20675
20676 void CallCompletedCallbackException() {
20677   v8::HandleScope scope(CcTest::isolate());
20678   CompileRun("throw 'second exception';");
20679 }
20680
20681
20682 TEST(CallCompletedCallbackOneException) {
20683   LocalContext env;
20684   v8::HandleScope scope(env->GetIsolate());
20685   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20686   CompileRun("throw 'exception';");
20687 }
20688
20689
20690 TEST(CallCompletedCallbackTwoExceptions) {
20691   LocalContext env;
20692   v8::HandleScope scope(env->GetIsolate());
20693   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20694   CompileRun("throw 'first exception';");
20695 }
20696
20697
20698 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20699   v8::HandleScope scope(info.GetIsolate());
20700   CompileRun("ext1Calls++;");
20701 }
20702
20703
20704 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20705   v8::HandleScope scope(info.GetIsolate());
20706   CompileRun("ext2Calls++;");
20707 }
20708
20709
20710 TEST(EnqueueMicrotask) {
20711   LocalContext env;
20712   v8::HandleScope scope(env->GetIsolate());
20713   CompileRun(
20714       "var ext1Calls = 0;"
20715       "var ext2Calls = 0;");
20716   CompileRun("1+1;");
20717   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20718   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20719
20720   env->GetIsolate()->EnqueueMicrotask(
20721       Function::New(env->GetIsolate(), MicrotaskOne));
20722   CompileRun("1+1;");
20723   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20724   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20725
20726   env->GetIsolate()->EnqueueMicrotask(
20727       Function::New(env->GetIsolate(), MicrotaskOne));
20728   env->GetIsolate()->EnqueueMicrotask(
20729       Function::New(env->GetIsolate(), MicrotaskTwo));
20730   CompileRun("1+1;");
20731   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20732   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20733
20734   env->GetIsolate()->EnqueueMicrotask(
20735       Function::New(env->GetIsolate(), MicrotaskTwo));
20736   CompileRun("1+1;");
20737   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20738   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20739
20740   CompileRun("1+1;");
20741   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20742   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20743 }
20744
20745
20746 TEST(SetAutorunMicrotasks) {
20747   LocalContext env;
20748   v8::HandleScope scope(env->GetIsolate());
20749   CompileRun(
20750       "var ext1Calls = 0;"
20751       "var ext2Calls = 0;");
20752   CompileRun("1+1;");
20753   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20754   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20755
20756   env->GetIsolate()->EnqueueMicrotask(
20757       Function::New(env->GetIsolate(), MicrotaskOne));
20758   CompileRun("1+1;");
20759   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20760   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20761
20762   env->GetIsolate()->SetAutorunMicrotasks(false);
20763   env->GetIsolate()->EnqueueMicrotask(
20764       Function::New(env->GetIsolate(), MicrotaskOne));
20765   env->GetIsolate()->EnqueueMicrotask(
20766       Function::New(env->GetIsolate(), MicrotaskTwo));
20767   CompileRun("1+1;");
20768   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20769   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20770
20771   env->GetIsolate()->RunMicrotasks();
20772   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20773   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20774
20775   env->GetIsolate()->EnqueueMicrotask(
20776       Function::New(env->GetIsolate(), MicrotaskTwo));
20777   CompileRun("1+1;");
20778   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20779   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20780
20781   env->GetIsolate()->RunMicrotasks();
20782   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20783   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20784
20785   env->GetIsolate()->SetAutorunMicrotasks(true);
20786   env->GetIsolate()->EnqueueMicrotask(
20787       Function::New(env->GetIsolate(), MicrotaskTwo));
20788   CompileRun("1+1;");
20789   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20790   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20791
20792   env->GetIsolate()->EnqueueMicrotask(
20793       Function::New(env->GetIsolate(), MicrotaskTwo));
20794   {
20795     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20796     CompileRun("1+1;");
20797     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20798     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20799   }
20800
20801   CompileRun("1+1;");
20802   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20803   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20804 }
20805
20806
20807 static int probes_counter = 0;
20808 static int misses_counter = 0;
20809 static int updates_counter = 0;
20810
20811
20812 static int* LookupCounter(const char* name) {
20813   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20814     return &probes_counter;
20815   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20816     return &misses_counter;
20817   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20818     return &updates_counter;
20819   }
20820   return NULL;
20821 }
20822
20823
20824 static const char* kMegamorphicTestProgram =
20825     "function ClassA() { };"
20826     "function ClassB() { };"
20827     "ClassA.prototype.foo = function() { };"
20828     "ClassB.prototype.foo = function() { };"
20829     "function fooify(obj) { obj.foo(); };"
20830     "var a = new ClassA();"
20831     "var b = new ClassB();"
20832     "for (var i = 0; i < 10000; i++) {"
20833     "  fooify(a);"
20834     "  fooify(b);"
20835     "}";
20836
20837
20838 static void StubCacheHelper(bool primary) {
20839   V8::SetCounterFunction(LookupCounter);
20840   USE(kMegamorphicTestProgram);
20841 #ifdef DEBUG
20842   i::FLAG_native_code_counters = true;
20843   if (primary) {
20844     i::FLAG_test_primary_stub_cache = true;
20845   } else {
20846     i::FLAG_test_secondary_stub_cache = true;
20847   }
20848   i::FLAG_crankshaft = false;
20849   LocalContext env;
20850   v8::HandleScope scope(env->GetIsolate());
20851   int initial_probes = probes_counter;
20852   int initial_misses = misses_counter;
20853   int initial_updates = updates_counter;
20854   CompileRun(kMegamorphicTestProgram);
20855   int probes = probes_counter - initial_probes;
20856   int misses = misses_counter - initial_misses;
20857   int updates = updates_counter - initial_updates;
20858   CHECK_LT(updates, 10);
20859   CHECK_LT(misses, 10);
20860   // TODO(verwaest): Update this test to overflow the degree of polymorphism
20861   // before megamorphism. The number of probes will only work once we teach the
20862   // serializer to embed references to counters in the stubs, given that the
20863   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20864   CHECK_GE(probes, 0);
20865 #endif
20866 }
20867
20868
20869 TEST(SecondaryStubCache) {
20870   StubCacheHelper(true);
20871 }
20872
20873
20874 TEST(PrimaryStubCache) {
20875   StubCacheHelper(false);
20876 }
20877
20878
20879 static int cow_arrays_created_runtime = 0;
20880
20881
20882 static int* LookupCounterCOWArrays(const char* name) {
20883   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20884     return &cow_arrays_created_runtime;
20885   }
20886   return NULL;
20887 }
20888
20889
20890 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20891   V8::SetCounterFunction(LookupCounterCOWArrays);
20892 #ifdef DEBUG
20893   i::FLAG_native_code_counters = true;
20894   LocalContext env;
20895   v8::HandleScope scope(env->GetIsolate());
20896   int initial_cow_arrays = cow_arrays_created_runtime;
20897   CompileRun("var o = [1, 2, 3];");
20898   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20899   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20900   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20901   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20902   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20903 #endif
20904 }
20905
20906
20907 TEST(StaticGetters) {
20908   LocalContext context;
20909   i::Factory* factory = CcTest::i_isolate()->factory();
20910   v8::Isolate* isolate = CcTest::isolate();
20911   v8::HandleScope scope(isolate);
20912   i::Handle<i::Object> undefined_value = factory->undefined_value();
20913   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20914   i::Handle<i::Object> null_value = factory->null_value();
20915   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20916   i::Handle<i::Object> true_value = factory->true_value();
20917   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20918   i::Handle<i::Object> false_value = factory->false_value();
20919   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20920 }
20921
20922
20923 UNINITIALIZED_TEST(IsolateEmbedderData) {
20924   CcTest::DisableAutomaticDispose();
20925   v8::Isolate* isolate = v8::Isolate::New();
20926   isolate->Enter();
20927   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20928   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20929     CHECK_EQ(NULL, isolate->GetData(slot));
20930     CHECK_EQ(NULL, i_isolate->GetData(slot));
20931   }
20932   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20933     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20934     isolate->SetData(slot, data);
20935   }
20936   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20937     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20938     CHECK_EQ(data, isolate->GetData(slot));
20939     CHECK_EQ(data, i_isolate->GetData(slot));
20940   }
20941   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20942     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20943     isolate->SetData(slot, data);
20944   }
20945   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20946     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20947     CHECK_EQ(data, isolate->GetData(slot));
20948     CHECK_EQ(data, i_isolate->GetData(slot));
20949   }
20950   isolate->Exit();
20951   isolate->Dispose();
20952 }
20953
20954
20955 TEST(StringEmpty) {
20956   LocalContext context;
20957   i::Factory* factory = CcTest::i_isolate()->factory();
20958   v8::Isolate* isolate = CcTest::isolate();
20959   v8::HandleScope scope(isolate);
20960   i::Handle<i::Object> empty_string = factory->empty_string();
20961   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20962 }
20963
20964
20965 static int instance_checked_getter_count = 0;
20966 static void InstanceCheckedGetter(
20967     Local<String> name,
20968     const v8::PropertyCallbackInfo<v8::Value>& info) {
20969   CHECK_EQ(name, v8_str("foo"));
20970   instance_checked_getter_count++;
20971   info.GetReturnValue().Set(v8_num(11));
20972 }
20973
20974
20975 static int instance_checked_setter_count = 0;
20976 static void InstanceCheckedSetter(Local<String> name,
20977                       Local<Value> value,
20978                       const v8::PropertyCallbackInfo<void>& info) {
20979   CHECK_EQ(name, v8_str("foo"));
20980   CHECK_EQ(value, v8_num(23));
20981   instance_checked_setter_count++;
20982 }
20983
20984
20985 static void CheckInstanceCheckedResult(int getters,
20986                                        int setters,
20987                                        bool expects_callbacks,
20988                                        TryCatch* try_catch) {
20989   if (expects_callbacks) {
20990     CHECK(!try_catch->HasCaught());
20991     CHECK_EQ(getters, instance_checked_getter_count);
20992     CHECK_EQ(setters, instance_checked_setter_count);
20993   } else {
20994     CHECK(try_catch->HasCaught());
20995     CHECK_EQ(0, instance_checked_getter_count);
20996     CHECK_EQ(0, instance_checked_setter_count);
20997   }
20998   try_catch->Reset();
20999 }
21000
21001
21002 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21003   instance_checked_getter_count = 0;
21004   instance_checked_setter_count = 0;
21005   TryCatch try_catch;
21006
21007   // Test path through generic runtime code.
21008   CompileRun("obj.foo");
21009   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21010   CompileRun("obj.foo = 23");
21011   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21012
21013   // Test path through generated LoadIC and StoredIC.
21014   CompileRun("function test_get(o) { o.foo; }"
21015              "test_get(obj);");
21016   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21017   CompileRun("test_get(obj);");
21018   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21019   CompileRun("test_get(obj);");
21020   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21021   CompileRun("function test_set(o) { o.foo = 23; }"
21022              "test_set(obj);");
21023   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21024   CompileRun("test_set(obj);");
21025   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21026   CompileRun("test_set(obj);");
21027   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21028
21029   // Test path through optimized code.
21030   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21031              "test_get(obj);");
21032   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21033   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21034              "test_set(obj);");
21035   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21036
21037   // Cleanup so that closures start out fresh in next check.
21038   CompileRun("%DeoptimizeFunction(test_get);"
21039              "%ClearFunctionTypeFeedback(test_get);"
21040              "%DeoptimizeFunction(test_set);"
21041              "%ClearFunctionTypeFeedback(test_set);");
21042 }
21043
21044
21045 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21046   v8::internal::FLAG_allow_natives_syntax = true;
21047   LocalContext context;
21048   v8::HandleScope scope(context->GetIsolate());
21049
21050   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21051   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21052   inst->SetAccessor(v8_str("foo"),
21053                     InstanceCheckedGetter, InstanceCheckedSetter,
21054                     Handle<Value>(),
21055                     v8::DEFAULT,
21056                     v8::None,
21057                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21058   context->Global()->Set(v8_str("f"), templ->GetFunction());
21059
21060   printf("Testing positive ...\n");
21061   CompileRun("var obj = new f();");
21062   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21063   CheckInstanceCheckedAccessors(true);
21064
21065   printf("Testing negative ...\n");
21066   CompileRun("var obj = {};"
21067              "obj.__proto__ = new f();");
21068   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21069   CheckInstanceCheckedAccessors(false);
21070 }
21071
21072
21073 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21074   v8::internal::FLAG_allow_natives_syntax = true;
21075   LocalContext context;
21076   v8::HandleScope scope(context->GetIsolate());
21077
21078   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21079   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21080   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21081   inst->SetAccessor(v8_str("foo"),
21082                     InstanceCheckedGetter, InstanceCheckedSetter,
21083                     Handle<Value>(),
21084                     v8::DEFAULT,
21085                     v8::None,
21086                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21087   context->Global()->Set(v8_str("f"), templ->GetFunction());
21088
21089   printf("Testing positive ...\n");
21090   CompileRun("var obj = new f();");
21091   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21092   CheckInstanceCheckedAccessors(true);
21093
21094   printf("Testing negative ...\n");
21095   CompileRun("var obj = {};"
21096              "obj.__proto__ = new f();");
21097   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21098   CheckInstanceCheckedAccessors(false);
21099 }
21100
21101
21102 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21103   v8::internal::FLAG_allow_natives_syntax = true;
21104   LocalContext context;
21105   v8::HandleScope scope(context->GetIsolate());
21106
21107   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21108   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21109   proto->SetAccessor(v8_str("foo"),
21110                      InstanceCheckedGetter, InstanceCheckedSetter,
21111                      Handle<Value>(),
21112                      v8::DEFAULT,
21113                      v8::None,
21114                      v8::AccessorSignature::New(context->GetIsolate(), templ));
21115   context->Global()->Set(v8_str("f"), templ->GetFunction());
21116
21117   printf("Testing positive ...\n");
21118   CompileRun("var obj = new f();");
21119   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21120   CheckInstanceCheckedAccessors(true);
21121
21122   printf("Testing negative ...\n");
21123   CompileRun("var obj = {};"
21124              "obj.__proto__ = new f();");
21125   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21126   CheckInstanceCheckedAccessors(false);
21127
21128   printf("Testing positive with modified prototype chain ...\n");
21129   CompileRun("var obj = new f();"
21130              "var pro = {};"
21131              "pro.__proto__ = obj.__proto__;"
21132              "obj.__proto__ = pro;");
21133   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21134   CheckInstanceCheckedAccessors(true);
21135 }
21136
21137
21138 TEST(TryFinallyMessage) {
21139   LocalContext context;
21140   v8::HandleScope scope(context->GetIsolate());
21141   {
21142     // Test that the original error message is not lost if there is a
21143     // recursive call into Javascript is done in the finally block, e.g. to
21144     // initialize an IC. (crbug.com/129171)
21145     TryCatch try_catch;
21146     const char* trigger_ic =
21147         "try {                      \n"
21148         "  throw new Error('test'); \n"
21149         "} finally {                \n"
21150         "  var x = 0;               \n"
21151         "  x++;                     \n"  // Trigger an IC initialization here.
21152         "}                          \n";
21153     CompileRun(trigger_ic);
21154     CHECK(try_catch.HasCaught());
21155     Local<Message> message = try_catch.Message();
21156     CHECK(!message.IsEmpty());
21157     CHECK_EQ(2, message->GetLineNumber());
21158   }
21159
21160   {
21161     // Test that the original exception message is indeed overwritten if
21162     // a new error is thrown in the finally block.
21163     TryCatch try_catch;
21164     const char* throw_again =
21165         "try {                       \n"
21166         "  throw new Error('test');  \n"
21167         "} finally {                 \n"
21168         "  var x = 0;                \n"
21169         "  x++;                      \n"
21170         "  throw new Error('again'); \n"  // This is the new uncaught error.
21171         "}                           \n";
21172     CompileRun(throw_again);
21173     CHECK(try_catch.HasCaught());
21174     Local<Message> message = try_catch.Message();
21175     CHECK(!message.IsEmpty());
21176     CHECK_EQ(6, message->GetLineNumber());
21177   }
21178 }
21179
21180
21181 static void Helper137002(bool do_store,
21182                          bool polymorphic,
21183                          bool remove_accessor,
21184                          bool interceptor) {
21185   LocalContext context;
21186   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21187   if (interceptor) {
21188     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21189   } else {
21190     templ->SetAccessor(v8_str("foo"),
21191                        GetterWhichReturns42,
21192                        SetterWhichSetsYOnThisTo23);
21193   }
21194   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21195
21196   // Turn monomorphic on slow object with native accessor, then turn
21197   // polymorphic, finally optimize to create negative lookup and fail.
21198   CompileRun(do_store ?
21199              "function f(x) { x.foo = void 0; }" :
21200              "function f(x) { return x.foo; }");
21201   CompileRun("obj.y = void 0;");
21202   if (!interceptor) {
21203     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21204   }
21205   CompileRun("obj.__proto__ = null;"
21206              "f(obj); f(obj); f(obj);");
21207   if (polymorphic) {
21208     CompileRun("f({});");
21209   }
21210   CompileRun("obj.y = void 0;"
21211              "%OptimizeFunctionOnNextCall(f);");
21212   if (remove_accessor) {
21213     CompileRun("delete obj.foo;");
21214   }
21215   CompileRun("var result = f(obj);");
21216   if (do_store) {
21217     CompileRun("result = obj.y;");
21218   }
21219   if (remove_accessor && !interceptor) {
21220     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21221   } else {
21222     CHECK_EQ(do_store ? 23 : 42,
21223              context->Global()->Get(v8_str("result"))->Int32Value());
21224   }
21225 }
21226
21227
21228 THREADED_TEST(Regress137002a) {
21229   i::FLAG_allow_natives_syntax = true;
21230   i::FLAG_compilation_cache = false;
21231   v8::HandleScope scope(CcTest::isolate());
21232   for (int i = 0; i < 16; i++) {
21233     Helper137002(i & 8, i & 4, i & 2, i & 1);
21234   }
21235 }
21236
21237
21238 THREADED_TEST(Regress137002b) {
21239   i::FLAG_allow_natives_syntax = true;
21240   LocalContext context;
21241   v8::Isolate* isolate = context->GetIsolate();
21242   v8::HandleScope scope(isolate);
21243   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21244   templ->SetAccessor(v8_str("foo"),
21245                      GetterWhichReturns42,
21246                      SetterWhichSetsYOnThisTo23);
21247   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21248
21249   // Turn monomorphic on slow object with native accessor, then just
21250   // delete the property and fail.
21251   CompileRun("function load(x) { return x.foo; }"
21252              "function store(x) { x.foo = void 0; }"
21253              "function keyed_load(x, key) { return x[key]; }"
21254              // Second version of function has a different source (add void 0)
21255              // so that it does not share code with the first version.  This
21256              // ensures that the ICs are monomorphic.
21257              "function load2(x) { void 0; return x.foo; }"
21258              "function store2(x) { void 0; x.foo = void 0; }"
21259              "function keyed_load2(x, key) { void 0; return x[key]; }"
21260
21261              "obj.y = void 0;"
21262              "obj.__proto__ = null;"
21263              "var subobj = {};"
21264              "subobj.y = void 0;"
21265              "subobj.__proto__ = obj;"
21266              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21267
21268              // Make the ICs monomorphic.
21269              "load(obj); load(obj);"
21270              "load2(subobj); load2(subobj);"
21271              "store(obj); store(obj);"
21272              "store2(subobj); store2(subobj);"
21273              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21274              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21275
21276              // Actually test the shiny new ICs and better not crash. This
21277              // serves as a regression test for issue 142088 as well.
21278              "load(obj);"
21279              "load2(subobj);"
21280              "store(obj);"
21281              "store2(subobj);"
21282              "keyed_load(obj, 'foo');"
21283              "keyed_load2(subobj, 'foo');"
21284
21285              // Delete the accessor.  It better not be called any more now.
21286              "delete obj.foo;"
21287              "obj.y = void 0;"
21288              "subobj.y = void 0;"
21289
21290              "var load_result = load(obj);"
21291              "var load_result2 = load2(subobj);"
21292              "var keyed_load_result = keyed_load(obj, 'foo');"
21293              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21294              "store(obj);"
21295              "store2(subobj);"
21296              "var y_from_obj = obj.y;"
21297              "var y_from_subobj = subobj.y;");
21298   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21299   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21300   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21301   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21302   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21303   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21304 }
21305
21306
21307 THREADED_TEST(Regress142088) {
21308   i::FLAG_allow_natives_syntax = true;
21309   LocalContext context;
21310   v8::Isolate* isolate = context->GetIsolate();
21311   v8::HandleScope scope(isolate);
21312   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21313   templ->SetAccessor(v8_str("foo"),
21314                      GetterWhichReturns42,
21315                      SetterWhichSetsYOnThisTo23);
21316   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21317
21318   CompileRun("function load(x) { return x.foo; }"
21319              "var o = Object.create(obj);"
21320              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21321              "load(o); load(o); load(o); load(o);");
21322 }
21323
21324
21325 THREADED_TEST(Regress137496) {
21326   i::FLAG_expose_gc = true;
21327   LocalContext context;
21328   v8::HandleScope scope(context->GetIsolate());
21329
21330   // Compile a try-finally clause where the finally block causes a GC
21331   // while there still is a message pending for external reporting.
21332   TryCatch try_catch;
21333   try_catch.SetVerbose(true);
21334   CompileRun("try { throw new Error(); } finally { gc(); }");
21335   CHECK(try_catch.HasCaught());
21336 }
21337
21338
21339 THREADED_TEST(Regress149912) {
21340   LocalContext context;
21341   v8::HandleScope scope(context->GetIsolate());
21342   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21343   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21344   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21345   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21346 }
21347
21348
21349 THREADED_TEST(Regress157124) {
21350   LocalContext context;
21351   v8::Isolate* isolate = context->GetIsolate();
21352   v8::HandleScope scope(isolate);
21353   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21354   Local<Object> obj = templ->NewInstance();
21355   obj->GetIdentityHash();
21356   obj->DeleteHiddenValue(v8_str("Bug"));
21357 }
21358
21359
21360 THREADED_TEST(Regress2535) {
21361   i::FLAG_harmony_collections = true;
21362   LocalContext context;
21363   v8::HandleScope scope(context->GetIsolate());
21364   Local<Value> set_value = CompileRun("new Set();");
21365   Local<Object> set_object(Local<Object>::Cast(set_value));
21366   CHECK_EQ(0, set_object->InternalFieldCount());
21367   Local<Value> map_value = CompileRun("new Map();");
21368   Local<Object> map_object(Local<Object>::Cast(map_value));
21369   CHECK_EQ(0, map_object->InternalFieldCount());
21370 }
21371
21372
21373 THREADED_TEST(Regress2746) {
21374   LocalContext context;
21375   v8::Isolate* isolate = context->GetIsolate();
21376   v8::HandleScope scope(isolate);
21377   Local<Object> obj = Object::New(isolate);
21378   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21379   obj->SetHiddenValue(key, v8::Undefined(isolate));
21380   Local<Value> value = obj->GetHiddenValue(key);
21381   CHECK(!value.IsEmpty());
21382   CHECK(value->IsUndefined());
21383 }
21384
21385
21386 THREADED_TEST(Regress260106) {
21387   LocalContext context;
21388   v8::Isolate* isolate = context->GetIsolate();
21389   v8::HandleScope scope(isolate);
21390   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21391                                                         DummyCallHandler);
21392   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21393   Local<Function> function = templ->GetFunction();
21394   CHECK(!function.IsEmpty());
21395   CHECK(function->IsFunction());
21396 }
21397
21398
21399 THREADED_TEST(JSONParseObject) {
21400   LocalContext context;
21401   HandleScope scope(context->GetIsolate());
21402   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21403   Handle<Object> global = context->Global();
21404   global->Set(v8_str("obj"), obj);
21405   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21406 }
21407
21408
21409 THREADED_TEST(JSONParseNumber) {
21410   LocalContext context;
21411   HandleScope scope(context->GetIsolate());
21412   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21413   Handle<Object> global = context->Global();
21414   global->Set(v8_str("obj"), obj);
21415   ExpectString("JSON.stringify(obj)", "42");
21416 }
21417
21418
21419 #if V8_OS_POSIX
21420 class ThreadInterruptTest {
21421  public:
21422   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21423   ~ThreadInterruptTest() {}
21424
21425   void RunTest() {
21426     InterruptThread i_thread(this);
21427     i_thread.Start();
21428
21429     sem_.Wait();
21430     CHECK_EQ(kExpectedValue, sem_value_);
21431   }
21432
21433  private:
21434   static const int kExpectedValue = 1;
21435
21436   class InterruptThread : public i::Thread {
21437    public:
21438     explicit InterruptThread(ThreadInterruptTest* test)
21439         : Thread("InterruptThread"), test_(test) {}
21440
21441     virtual void Run() {
21442       struct sigaction action;
21443
21444       // Ensure that we'll enter waiting condition
21445       i::OS::Sleep(100);
21446
21447       // Setup signal handler
21448       memset(&action, 0, sizeof(action));
21449       action.sa_handler = SignalHandler;
21450       sigaction(SIGCHLD, &action, NULL);
21451
21452       // Send signal
21453       kill(getpid(), SIGCHLD);
21454
21455       // Ensure that if wait has returned because of error
21456       i::OS::Sleep(100);
21457
21458       // Set value and signal semaphore
21459       test_->sem_value_ = 1;
21460       test_->sem_.Signal();
21461     }
21462
21463     static void SignalHandler(int signal) {
21464     }
21465
21466    private:
21467      ThreadInterruptTest* test_;
21468   };
21469
21470   i::Semaphore sem_;
21471   volatile int sem_value_;
21472 };
21473
21474
21475 THREADED_TEST(SemaphoreInterruption) {
21476   ThreadInterruptTest().RunTest();
21477 }
21478
21479
21480 #endif  // V8_OS_POSIX
21481
21482
21483 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21484                                      Local<Value> name,
21485                                      v8::AccessType type,
21486                                      Local<Value> data) {
21487   i::PrintF("Named access blocked.\n");
21488   return false;
21489 }
21490
21491
21492 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21493                                      uint32_t key,
21494                                      v8::AccessType type,
21495                                      Local<Value> data) {
21496   i::PrintF("Indexed access blocked.\n");
21497   return false;
21498 }
21499
21500
21501 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21502   CHECK(false);
21503 }
21504
21505
21506 TEST(JSONStringifyAccessCheck) {
21507   v8::V8::Initialize();
21508   v8::Isolate* isolate = CcTest::isolate();
21509   v8::HandleScope scope(isolate);
21510
21511   // Create an ObjectTemplate for global objects and install access
21512   // check callbacks that will block access.
21513   v8::Handle<v8::ObjectTemplate> global_template =
21514       v8::ObjectTemplate::New(isolate);
21515   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21516                                            IndexAccessAlwaysBlocked);
21517
21518   // Create a context and set an x property on it's global object.
21519   LocalContext context0(NULL, global_template);
21520   v8::Handle<v8::Object> global0 = context0->Global();
21521   global0->Set(v8_str("x"), v8_num(42));
21522   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21523
21524   for (int i = 0; i < 2; i++) {
21525     if (i == 1) {
21526       // Install a toJSON function on the second run.
21527       v8::Handle<v8::FunctionTemplate> toJSON =
21528           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21529
21530       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21531     }
21532     // Create a context with a different security token so that the
21533     // failed access check callback will be called on each access.
21534     LocalContext context1(NULL, global_template);
21535     context1->Global()->Set(v8_str("other"), global0);
21536
21537     ExpectString("JSON.stringify(other)", "{}");
21538     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21539                  "{\"a\":{},\"b\":[\"c\"]}");
21540     ExpectString("JSON.stringify([other, 'b', 'c'])",
21541                  "[{},\"b\",\"c\"]");
21542
21543     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21544     array->Set(0, v8_str("a"));
21545     array->Set(1, v8_str("b"));
21546     context1->Global()->Set(v8_str("array"), array);
21547     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21548     array->TurnOnAccessCheck();
21549     ExpectString("JSON.stringify(array)", "[]");
21550     ExpectString("JSON.stringify([array])", "[[]]");
21551     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21552   }
21553 }
21554
21555
21556 bool access_check_fail_thrown = false;
21557 bool catch_callback_called = false;
21558
21559
21560 // Failed access check callback that performs a GC on each invocation.
21561 void FailedAccessCheckThrows(Local<v8::Object> target,
21562                              v8::AccessType type,
21563                              Local<v8::Value> data) {
21564   access_check_fail_thrown = true;
21565   i::PrintF("Access check failed. Error thrown.\n");
21566   CcTest::isolate()->ThrowException(
21567       v8::Exception::Error(v8_str("cross context")));
21568 }
21569
21570
21571 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21572   for (int i = 0; i < args.Length(); i++) {
21573     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21574   }
21575   catch_callback_called = true;
21576 }
21577
21578
21579 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21580   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21581 }
21582
21583
21584 void CheckCorrectThrow(const char* script) {
21585   // Test that the script, when wrapped into a try-catch, triggers the catch
21586   // clause due to failed access check throwing an exception.
21587   // The subsequent try-catch should run without any exception.
21588   access_check_fail_thrown = false;
21589   catch_callback_called = false;
21590   i::ScopedVector<char> source(1024);
21591   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21592   CompileRun(source.start());
21593   CHECK(access_check_fail_thrown);
21594   CHECK(catch_callback_called);
21595
21596   access_check_fail_thrown = false;
21597   catch_callback_called = false;
21598   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21599   CHECK(!access_check_fail_thrown);
21600   CHECK(!catch_callback_called);
21601 }
21602
21603
21604 TEST(AccessCheckThrows) {
21605   i::FLAG_allow_natives_syntax = true;
21606   v8::V8::Initialize();
21607   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21608   v8::Isolate* isolate = CcTest::isolate();
21609   v8::HandleScope scope(isolate);
21610
21611   // Create an ObjectTemplate for global objects and install access
21612   // check callbacks that will block access.
21613   v8::Handle<v8::ObjectTemplate> global_template =
21614       v8::ObjectTemplate::New(isolate);
21615   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21616                                            IndexAccessAlwaysBlocked);
21617
21618   // Create a context and set an x property on it's global object.
21619   LocalContext context0(NULL, global_template);
21620   context0->Global()->Set(v8_str("x"), v8_num(42));
21621   v8::Handle<v8::Object> global0 = context0->Global();
21622
21623   // Create a context with a different security token so that the
21624   // failed access check callback will be called on each access.
21625   LocalContext context1(NULL, global_template);
21626   context1->Global()->Set(v8_str("other"), global0);
21627
21628   v8::Handle<v8::FunctionTemplate> catcher_fun =
21629       v8::FunctionTemplate::New(isolate, CatcherCallback);
21630   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21631
21632   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21633       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21634   context1->Global()->Set(v8_str("has_own_property"),
21635                           has_own_property_fun->GetFunction());
21636
21637   { v8::TryCatch try_catch;
21638     access_check_fail_thrown = false;
21639     CompileRun("other.x;");
21640     CHECK(access_check_fail_thrown);
21641     CHECK(try_catch.HasCaught());
21642   }
21643
21644   CheckCorrectThrow("other.x");
21645   CheckCorrectThrow("other[1]");
21646   CheckCorrectThrow("JSON.stringify(other)");
21647   CheckCorrectThrow("has_own_property(other, 'x')");
21648   CheckCorrectThrow("%GetProperty(other, 'x')");
21649   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21650   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21651   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21652   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21653   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21654   CheckCorrectThrow("%HasProperty(other, 'x')");
21655   CheckCorrectThrow("%HasElement(other, 1)");
21656   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21657   CheckCorrectThrow("%GetPropertyNames(other)");
21658   // PROPERTY_ATTRIBUTES_NONE = 0
21659   CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21660   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21661                         "other, 'x', null, null, 1)");
21662
21663   // Reset the failed access check callback so it does not influence
21664   // the other tests.
21665   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21666 }
21667
21668
21669 THREADED_TEST(Regress256330) {
21670   i::FLAG_allow_natives_syntax = true;
21671   LocalContext context;
21672   v8::HandleScope scope(context->GetIsolate());
21673   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21674   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21675   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21676   CompileRun("\"use strict\"; var o = new Bug;"
21677              "function f(o) { o.x = 10; };"
21678              "f(o); f(o); f(o);"
21679              "%OptimizeFunctionOnNextCall(f);"
21680              "f(o);");
21681   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21682 }
21683
21684
21685 THREADED_TEST(CrankshaftInterceptorSetter) {
21686   i::FLAG_allow_natives_syntax = true;
21687   v8::HandleScope scope(CcTest::isolate());
21688   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21689   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21690   LocalContext env;
21691   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21692   CompileRun("var obj = new Obj;"
21693              // Initialize fields to avoid transitions later.
21694              "obj.age = 0;"
21695              "obj.accessor_age = 42;"
21696              "function setter(i) { this.accessor_age = i; };"
21697              "function getter() { return this.accessor_age; };"
21698              "function setAge(i) { obj.age = i; };"
21699              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21700              "setAge(1);"
21701              "setAge(2);"
21702              "setAge(3);"
21703              "%OptimizeFunctionOnNextCall(setAge);"
21704              "setAge(4);");
21705   // All stores went through the interceptor.
21706   ExpectInt32("obj.interceptor_age", 4);
21707   ExpectInt32("obj.accessor_age", 42);
21708 }
21709
21710
21711 THREADED_TEST(CrankshaftInterceptorGetter) {
21712   i::FLAG_allow_natives_syntax = true;
21713   v8::HandleScope scope(CcTest::isolate());
21714   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21715   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21716   LocalContext env;
21717   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21718   CompileRun("var obj = new Obj;"
21719              // Initialize fields to avoid transitions later.
21720              "obj.age = 1;"
21721              "obj.accessor_age = 42;"
21722              "function getter() { return this.accessor_age; };"
21723              "function getAge() { return obj.interceptor_age; };"
21724              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21725              "getAge();"
21726              "getAge();"
21727              "getAge();"
21728              "%OptimizeFunctionOnNextCall(getAge);");
21729   // Access through interceptor.
21730   ExpectInt32("getAge()", 1);
21731 }
21732
21733
21734 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21735   i::FLAG_allow_natives_syntax = true;
21736   v8::HandleScope scope(CcTest::isolate());
21737   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21738   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21739   LocalContext env;
21740   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21741   CompileRun("var obj = new Obj;"
21742              "obj.__proto__.interceptor_age = 42;"
21743              "obj.age = 100;"
21744              "function getAge() { return obj.interceptor_age; };");
21745   ExpectInt32("getAge();", 100);
21746   ExpectInt32("getAge();", 100);
21747   ExpectInt32("getAge();", 100);
21748   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21749   // Access through interceptor.
21750   ExpectInt32("getAge();", 100);
21751 }
21752
21753
21754 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21755   i::FLAG_allow_natives_syntax = true;
21756   v8::HandleScope scope(CcTest::isolate());
21757   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21758   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21759   LocalContext env;
21760   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21761   CompileRun("var obj = new Obj;"
21762              "obj.age = 100000;"
21763              "function setAge(i) { obj.age = i };"
21764              "setAge(100);"
21765              "setAge(101);"
21766              "setAge(102);"
21767              "%OptimizeFunctionOnNextCall(setAge);"
21768              "setAge(103);");
21769   ExpectInt32("obj.age", 100000);
21770   ExpectInt32("obj.interceptor_age", 103);
21771 }
21772
21773
21774 class RequestInterruptTestBase {
21775  public:
21776   RequestInterruptTestBase()
21777       : env_(),
21778         isolate_(env_->GetIsolate()),
21779         sem_(0),
21780         warmup_(20000),
21781         should_continue_(true) {
21782   }
21783
21784   virtual ~RequestInterruptTestBase() { }
21785
21786   virtual void TestBody() = 0;
21787
21788   void RunTest() {
21789     InterruptThread i_thread(this);
21790     i_thread.Start();
21791
21792     v8::HandleScope handle_scope(isolate_);
21793
21794     TestBody();
21795
21796     isolate_->ClearInterrupt();
21797
21798     // Verify we arrived here because interruptor was called
21799     // not due to a bug causing us to exit the loop too early.
21800     CHECK(!should_continue());
21801   }
21802
21803   void WakeUpInterruptor() {
21804     sem_.Signal();
21805   }
21806
21807   bool should_continue() const { return should_continue_; }
21808
21809   bool ShouldContinue() {
21810     if (warmup_ > 0) {
21811       if (--warmup_ == 0) {
21812         WakeUpInterruptor();
21813       }
21814     }
21815
21816     return should_continue_;
21817   }
21818
21819  protected:
21820   static void ShouldContinueCallback(
21821       const v8::FunctionCallbackInfo<Value>& info) {
21822     RequestInterruptTestBase* test =
21823         reinterpret_cast<RequestInterruptTestBase*>(
21824             info.Data().As<v8::External>()->Value());
21825     info.GetReturnValue().Set(test->ShouldContinue());
21826   }
21827
21828   class InterruptThread : public i::Thread {
21829    public:
21830     explicit InterruptThread(RequestInterruptTestBase* test)
21831         : Thread("RequestInterruptTest"), test_(test) {}
21832
21833     virtual void Run() {
21834       test_->sem_.Wait();
21835       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21836     }
21837
21838     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21839       reinterpret_cast<RequestInterruptTestBase*>(data)->
21840           should_continue_ = false;
21841     }
21842
21843    private:
21844      RequestInterruptTestBase* test_;
21845   };
21846
21847   LocalContext env_;
21848   v8::Isolate* isolate_;
21849   i::Semaphore sem_;
21850   int warmup_;
21851   bool should_continue_;
21852 };
21853
21854
21855 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21856  public:
21857   virtual void TestBody() {
21858     Local<Function> func = Function::New(
21859         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21860     env_->Global()->Set(v8_str("ShouldContinue"), func);
21861
21862     CompileRun("while (ShouldContinue()) { }");
21863   }
21864 };
21865
21866
21867 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21868  public:
21869   virtual void TestBody() {
21870     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21871     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21872     proto->Set(v8_str("shouldContinue"), Function::New(
21873         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21874     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21875
21876     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21877   }
21878 };
21879
21880
21881 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21882  public:
21883   virtual void TestBody() {
21884     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21885     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21886     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21887         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21888     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21889
21890     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21891   }
21892 };
21893
21894
21895 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21896  public:
21897   virtual void TestBody() {
21898     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21899     t->InstanceTemplate()->SetNativeDataProperty(
21900         v8_str("shouldContinue"),
21901         &ShouldContinueNativeGetter,
21902         NULL,
21903         v8::External::New(isolate_, this));
21904     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21905
21906     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21907   }
21908
21909  private:
21910   static void ShouldContinueNativeGetter(
21911       Local<String> property,
21912       const v8::PropertyCallbackInfo<v8::Value>& info) {
21913     RequestInterruptTestBase* test =
21914         reinterpret_cast<RequestInterruptTestBase*>(
21915             info.Data().As<v8::External>()->Value());
21916     info.GetReturnValue().Set(test->ShouldContinue());
21917   }
21918 };
21919
21920
21921 class RequestInterruptTestWithMethodCallAndInterceptor
21922     : public RequestInterruptTestBase {
21923  public:
21924   virtual void TestBody() {
21925     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21926     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21927     proto->Set(v8_str("shouldContinue"), Function::New(
21928         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21929     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21930     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21931
21932     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21933
21934     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21935   }
21936
21937  private:
21938   static void EmptyInterceptor(
21939       Local<String> property,
21940       const v8::PropertyCallbackInfo<v8::Value>& info) {
21941   }
21942 };
21943
21944
21945 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21946  public:
21947   virtual void TestBody() {
21948     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21949         isolate_,
21950         WakeUpInterruptorCallback,
21951         v8::External::New(isolate_, this)));
21952
21953     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21954         isolate_,
21955         ShouldContinueCallback,
21956         v8::External::New(isolate_, this)));
21957
21958     i::FLAG_allow_natives_syntax = true;
21959     CompileRun("function loopish(o) {"
21960                "  var pre = 10;"
21961                "  while (o.abs(1) > 0) {"
21962                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21963                "    if (pre > 0) {"
21964                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
21965                "    }"
21966                "  }"
21967                "}"
21968                "var i = 50;"
21969                "var obj = {abs: function () { return i-- }, x: null};"
21970                "delete obj.x;"
21971                "loopish(obj);"
21972                "%OptimizeFunctionOnNextCall(loopish);"
21973                "loopish(Math);");
21974
21975     i::FLAG_allow_natives_syntax = false;
21976   }
21977
21978  private:
21979   static void WakeUpInterruptorCallback(
21980       const v8::FunctionCallbackInfo<Value>& info) {
21981     if (!info[0]->BooleanValue()) return;
21982
21983     RequestInterruptTestBase* test =
21984         reinterpret_cast<RequestInterruptTestBase*>(
21985             info.Data().As<v8::External>()->Value());
21986     test->WakeUpInterruptor();
21987   }
21988
21989   static void ShouldContinueCallback(
21990       const v8::FunctionCallbackInfo<Value>& info) {
21991     RequestInterruptTestBase* test =
21992         reinterpret_cast<RequestInterruptTestBase*>(
21993             info.Data().As<v8::External>()->Value());
21994     info.GetReturnValue().Set(test->should_continue());
21995   }
21996 };
21997
21998
21999 TEST(RequestInterruptTestWithFunctionCall) {
22000   RequestInterruptTestWithFunctionCall().RunTest();
22001 }
22002
22003
22004 TEST(RequestInterruptTestWithMethodCall) {
22005   RequestInterruptTestWithMethodCall().RunTest();
22006 }
22007
22008
22009 TEST(RequestInterruptTestWithAccessor) {
22010   RequestInterruptTestWithAccessor().RunTest();
22011 }
22012
22013
22014 TEST(RequestInterruptTestWithNativeAccessor) {
22015   RequestInterruptTestWithNativeAccessor().RunTest();
22016 }
22017
22018
22019 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22020   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22021 }
22022
22023
22024 TEST(RequestInterruptTestWithMathAbs) {
22025   RequestInterruptTestWithMathAbs().RunTest();
22026 }
22027
22028
22029 static Local<Value> function_new_expected_env;
22030 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22031   CHECK_EQ(function_new_expected_env, info.Data());
22032   info.GetReturnValue().Set(17);
22033 }
22034
22035
22036 THREADED_TEST(FunctionNew) {
22037   LocalContext env;
22038   v8::Isolate* isolate = env->GetIsolate();
22039   v8::HandleScope scope(isolate);
22040   Local<Object> data = v8::Object::New(isolate);
22041   function_new_expected_env = data;
22042   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22043   env->Global()->Set(v8_str("func"), func);
22044   Local<Value> result = CompileRun("func();");
22045   CHECK_EQ(v8::Integer::New(isolate, 17), result);
22046   // Verify function not cached
22047   int serial_number =
22048       i::Smi::cast(v8::Utils::OpenHandle(*func)
22049           ->shared()->get_api_func_data()->serial_number())->value();
22050   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22051   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22052   i::Handle<i::Object> elm =
22053       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22054   CHECK(elm->IsUndefined());
22055   // Verify that each Function::New creates a new function instance
22056   Local<Object> data2 = v8::Object::New(isolate);
22057   function_new_expected_env = data2;
22058   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22059   CHECK(!func2->IsNull());
22060   CHECK_NE(func, func2);
22061   env->Global()->Set(v8_str("func2"), func2);
22062   Local<Value> result2 = CompileRun("func2();");
22063   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22064 }
22065
22066
22067 TEST(EscapeableHandleScope) {
22068   HandleScope outer_scope(CcTest::isolate());
22069   LocalContext context;
22070   const int runs = 10;
22071   Local<String> values[runs];
22072   for (int i = 0; i < runs; i++) {
22073     v8::EscapableHandleScope inner_scope(CcTest::isolate());
22074     Local<String> value;
22075     if (i != 0) value = v8_str("escape value");
22076     values[i] = inner_scope.Escape(value);
22077   }
22078   for (int i = 0; i < runs; i++) {
22079     Local<String> expected;
22080     if (i != 0) {
22081       CHECK_EQ(v8_str("escape value"), values[i]);
22082     } else {
22083       CHECK(values[i].IsEmpty());
22084     }
22085   }
22086 }
22087
22088
22089 static void SetterWhichExpectsThisAndHolderToDiffer(
22090     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22091   CHECK(info.Holder() != info.This());
22092 }
22093
22094
22095 TEST(Regress239669) {
22096   LocalContext context;
22097   v8::Isolate* isolate = context->GetIsolate();
22098   v8::HandleScope scope(isolate);
22099   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22100   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22101   context->Global()->Set(v8_str("P"), templ->NewInstance());
22102   CompileRun(
22103       "function C1() {"
22104       "  this.x = 23;"
22105       "};"
22106       "C1.prototype = P;"
22107       "for (var i = 0; i < 4; i++ ) {"
22108       "  new C1();"
22109       "}");
22110 }
22111
22112
22113 class ApiCallOptimizationChecker {
22114  private:
22115   static Local<Object> data;
22116   static Local<Object> receiver;
22117   static Local<Object> holder;
22118   static Local<Object> callee;
22119   static int count;
22120
22121   static void OptimizationCallback(
22122       const v8::FunctionCallbackInfo<v8::Value>& info) {
22123     CHECK(callee == info.Callee());
22124     CHECK(data == info.Data());
22125     CHECK(receiver == info.This());
22126     if (info.Length() == 1) {
22127       CHECK_EQ(v8_num(1), info[0]);
22128     }
22129     CHECK(holder == info.Holder());
22130     count++;
22131     info.GetReturnValue().Set(v8_str("returned"));
22132   }
22133
22134   public:
22135     enum SignatureType {
22136       kNoSignature,
22137       kSignatureOnReceiver,
22138       kSignatureOnPrototype
22139     };
22140
22141     void RunAll() {
22142       SignatureType signature_types[] =
22143         {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22144       for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22145         SignatureType signature_type = signature_types[i];
22146         for (int j = 0; j < 2; j++) {
22147           bool global = j == 0;
22148           int key = signature_type +
22149               ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22150           Run(signature_type, global, key);
22151         }
22152       }
22153     }
22154
22155     void Run(SignatureType signature_type, bool global, int key) {
22156       v8::Isolate* isolate = CcTest::isolate();
22157       v8::HandleScope scope(isolate);
22158       // Build a template for signature checks.
22159       Local<v8::ObjectTemplate> signature_template;
22160       Local<v8::Signature> signature;
22161       {
22162         Local<v8::FunctionTemplate> parent_template =
22163           FunctionTemplate::New(isolate);
22164         parent_template->SetHiddenPrototype(true);
22165         Local<v8::FunctionTemplate> function_template
22166             = FunctionTemplate::New(isolate);
22167         function_template->Inherit(parent_template);
22168         switch (signature_type) {
22169           case kNoSignature:
22170             break;
22171           case kSignatureOnReceiver:
22172             signature = v8::Signature::New(isolate, function_template);
22173             break;
22174           case kSignatureOnPrototype:
22175             signature = v8::Signature::New(isolate, parent_template);
22176             break;
22177         }
22178         signature_template = function_template->InstanceTemplate();
22179       }
22180       // Global object must pass checks.
22181       Local<v8::Context> context =
22182           v8::Context::New(isolate, NULL, signature_template);
22183       v8::Context::Scope context_scope(context);
22184       // Install regular object that can pass signature checks.
22185       Local<Object> function_receiver = signature_template->NewInstance();
22186       context->Global()->Set(v8_str("function_receiver"), function_receiver);
22187       // Get the holder objects.
22188       Local<Object> inner_global =
22189           Local<Object>::Cast(context->Global()->GetPrototype());
22190       // Install functions on hidden prototype object if there is one.
22191       data = Object::New(isolate);
22192       Local<FunctionTemplate> function_template = FunctionTemplate::New(
22193           isolate, OptimizationCallback, data, signature);
22194       Local<Function> function = function_template->GetFunction();
22195       Local<Object> global_holder = inner_global;
22196       Local<Object> function_holder = function_receiver;
22197       if (signature_type == kSignatureOnPrototype) {
22198         function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22199         global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22200       }
22201       global_holder->Set(v8_str("g_f"), function);
22202       global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22203       function_holder->Set(v8_str("f"), function);
22204       function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22205       // Initialize expected values.
22206       callee = function;
22207       count = 0;
22208       if (global) {
22209         receiver = context->Global();
22210         holder = inner_global;
22211       } else {
22212         holder = function_receiver;
22213         // If not using a signature, add something else to the prototype chain
22214         // to test the case that holder != receiver
22215         if (signature_type == kNoSignature) {
22216           receiver = Local<Object>::Cast(CompileRun(
22217               "var receiver_subclass = {};\n"
22218               "receiver_subclass.__proto__ = function_receiver;\n"
22219               "receiver_subclass"));
22220         } else {
22221           receiver = Local<Object>::Cast(CompileRun(
22222             "var receiver_subclass = function_receiver;\n"
22223             "receiver_subclass"));
22224         }
22225       }
22226       // With no signature, the holder is not set.
22227       if (signature_type == kNoSignature) holder = receiver;
22228       // build wrap_function
22229       i::ScopedVector<char> wrap_function(200);
22230       if (global) {
22231         i::OS::SNPrintF(
22232             wrap_function,
22233             "function wrap_f_%d() { var f = g_f; return f(); }\n"
22234             "function wrap_get_%d() { return this.g_acc; }\n"
22235             "function wrap_set_%d() { return this.g_acc = 1; }\n",
22236             key, key, key);
22237       } else {
22238         i::OS::SNPrintF(
22239             wrap_function,
22240             "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22241             "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22242             "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22243             key, key, key);
22244       }
22245       // build source string
22246       i::ScopedVector<char> source(1000);
22247       i::OS::SNPrintF(
22248           source,
22249           "%s\n"  // wrap functions
22250           "function wrap_f() { return wrap_f_%d(); }\n"
22251           "function wrap_get() { return wrap_get_%d(); }\n"
22252           "function wrap_set() { return wrap_set_%d(); }\n"
22253           "check = function(returned) {\n"
22254           "  if (returned !== 'returned') { throw returned; }\n"
22255           "}\n"
22256           "\n"
22257           "check(wrap_f());\n"
22258           "check(wrap_f());\n"
22259           "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22260           "check(wrap_f());\n"
22261           "\n"
22262           "check(wrap_get());\n"
22263           "check(wrap_get());\n"
22264           "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22265           "check(wrap_get());\n"
22266           "\n"
22267           "check = function(returned) {\n"
22268           "  if (returned !== 1) { throw returned; }\n"
22269           "}\n"
22270           "check(wrap_set());\n"
22271           "check(wrap_set());\n"
22272           "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22273           "check(wrap_set());\n",
22274           wrap_function.start(), key, key, key, key, key, key);
22275       v8::TryCatch try_catch;
22276       CompileRun(source.start());
22277       ASSERT(!try_catch.HasCaught());
22278       CHECK_EQ(9, count);
22279     }
22280 };
22281
22282
22283 Local<Object> ApiCallOptimizationChecker::data;
22284 Local<Object> ApiCallOptimizationChecker::receiver;
22285 Local<Object> ApiCallOptimizationChecker::holder;
22286 Local<Object> ApiCallOptimizationChecker::callee;
22287 int ApiCallOptimizationChecker::count = 0;
22288
22289
22290 TEST(TestFunctionCallOptimization) {
22291   i::FLAG_allow_natives_syntax = true;
22292   ApiCallOptimizationChecker checker;
22293   checker.RunAll();
22294 }
22295
22296
22297 static const char* last_event_message;
22298 static int last_event_status;
22299 void StoringEventLoggerCallback(const char* message, int status) {
22300     last_event_message = message;
22301     last_event_status = status;
22302 }
22303
22304
22305 TEST(EventLogging) {
22306   v8::Isolate* isolate = CcTest::isolate();
22307   isolate->SetEventLogger(StoringEventLoggerCallback);
22308   v8::internal::HistogramTimer* histogramTimer =
22309       new v8::internal::HistogramTimer(
22310           "V8.Test", 0, 10000, 50,
22311           reinterpret_cast<v8::internal::Isolate*>(isolate));
22312   histogramTimer->Start();
22313   CHECK_EQ("V8.Test", last_event_message);
22314   CHECK_EQ(0, last_event_status);
22315   histogramTimer->Stop();
22316   CHECK_EQ("V8.Test", last_event_message);
22317   CHECK_EQ(1, last_event_status);
22318 }
22319
22320
22321 TEST(Promises) {
22322   i::FLAG_harmony_promises = true;
22323
22324   LocalContext context;
22325   v8::Isolate* isolate = context->GetIsolate();
22326   v8::HandleScope scope(isolate);
22327   Handle<Object> global = context->Global();
22328
22329   // Creation.
22330   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22331   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22332   Handle<v8::Promise> p = pr->GetPromise();
22333   Handle<v8::Promise> r = rr->GetPromise();
22334
22335   // IsPromise predicate.
22336   CHECK(p->IsPromise());
22337   CHECK(r->IsPromise());
22338   Handle<Value> o = v8::Object::New(isolate);
22339   CHECK(!o->IsPromise());
22340
22341   // Resolution and rejection.
22342   pr->Resolve(v8::Integer::New(isolate, 1));
22343   CHECK(p->IsPromise());
22344   rr->Reject(v8::Integer::New(isolate, 2));
22345   CHECK(r->IsPromise());
22346
22347   // Chaining non-pending promises.
22348   CompileRun(
22349       "var x1 = 0;\n"
22350       "var x2 = 0;\n"
22351       "function f1(x) { x1 = x; return x+1 };\n"
22352       "function f2(x) { x2 = x; return x+1 };\n");
22353   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22354   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22355
22356   p->Chain(f1);
22357   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22358   isolate->RunMicrotasks();
22359   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22360
22361   p->Catch(f2);
22362   isolate->RunMicrotasks();
22363   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22364
22365   r->Catch(f2);
22366   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22367   isolate->RunMicrotasks();
22368   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22369
22370   r->Chain(f1);
22371   isolate->RunMicrotasks();
22372   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22373
22374   // Chaining pending promises.
22375   CompileRun("x1 = x2 = 0;");
22376   pr = v8::Promise::Resolver::New(isolate);
22377   rr = v8::Promise::Resolver::New(isolate);
22378
22379   pr->GetPromise()->Chain(f1);
22380   rr->GetPromise()->Catch(f2);
22381   isolate->RunMicrotasks();
22382   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22383   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22384
22385   pr->Resolve(v8::Integer::New(isolate, 1));
22386   rr->Reject(v8::Integer::New(isolate, 2));
22387   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22388   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22389
22390   isolate->RunMicrotasks();
22391   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22392   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22393
22394   // Multi-chaining.
22395   CompileRun("x1 = x2 = 0;");
22396   pr = v8::Promise::Resolver::New(isolate);
22397   pr->GetPromise()->Chain(f1)->Chain(f2);
22398   pr->Resolve(v8::Integer::New(isolate, 3));
22399   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22400   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22401   isolate->RunMicrotasks();
22402   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22403   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22404
22405   CompileRun("x1 = x2 = 0;");
22406   rr = v8::Promise::Resolver::New(isolate);
22407   rr->GetPromise()->Catch(f1)->Chain(f2);
22408   rr->Reject(v8::Integer::New(isolate, 3));
22409   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22410   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22411   isolate->RunMicrotasks();
22412   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22413   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22414 }
22415
22416
22417 TEST(DisallowJavascriptExecutionScope) {
22418   LocalContext context;
22419   v8::Isolate* isolate = context->GetIsolate();
22420   v8::HandleScope scope(isolate);
22421   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22422       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22423   CompileRun("2+2");
22424 }
22425
22426
22427 TEST(AllowJavascriptExecutionScope) {
22428   LocalContext context;
22429   v8::Isolate* isolate = context->GetIsolate();
22430   v8::HandleScope scope(isolate);
22431   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22432       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22433   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22434       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22435   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22436     CompileRun("1+1");
22437   }
22438 }
22439
22440
22441 TEST(ThrowOnJavascriptExecution) {
22442   LocalContext context;
22443   v8::Isolate* isolate = context->GetIsolate();
22444   v8::HandleScope scope(isolate);
22445   v8::TryCatch try_catch;
22446   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22447       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22448   CompileRun("1+1");
22449   CHECK(try_catch.HasCaught());
22450 }
22451
22452
22453 TEST(Regress354123) {
22454   LocalContext current;
22455   v8::Isolate* isolate = current->GetIsolate();
22456   v8::HandleScope scope(isolate);
22457
22458   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22459   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22460   current->Global()->Set(v8_str("friend"), templ->NewInstance());
22461
22462   // Test access using __proto__ from the prototype chain.
22463   named_access_count = 0;
22464   CompileRun("friend.__proto__ = {};");
22465   CHECK_EQ(2, named_access_count);
22466   CompileRun("friend.__proto__;");
22467   CHECK_EQ(4, named_access_count);
22468
22469   // Test access using __proto__ as a hijacked function (A).
22470   named_access_count = 0;
22471   CompileRun("var p = Object.prototype;"
22472              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22473              "f.call(friend, {});");
22474   CHECK_EQ(1, named_access_count);
22475   CompileRun("var p = Object.prototype;"
22476              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22477              "f.call(friend);");
22478   CHECK_EQ(2, named_access_count);
22479
22480   // Test access using __proto__ as a hijacked function (B).
22481   named_access_count = 0;
22482   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22483              "f.call(friend, {});");
22484   CHECK_EQ(1, named_access_count);
22485   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22486              "f.call(friend);");
22487   CHECK_EQ(2, named_access_count);
22488
22489   // Test access using Object.setPrototypeOf reflective method.
22490   named_access_count = 0;
22491   CompileRun("Object.setPrototypeOf(friend, {});");
22492   CHECK_EQ(1, named_access_count);
22493   CompileRun("Object.getPrototypeOf(friend);");
22494   CHECK_EQ(2, named_access_count);
22495 }
22496
22497
22498 TEST(CaptureStackTraceForStackOverflow) {
22499   v8::internal::FLAG_stack_size = 150;
22500   LocalContext current;
22501   v8::Isolate* isolate = current->GetIsolate();
22502   v8::HandleScope scope(isolate);
22503   V8::SetCaptureStackTraceForUncaughtExceptions(
22504       true, 10, v8::StackTrace::kDetailed);
22505   v8::TryCatch try_catch;
22506   CompileRun("(function f(x) { f(x+1); })(0)");
22507   CHECK(try_catch.HasCaught());
22508 }