Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <string>
31 #include <map>
32
33 #include "v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "api.h"
40 #include "arguments.h"
41 #include "cctest.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
45 #include "isolate.h"
46 #include "objects.h"
47 #include "parser.h"
48 #include "platform.h"
49 #include "snapshot.h"
50 #include "unicode-inl.h"
51 #include "utils.h"
52 #include "vm-state.h"
53
54 static const bool kLogThreading = false;
55
56 using ::v8::Boolean;
57 using ::v8::BooleanObject;
58 using ::v8::Context;
59 using ::v8::Extension;
60 using ::v8::Function;
61 using ::v8::FunctionTemplate;
62 using ::v8::Handle;
63 using ::v8::HandleScope;
64 using ::v8::Local;
65 using ::v8::Message;
66 using ::v8::MessageCallback;
67 using ::v8::Object;
68 using ::v8::ObjectTemplate;
69 using ::v8::Persistent;
70 using ::v8::Script;
71 using ::v8::StackTrace;
72 using ::v8::String;
73 using ::v8::TryCatch;
74 using ::v8::Undefined;
75 using ::v8::UniqueId;
76 using ::v8::V8;
77 using ::v8::Value;
78
79
80 #define THREADED_PROFILED_TEST(Name)                                 \
81   static void Test##Name();                                          \
82   TEST(Name##WithProfiler) {                                         \
83     RunWithProfiler(&Test##Name);                                    \
84   }                                                                  \
85   THREADED_TEST(Name)
86
87
88 void RunWithProfiler(void (*test)()) {
89   LocalContext env;
90   v8::HandleScope scope(env->GetIsolate());
91   v8::Local<v8::String> profile_name =
92       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
93   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
94
95   cpu_profiler->StartCpuProfiling(profile_name);
96   (*test)();
97   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
98 }
99
100
101 static void ExpectString(const char* code, const char* expected) {
102   Local<Value> result = CompileRun(code);
103   CHECK(result->IsString());
104   String::Utf8Value utf8(result);
105   CHECK_EQ(expected, *utf8);
106 }
107
108
109 static void ExpectInt32(const char* code, int expected) {
110   Local<Value> result = CompileRun(code);
111   CHECK(result->IsInt32());
112   CHECK_EQ(expected, result->Int32Value());
113 }
114
115
116 static void ExpectBoolean(const char* code, bool expected) {
117   Local<Value> result = CompileRun(code);
118   CHECK(result->IsBoolean());
119   CHECK_EQ(expected, result->BooleanValue());
120 }
121
122
123 static void ExpectTrue(const char* code) {
124   ExpectBoolean(code, true);
125 }
126
127
128 static void ExpectFalse(const char* code) {
129   ExpectBoolean(code, false);
130 }
131
132
133 static void ExpectObject(const char* code, Local<Value> expected) {
134   Local<Value> result = CompileRun(code);
135   CHECK(result->Equals(expected));
136 }
137
138
139 static void ExpectUndefined(const char* code) {
140   Local<Value> result = CompileRun(code);
141   CHECK(result->IsUndefined());
142 }
143
144
145 static int signature_callback_count;
146 static Local<Value> signature_expected_receiver;
147 static void IncrementingSignatureCallback(
148     const v8::FunctionCallbackInfo<v8::Value>& args) {
149   ApiTestFuzzer::Fuzz();
150   signature_callback_count++;
151   CHECK_EQ(signature_expected_receiver, args.Holder());
152   CHECK_EQ(signature_expected_receiver, args.This());
153   v8::Handle<v8::Array> result =
154       v8::Array::New(args.GetIsolate(), args.Length());
155   for (int i = 0; i < args.Length(); i++)
156     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
157   args.GetReturnValue().Set(result);
158 }
159
160
161 static void SignatureCallback(
162     const v8::FunctionCallbackInfo<v8::Value>& args) {
163   ApiTestFuzzer::Fuzz();
164   v8::Handle<v8::Array> result =
165       v8::Array::New(args.GetIsolate(), args.Length());
166   for (int i = 0; i < args.Length(); i++) {
167     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
168   }
169   args.GetReturnValue().Set(result);
170 }
171
172
173 // Tests that call v8::V8::Dispose() cannot be threaded.
174 TEST(InitializeAndDisposeOnce) {
175   CHECK(v8::V8::Initialize());
176   CHECK(v8::V8::Dispose());
177 }
178
179
180 // Tests that call v8::V8::Dispose() cannot be threaded.
181 TEST(InitializeAndDisposeMultiple) {
182   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
183   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
184   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
185   // TODO(mstarzinger): This should fail gracefully instead of asserting.
186   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
187   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
188 }
189
190
191 THREADED_TEST(Handles) {
192   v8::HandleScope scope(CcTest::isolate());
193   Local<Context> local_env;
194   {
195     LocalContext env;
196     local_env = env.local();
197   }
198
199   // Local context should still be live.
200   CHECK(!local_env.IsEmpty());
201   local_env->Enter();
202
203   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
204   CHECK(!undef.IsEmpty());
205   CHECK(undef->IsUndefined());
206
207   const char* c_source = "1 + 2 + 3";
208   Local<String> source = String::NewFromUtf8(CcTest::isolate(), c_source);
209   Local<Script> script = Script::Compile(source);
210   CHECK_EQ(6, script->Run()->Int32Value());
211
212   local_env->Exit();
213 }
214
215
216 THREADED_TEST(IsolateOfContext) {
217   v8::HandleScope scope(CcTest::isolate());
218   v8::Handle<Context> env = Context::New(CcTest::isolate());
219
220   CHECK(!env->GetIsolate()->InContext());
221   CHECK(env->GetIsolate() == CcTest::isolate());
222   env->Enter();
223   CHECK(env->GetIsolate()->InContext());
224   CHECK(env->GetIsolate() == CcTest::isolate());
225   env->Exit();
226   CHECK(!env->GetIsolate()->InContext());
227   CHECK(env->GetIsolate() == CcTest::isolate());
228 }
229
230
231 static void TestSignature(const char* loop_js, Local<Value> receiver) {
232   i::ScopedVector<char> source(200);
233   i::OS::SNPrintF(source,
234                   "for (var i = 0; i < 10; i++) {"
235                   "  %s"
236                   "}",
237                   loop_js);
238   signature_callback_count = 0;
239   signature_expected_receiver = receiver;
240   bool expected_to_throw = receiver.IsEmpty();
241   v8::TryCatch try_catch;
242   CompileRun(source.start());
243   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
244   if (!expected_to_throw) {
245     CHECK_EQ(10, signature_callback_count);
246   } else {
247     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
248              try_catch.Exception()->ToString());
249   }
250 }
251
252
253 THREADED_TEST(ReceiverSignature) {
254   LocalContext env;
255   v8::Isolate* isolate = env->GetIsolate();
256   v8::HandleScope scope(isolate);
257   // Setup templates.
258   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
259   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
260   v8::Handle<v8::FunctionTemplate> callback_sig =
261       v8::FunctionTemplate::New(
262           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
263   v8::Handle<v8::FunctionTemplate> callback =
264       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
265   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
266   sub_fun->Inherit(fun);
267   v8::Handle<v8::FunctionTemplate> unrel_fun =
268       v8::FunctionTemplate::New(isolate);
269   // Install properties.
270   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
271   fun_proto->Set(v8_str("prop_sig"), callback_sig);
272   fun_proto->Set(v8_str("prop"), callback);
273   fun_proto->SetAccessorProperty(
274       v8_str("accessor_sig"), callback_sig, callback_sig);
275   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
276   // Instantiate templates.
277   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
278   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
279   // Setup global variables.
280   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
281   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
282   env->Global()->Set(v8_str("fun_instance"), fun_instance);
283   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
284   CompileRun(
285       "var accessor_sig_key = 'accessor_sig';"
286       "var accessor_key = 'accessor';"
287       "var prop_sig_key = 'prop_sig';"
288       "var prop_key = 'prop';"
289       ""
290       "function copy_props(obj) {"
291       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
292       "  var source = Fun.prototype;"
293       "  for (var i in keys) {"
294       "    var key = keys[i];"
295       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
296       "    Object.defineProperty(obj, key, desc);"
297       "  }"
298       "}"
299       ""
300       "var obj = {};"
301       "copy_props(obj);"
302       "var unrel = new UnrelFun();"
303       "copy_props(unrel);");
304   // Test with and without ICs
305   const char* test_objects[] = {
306       "fun_instance", "sub_fun_instance", "obj", "unrel" };
307   unsigned bad_signature_start_offset = 2;
308   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
309     i::ScopedVector<char> source(200);
310     i::OS::SNPrintF(
311         source, "var test_object = %s; test_object", test_objects[i]);
312     Local<Value> test_object = CompileRun(source.start());
313     TestSignature("test_object.prop();", test_object);
314     TestSignature("test_object.accessor;", test_object);
315     TestSignature("test_object[accessor_key];", test_object);
316     TestSignature("test_object.accessor = 1;", test_object);
317     TestSignature("test_object[accessor_key] = 1;", test_object);
318     if (i >= bad_signature_start_offset) test_object = Local<Value>();
319     TestSignature("test_object.prop_sig();", test_object);
320     TestSignature("test_object.accessor_sig;", test_object);
321     TestSignature("test_object[accessor_sig_key];", test_object);
322     TestSignature("test_object.accessor_sig = 1;", test_object);
323     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
324   }
325 }
326
327
328 THREADED_TEST(ArgumentSignature) {
329   LocalContext env;
330   v8::Isolate* isolate = env->GetIsolate();
331   v8::HandleScope scope(isolate);
332   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
333   cons->SetClassName(v8_str("Cons"));
334   v8::Handle<v8::Signature> sig = v8::Signature::New(
335       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
336   v8::Handle<v8::FunctionTemplate> fun =
337       v8::FunctionTemplate::New(isolate,
338                                 SignatureCallback,
339                                 v8::Handle<Value>(),
340                                 sig);
341   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
342   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
343
344   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
345   CHECK(value1->IsTrue());
346
347   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
348   CHECK(value2->IsTrue());
349
350   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
351   CHECK(value3->IsTrue());
352
353   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
354   cons1->SetClassName(v8_str("Cons1"));
355   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
356   cons2->SetClassName(v8_str("Cons2"));
357   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
358   cons3->SetClassName(v8_str("Cons3"));
359
360   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
361   v8::Handle<v8::Signature> wsig = v8::Signature::New(
362       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
363   v8::Handle<v8::FunctionTemplate> fun2 =
364       v8::FunctionTemplate::New(isolate,
365                                 SignatureCallback,
366                                 v8::Handle<Value>(),
367                                 wsig);
368
369   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
370   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
371   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
372   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
373   v8::Handle<Value> value4 = CompileRun(
374       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
375       "'[object Cons1],[object Cons2],[object Cons3]'");
376   CHECK(value4->IsTrue());
377
378   v8::Handle<Value> value5 = CompileRun(
379       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
380   CHECK(value5->IsTrue());
381
382   v8::Handle<Value> value6 = CompileRun(
383       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
384   CHECK(value6->IsTrue());
385
386   v8::Handle<Value> value7 = CompileRun(
387       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
388       "'[object Cons1],[object Cons2],[object Cons3],d';");
389   CHECK(value7->IsTrue());
390
391   v8::Handle<Value> value8 = CompileRun(
392       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
393   CHECK(value8->IsTrue());
394 }
395
396
397 THREADED_TEST(HulIgennem) {
398   LocalContext env;
399   v8::Isolate* isolate = env->GetIsolate();
400   v8::HandleScope scope(isolate);
401   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
402   Local<String> undef_str = undef->ToString();
403   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
404   undef_str->WriteUtf8(value);
405   CHECK_EQ(0, strcmp(value, "undefined"));
406   i::DeleteArray(value);
407 }
408
409
410 THREADED_TEST(Access) {
411   LocalContext env;
412   v8::Isolate* isolate = env->GetIsolate();
413   v8::HandleScope scope(isolate);
414   Local<v8::Object> obj = v8::Object::New(isolate);
415   Local<Value> foo_before = obj->Get(v8_str("foo"));
416   CHECK(foo_before->IsUndefined());
417   Local<String> bar_str = v8_str("bar");
418   obj->Set(v8_str("foo"), bar_str);
419   Local<Value> foo_after = obj->Get(v8_str("foo"));
420   CHECK(!foo_after->IsUndefined());
421   CHECK(foo_after->IsString());
422   CHECK_EQ(bar_str, foo_after);
423 }
424
425
426 THREADED_TEST(AccessElement) {
427   LocalContext env;
428   v8::HandleScope scope(env->GetIsolate());
429   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
430   Local<Value> before = obj->Get(1);
431   CHECK(before->IsUndefined());
432   Local<String> bar_str = v8_str("bar");
433   obj->Set(1, bar_str);
434   Local<Value> after = obj->Get(1);
435   CHECK(!after->IsUndefined());
436   CHECK(after->IsString());
437   CHECK_EQ(bar_str, after);
438
439   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
440   CHECK_EQ(v8_str("a"), value->Get(0));
441   CHECK_EQ(v8_str("b"), value->Get(1));
442 }
443
444
445 THREADED_TEST(Script) {
446   LocalContext env;
447   v8::HandleScope scope(env->GetIsolate());
448   const char* c_source = "1 + 2 + 3";
449   Local<String> source = String::NewFromUtf8(env->GetIsolate(), c_source);
450   Local<Script> script = Script::Compile(source);
451   CHECK_EQ(6, script->Run()->Int32Value());
452 }
453
454
455 static uint16_t* AsciiToTwoByteString(const char* source) {
456   int array_length = i::StrLength(source) + 1;
457   uint16_t* converted = i::NewArray<uint16_t>(array_length);
458   for (int i = 0; i < array_length; i++) converted[i] = source[i];
459   return converted;
460 }
461
462
463 class TestResource: public String::ExternalStringResource {
464  public:
465   explicit TestResource(uint16_t* data, int* counter = NULL)
466     : data_(data), length_(0), counter_(counter) {
467     while (data[length_]) ++length_;
468   }
469
470   ~TestResource() {
471     i::DeleteArray(data_);
472     if (counter_ != NULL) ++*counter_;
473   }
474
475   const uint16_t* data() const {
476     return data_;
477   }
478
479   size_t length() const {
480     return length_;
481   }
482  private:
483   uint16_t* data_;
484   size_t length_;
485   int* counter_;
486 };
487
488
489 class TestAsciiResource: public String::ExternalAsciiStringResource {
490  public:
491   explicit TestAsciiResource(const char* data, int* counter = NULL)
492     : data_(data), length_(strlen(data)), counter_(counter) { }
493
494   ~TestAsciiResource() {
495     i::DeleteArray(data_);
496     if (counter_ != NULL) ++*counter_;
497   }
498
499   const char* data() const {
500     return data_;
501   }
502
503   size_t length() const {
504     return length_;
505   }
506  private:
507   const char* data_;
508   size_t length_;
509   int* counter_;
510 };
511
512
513 THREADED_TEST(ScriptUsingStringResource) {
514   int dispose_count = 0;
515   const char* c_source = "1 + 2 * 3";
516   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
517   {
518     LocalContext env;
519     v8::HandleScope scope(env->GetIsolate());
520     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
521     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
522     Local<Script> script = Script::Compile(source);
523     Local<Value> value = script->Run();
524     CHECK(value->IsNumber());
525     CHECK_EQ(7, value->Int32Value());
526     CHECK(source->IsExternal());
527     CHECK_EQ(resource,
528              static_cast<TestResource*>(source->GetExternalStringResource()));
529     String::Encoding encoding = String::UNKNOWN_ENCODING;
530     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
531              source->GetExternalStringResourceBase(&encoding));
532     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
533     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
534     CHECK_EQ(0, dispose_count);
535   }
536   CcTest::i_isolate()->compilation_cache()->Clear();
537   CcTest::heap()->CollectAllAvailableGarbage();
538   CHECK_EQ(1, dispose_count);
539 }
540
541
542 THREADED_TEST(ScriptUsingAsciiStringResource) {
543   int dispose_count = 0;
544   const char* c_source = "1 + 2 * 3";
545   {
546     LocalContext env;
547     v8::HandleScope scope(env->GetIsolate());
548     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
549                                                         &dispose_count);
550     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
551     CHECK(source->IsExternalAscii());
552     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
553              source->GetExternalAsciiStringResource());
554     String::Encoding encoding = String::UNKNOWN_ENCODING;
555     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
556              source->GetExternalStringResourceBase(&encoding));
557     CHECK_EQ(String::ASCII_ENCODING, encoding);
558     Local<Script> script = Script::Compile(source);
559     Local<Value> value = script->Run();
560     CHECK(value->IsNumber());
561     CHECK_EQ(7, value->Int32Value());
562     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
563     CHECK_EQ(0, dispose_count);
564   }
565   CcTest::i_isolate()->compilation_cache()->Clear();
566   CcTest::heap()->CollectAllAvailableGarbage();
567   CHECK_EQ(1, dispose_count);
568 }
569
570
571 THREADED_TEST(ScriptMakingExternalString) {
572   int dispose_count = 0;
573   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
574   {
575     LocalContext env;
576     v8::HandleScope scope(env->GetIsolate());
577     Local<String> source =
578         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
579     // Trigger GCs so that the newly allocated string moves to old gen.
580     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
581     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
582     CHECK_EQ(source->IsExternal(), false);
583     CHECK_EQ(source->IsExternalAscii(), false);
584     String::Encoding encoding = String::UNKNOWN_ENCODING;
585     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
586     CHECK_EQ(String::ASCII_ENCODING, encoding);
587     bool success = source->MakeExternal(new TestResource(two_byte_source,
588                                                          &dispose_count));
589     CHECK(success);
590     Local<Script> script = Script::Compile(source);
591     Local<Value> value = script->Run();
592     CHECK(value->IsNumber());
593     CHECK_EQ(7, value->Int32Value());
594     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
595     CHECK_EQ(0, dispose_count);
596   }
597   CcTest::i_isolate()->compilation_cache()->Clear();
598   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
599   CHECK_EQ(1, dispose_count);
600 }
601
602
603 THREADED_TEST(ScriptMakingExternalAsciiString) {
604   int dispose_count = 0;
605   const char* c_source = "1 + 2 * 3";
606   {
607     LocalContext env;
608     v8::HandleScope scope(env->GetIsolate());
609     Local<String> source = v8_str(c_source);
610     // Trigger GCs so that the newly allocated string moves to old gen.
611     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
612     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
613     bool success = source->MakeExternal(
614         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
615     CHECK(success);
616     Local<Script> script = Script::Compile(source);
617     Local<Value> value = script->Run();
618     CHECK(value->IsNumber());
619     CHECK_EQ(7, value->Int32Value());
620     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
621     CHECK_EQ(0, dispose_count);
622   }
623   CcTest::i_isolate()->compilation_cache()->Clear();
624   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
625   CHECK_EQ(1, dispose_count);
626 }
627
628
629 TEST(MakingExternalStringConditions) {
630   LocalContext env;
631   v8::HandleScope scope(env->GetIsolate());
632
633   // Free some space in the new space so that we can check freshness.
634   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
635   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
636
637   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
638   Local<String> small_string =
639       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
640   i::DeleteArray(two_byte_string);
641
642   // We should refuse to externalize newly created small string.
643   CHECK(!small_string->CanMakeExternal());
644   // Trigger GCs so that the newly allocated string moves to old gen.
645   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
646   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
647   // Old space strings should be accepted.
648   CHECK(small_string->CanMakeExternal());
649
650   two_byte_string = AsciiToTwoByteString("small string 2");
651   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
652   i::DeleteArray(two_byte_string);
653
654   // We should refuse externalizing newly created small string.
655   CHECK(!small_string->CanMakeExternal());
656   for (int i = 0; i < 100; i++) {
657     String::Value value(small_string);
658   }
659   // Frequently used strings should be accepted.
660   CHECK(small_string->CanMakeExternal());
661
662   const int buf_size = 10 * 1024;
663   char* buf = i::NewArray<char>(buf_size);
664   memset(buf, 'a', buf_size);
665   buf[buf_size - 1] = '\0';
666
667   two_byte_string = AsciiToTwoByteString(buf);
668   Local<String> large_string =
669       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
670   i::DeleteArray(buf);
671   i::DeleteArray(two_byte_string);
672   // Large strings should be immediately accepted.
673   CHECK(large_string->CanMakeExternal());
674 }
675
676
677 TEST(MakingExternalAsciiStringConditions) {
678   LocalContext env;
679   v8::HandleScope scope(env->GetIsolate());
680
681   // Free some space in the new space so that we can check freshness.
682   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
683   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
684
685   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
686   // We should refuse to externalize newly created small string.
687   CHECK(!small_string->CanMakeExternal());
688   // Trigger GCs so that the newly allocated string moves to old gen.
689   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
690   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
691   // Old space strings should be accepted.
692   CHECK(small_string->CanMakeExternal());
693
694   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
695   // We should refuse externalizing newly created small string.
696   CHECK(!small_string->CanMakeExternal());
697   for (int i = 0; i < 100; i++) {
698     String::Value value(small_string);
699   }
700   // Frequently used strings should be accepted.
701   CHECK(small_string->CanMakeExternal());
702
703   const int buf_size = 10 * 1024;
704   char* buf = i::NewArray<char>(buf_size);
705   memset(buf, 'a', buf_size);
706   buf[buf_size - 1] = '\0';
707   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
708   i::DeleteArray(buf);
709   // Large strings should be immediately accepted.
710   CHECK(large_string->CanMakeExternal());
711 }
712
713
714 TEST(MakingExternalUnalignedAsciiString) {
715   LocalContext env;
716   v8::HandleScope scope(env->GetIsolate());
717
718   CompileRun("function cons(a, b) { return a + b; }"
719              "function slice(a) { return a.substring(1); }");
720   // Create a cons string that will land in old pointer space.
721   Local<String> cons = Local<String>::Cast(CompileRun(
722       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
723   // Create a sliced string that will land in old pointer space.
724   Local<String> slice = Local<String>::Cast(CompileRun(
725       "slice('abcdefghijklmnopqrstuvwxyz');"));
726
727   // Trigger GCs so that the newly allocated string moves to old gen.
728   SimulateFullSpace(CcTest::heap()->old_pointer_space());
729   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
730   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
731
732   // Turn into external string with unaligned resource data.
733   int dispose_count = 0;
734   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
735   bool success = cons->MakeExternal(
736       new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
737   CHECK(success);
738   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
739   success = slice->MakeExternal(
740       new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
741   CHECK(success);
742
743   // Trigger GCs and force evacuation.
744   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
745   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
746 }
747
748
749 THREADED_TEST(UsingExternalString) {
750   i::Factory* factory = CcTest::i_isolate()->factory();
751   {
752     v8::HandleScope scope(CcTest::isolate());
753     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
754     Local<String> string = String::NewExternal(
755         CcTest::isolate(), new TestResource(two_byte_string));
756     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
757     // Trigger GCs so that the newly allocated string moves to old gen.
758     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
759     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
760     i::Handle<i::String> isymbol =
761         factory->InternalizedStringFromString(istring);
762     CHECK(isymbol->IsInternalizedString());
763   }
764   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
765   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
766 }
767
768
769 THREADED_TEST(UsingExternalAsciiString) {
770   i::Factory* factory = CcTest::i_isolate()->factory();
771   {
772     v8::HandleScope scope(CcTest::isolate());
773     const char* one_byte_string = "test string";
774     Local<String> string = String::NewExternal(
775         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
776     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
777     // Trigger GCs so that the newly allocated string moves to old gen.
778     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
779     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
780     i::Handle<i::String> isymbol =
781         factory->InternalizedStringFromString(istring);
782     CHECK(isymbol->IsInternalizedString());
783   }
784   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
785   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
786 }
787
788
789 THREADED_TEST(ScavengeExternalString) {
790   i::FLAG_stress_compaction = false;
791   i::FLAG_gc_global = false;
792   int dispose_count = 0;
793   bool in_new_space = false;
794   {
795     v8::HandleScope scope(CcTest::isolate());
796     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
797     Local<String> string = String::NewExternal(
798         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
799     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
800     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
801     in_new_space = CcTest::heap()->InNewSpace(*istring);
802     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
803     CHECK_EQ(0, dispose_count);
804   }
805   CcTest::heap()->CollectGarbage(
806       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
807   CHECK_EQ(1, dispose_count);
808 }
809
810
811 THREADED_TEST(ScavengeExternalAsciiString) {
812   i::FLAG_stress_compaction = false;
813   i::FLAG_gc_global = false;
814   int dispose_count = 0;
815   bool in_new_space = false;
816   {
817     v8::HandleScope scope(CcTest::isolate());
818     const char* one_byte_string = "test string";
819     Local<String> string = String::NewExternal(
820         CcTest::isolate(),
821         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
822     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
823     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
824     in_new_space = CcTest::heap()->InNewSpace(*istring);
825     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
826     CHECK_EQ(0, dispose_count);
827   }
828   CcTest::heap()->CollectGarbage(
829       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
830   CHECK_EQ(1, dispose_count);
831 }
832
833
834 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
835  public:
836   // Only used by non-threaded tests, so it can use static fields.
837   static int dispose_calls;
838   static int dispose_count;
839
840   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
841       : TestAsciiResource(data, &dispose_count),
842         dispose_(dispose) { }
843
844   void Dispose() {
845     ++dispose_calls;
846     if (dispose_) delete this;
847   }
848  private:
849   bool dispose_;
850 };
851
852
853 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
854 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
855
856
857 TEST(ExternalStringWithDisposeHandling) {
858   const char* c_source = "1 + 2 * 3";
859
860   // Use a stack allocated external string resource allocated object.
861   TestAsciiResourceWithDisposeControl::dispose_count = 0;
862   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
863   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
864   {
865     LocalContext env;
866     v8::HandleScope scope(env->GetIsolate());
867     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
868     Local<Script> script = Script::Compile(source);
869     Local<Value> value = script->Run();
870     CHECK(value->IsNumber());
871     CHECK_EQ(7, value->Int32Value());
872     CcTest::heap()->CollectAllAvailableGarbage();
873     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
874   }
875   CcTest::i_isolate()->compilation_cache()->Clear();
876   CcTest::heap()->CollectAllAvailableGarbage();
877   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
878   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
879
880   // Use a heap allocated external string resource allocated object.
881   TestAsciiResourceWithDisposeControl::dispose_count = 0;
882   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
883   TestAsciiResource* res_heap =
884       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
885   {
886     LocalContext env;
887     v8::HandleScope scope(env->GetIsolate());
888     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
889     Local<Script> script = Script::Compile(source);
890     Local<Value> value = script->Run();
891     CHECK(value->IsNumber());
892     CHECK_EQ(7, value->Int32Value());
893     CcTest::heap()->CollectAllAvailableGarbage();
894     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
895   }
896   CcTest::i_isolate()->compilation_cache()->Clear();
897   CcTest::heap()->CollectAllAvailableGarbage();
898   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
899   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
900 }
901
902
903 THREADED_TEST(StringConcat) {
904   {
905     LocalContext env;
906     v8::HandleScope scope(env->GetIsolate());
907     const char* one_byte_string_1 = "function a_times_t";
908     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
909     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
910     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
911     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
912     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
913     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
914     Local<String> left = v8_str(one_byte_string_1);
915
916     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
917     Local<String> right =
918         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
919     i::DeleteArray(two_byte_source);
920
921     Local<String> source = String::Concat(left, right);
922     right = String::NewExternal(
923         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
924     source = String::Concat(source, right);
925     right = String::NewExternal(
926         env->GetIsolate(),
927         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
928     source = String::Concat(source, right);
929     right = v8_str(one_byte_string_2);
930     source = String::Concat(source, right);
931
932     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
933     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
934     i::DeleteArray(two_byte_source);
935
936     source = String::Concat(source, right);
937     right = String::NewExternal(
938         env->GetIsolate(),
939         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
940     source = String::Concat(source, right);
941     Local<Script> script = Script::Compile(source);
942     Local<Value> value = script->Run();
943     CHECK(value->IsNumber());
944     CHECK_EQ(68, value->Int32Value());
945   }
946   CcTest::i_isolate()->compilation_cache()->Clear();
947   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
948   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
949 }
950
951
952 THREADED_TEST(GlobalProperties) {
953   LocalContext env;
954   v8::HandleScope scope(env->GetIsolate());
955   v8::Handle<v8::Object> global = env->Global();
956   global->Set(v8_str("pi"), v8_num(3.1415926));
957   Local<Value> pi = global->Get(v8_str("pi"));
958   CHECK_EQ(3.1415926, pi->NumberValue());
959 }
960
961
962 template<typename T>
963 static void CheckReturnValue(const T& t, i::Address callback) {
964   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
965   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
966   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
967   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
968   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
969   // Verify reset
970   bool is_runtime = (*o)->IsTheHole();
971   rv.Set(true);
972   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
973   rv.Set(v8::Handle<v8::Object>());
974   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
975   CHECK_EQ(is_runtime, (*o)->IsTheHole());
976
977   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
978   // If CPU profiler is active check that when API callback is invoked
979   // VMState is set to EXTERNAL.
980   if (isolate->cpu_profiler()->is_profiling()) {
981     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
982     CHECK(isolate->external_callback_scope());
983     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
984   }
985 }
986
987
988 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
989                                  i::Address callback) {
990   ApiTestFuzzer::Fuzz();
991   CheckReturnValue(info, callback);
992   info.GetReturnValue().Set(v8_str("bad value"));
993   info.GetReturnValue().Set(v8_num(102));
994 }
995
996
997 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
998   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
999 }
1000
1001
1002 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1003   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1004 }
1005
1006 static void construct_callback(
1007     const v8::FunctionCallbackInfo<Value>& info) {
1008   ApiTestFuzzer::Fuzz();
1009   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1010   info.This()->Set(v8_str("x"), v8_num(1));
1011   info.This()->Set(v8_str("y"), v8_num(2));
1012   info.GetReturnValue().Set(v8_str("bad value"));
1013   info.GetReturnValue().Set(info.This());
1014 }
1015
1016
1017 static void Return239Callback(
1018     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1019   ApiTestFuzzer::Fuzz();
1020   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1021   info.GetReturnValue().Set(v8_str("bad value"));
1022   info.GetReturnValue().Set(v8_num(239));
1023 }
1024
1025
1026 template<typename Handler>
1027 static void TestFunctionTemplateInitializer(Handler handler,
1028                                             Handler handler_2) {
1029   // Test constructor calls.
1030   {
1031     LocalContext env;
1032     v8::Isolate* isolate = env->GetIsolate();
1033     v8::HandleScope scope(isolate);
1034
1035     Local<v8::FunctionTemplate> fun_templ =
1036         v8::FunctionTemplate::New(isolate, handler);
1037     Local<Function> fun = fun_templ->GetFunction();
1038     env->Global()->Set(v8_str("obj"), fun);
1039     Local<Script> script = v8_compile("obj()");
1040     for (int i = 0; i < 30; i++) {
1041       CHECK_EQ(102, script->Run()->Int32Value());
1042     }
1043   }
1044   // Use SetCallHandler to initialize a function template, should work like
1045   // the previous one.
1046   {
1047     LocalContext env;
1048     v8::Isolate* isolate = env->GetIsolate();
1049     v8::HandleScope scope(isolate);
1050
1051     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1052     fun_templ->SetCallHandler(handler_2);
1053     Local<Function> fun = fun_templ->GetFunction();
1054     env->Global()->Set(v8_str("obj"), fun);
1055     Local<Script> script = v8_compile("obj()");
1056     for (int i = 0; i < 30; i++) {
1057       CHECK_EQ(102, script->Run()->Int32Value());
1058     }
1059   }
1060 }
1061
1062
1063 template<typename Constructor, typename Accessor>
1064 static void TestFunctionTemplateAccessor(Constructor constructor,
1065                                          Accessor accessor) {
1066   LocalContext env;
1067   v8::HandleScope scope(env->GetIsolate());
1068
1069   Local<v8::FunctionTemplate> fun_templ =
1070       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1071   fun_templ->SetClassName(v8_str("funky"));
1072   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1073   Local<Function> fun = fun_templ->GetFunction();
1074   env->Global()->Set(v8_str("obj"), fun);
1075   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1076   CHECK_EQ(v8_str("[object funky]"), result);
1077   CompileRun("var obj_instance = new obj();");
1078   Local<Script> script;
1079   script = v8_compile("obj_instance.x");
1080   for (int i = 0; i < 30; i++) {
1081     CHECK_EQ(1, script->Run()->Int32Value());
1082   }
1083   script = v8_compile("obj_instance.m");
1084   for (int i = 0; i < 30; i++) {
1085     CHECK_EQ(239, script->Run()->Int32Value());
1086   }
1087 }
1088
1089
1090 THREADED_PROFILED_TEST(FunctionTemplate) {
1091   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1092   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1093 }
1094
1095
1096 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1097   ApiTestFuzzer::Fuzz();
1098   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1099   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1100 }
1101
1102
1103 template<typename Callback>
1104 static void TestSimpleCallback(Callback callback) {
1105   LocalContext env;
1106   v8::Isolate* isolate = env->GetIsolate();
1107   v8::HandleScope scope(isolate);
1108
1109   v8::Handle<v8::ObjectTemplate> object_template =
1110       v8::ObjectTemplate::New(isolate);
1111   object_template->Set(isolate, "callback",
1112                        v8::FunctionTemplate::New(isolate, callback));
1113   v8::Local<v8::Object> object = object_template->NewInstance();
1114   (*env)->Global()->Set(v8_str("callback_object"), object);
1115   v8::Handle<v8::Script> script;
1116   script = v8_compile("callback_object.callback(17)");
1117   for (int i = 0; i < 30; i++) {
1118     CHECK_EQ(51424, script->Run()->Int32Value());
1119   }
1120   script = v8_compile("callback_object.callback(17, 24)");
1121   for (int i = 0; i < 30; i++) {
1122     CHECK_EQ(51425, script->Run()->Int32Value());
1123   }
1124 }
1125
1126
1127 THREADED_PROFILED_TEST(SimpleCallback) {
1128   TestSimpleCallback(SimpleCallback);
1129 }
1130
1131
1132 template<typename T>
1133 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1134
1135 // constant return values
1136 static int32_t fast_return_value_int32 = 471;
1137 static uint32_t fast_return_value_uint32 = 571;
1138 static const double kFastReturnValueDouble = 2.7;
1139 // variable return values
1140 static bool fast_return_value_bool = false;
1141 enum ReturnValueOddball {
1142   kNullReturnValue,
1143   kUndefinedReturnValue,
1144   kEmptyStringReturnValue
1145 };
1146 static ReturnValueOddball fast_return_value_void;
1147 static bool fast_return_value_object_is_empty = false;
1148
1149 // Helper function to avoid compiler error: insufficient contextual information
1150 // to determine type when applying FUNCTION_ADDR to a template function.
1151 static i::Address address_of(v8::FunctionCallback callback) {
1152   return FUNCTION_ADDR(callback);
1153 }
1154
1155 template<>
1156 void FastReturnValueCallback<int32_t>(
1157     const v8::FunctionCallbackInfo<v8::Value>& info) {
1158   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1159   info.GetReturnValue().Set(fast_return_value_int32);
1160 }
1161
1162 template<>
1163 void FastReturnValueCallback<uint32_t>(
1164     const v8::FunctionCallbackInfo<v8::Value>& info) {
1165   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1166   info.GetReturnValue().Set(fast_return_value_uint32);
1167 }
1168
1169 template<>
1170 void FastReturnValueCallback<double>(
1171     const v8::FunctionCallbackInfo<v8::Value>& info) {
1172   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1173   info.GetReturnValue().Set(kFastReturnValueDouble);
1174 }
1175
1176 template<>
1177 void FastReturnValueCallback<bool>(
1178     const v8::FunctionCallbackInfo<v8::Value>& info) {
1179   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1180   info.GetReturnValue().Set(fast_return_value_bool);
1181 }
1182
1183 template<>
1184 void FastReturnValueCallback<void>(
1185     const v8::FunctionCallbackInfo<v8::Value>& info) {
1186   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1187   switch (fast_return_value_void) {
1188     case kNullReturnValue:
1189       info.GetReturnValue().SetNull();
1190       break;
1191     case kUndefinedReturnValue:
1192       info.GetReturnValue().SetUndefined();
1193       break;
1194     case kEmptyStringReturnValue:
1195       info.GetReturnValue().SetEmptyString();
1196       break;
1197   }
1198 }
1199
1200 template<>
1201 void FastReturnValueCallback<Object>(
1202     const v8::FunctionCallbackInfo<v8::Value>& info) {
1203   v8::Handle<v8::Object> object;
1204   if (!fast_return_value_object_is_empty) {
1205     object = Object::New(info.GetIsolate());
1206   }
1207   info.GetReturnValue().Set(object);
1208 }
1209
1210 template<typename T>
1211 Handle<Value> TestFastReturnValues() {
1212   LocalContext env;
1213   v8::Isolate* isolate = env->GetIsolate();
1214   v8::EscapableHandleScope scope(isolate);
1215   v8::Handle<v8::ObjectTemplate> object_template =
1216       v8::ObjectTemplate::New(isolate);
1217   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1218   object_template->Set(isolate, "callback",
1219                        v8::FunctionTemplate::New(isolate, callback));
1220   v8::Local<v8::Object> object = object_template->NewInstance();
1221   (*env)->Global()->Set(v8_str("callback_object"), object);
1222   return scope.Escape(CompileRun("callback_object.callback()"));
1223 }
1224
1225
1226 THREADED_PROFILED_TEST(FastReturnValues) {
1227   LocalContext env;
1228   v8::HandleScope scope(CcTest::isolate());
1229   v8::Handle<v8::Value> value;
1230   // check int32_t and uint32_t
1231   int32_t int_values[] = {
1232       0, 234, -723,
1233       i::Smi::kMinValue, i::Smi::kMaxValue
1234   };
1235   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1236     for (int modifier = -1; modifier <= 1; modifier++) {
1237       int int_value = int_values[i] + modifier;
1238       // check int32_t
1239       fast_return_value_int32 = int_value;
1240       value = TestFastReturnValues<int32_t>();
1241       CHECK(value->IsInt32());
1242       CHECK(fast_return_value_int32 == value->Int32Value());
1243       // check uint32_t
1244       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1245       value = TestFastReturnValues<uint32_t>();
1246       CHECK(value->IsUint32());
1247       CHECK(fast_return_value_uint32 == value->Uint32Value());
1248     }
1249   }
1250   // check double
1251   value = TestFastReturnValues<double>();
1252   CHECK(value->IsNumber());
1253   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1254   // check bool values
1255   for (int i = 0; i < 2; i++) {
1256     fast_return_value_bool = i == 0;
1257     value = TestFastReturnValues<bool>();
1258     CHECK(value->IsBoolean());
1259     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1260   }
1261   // check oddballs
1262   ReturnValueOddball oddballs[] = {
1263       kNullReturnValue,
1264       kUndefinedReturnValue,
1265       kEmptyStringReturnValue
1266   };
1267   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1268     fast_return_value_void = oddballs[i];
1269     value = TestFastReturnValues<void>();
1270     switch (fast_return_value_void) {
1271       case kNullReturnValue:
1272         CHECK(value->IsNull());
1273         break;
1274       case kUndefinedReturnValue:
1275         CHECK(value->IsUndefined());
1276         break;
1277       case kEmptyStringReturnValue:
1278         CHECK(value->IsString());
1279         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1280         break;
1281     }
1282   }
1283   // check handles
1284   fast_return_value_object_is_empty = false;
1285   value = TestFastReturnValues<Object>();
1286   CHECK(value->IsObject());
1287   fast_return_value_object_is_empty = true;
1288   value = TestFastReturnValues<Object>();
1289   CHECK(value->IsUndefined());
1290 }
1291
1292
1293 THREADED_TEST(FunctionTemplateSetLength) {
1294   LocalContext env;
1295   v8::Isolate* isolate = env->GetIsolate();
1296   v8::HandleScope scope(isolate);
1297   {
1298     Local<v8::FunctionTemplate> fun_templ =
1299         v8::FunctionTemplate::New(isolate,
1300                                   handle_callback,
1301                                   Handle<v8::Value>(),
1302                                   Handle<v8::Signature>(),
1303                                   23);
1304     Local<Function> fun = fun_templ->GetFunction();
1305     env->Global()->Set(v8_str("obj"), fun);
1306     Local<Script> script = v8_compile("obj.length");
1307     CHECK_EQ(23, script->Run()->Int32Value());
1308   }
1309   {
1310     Local<v8::FunctionTemplate> fun_templ =
1311         v8::FunctionTemplate::New(isolate, handle_callback);
1312     fun_templ->SetLength(22);
1313     Local<Function> fun = fun_templ->GetFunction();
1314     env->Global()->Set(v8_str("obj"), fun);
1315     Local<Script> script = v8_compile("obj.length");
1316     CHECK_EQ(22, script->Run()->Int32Value());
1317   }
1318   {
1319     // Without setting length it defaults to 0.
1320     Local<v8::FunctionTemplate> fun_templ =
1321         v8::FunctionTemplate::New(isolate, handle_callback);
1322     Local<Function> fun = fun_templ->GetFunction();
1323     env->Global()->Set(v8_str("obj"), fun);
1324     Local<Script> script = v8_compile("obj.length");
1325     CHECK_EQ(0, script->Run()->Int32Value());
1326   }
1327 }
1328
1329
1330 static void* expected_ptr;
1331 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1332   void* ptr = v8::External::Cast(*args.Data())->Value();
1333   CHECK_EQ(expected_ptr, ptr);
1334   args.GetReturnValue().Set(true);
1335 }
1336
1337
1338 static void TestExternalPointerWrapping() {
1339   LocalContext env;
1340   v8::Isolate* isolate = env->GetIsolate();
1341   v8::HandleScope scope(isolate);
1342
1343   v8::Handle<v8::Value> data =
1344       v8::External::New(isolate, expected_ptr);
1345
1346   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1347   obj->Set(v8_str("func"),
1348            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1349   env->Global()->Set(v8_str("obj"), obj);
1350
1351   CHECK(CompileRun(
1352         "function foo() {\n"
1353         "  for (var i = 0; i < 13; i++) obj.func();\n"
1354         "}\n"
1355         "foo(), true")->BooleanValue());
1356 }
1357
1358
1359 THREADED_TEST(ExternalWrap) {
1360   // Check heap allocated object.
1361   int* ptr = new int;
1362   expected_ptr = ptr;
1363   TestExternalPointerWrapping();
1364   delete ptr;
1365
1366   // Check stack allocated object.
1367   int foo;
1368   expected_ptr = &foo;
1369   TestExternalPointerWrapping();
1370
1371   // Check not aligned addresses.
1372   const int n = 100;
1373   char* s = new char[n];
1374   for (int i = 0; i < n; i++) {
1375     expected_ptr = s + i;
1376     TestExternalPointerWrapping();
1377   }
1378
1379   delete[] s;
1380
1381   // Check several invalid addresses.
1382   expected_ptr = reinterpret_cast<void*>(1);
1383   TestExternalPointerWrapping();
1384
1385   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1386   TestExternalPointerWrapping();
1387
1388   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1389   TestExternalPointerWrapping();
1390
1391 #if defined(V8_HOST_ARCH_X64)
1392   // Check a value with a leading 1 bit in x64 Smi encoding.
1393   expected_ptr = reinterpret_cast<void*>(0x400000000);
1394   TestExternalPointerWrapping();
1395
1396   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1397   TestExternalPointerWrapping();
1398
1399   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1400   TestExternalPointerWrapping();
1401 #endif
1402 }
1403
1404
1405 THREADED_TEST(FindInstanceInPrototypeChain) {
1406   LocalContext env;
1407   v8::Isolate* isolate = env->GetIsolate();
1408   v8::HandleScope scope(isolate);
1409
1410   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1411   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1412   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1413   derived->Inherit(base);
1414
1415   Local<v8::Function> base_function = base->GetFunction();
1416   Local<v8::Function> derived_function = derived->GetFunction();
1417   Local<v8::Function> other_function = other->GetFunction();
1418
1419   Local<v8::Object> base_instance = base_function->NewInstance();
1420   Local<v8::Object> derived_instance = derived_function->NewInstance();
1421   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1422   Local<v8::Object> other_instance = other_function->NewInstance();
1423   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1424   other_instance->Set(v8_str("__proto__"), derived_instance2);
1425
1426   // base_instance is only an instance of base.
1427   CHECK_EQ(base_instance,
1428            base_instance->FindInstanceInPrototypeChain(base));
1429   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1430   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1431
1432   // derived_instance is an instance of base and derived.
1433   CHECK_EQ(derived_instance,
1434            derived_instance->FindInstanceInPrototypeChain(base));
1435   CHECK_EQ(derived_instance,
1436            derived_instance->FindInstanceInPrototypeChain(derived));
1437   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1438
1439   // other_instance is an instance of other and its immediate
1440   // prototype derived_instance2 is an instance of base and derived.
1441   // Note, derived_instance is an instance of base and derived too,
1442   // but it comes after derived_instance2 in the prototype chain of
1443   // other_instance.
1444   CHECK_EQ(derived_instance2,
1445            other_instance->FindInstanceInPrototypeChain(base));
1446   CHECK_EQ(derived_instance2,
1447            other_instance->FindInstanceInPrototypeChain(derived));
1448   CHECK_EQ(other_instance,
1449            other_instance->FindInstanceInPrototypeChain(other));
1450 }
1451
1452
1453 THREADED_TEST(TinyInteger) {
1454   LocalContext env;
1455   v8::Isolate* isolate = env->GetIsolate();
1456   v8::HandleScope scope(isolate);
1457
1458   int32_t value = 239;
1459   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1460   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1461
1462   value_obj = v8::Integer::New(isolate, value);
1463   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1464 }
1465
1466
1467 THREADED_TEST(BigSmiInteger) {
1468   LocalContext env;
1469   v8::HandleScope scope(env->GetIsolate());
1470   v8::Isolate* isolate = CcTest::isolate();
1471
1472   int32_t value = i::Smi::kMaxValue;
1473   // We cannot add one to a Smi::kMaxValue without wrapping.
1474   if (i::SmiValuesAre31Bits()) {
1475     CHECK(i::Smi::IsValid(value));
1476     CHECK(!i::Smi::IsValid(value + 1));
1477
1478     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1479     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1480
1481     value_obj = v8::Integer::New(isolate, value);
1482     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1483   }
1484 }
1485
1486
1487 THREADED_TEST(BigInteger) {
1488   LocalContext env;
1489   v8::HandleScope scope(env->GetIsolate());
1490   v8::Isolate* isolate = CcTest::isolate();
1491
1492   // We cannot add one to a Smi::kMaxValue without wrapping.
1493   if (i::SmiValuesAre31Bits()) {
1494     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1495     // The code will not be run in that case, due to the "if" guard.
1496     int32_t value =
1497         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1498     CHECK(value > i::Smi::kMaxValue);
1499     CHECK(!i::Smi::IsValid(value));
1500
1501     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1502     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1503
1504     value_obj = v8::Integer::New(isolate, value);
1505     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1506   }
1507 }
1508
1509
1510 THREADED_TEST(TinyUnsignedInteger) {
1511   LocalContext env;
1512   v8::HandleScope scope(env->GetIsolate());
1513   v8::Isolate* isolate = CcTest::isolate();
1514
1515   uint32_t value = 239;
1516
1517   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1518   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1519
1520   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1521   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1522 }
1523
1524
1525 THREADED_TEST(BigUnsignedSmiInteger) {
1526   LocalContext env;
1527   v8::HandleScope scope(env->GetIsolate());
1528   v8::Isolate* isolate = CcTest::isolate();
1529
1530   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1531   CHECK(i::Smi::IsValid(value));
1532   CHECK(!i::Smi::IsValid(value + 1));
1533
1534   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1535   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1536
1537   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1538   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1539 }
1540
1541
1542 THREADED_TEST(BigUnsignedInteger) {
1543   LocalContext env;
1544   v8::HandleScope scope(env->GetIsolate());
1545   v8::Isolate* isolate = CcTest::isolate();
1546
1547   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1548   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1549   CHECK(!i::Smi::IsValid(value));
1550
1551   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1552   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1553
1554   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1555   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1556 }
1557
1558
1559 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1560   LocalContext env;
1561   v8::HandleScope scope(env->GetIsolate());
1562   v8::Isolate* isolate = CcTest::isolate();
1563
1564   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1565   uint32_t value = INT32_MAX_AS_UINT + 1;
1566   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1567
1568   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1569   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1570
1571   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1572   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1573 }
1574
1575
1576 THREADED_TEST(IsNativeError) {
1577   LocalContext env;
1578   v8::HandleScope scope(env->GetIsolate());
1579   v8::Handle<Value> syntax_error = CompileRun(
1580       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1581   CHECK(syntax_error->IsNativeError());
1582   v8::Handle<Value> not_error = CompileRun("{a:42}");
1583   CHECK(!not_error->IsNativeError());
1584   v8::Handle<Value> not_object = CompileRun("42");
1585   CHECK(!not_object->IsNativeError());
1586 }
1587
1588
1589 THREADED_TEST(StringObject) {
1590   LocalContext env;
1591   v8::HandleScope scope(env->GetIsolate());
1592   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1593   CHECK(boxed_string->IsStringObject());
1594   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1595   CHECK(!unboxed_string->IsStringObject());
1596   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1597   CHECK(!boxed_not_string->IsStringObject());
1598   v8::Handle<Value> not_object = CompileRun("0");
1599   CHECK(!not_object->IsStringObject());
1600   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1601   CHECK(!as_boxed.IsEmpty());
1602   Local<v8::String> the_string = as_boxed->ValueOf();
1603   CHECK(!the_string.IsEmpty());
1604   ExpectObject("\"test\"", the_string);
1605   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1606   CHECK(new_boxed_string->IsStringObject());
1607   as_boxed = new_boxed_string.As<v8::StringObject>();
1608   the_string = as_boxed->ValueOf();
1609   CHECK(!the_string.IsEmpty());
1610   ExpectObject("\"test\"", the_string);
1611 }
1612
1613
1614 THREADED_TEST(NumberObject) {
1615   LocalContext env;
1616   v8::HandleScope scope(env->GetIsolate());
1617   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1618   CHECK(boxed_number->IsNumberObject());
1619   v8::Handle<Value> unboxed_number = CompileRun("42");
1620   CHECK(!unboxed_number->IsNumberObject());
1621   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1622   CHECK(!boxed_not_number->IsNumberObject());
1623   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1624   CHECK(!as_boxed.IsEmpty());
1625   double the_number = as_boxed->ValueOf();
1626   CHECK_EQ(42.0, the_number);
1627   v8::Handle<v8::Value> new_boxed_number =
1628       v8::NumberObject::New(env->GetIsolate(), 43);
1629   CHECK(new_boxed_number->IsNumberObject());
1630   as_boxed = new_boxed_number.As<v8::NumberObject>();
1631   the_number = as_boxed->ValueOf();
1632   CHECK_EQ(43.0, the_number);
1633 }
1634
1635
1636 THREADED_TEST(BooleanObject) {
1637   LocalContext env;
1638   v8::HandleScope scope(env->GetIsolate());
1639   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1640   CHECK(boxed_boolean->IsBooleanObject());
1641   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1642   CHECK(!unboxed_boolean->IsBooleanObject());
1643   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1644   CHECK(!boxed_not_boolean->IsBooleanObject());
1645   v8::Handle<v8::BooleanObject> as_boxed =
1646       boxed_boolean.As<v8::BooleanObject>();
1647   CHECK(!as_boxed.IsEmpty());
1648   bool the_boolean = as_boxed->ValueOf();
1649   CHECK_EQ(true, the_boolean);
1650   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1651   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1652   CHECK(boxed_true->IsBooleanObject());
1653   CHECK(boxed_false->IsBooleanObject());
1654   as_boxed = boxed_true.As<v8::BooleanObject>();
1655   CHECK_EQ(true, as_boxed->ValueOf());
1656   as_boxed = boxed_false.As<v8::BooleanObject>();
1657   CHECK_EQ(false, as_boxed->ValueOf());
1658 }
1659
1660
1661 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1662   LocalContext env;
1663   v8::HandleScope scope(env->GetIsolate());
1664
1665   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1666   CHECK(primitive_false->IsBoolean());
1667   CHECK(!primitive_false->IsBooleanObject());
1668   CHECK(!primitive_false->BooleanValue());
1669   CHECK(!primitive_false->IsTrue());
1670   CHECK(primitive_false->IsFalse());
1671
1672   Local<Value> false_value = BooleanObject::New(false);
1673   CHECK(!false_value->IsBoolean());
1674   CHECK(false_value->IsBooleanObject());
1675   CHECK(false_value->BooleanValue());
1676   CHECK(!false_value->IsTrue());
1677   CHECK(!false_value->IsFalse());
1678
1679   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1680   CHECK(!false_boolean_object->IsBoolean());
1681   CHECK(false_boolean_object->IsBooleanObject());
1682   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1683   // CHECK(false_boolean_object->BooleanValue());
1684   CHECK(!false_boolean_object->ValueOf());
1685   CHECK(!false_boolean_object->IsTrue());
1686   CHECK(!false_boolean_object->IsFalse());
1687
1688   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1689   CHECK(primitive_true->IsBoolean());
1690   CHECK(!primitive_true->IsBooleanObject());
1691   CHECK(primitive_true->BooleanValue());
1692   CHECK(primitive_true->IsTrue());
1693   CHECK(!primitive_true->IsFalse());
1694
1695   Local<Value> true_value = BooleanObject::New(true);
1696   CHECK(!true_value->IsBoolean());
1697   CHECK(true_value->IsBooleanObject());
1698   CHECK(true_value->BooleanValue());
1699   CHECK(!true_value->IsTrue());
1700   CHECK(!true_value->IsFalse());
1701
1702   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1703   CHECK(!true_boolean_object->IsBoolean());
1704   CHECK(true_boolean_object->IsBooleanObject());
1705   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1706   // CHECK(true_boolean_object->BooleanValue());
1707   CHECK(true_boolean_object->ValueOf());
1708   CHECK(!true_boolean_object->IsTrue());
1709   CHECK(!true_boolean_object->IsFalse());
1710 }
1711
1712
1713 THREADED_TEST(Number) {
1714   LocalContext env;
1715   v8::HandleScope scope(env->GetIsolate());
1716   double PI = 3.1415926;
1717   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1718   CHECK_EQ(PI, pi_obj->NumberValue());
1719 }
1720
1721
1722 THREADED_TEST(ToNumber) {
1723   LocalContext env;
1724   v8::Isolate* isolate = CcTest::isolate();
1725   v8::HandleScope scope(isolate);
1726   Local<String> str = v8_str("3.1415926");
1727   CHECK_EQ(3.1415926, str->NumberValue());
1728   v8::Handle<v8::Boolean> t = v8::True(isolate);
1729   CHECK_EQ(1.0, t->NumberValue());
1730   v8::Handle<v8::Boolean> f = v8::False(isolate);
1731   CHECK_EQ(0.0, f->NumberValue());
1732 }
1733
1734
1735 THREADED_TEST(Date) {
1736   LocalContext env;
1737   v8::HandleScope scope(env->GetIsolate());
1738   double PI = 3.1415926;
1739   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1740   CHECK_EQ(3.0, date->NumberValue());
1741   date.As<v8::Date>()->Set(v8_str("property"),
1742                            v8::Integer::New(env->GetIsolate(), 42));
1743   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1744 }
1745
1746
1747 THREADED_TEST(Boolean) {
1748   LocalContext env;
1749   v8::Isolate* isolate = env->GetIsolate();
1750   v8::HandleScope scope(isolate);
1751   v8::Handle<v8::Boolean> t = v8::True(isolate);
1752   CHECK(t->Value());
1753   v8::Handle<v8::Boolean> f = v8::False(isolate);
1754   CHECK(!f->Value());
1755   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1756   CHECK(!u->BooleanValue());
1757   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1758   CHECK(!n->BooleanValue());
1759   v8::Handle<String> str1 = v8_str("");
1760   CHECK(!str1->BooleanValue());
1761   v8::Handle<String> str2 = v8_str("x");
1762   CHECK(str2->BooleanValue());
1763   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1764   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1765   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1766   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1767   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1768 }
1769
1770
1771 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1772   ApiTestFuzzer::Fuzz();
1773   args.GetReturnValue().Set(v8_num(13.4));
1774 }
1775
1776
1777 static void GetM(Local<String> name,
1778                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1779   ApiTestFuzzer::Fuzz();
1780   info.GetReturnValue().Set(v8_num(876));
1781 }
1782
1783
1784 THREADED_TEST(GlobalPrototype) {
1785   v8::Isolate* isolate = CcTest::isolate();
1786   v8::HandleScope scope(isolate);
1787   v8::Handle<v8::FunctionTemplate> func_templ =
1788       v8::FunctionTemplate::New(isolate);
1789   func_templ->PrototypeTemplate()->Set(
1790       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1791   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1792   templ->Set(isolate, "x", v8_num(200));
1793   templ->SetAccessor(v8_str("m"), GetM);
1794   LocalContext env(0, templ);
1795   v8::Handle<Script> script(v8_compile("dummy()"));
1796   v8::Handle<Value> result(script->Run());
1797   CHECK_EQ(13.4, result->NumberValue());
1798   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1799   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1800 }
1801
1802
1803 THREADED_TEST(ObjectTemplate) {
1804   v8::Isolate* isolate = CcTest::isolate();
1805   v8::HandleScope scope(isolate);
1806   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1807   templ1->Set(isolate, "x", v8_num(10));
1808   templ1->Set(isolate, "y", v8_num(13));
1809   LocalContext env;
1810   Local<v8::Object> instance1 = templ1->NewInstance();
1811   env->Global()->Set(v8_str("p"), instance1);
1812   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1813   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1814   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1815   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1816   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1817   templ2->Set(isolate, "a", v8_num(12));
1818   templ2->Set(isolate, "b", templ1);
1819   Local<v8::Object> instance2 = templ2->NewInstance();
1820   env->Global()->Set(v8_str("q"), instance2);
1821   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1822   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1823   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1824   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1825 }
1826
1827
1828 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1829   ApiTestFuzzer::Fuzz();
1830   args.GetReturnValue().Set(v8_num(17.2));
1831 }
1832
1833
1834 static void GetKnurd(Local<String> property,
1835                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1836   ApiTestFuzzer::Fuzz();
1837   info.GetReturnValue().Set(v8_num(15.2));
1838 }
1839
1840
1841 THREADED_TEST(DescriptorInheritance) {
1842   v8::Isolate* isolate = CcTest::isolate();
1843   v8::HandleScope scope(isolate);
1844   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1845   super->PrototypeTemplate()->Set(isolate, "flabby",
1846                                   v8::FunctionTemplate::New(isolate,
1847                                                             GetFlabby));
1848   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1849
1850   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1851
1852   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1853   base1->Inherit(super);
1854   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1855
1856   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1857   base2->Inherit(super);
1858   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1859
1860   LocalContext env;
1861
1862   env->Global()->Set(v8_str("s"), super->GetFunction());
1863   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1864   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1865
1866   // Checks right __proto__ chain.
1867   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1868   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1869
1870   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1871
1872   // Instance accessor should not be visible on function object or its prototype
1873   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1874   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1875   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1876
1877   env->Global()->Set(v8_str("obj"),
1878                      base1->GetFunction()->NewInstance());
1879   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1880   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1881   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1882   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1883   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1884
1885   env->Global()->Set(v8_str("obj2"),
1886                      base2->GetFunction()->NewInstance());
1887   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1888   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1889   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1890   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1891   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1892
1893   // base1 and base2 cannot cross reference to each's prototype
1894   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1895   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1896 }
1897
1898
1899 int echo_named_call_count;
1900
1901
1902 static void EchoNamedProperty(Local<String> name,
1903                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1904   ApiTestFuzzer::Fuzz();
1905   CHECK_EQ(v8_str("data"), info.Data());
1906   echo_named_call_count++;
1907   info.GetReturnValue().Set(name);
1908 }
1909
1910
1911 // Helper functions for Interceptor/Accessor interaction tests
1912
1913 void SimpleAccessorGetter(Local<String> name,
1914                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1915   Handle<Object> self = info.This();
1916   info.GetReturnValue().Set(
1917       self->Get(String::Concat(v8_str("accessor_"), name)));
1918 }
1919
1920 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1921                           const v8::PropertyCallbackInfo<void>& info) {
1922   Handle<Object> self = info.This();
1923   self->Set(String::Concat(v8_str("accessor_"), name), value);
1924 }
1925
1926 void EmptyInterceptorGetter(Local<String> name,
1927                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1928 }
1929
1930 void EmptyInterceptorSetter(Local<String> name,
1931                             Local<Value> value,
1932                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1933 }
1934
1935 void InterceptorGetter(Local<String> name,
1936                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1937   // Intercept names that start with 'interceptor_'.
1938   String::Utf8Value utf8(name);
1939   char* name_str = *utf8;
1940   char prefix[] = "interceptor_";
1941   int i;
1942   for (i = 0; name_str[i] && prefix[i]; ++i) {
1943     if (name_str[i] != prefix[i]) return;
1944   }
1945   Handle<Object> self = info.This();
1946   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1947 }
1948
1949 void InterceptorSetter(Local<String> name,
1950                        Local<Value> value,
1951                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1952   // Intercept accesses that set certain integer values, for which the name does
1953   // not start with 'accessor_'.
1954   String::Utf8Value utf8(name);
1955   char* name_str = *utf8;
1956   char prefix[] = "accessor_";
1957   int i;
1958   for (i = 0; name_str[i] && prefix[i]; ++i) {
1959     if (name_str[i] != prefix[i]) break;
1960   }
1961   if (!prefix[i]) return;
1962
1963   if (value->IsInt32() && value->Int32Value() < 10000) {
1964     Handle<Object> self = info.This();
1965     self->SetHiddenValue(name, value);
1966     info.GetReturnValue().Set(value);
1967   }
1968 }
1969
1970 void AddAccessor(Handle<FunctionTemplate> templ,
1971                  Handle<String> name,
1972                  v8::AccessorGetterCallback getter,
1973                  v8::AccessorSetterCallback setter) {
1974   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1975 }
1976
1977 void AddInterceptor(Handle<FunctionTemplate> templ,
1978                     v8::NamedPropertyGetterCallback getter,
1979                     v8::NamedPropertySetterCallback setter) {
1980   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1981 }
1982
1983
1984 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1985   v8::HandleScope scope(CcTest::isolate());
1986   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1987   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1988   child->Inherit(parent);
1989   AddAccessor(parent, v8_str("age"),
1990               SimpleAccessorGetter, SimpleAccessorSetter);
1991   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1992   LocalContext env;
1993   env->Global()->Set(v8_str("Child"), child->GetFunction());
1994   CompileRun("var child = new Child;"
1995              "child.age = 10;");
1996   ExpectBoolean("child.hasOwnProperty('age')", false);
1997   ExpectInt32("child.age", 10);
1998   ExpectInt32("child.accessor_age", 10);
1999 }
2000
2001
2002 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2003   v8::HandleScope scope(CcTest::isolate());
2004   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2005   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2006   LocalContext env;
2007   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2008   CompileRun("var o1 = new Constructor;"
2009              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2010              "Object.defineProperty(o1, 'x', {value: 10});");
2011   CompileRun("var o2 = new Constructor;"
2012              "o2.a = 1;"
2013              "Object.defineProperty(o2, 'x', {value: 10});");
2014 }
2015
2016
2017 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2018   v8::Isolate* isolate = CcTest::isolate();
2019   v8::HandleScope scope(isolate);
2020   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2021   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2022   child->Inherit(parent);
2023   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2024   LocalContext env;
2025   env->Global()->Set(v8_str("Child"), child->GetFunction());
2026   CompileRun("var child = new Child;"
2027              "var parent = child.__proto__;"
2028              "Object.defineProperty(parent, 'age', "
2029              "  {get: function(){ return this.accessor_age; }, "
2030              "   set: function(v){ this.accessor_age = v; }, "
2031              "   enumerable: true, configurable: true});"
2032              "child.age = 10;");
2033   ExpectBoolean("child.hasOwnProperty('age')", false);
2034   ExpectInt32("child.age", 10);
2035   ExpectInt32("child.accessor_age", 10);
2036 }
2037
2038
2039 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2040   v8::Isolate* isolate = CcTest::isolate();
2041   v8::HandleScope scope(isolate);
2042   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2043   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2044   child->Inherit(parent);
2045   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2046   LocalContext env;
2047   env->Global()->Set(v8_str("Child"), child->GetFunction());
2048   CompileRun("var child = new Child;"
2049              "var parent = child.__proto__;"
2050              "parent.name = 'Alice';");
2051   ExpectBoolean("child.hasOwnProperty('name')", false);
2052   ExpectString("child.name", "Alice");
2053   CompileRun("child.name = 'Bob';");
2054   ExpectString("child.name", "Bob");
2055   ExpectBoolean("child.hasOwnProperty('name')", true);
2056   ExpectString("parent.name", "Alice");
2057 }
2058
2059
2060 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2061   v8::HandleScope scope(CcTest::isolate());
2062   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2063   AddAccessor(templ, v8_str("age"),
2064               SimpleAccessorGetter, SimpleAccessorSetter);
2065   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2066   LocalContext env;
2067   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2068   CompileRun("var obj = new Obj;"
2069              "function setAge(i){ obj.age = i; };"
2070              "for(var i = 0; i <= 10000; i++) setAge(i);");
2071   // All i < 10000 go to the interceptor.
2072   ExpectInt32("obj.interceptor_age", 9999);
2073   // The last i goes to the accessor.
2074   ExpectInt32("obj.accessor_age", 10000);
2075 }
2076
2077
2078 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2079   v8::HandleScope scope(CcTest::isolate());
2080   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2081   AddAccessor(templ, v8_str("age"),
2082               SimpleAccessorGetter, SimpleAccessorSetter);
2083   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2084   LocalContext env;
2085   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2086   CompileRun("var obj = new Obj;"
2087              "function setAge(i){ obj.age = i; };"
2088              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2089   // All i >= 10000 go to the accessor.
2090   ExpectInt32("obj.accessor_age", 10000);
2091   // The last i goes to the interceptor.
2092   ExpectInt32("obj.interceptor_age", 9999);
2093 }
2094
2095
2096 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2097   v8::HandleScope scope(CcTest::isolate());
2098   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2099   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2100   child->Inherit(parent);
2101   AddAccessor(parent, v8_str("age"),
2102               SimpleAccessorGetter, SimpleAccessorSetter);
2103   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2104   LocalContext env;
2105   env->Global()->Set(v8_str("Child"), child->GetFunction());
2106   CompileRun("var child = new Child;"
2107              "function setAge(i){ child.age = i; };"
2108              "for(var i = 0; i <= 10000; i++) setAge(i);");
2109   // All i < 10000 go to the interceptor.
2110   ExpectInt32("child.interceptor_age", 9999);
2111   // The last i goes to the accessor.
2112   ExpectInt32("child.accessor_age", 10000);
2113 }
2114
2115
2116 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2117   v8::HandleScope scope(CcTest::isolate());
2118   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2119   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2120   child->Inherit(parent);
2121   AddAccessor(parent, v8_str("age"),
2122               SimpleAccessorGetter, SimpleAccessorSetter);
2123   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2124   LocalContext env;
2125   env->Global()->Set(v8_str("Child"), child->GetFunction());
2126   CompileRun("var child = new Child;"
2127              "function setAge(i){ child.age = i; };"
2128              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2129   // All i >= 10000 go to the accessor.
2130   ExpectInt32("child.accessor_age", 10000);
2131   // The last i goes to the interceptor.
2132   ExpectInt32("child.interceptor_age", 9999);
2133 }
2134
2135
2136 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2137   v8::HandleScope scope(CcTest::isolate());
2138   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2139   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2140   LocalContext env;
2141   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2142   CompileRun("var obj = new Obj;"
2143              "function setter(i) { this.accessor_age = i; };"
2144              "function getter() { return this.accessor_age; };"
2145              "function setAge(i) { obj.age = i; };"
2146              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2147              "for(var i = 0; i <= 10000; i++) setAge(i);");
2148   // All i < 10000 go to the interceptor.
2149   ExpectInt32("obj.interceptor_age", 9999);
2150   // The last i goes to the JavaScript accessor.
2151   ExpectInt32("obj.accessor_age", 10000);
2152   // The installed JavaScript getter is still intact.
2153   // This last part is a regression test for issue 1651 and relies on the fact
2154   // that both interceptor and accessor are being installed on the same object.
2155   ExpectInt32("obj.age", 10000);
2156   ExpectBoolean("obj.hasOwnProperty('age')", true);
2157   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2158 }
2159
2160
2161 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2162   v8::HandleScope scope(CcTest::isolate());
2163   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2164   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2165   LocalContext env;
2166   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2167   CompileRun("var obj = new Obj;"
2168              "function setter(i) { this.accessor_age = i; };"
2169              "function getter() { return this.accessor_age; };"
2170              "function setAge(i) { obj.age = i; };"
2171              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2172              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2173   // All i >= 10000 go to the accessor.
2174   ExpectInt32("obj.accessor_age", 10000);
2175   // The last i goes to the interceptor.
2176   ExpectInt32("obj.interceptor_age", 9999);
2177   // The installed JavaScript getter is still intact.
2178   // This last part is a regression test for issue 1651 and relies on the fact
2179   // that both interceptor and accessor are being installed on the same object.
2180   ExpectInt32("obj.age", 10000);
2181   ExpectBoolean("obj.hasOwnProperty('age')", true);
2182   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2183 }
2184
2185
2186 THREADED_TEST(SwitchFromInterceptorToProperty) {
2187   v8::HandleScope scope(CcTest::isolate());
2188   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2189   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2190   child->Inherit(parent);
2191   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2192   LocalContext env;
2193   env->Global()->Set(v8_str("Child"), child->GetFunction());
2194   CompileRun("var child = new Child;"
2195              "function setAge(i){ child.age = i; };"
2196              "for(var i = 0; i <= 10000; i++) setAge(i);");
2197   // All i < 10000 go to the interceptor.
2198   ExpectInt32("child.interceptor_age", 9999);
2199   // The last i goes to child's own property.
2200   ExpectInt32("child.age", 10000);
2201 }
2202
2203
2204 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2205   v8::HandleScope scope(CcTest::isolate());
2206   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2207   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2208   child->Inherit(parent);
2209   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2210   LocalContext env;
2211   env->Global()->Set(v8_str("Child"), child->GetFunction());
2212   CompileRun("var child = new Child;"
2213              "function setAge(i){ child.age = i; };"
2214              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2215   // All i >= 10000 go to child's own property.
2216   ExpectInt32("child.age", 10000);
2217   // The last i goes to the interceptor.
2218   ExpectInt32("child.interceptor_age", 9999);
2219 }
2220
2221
2222 THREADED_TEST(NamedPropertyHandlerGetter) {
2223   echo_named_call_count = 0;
2224   v8::HandleScope scope(CcTest::isolate());
2225   v8::Handle<v8::FunctionTemplate> templ =
2226       v8::FunctionTemplate::New(CcTest::isolate());
2227   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2228                                                      0, 0, 0, 0,
2229                                                      v8_str("data"));
2230   LocalContext env;
2231   env->Global()->Set(v8_str("obj"),
2232                      templ->GetFunction()->NewInstance());
2233   CHECK_EQ(echo_named_call_count, 0);
2234   v8_compile("obj.x")->Run();
2235   CHECK_EQ(echo_named_call_count, 1);
2236   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2237   v8::Handle<Value> str = CompileRun(code);
2238   String::Utf8Value value(str);
2239   CHECK_EQ(*value, "oddlepoddle");
2240   // Check default behavior
2241   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2242   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2243   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2244 }
2245
2246
2247 int echo_indexed_call_count = 0;
2248
2249
2250 static void EchoIndexedProperty(
2251     uint32_t index,
2252     const v8::PropertyCallbackInfo<v8::Value>& info) {
2253   ApiTestFuzzer::Fuzz();
2254   CHECK_EQ(v8_num(637), info.Data());
2255   echo_indexed_call_count++;
2256   info.GetReturnValue().Set(v8_num(index));
2257 }
2258
2259
2260 THREADED_TEST(IndexedPropertyHandlerGetter) {
2261   v8::Isolate* isolate = CcTest::isolate();
2262   v8::HandleScope scope(isolate);
2263   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2264   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2265                                                        0, 0, 0, 0,
2266                                                        v8_num(637));
2267   LocalContext env;
2268   env->Global()->Set(v8_str("obj"),
2269                      templ->GetFunction()->NewInstance());
2270   Local<Script> script = v8_compile("obj[900]");
2271   CHECK_EQ(script->Run()->Int32Value(), 900);
2272 }
2273
2274
2275 v8::Handle<v8::Object> bottom;
2276
2277 static void CheckThisIndexedPropertyHandler(
2278     uint32_t index,
2279     const v8::PropertyCallbackInfo<v8::Value>& info) {
2280   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2281   ApiTestFuzzer::Fuzz();
2282   CHECK(info.This()->Equals(bottom));
2283 }
2284
2285 static void CheckThisNamedPropertyHandler(
2286     Local<String> name,
2287     const v8::PropertyCallbackInfo<v8::Value>& info) {
2288   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2289   ApiTestFuzzer::Fuzz();
2290   CHECK(info.This()->Equals(bottom));
2291 }
2292
2293 void CheckThisIndexedPropertySetter(
2294     uint32_t index,
2295     Local<Value> value,
2296     const v8::PropertyCallbackInfo<v8::Value>& info) {
2297   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2298   ApiTestFuzzer::Fuzz();
2299   CHECK(info.This()->Equals(bottom));
2300 }
2301
2302
2303 void CheckThisNamedPropertySetter(
2304     Local<String> property,
2305     Local<Value> value,
2306     const v8::PropertyCallbackInfo<v8::Value>& info) {
2307   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2308   ApiTestFuzzer::Fuzz();
2309   CHECK(info.This()->Equals(bottom));
2310 }
2311
2312 void CheckThisIndexedPropertyQuery(
2313     uint32_t index,
2314     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2315   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2316   ApiTestFuzzer::Fuzz();
2317   CHECK(info.This()->Equals(bottom));
2318 }
2319
2320
2321 void CheckThisNamedPropertyQuery(
2322     Local<String> property,
2323     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2324   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2325   ApiTestFuzzer::Fuzz();
2326   CHECK(info.This()->Equals(bottom));
2327 }
2328
2329
2330 void CheckThisIndexedPropertyDeleter(
2331     uint32_t index,
2332     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2333   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2334   ApiTestFuzzer::Fuzz();
2335   CHECK(info.This()->Equals(bottom));
2336 }
2337
2338
2339 void CheckThisNamedPropertyDeleter(
2340     Local<String> property,
2341     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2342   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2343   ApiTestFuzzer::Fuzz();
2344   CHECK(info.This()->Equals(bottom));
2345 }
2346
2347
2348 void CheckThisIndexedPropertyEnumerator(
2349     const v8::PropertyCallbackInfo<v8::Array>& info) {
2350   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2351   ApiTestFuzzer::Fuzz();
2352   CHECK(info.This()->Equals(bottom));
2353 }
2354
2355
2356 void CheckThisNamedPropertyEnumerator(
2357     const v8::PropertyCallbackInfo<v8::Array>& info) {
2358   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2359   ApiTestFuzzer::Fuzz();
2360   CHECK(info.This()->Equals(bottom));
2361 }
2362
2363
2364 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2365   LocalContext env;
2366   v8::Isolate* isolate = env->GetIsolate();
2367   v8::HandleScope scope(isolate);
2368
2369   // Set up a prototype chain with three interceptors.
2370   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2371   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2372       CheckThisIndexedPropertyHandler,
2373       CheckThisIndexedPropertySetter,
2374       CheckThisIndexedPropertyQuery,
2375       CheckThisIndexedPropertyDeleter,
2376       CheckThisIndexedPropertyEnumerator);
2377
2378   templ->InstanceTemplate()->SetNamedPropertyHandler(
2379       CheckThisNamedPropertyHandler,
2380       CheckThisNamedPropertySetter,
2381       CheckThisNamedPropertyQuery,
2382       CheckThisNamedPropertyDeleter,
2383       CheckThisNamedPropertyEnumerator);
2384
2385   bottom = templ->GetFunction()->NewInstance();
2386   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2387   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2388
2389   bottom->SetPrototype(middle);
2390   middle->SetPrototype(top);
2391   env->Global()->Set(v8_str("obj"), bottom);
2392
2393   // Indexed and named get.
2394   Script::Compile(v8_str("obj[0]"))->Run();
2395   Script::Compile(v8_str("obj.x"))->Run();
2396
2397   // Indexed and named set.
2398   Script::Compile(v8_str("obj[1] = 42"))->Run();
2399   Script::Compile(v8_str("obj.y = 42"))->Run();
2400
2401   // Indexed and named query.
2402   Script::Compile(v8_str("0 in obj"))->Run();
2403   Script::Compile(v8_str("'x' in obj"))->Run();
2404
2405   // Indexed and named deleter.
2406   Script::Compile(v8_str("delete obj[0]"))->Run();
2407   Script::Compile(v8_str("delete obj.x"))->Run();
2408
2409   // Enumerators.
2410   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2411 }
2412
2413
2414 static void PrePropertyHandlerGet(
2415     Local<String> key,
2416     const v8::PropertyCallbackInfo<v8::Value>& info) {
2417   ApiTestFuzzer::Fuzz();
2418   if (v8_str("pre")->Equals(key)) {
2419     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2420   }
2421 }
2422
2423
2424 static void PrePropertyHandlerQuery(
2425     Local<String> key,
2426     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2427   if (v8_str("pre")->Equals(key)) {
2428     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2429   }
2430 }
2431
2432
2433 THREADED_TEST(PrePropertyHandler) {
2434   v8::Isolate* isolate = CcTest::isolate();
2435   v8::HandleScope scope(isolate);
2436   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2437   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2438                                                     0,
2439                                                     PrePropertyHandlerQuery);
2440   LocalContext env(NULL, desc->InstanceTemplate());
2441   Script::Compile(v8_str(
2442       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2443   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2444   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2445   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2446   CHECK_EQ(v8_str("Object: on"), result_on);
2447   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2448   CHECK(result_post.IsEmpty());
2449 }
2450
2451
2452 THREADED_TEST(UndefinedIsNotEnumerable) {
2453   LocalContext env;
2454   v8::HandleScope scope(env->GetIsolate());
2455   v8::Handle<Value> result = Script::Compile(v8_str(
2456       "this.propertyIsEnumerable(undefined)"))->Run();
2457   CHECK(result->IsFalse());
2458 }
2459
2460
2461 v8::Handle<Script> call_recursively_script;
2462 static const int kTargetRecursionDepth = 200;  // near maximum
2463
2464
2465 static void CallScriptRecursivelyCall(
2466     const v8::FunctionCallbackInfo<v8::Value>& args) {
2467   ApiTestFuzzer::Fuzz();
2468   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2469   if (depth == kTargetRecursionDepth) return;
2470   args.This()->Set(v8_str("depth"),
2471                    v8::Integer::New(args.GetIsolate(), depth + 1));
2472   args.GetReturnValue().Set(call_recursively_script->Run());
2473 }
2474
2475
2476 static void CallFunctionRecursivelyCall(
2477     const v8::FunctionCallbackInfo<v8::Value>& args) {
2478   ApiTestFuzzer::Fuzz();
2479   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2480   if (depth == kTargetRecursionDepth) {
2481     printf("[depth = %d]\n", depth);
2482     return;
2483   }
2484   args.This()->Set(v8_str("depth"),
2485                    v8::Integer::New(args.GetIsolate(), depth + 1));
2486   v8::Handle<Value> function =
2487       args.This()->Get(v8_str("callFunctionRecursively"));
2488   args.GetReturnValue().Set(
2489       function.As<Function>()->Call(args.This(), 0, NULL));
2490 }
2491
2492
2493 THREADED_TEST(DeepCrossLanguageRecursion) {
2494   v8::Isolate* isolate = CcTest::isolate();
2495   v8::HandleScope scope(isolate);
2496   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2497   global->Set(v8_str("callScriptRecursively"),
2498               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2499   global->Set(v8_str("callFunctionRecursively"),
2500               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2501   LocalContext env(NULL, global);
2502
2503   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2504   call_recursively_script = v8_compile("callScriptRecursively()");
2505   call_recursively_script->Run();
2506   call_recursively_script = v8::Handle<Script>();
2507
2508   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2509   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2510 }
2511
2512
2513 static void ThrowingPropertyHandlerGet(
2514     Local<String> key,
2515     const v8::PropertyCallbackInfo<v8::Value>& info) {
2516   ApiTestFuzzer::Fuzz();
2517   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2518 }
2519
2520
2521 static void ThrowingPropertyHandlerSet(
2522     Local<String> key,
2523     Local<Value>,
2524     const v8::PropertyCallbackInfo<v8::Value>& info) {
2525   info.GetIsolate()->ThrowException(key);
2526   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2527 }
2528
2529
2530 THREADED_TEST(CallbackExceptionRegression) {
2531   v8::Isolate* isolate = CcTest::isolate();
2532   v8::HandleScope scope(isolate);
2533   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2534   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2535                                ThrowingPropertyHandlerSet);
2536   LocalContext env;
2537   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2538   v8::Handle<Value> otto = Script::Compile(v8_str(
2539       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2540   CHECK_EQ(v8_str("otto"), otto);
2541   v8::Handle<Value> netto = Script::Compile(v8_str(
2542       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2543   CHECK_EQ(v8_str("netto"), netto);
2544 }
2545
2546
2547 THREADED_TEST(FunctionPrototype) {
2548   v8::Isolate* isolate = CcTest::isolate();
2549   v8::HandleScope scope(isolate);
2550   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2551   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2552   LocalContext env;
2553   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2554   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2555   CHECK_EQ(script->Run()->Int32Value(), 321);
2556 }
2557
2558
2559 THREADED_TEST(InternalFields) {
2560   LocalContext env;
2561   v8::Isolate* isolate = env->GetIsolate();
2562   v8::HandleScope scope(isolate);
2563
2564   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2565   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2566   instance_templ->SetInternalFieldCount(1);
2567   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2568   CHECK_EQ(1, obj->InternalFieldCount());
2569   CHECK(obj->GetInternalField(0)->IsUndefined());
2570   obj->SetInternalField(0, v8_num(17));
2571   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2572 }
2573
2574
2575 THREADED_TEST(GlobalObjectInternalFields) {
2576   v8::Isolate* isolate = CcTest::isolate();
2577   v8::HandleScope scope(isolate);
2578   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2579   global_template->SetInternalFieldCount(1);
2580   LocalContext env(NULL, global_template);
2581   v8::Handle<v8::Object> global_proxy = env->Global();
2582   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2583   CHECK_EQ(1, global->InternalFieldCount());
2584   CHECK(global->GetInternalField(0)->IsUndefined());
2585   global->SetInternalField(0, v8_num(17));
2586   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2587 }
2588
2589
2590 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2591   LocalContext env;
2592   v8::HandleScope scope(CcTest::isolate());
2593
2594   v8::Local<v8::Object> global = env->Global();
2595   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2596   CHECK(global->HasRealIndexedProperty(0));
2597 }
2598
2599
2600 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2601                                                void* value) {
2602   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2603   obj->SetAlignedPointerInInternalField(0, value);
2604   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2605   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2606 }
2607
2608
2609 THREADED_TEST(InternalFieldsAlignedPointers) {
2610   LocalContext env;
2611   v8::Isolate* isolate = env->GetIsolate();
2612   v8::HandleScope scope(isolate);
2613
2614   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2615   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2616   instance_templ->SetInternalFieldCount(1);
2617   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2618   CHECK_EQ(1, obj->InternalFieldCount());
2619
2620   CheckAlignedPointerInInternalField(obj, NULL);
2621
2622   int* heap_allocated = new int[100];
2623   CheckAlignedPointerInInternalField(obj, heap_allocated);
2624   delete[] heap_allocated;
2625
2626   int stack_allocated[100];
2627   CheckAlignedPointerInInternalField(obj, stack_allocated);
2628
2629   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2630   CheckAlignedPointerInInternalField(obj, huge);
2631 }
2632
2633
2634 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2635                                               int index,
2636                                               void* value) {
2637   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2638   (*env)->SetAlignedPointerInEmbedderData(index, value);
2639   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2640   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2641 }
2642
2643
2644 static void* AlignedTestPointer(int i) {
2645   return reinterpret_cast<void*>(i * 1234);
2646 }
2647
2648
2649 THREADED_TEST(EmbedderDataAlignedPointers) {
2650   LocalContext env;
2651   v8::HandleScope scope(env->GetIsolate());
2652
2653   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2654
2655   int* heap_allocated = new int[100];
2656   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2657   delete[] heap_allocated;
2658
2659   int stack_allocated[100];
2660   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2661
2662   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2663   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2664
2665   // Test growing of the embedder data's backing store.
2666   for (int i = 0; i < 100; i++) {
2667     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2668   }
2669   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2670   for (int i = 0; i < 100; i++) {
2671     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2672   }
2673 }
2674
2675
2676 static void CheckEmbedderData(LocalContext* env,
2677                               int index,
2678                               v8::Handle<Value> data) {
2679   (*env)->SetEmbedderData(index, data);
2680   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2681 }
2682
2683
2684 THREADED_TEST(EmbedderData) {
2685   LocalContext env;
2686   v8::Isolate* isolate = env->GetIsolate();
2687   v8::HandleScope scope(isolate);
2688
2689   CheckEmbedderData(
2690       &env, 3,
2691       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2692   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2693                                                      "over the lazy dog."));
2694   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2695   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2696 }
2697
2698
2699 THREADED_TEST(IdentityHash) {
2700   LocalContext env;
2701   v8::Isolate* isolate = env->GetIsolate();
2702   v8::HandleScope scope(isolate);
2703
2704   // Ensure that the test starts with an fresh heap to test whether the hash
2705   // code is based on the address.
2706   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2707   Local<v8::Object> obj = v8::Object::New(isolate);
2708   int hash = obj->GetIdentityHash();
2709   int hash1 = obj->GetIdentityHash();
2710   CHECK_EQ(hash, hash1);
2711   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2712   // Since the identity hash is essentially a random number two consecutive
2713   // objects should not be assigned the same hash code. If the test below fails
2714   // the random number generator should be evaluated.
2715   CHECK_NE(hash, hash2);
2716   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2717   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2718   // Make sure that the identity hash is not based on the initial address of
2719   // the object alone. If the test below fails the random number generator
2720   // should be evaluated.
2721   CHECK_NE(hash, hash3);
2722   int hash4 = obj->GetIdentityHash();
2723   CHECK_EQ(hash, hash4);
2724
2725   // Check identity hashes behaviour in the presence of JS accessors.
2726   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2727   {
2728     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2729     Local<v8::Object> o1 = v8::Object::New(isolate);
2730     Local<v8::Object> o2 = v8::Object::New(isolate);
2731     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2732   }
2733   {
2734     CompileRun(
2735         "function cnst() { return 42; };\n"
2736         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2737     Local<v8::Object> o1 = v8::Object::New(isolate);
2738     Local<v8::Object> o2 = v8::Object::New(isolate);
2739     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2740   }
2741 }
2742
2743
2744 THREADED_TEST(SymbolProperties) {
2745   i::FLAG_harmony_symbols = true;
2746
2747   LocalContext env;
2748   v8::Isolate* isolate = env->GetIsolate();
2749   v8::HandleScope scope(isolate);
2750
2751   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2752   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2753   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2754
2755   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2756
2757   // Check basic symbol functionality.
2758   CHECK(sym1->IsSymbol());
2759   CHECK(sym2->IsSymbol());
2760   CHECK(!obj->IsSymbol());
2761
2762   CHECK(sym1->Equals(sym1));
2763   CHECK(sym2->Equals(sym2));
2764   CHECK(!sym1->Equals(sym2));
2765   CHECK(!sym2->Equals(sym1));
2766   CHECK(sym1->StrictEquals(sym1));
2767   CHECK(sym2->StrictEquals(sym2));
2768   CHECK(!sym1->StrictEquals(sym2));
2769   CHECK(!sym2->StrictEquals(sym1));
2770
2771   CHECK(sym2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-symbol")));
2772
2773   v8::Local<v8::Value> sym_val = sym2;
2774   CHECK(sym_val->IsSymbol());
2775   CHECK(sym_val->Equals(sym2));
2776   CHECK(sym_val->StrictEquals(sym2));
2777   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2778
2779   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2780   CHECK(sym_obj->IsSymbolObject());
2781   CHECK(!sym2->IsSymbolObject());
2782   CHECK(!obj->IsSymbolObject());
2783   CHECK(sym_obj->Equals(sym2));
2784   CHECK(!sym_obj->StrictEquals(sym2));
2785   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2786   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2787
2788   // Make sure delete of a non-existent symbol property works.
2789   CHECK(obj->Delete(sym1));
2790   CHECK(!obj->Has(sym1));
2791
2792   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2793   CHECK(obj->Has(sym1));
2794   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2795   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2796   CHECK(obj->Has(sym1));
2797   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2798   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2799
2800   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2801   int num_props = obj->GetPropertyNames()->Length();
2802   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2803                  v8::Integer::New(isolate, 20)));
2804   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2805   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2806
2807   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2808
2809   // Add another property and delete it afterwards to force the object in
2810   // slow case.
2811   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2812   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2813   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2814   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2815   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2816
2817   CHECK(obj->Has(sym1));
2818   CHECK(obj->Has(sym2));
2819   CHECK(obj->Delete(sym2));
2820   CHECK(obj->Has(sym1));
2821   CHECK(!obj->Has(sym2));
2822   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2823   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2824
2825   // Symbol properties are inherited.
2826   v8::Local<v8::Object> child = v8::Object::New(isolate);
2827   child->SetPrototype(obj);
2828   CHECK(child->Has(sym1));
2829   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2830   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2831 }
2832
2833
2834 THREADED_TEST(PrivateProperties) {
2835   LocalContext env;
2836   v8::Isolate* isolate = env->GetIsolate();
2837   v8::HandleScope scope(isolate);
2838
2839   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2840   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2841   v8::Local<v8::Private> priv2 = v8::Private::New(isolate, "my-private");
2842
2843   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2844
2845   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2846
2847   // Make sure delete of a non-existent private symbol property works.
2848   CHECK(obj->DeletePrivate(priv1));
2849   CHECK(!obj->HasPrivate(priv1));
2850
2851   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2852   CHECK(obj->HasPrivate(priv1));
2853   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2854   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2855   CHECK(obj->HasPrivate(priv1));
2856   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2857
2858   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2859   int num_props = obj->GetPropertyNames()->Length();
2860   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2861                  v8::Integer::New(isolate, 20)));
2862   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2863   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2864
2865   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2866
2867   // Add another property and delete it afterwards to force the object in
2868   // slow case.
2869   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2870   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2871   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2872   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2873   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2874
2875   CHECK(obj->HasPrivate(priv1));
2876   CHECK(obj->HasPrivate(priv2));
2877   CHECK(obj->DeletePrivate(priv2));
2878   CHECK(obj->HasPrivate(priv1));
2879   CHECK(!obj->HasPrivate(priv2));
2880   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2881   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2882
2883   // Private properties are inherited (for the time being).
2884   v8::Local<v8::Object> child = v8::Object::New(isolate);
2885   child->SetPrototype(obj);
2886   CHECK(child->HasPrivate(priv1));
2887   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2888   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2889 }
2890
2891
2892 class ScopedArrayBufferContents {
2893  public:
2894   explicit ScopedArrayBufferContents(
2895       const v8::ArrayBuffer::Contents& contents)
2896     : contents_(contents) {}
2897   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2898   void* Data() const { return contents_.Data(); }
2899   size_t ByteLength() const { return contents_.ByteLength(); }
2900  private:
2901   const v8::ArrayBuffer::Contents contents_;
2902 };
2903
2904 template <typename T>
2905 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2906   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2907   for (int i = 0; i < value->InternalFieldCount(); i++) {
2908     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2909   }
2910 }
2911
2912
2913 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2914   LocalContext env;
2915   v8::Isolate* isolate = env->GetIsolate();
2916   v8::HandleScope handle_scope(isolate);
2917
2918   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2919   CheckInternalFieldsAreZero(ab);
2920   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2921   CHECK(!ab->IsExternal());
2922   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2923
2924   ScopedArrayBufferContents ab_contents(ab->Externalize());
2925   CHECK(ab->IsExternal());
2926
2927   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2928   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2929   ASSERT(data != NULL);
2930   env->Global()->Set(v8_str("ab"), ab);
2931
2932   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2933   CHECK_EQ(1024, result->Int32Value());
2934
2935   result = CompileRun("var u8 = new Uint8Array(ab);"
2936                       "u8[0] = 0xFF;"
2937                       "u8[1] = 0xAA;"
2938                       "u8.length");
2939   CHECK_EQ(1024, result->Int32Value());
2940   CHECK_EQ(0xFF, data[0]);
2941   CHECK_EQ(0xAA, data[1]);
2942   data[0] = 0xCC;
2943   data[1] = 0x11;
2944   result = CompileRun("u8[0] + u8[1]");
2945   CHECK_EQ(0xDD, result->Int32Value());
2946 }
2947
2948
2949 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2950   LocalContext env;
2951   v8::Isolate* isolate = env->GetIsolate();
2952   v8::HandleScope handle_scope(isolate);
2953
2954
2955   v8::Local<v8::Value> result =
2956       CompileRun("var ab1 = new ArrayBuffer(2);"
2957                  "var u8_a = new Uint8Array(ab1);"
2958                  "u8_a[0] = 0xAA;"
2959                  "u8_a[1] = 0xFF; u8_a.buffer");
2960   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2961   CheckInternalFieldsAreZero(ab1);
2962   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2963   CHECK(!ab1->IsExternal());
2964   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2965   CHECK(ab1->IsExternal());
2966
2967   result = CompileRun("ab1.byteLength");
2968   CHECK_EQ(2, result->Int32Value());
2969   result = CompileRun("u8_a[0]");
2970   CHECK_EQ(0xAA, result->Int32Value());
2971   result = CompileRun("u8_a[1]");
2972   CHECK_EQ(0xFF, result->Int32Value());
2973   result = CompileRun("var u8_b = new Uint8Array(ab1);"
2974                       "u8_b[0] = 0xBB;"
2975                       "u8_a[0]");
2976   CHECK_EQ(0xBB, result->Int32Value());
2977   result = CompileRun("u8_b[1]");
2978   CHECK_EQ(0xFF, result->Int32Value());
2979
2980   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2981   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2982   CHECK_EQ(0xBB, ab1_data[0]);
2983   CHECK_EQ(0xFF, ab1_data[1]);
2984   ab1_data[0] = 0xCC;
2985   ab1_data[1] = 0x11;
2986   result = CompileRun("u8_a[0] + u8_a[1]");
2987   CHECK_EQ(0xDD, result->Int32Value());
2988 }
2989
2990
2991 THREADED_TEST(ArrayBuffer_External) {
2992   LocalContext env;
2993   v8::Isolate* isolate = env->GetIsolate();
2994   v8::HandleScope handle_scope(isolate);
2995
2996   i::ScopedVector<uint8_t> my_data(100);
2997   memset(my_data.start(), 0, 100);
2998   Local<v8::ArrayBuffer> ab3 =
2999       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3000   CheckInternalFieldsAreZero(ab3);
3001   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3002   CHECK(ab3->IsExternal());
3003
3004   env->Global()->Set(v8_str("ab3"), ab3);
3005
3006   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3007   CHECK_EQ(100, result->Int32Value());
3008
3009   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3010                       "u8_b[0] = 0xBB;"
3011                       "u8_b[1] = 0xCC;"
3012                       "u8_b.length");
3013   CHECK_EQ(100, result->Int32Value());
3014   CHECK_EQ(0xBB, my_data[0]);
3015   CHECK_EQ(0xCC, my_data[1]);
3016   my_data[0] = 0xCC;
3017   my_data[1] = 0x11;
3018   result = CompileRun("u8_b[0] + u8_b[1]");
3019   CHECK_EQ(0xDD, result->Int32Value());
3020 }
3021
3022
3023 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3024   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3025   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3026 }
3027
3028
3029 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3030   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3031   CHECK_EQ(0, static_cast<int>(ta->Length()));
3032   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3033 }
3034
3035
3036 static void CheckIsTypedArrayVarNeutered(const char* name) {
3037   i::ScopedVector<char> source(1024);
3038   i::OS::SNPrintF(source,
3039       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3040       name, name, name);
3041   CHECK(CompileRun(source.start())->IsTrue());
3042   v8::Handle<v8::TypedArray> ta =
3043     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3044   CheckIsNeutered(ta);
3045 }
3046
3047
3048 template <typename TypedArray, int kElementSize>
3049 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3050                                          int byteOffset,
3051                                          int length) {
3052   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3053   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3054   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3055   CHECK_EQ(length, static_cast<int>(ta->Length()));
3056   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3057   return ta;
3058 }
3059
3060
3061 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3062   LocalContext env;
3063   v8::Isolate* isolate = env->GetIsolate();
3064   v8::HandleScope handle_scope(isolate);
3065
3066   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3067
3068   v8::Handle<v8::Uint8Array> u8a =
3069     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3070   v8::Handle<v8::Uint8ClampedArray> u8c =
3071     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3072   v8::Handle<v8::Int8Array> i8a =
3073     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3074
3075   v8::Handle<v8::Uint16Array> u16a =
3076     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3077   v8::Handle<v8::Int16Array> i16a =
3078     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3079
3080   v8::Handle<v8::Uint32Array> u32a =
3081     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3082   v8::Handle<v8::Int32Array> i32a =
3083     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3084
3085   v8::Handle<v8::Float32Array> f32a =
3086     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3087   v8::Handle<v8::Float64Array> f64a =
3088     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3089
3090   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3091   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3092   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3093   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3094
3095   ScopedArrayBufferContents contents(buffer->Externalize());
3096   buffer->Neuter();
3097   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3098   CheckIsNeutered(u8a);
3099   CheckIsNeutered(u8c);
3100   CheckIsNeutered(i8a);
3101   CheckIsNeutered(u16a);
3102   CheckIsNeutered(i16a);
3103   CheckIsNeutered(u32a);
3104   CheckIsNeutered(i32a);
3105   CheckIsNeutered(f32a);
3106   CheckIsNeutered(f64a);
3107   CheckDataViewIsNeutered(dv);
3108 }
3109
3110
3111 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3112   LocalContext env;
3113   v8::Isolate* isolate = env->GetIsolate();
3114   v8::HandleScope handle_scope(isolate);
3115
3116   CompileRun(
3117       "var ab = new ArrayBuffer(1024);"
3118       "var u8a = new Uint8Array(ab, 1, 1023);"
3119       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3120       "var i8a = new Int8Array(ab, 1, 1023);"
3121       "var u16a = new Uint16Array(ab, 2, 511);"
3122       "var i16a = new Int16Array(ab, 2, 511);"
3123       "var u32a = new Uint32Array(ab, 4, 255);"
3124       "var i32a = new Int32Array(ab, 4, 255);"
3125       "var f32a = new Float32Array(ab, 4, 255);"
3126       "var f64a = new Float64Array(ab, 8, 127);"
3127       "var dv = new DataView(ab, 1, 1023);");
3128
3129   v8::Handle<v8::ArrayBuffer> ab =
3130       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3131
3132   v8::Handle<v8::DataView> dv =
3133     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3134
3135   ScopedArrayBufferContents contents(ab->Externalize());
3136   ab->Neuter();
3137   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3138   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3139
3140   CheckIsTypedArrayVarNeutered("u8a");
3141   CheckIsTypedArrayVarNeutered("u8c");
3142   CheckIsTypedArrayVarNeutered("i8a");
3143   CheckIsTypedArrayVarNeutered("u16a");
3144   CheckIsTypedArrayVarNeutered("i16a");
3145   CheckIsTypedArrayVarNeutered("u32a");
3146   CheckIsTypedArrayVarNeutered("i32a");
3147   CheckIsTypedArrayVarNeutered("f32a");
3148   CheckIsTypedArrayVarNeutered("f64a");
3149
3150   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3151   CheckDataViewIsNeutered(dv);
3152 }
3153
3154
3155
3156 THREADED_TEST(HiddenProperties) {
3157   LocalContext env;
3158   v8::Isolate* isolate = env->GetIsolate();
3159   v8::HandleScope scope(isolate);
3160
3161   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3162   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3163   v8::Local<v8::String> empty = v8_str("");
3164   v8::Local<v8::String> prop_name = v8_str("prop_name");
3165
3166   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3167
3168   // Make sure delete of a non-existent hidden value works
3169   CHECK(obj->DeleteHiddenValue(key));
3170
3171   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3172   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3173   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3174   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3175
3176   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3177
3178   // Make sure we do not find the hidden property.
3179   CHECK(!obj->Has(empty));
3180   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3181   CHECK(obj->Get(empty)->IsUndefined());
3182   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3183   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3184   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3185   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3186
3187   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3188
3189   // Add another property and delete it afterwards to force the object in
3190   // slow case.
3191   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3192   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3193   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3194   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3195   CHECK(obj->Delete(prop_name));
3196   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3197
3198   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3199
3200   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3201   CHECK(obj->GetHiddenValue(key).IsEmpty());
3202
3203   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3204   CHECK(obj->DeleteHiddenValue(key));
3205   CHECK(obj->GetHiddenValue(key).IsEmpty());
3206 }
3207
3208
3209 THREADED_TEST(Regress97784) {
3210   // Regression test for crbug.com/97784
3211   // Messing with the Object.prototype should not have effect on
3212   // hidden properties.
3213   LocalContext env;
3214   v8::HandleScope scope(env->GetIsolate());
3215
3216   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3217   v8::Local<v8::String> key = v8_str("hidden");
3218
3219   CompileRun(
3220       "set_called = false;"
3221       "Object.defineProperty("
3222       "    Object.prototype,"
3223       "    'hidden',"
3224       "    {get: function() { return 45; },"
3225       "     set: function() { set_called = true; }})");
3226
3227   CHECK(obj->GetHiddenValue(key).IsEmpty());
3228   // Make sure that the getter and setter from Object.prototype is not invoked.
3229   // If it did we would have full access to the hidden properties in
3230   // the accessor.
3231   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3232   ExpectFalse("set_called");
3233   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3234 }
3235
3236
3237 static bool interceptor_for_hidden_properties_called;
3238 static void InterceptorForHiddenProperties(
3239     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3240   interceptor_for_hidden_properties_called = true;
3241 }
3242
3243
3244 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3245   LocalContext context;
3246   v8::Isolate* isolate = context->GetIsolate();
3247   v8::HandleScope scope(isolate);
3248
3249   interceptor_for_hidden_properties_called = false;
3250
3251   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3252
3253   // Associate an interceptor with an object and start setting hidden values.
3254   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3255   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3256   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3257   Local<v8::Function> function = fun_templ->GetFunction();
3258   Local<v8::Object> obj = function->NewInstance();
3259   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3260   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3261   CHECK(!interceptor_for_hidden_properties_called);
3262 }
3263
3264
3265 THREADED_TEST(External) {
3266   v8::HandleScope scope(CcTest::isolate());
3267   int x = 3;
3268   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3269   LocalContext env;
3270   env->Global()->Set(v8_str("ext"), ext);
3271   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3272   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3273   int* ptr = static_cast<int*>(reext->Value());
3274   CHECK_EQ(x, 3);
3275   *ptr = 10;
3276   CHECK_EQ(x, 10);
3277
3278   // Make sure unaligned pointers are wrapped properly.
3279   char* data = i::StrDup("0123456789");
3280   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3281   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3282   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3283   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3284
3285   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3286   CHECK_EQ('0', *char_ptr);
3287   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3288   CHECK_EQ('1', *char_ptr);
3289   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3290   CHECK_EQ('2', *char_ptr);
3291   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3292   CHECK_EQ('3', *char_ptr);
3293   i::DeleteArray(data);
3294 }
3295
3296
3297 THREADED_TEST(GlobalHandle) {
3298   v8::Isolate* isolate = CcTest::isolate();
3299   v8::Persistent<String> global;
3300   {
3301     v8::HandleScope scope(isolate);
3302     global.Reset(isolate, v8_str("str"));
3303   }
3304   {
3305     v8::HandleScope scope(isolate);
3306     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3307   }
3308   global.Reset();
3309   {
3310     v8::HandleScope scope(isolate);
3311     global.Reset(isolate, v8_str("str"));
3312   }
3313   {
3314     v8::HandleScope scope(isolate);
3315     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3316   }
3317   global.Reset();
3318 }
3319
3320
3321 THREADED_TEST(ResettingGlobalHandle) {
3322   v8::Isolate* isolate = CcTest::isolate();
3323   v8::Persistent<String> global;
3324   {
3325     v8::HandleScope scope(isolate);
3326     global.Reset(isolate, v8_str("str"));
3327   }
3328   v8::internal::GlobalHandles* global_handles =
3329       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3330   int initial_handle_count = global_handles->global_handles_count();
3331   {
3332     v8::HandleScope scope(isolate);
3333     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3334   }
3335   {
3336     v8::HandleScope scope(isolate);
3337     global.Reset(isolate, v8_str("longer"));
3338   }
3339   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3340   {
3341     v8::HandleScope scope(isolate);
3342     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3343   }
3344   global.Reset();
3345   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3346 }
3347
3348
3349 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3350   v8::Isolate* isolate = CcTest::isolate();
3351   v8::Persistent<String> global;
3352   {
3353     v8::HandleScope scope(isolate);
3354     global.Reset(isolate, v8_str("str"));
3355   }
3356   v8::internal::GlobalHandles* global_handles =
3357       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3358   int initial_handle_count = global_handles->global_handles_count();
3359   {
3360     v8::HandleScope scope(isolate);
3361     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3362   }
3363   {
3364     v8::HandleScope scope(isolate);
3365     Local<String> empty;
3366     global.Reset(isolate, empty);
3367   }
3368   CHECK(global.IsEmpty());
3369   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3370 }
3371
3372
3373 template<class T>
3374 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3375   return unique.Pass();
3376 }
3377
3378
3379 template<class T>
3380 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3381                                             const v8::Persistent<T> & global) {
3382   v8::UniquePersistent<String> unique(isolate, global);
3383   return unique.Pass();
3384 }
3385
3386
3387 THREADED_TEST(UniquePersistent) {
3388   v8::Isolate* isolate = CcTest::isolate();
3389   v8::Persistent<String> global;
3390   {
3391     v8::HandleScope scope(isolate);
3392     global.Reset(isolate, v8_str("str"));
3393   }
3394   v8::internal::GlobalHandles* global_handles =
3395       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3396   int initial_handle_count = global_handles->global_handles_count();
3397   {
3398     v8::UniquePersistent<String> unique(isolate, global);
3399     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3400     // Test assignment via Pass
3401     {
3402       v8::UniquePersistent<String> copy = unique.Pass();
3403       CHECK(unique.IsEmpty());
3404       CHECK(copy == global);
3405       CHECK_EQ(initial_handle_count + 1,
3406                global_handles->global_handles_count());
3407       unique = copy.Pass();
3408     }
3409     // Test ctor via Pass
3410     {
3411       v8::UniquePersistent<String> copy(unique.Pass());
3412       CHECK(unique.IsEmpty());
3413       CHECK(copy == global);
3414       CHECK_EQ(initial_handle_count + 1,
3415                global_handles->global_handles_count());
3416       unique = copy.Pass();
3417     }
3418     // Test pass through function call
3419     {
3420       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3421       CHECK(unique.IsEmpty());
3422       CHECK(copy == global);
3423       CHECK_EQ(initial_handle_count + 1,
3424                global_handles->global_handles_count());
3425       unique = copy.Pass();
3426     }
3427     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3428   }
3429   // Test pass from function call
3430   {
3431     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3432     CHECK(unique == global);
3433     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3434   }
3435   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3436   global.Reset();
3437 }
3438
3439
3440 THREADED_TEST(GlobalHandleUpcast) {
3441   v8::Isolate* isolate = CcTest::isolate();
3442   v8::HandleScope scope(isolate);
3443   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3444   v8::Persistent<String> global_string(isolate, local);
3445   v8::Persistent<Value>& global_value =
3446       v8::Persistent<Value>::Cast(global_string);
3447   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3448   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3449   global_string.Reset();
3450 }
3451
3452
3453 THREADED_TEST(HandleEquality) {
3454   v8::Isolate* isolate = CcTest::isolate();
3455   v8::Persistent<String> global1;
3456   v8::Persistent<String> global2;
3457   {
3458     v8::HandleScope scope(isolate);
3459     global1.Reset(isolate, v8_str("str"));
3460     global2.Reset(isolate, v8_str("str2"));
3461   }
3462   CHECK_EQ(global1 == global1, true);
3463   CHECK_EQ(global1 != global1, false);
3464   {
3465     v8::HandleScope scope(isolate);
3466     Local<String> local1 = Local<String>::New(isolate, global1);
3467     Local<String> local2 = Local<String>::New(isolate, global2);
3468
3469     CHECK_EQ(global1 == local1, true);
3470     CHECK_EQ(global1 != local1, false);
3471     CHECK_EQ(local1 == global1, true);
3472     CHECK_EQ(local1 != global1, false);
3473
3474     CHECK_EQ(global1 == local2, false);
3475     CHECK_EQ(global1 != local2, true);
3476     CHECK_EQ(local2 == global1, false);
3477     CHECK_EQ(local2 != global1, true);
3478
3479     CHECK_EQ(local1 == local2, false);
3480     CHECK_EQ(local1 != local2, true);
3481
3482     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3483     CHECK_EQ(local1 == anotherLocal1, true);
3484     CHECK_EQ(local1 != anotherLocal1, false);
3485   }
3486   global1.Reset();
3487   global2.Reset();
3488 }
3489
3490
3491 THREADED_TEST(LocalHandle) {
3492   v8::HandleScope scope(CcTest::isolate());
3493   v8::Local<String> local =
3494       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3495   CHECK_EQ(local->Length(), 3);
3496 }
3497
3498
3499 class WeakCallCounter {
3500  public:
3501   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3502   int id() { return id_; }
3503   void increment() { number_of_weak_calls_++; }
3504   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3505  private:
3506   int id_;
3507   int number_of_weak_calls_;
3508 };
3509
3510
3511 template<typename T>
3512 struct WeakCallCounterAndPersistent {
3513   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3514       : counter(counter) {}
3515   WeakCallCounter* counter;
3516   v8::Persistent<T> handle;
3517 };
3518
3519
3520 template <typename T>
3521 static void WeakPointerCallback(
3522     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3523   CHECK_EQ(1234, data.GetParameter()->counter->id());
3524   data.GetParameter()->counter->increment();
3525   data.GetParameter()->handle.Reset();
3526 }
3527
3528
3529 template<typename T>
3530 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3531   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3532 }
3533
3534
3535 THREADED_TEST(ApiObjectGroups) {
3536   LocalContext env;
3537   v8::Isolate* iso = env->GetIsolate();
3538   HandleScope scope(iso);
3539
3540   WeakCallCounter counter(1234);
3541
3542   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3543   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3544   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3545   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3546   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3547   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3548
3549   {
3550     HandleScope scope(iso);
3551     g1s1.handle.Reset(iso, Object::New(iso));
3552     g1s2.handle.Reset(iso, Object::New(iso));
3553     g1c1.handle.Reset(iso, Object::New(iso));
3554     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3555     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3556     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3557
3558     g2s1.handle.Reset(iso, Object::New(iso));
3559     g2s2.handle.Reset(iso, Object::New(iso));
3560     g2c1.handle.Reset(iso, Object::New(iso));
3561     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3562     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3563     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3564   }
3565
3566   WeakCallCounterAndPersistent<Value> root(&counter);
3567   root.handle.Reset(iso, g1s1.handle);  // make a root.
3568
3569   // Connect group 1 and 2, make a cycle.
3570   {
3571     HandleScope scope(iso);
3572     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3573             Set(0, Local<Value>::New(iso, g2s2.handle)));
3574     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3575             Set(0, Local<Value>::New(iso, g1s1.handle)));
3576   }
3577
3578   {
3579     UniqueId id1 = MakeUniqueId(g1s1.handle);
3580     UniqueId id2 = MakeUniqueId(g2s2.handle);
3581     iso->SetObjectGroupId(g1s1.handle, id1);
3582     iso->SetObjectGroupId(g1s2.handle, id1);
3583     iso->SetReferenceFromGroup(id1, g1c1.handle);
3584     iso->SetObjectGroupId(g2s1.handle, id2);
3585     iso->SetObjectGroupId(g2s2.handle, id2);
3586     iso->SetReferenceFromGroup(id2, g2c1.handle);
3587   }
3588   // Do a single full GC, ensure incremental marking is stopped.
3589   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3590       iso)->heap();
3591   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3592
3593   // All object should be alive.
3594   CHECK_EQ(0, counter.NumberOfWeakCalls());
3595
3596   // Weaken the root.
3597   root.handle.SetWeak(&root, &WeakPointerCallback);
3598   // But make children strong roots---all the objects (except for children)
3599   // should be collectable now.
3600   g1c1.handle.ClearWeak();
3601   g2c1.handle.ClearWeak();
3602
3603   // Groups are deleted, rebuild groups.
3604   {
3605     UniqueId id1 = MakeUniqueId(g1s1.handle);
3606     UniqueId id2 = MakeUniqueId(g2s2.handle);
3607     iso->SetObjectGroupId(g1s1.handle, id1);
3608     iso->SetObjectGroupId(g1s2.handle, id1);
3609     iso->SetReferenceFromGroup(id1, g1c1.handle);
3610     iso->SetObjectGroupId(g2s1.handle, id2);
3611     iso->SetObjectGroupId(g2s2.handle, id2);
3612     iso->SetReferenceFromGroup(id2, g2c1.handle);
3613   }
3614
3615   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3616
3617   // All objects should be gone. 5 global handles in total.
3618   CHECK_EQ(5, counter.NumberOfWeakCalls());
3619
3620   // And now make children weak again and collect them.
3621   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3622   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3623
3624   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3625   CHECK_EQ(7, counter.NumberOfWeakCalls());
3626 }
3627
3628
3629 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3630   LocalContext env;
3631   v8::Isolate* iso = env->GetIsolate();
3632   HandleScope scope(iso);
3633
3634   WeakCallCounter counter(1234);
3635
3636   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3637   WeakCallCounterAndPersistent<String> g1s2(&counter);
3638   WeakCallCounterAndPersistent<String> g1c1(&counter);
3639   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3640   WeakCallCounterAndPersistent<String> g2s2(&counter);
3641   WeakCallCounterAndPersistent<String> g2c1(&counter);
3642
3643   {
3644     HandleScope scope(iso);
3645     g1s1.handle.Reset(iso, Object::New(iso));
3646     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3647     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3648     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3649     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3650     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3651
3652     g2s1.handle.Reset(iso, Object::New(iso));
3653     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3654     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3655     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3656     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3657     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3658   }
3659
3660   WeakCallCounterAndPersistent<Value> root(&counter);
3661   root.handle.Reset(iso, g1s1.handle);  // make a root.
3662
3663   // Connect group 1 and 2, make a cycle.
3664   {
3665     HandleScope scope(iso);
3666     CHECK(Local<Object>::New(iso, g1s1.handle)
3667               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3668     CHECK(Local<Object>::New(iso, g2s1.handle)
3669               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3670   }
3671
3672   {
3673     UniqueId id1 = MakeUniqueId(g1s1.handle);
3674     UniqueId id2 = MakeUniqueId(g2s2.handle);
3675     iso->SetObjectGroupId(g1s1.handle, id1);
3676     iso->SetObjectGroupId(g1s2.handle, id1);
3677     iso->SetReference(g1s1.handle, g1c1.handle);
3678     iso->SetObjectGroupId(g2s1.handle, id2);
3679     iso->SetObjectGroupId(g2s2.handle, id2);
3680     iso->SetReferenceFromGroup(id2, g2c1.handle);
3681   }
3682   // Do a single full GC, ensure incremental marking is stopped.
3683   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3684       iso)->heap();
3685   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3686
3687   // All object should be alive.
3688   CHECK_EQ(0, counter.NumberOfWeakCalls());
3689
3690   // Weaken the root.
3691   root.handle.SetWeak(&root, &WeakPointerCallback);
3692   // But make children strong roots---all the objects (except for children)
3693   // should be collectable now.
3694   g1c1.handle.ClearWeak();
3695   g2c1.handle.ClearWeak();
3696
3697   // Groups are deleted, rebuild groups.
3698   {
3699     UniqueId id1 = MakeUniqueId(g1s1.handle);
3700     UniqueId id2 = MakeUniqueId(g2s2.handle);
3701     iso->SetObjectGroupId(g1s1.handle, id1);
3702     iso->SetObjectGroupId(g1s2.handle, id1);
3703     iso->SetReference(g1s1.handle, g1c1.handle);
3704     iso->SetObjectGroupId(g2s1.handle, id2);
3705     iso->SetObjectGroupId(g2s2.handle, id2);
3706     iso->SetReferenceFromGroup(id2, g2c1.handle);
3707   }
3708
3709   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3710
3711   // All objects should be gone. 5 global handles in total.
3712   CHECK_EQ(5, counter.NumberOfWeakCalls());
3713
3714   // And now make children weak again and collect them.
3715   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3716   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3717
3718   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3719   CHECK_EQ(7, counter.NumberOfWeakCalls());
3720 }
3721
3722
3723 THREADED_TEST(ApiObjectGroupsCycle) {
3724   LocalContext env;
3725   v8::Isolate* iso = env->GetIsolate();
3726   HandleScope scope(iso);
3727
3728   WeakCallCounter counter(1234);
3729
3730   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3731   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3732   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3733   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3734   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3735   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3736   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3737   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3738
3739   {
3740     HandleScope scope(iso);
3741     g1s1.handle.Reset(iso, Object::New(iso));
3742     g1s2.handle.Reset(iso, Object::New(iso));
3743     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3744     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3745     CHECK(g1s1.handle.IsWeak());
3746     CHECK(g1s2.handle.IsWeak());
3747
3748     g2s1.handle.Reset(iso, Object::New(iso));
3749     g2s2.handle.Reset(iso, Object::New(iso));
3750     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3751     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3752     CHECK(g2s1.handle.IsWeak());
3753     CHECK(g2s2.handle.IsWeak());
3754
3755     g3s1.handle.Reset(iso, Object::New(iso));
3756     g3s2.handle.Reset(iso, Object::New(iso));
3757     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3758     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3759     CHECK(g3s1.handle.IsWeak());
3760     CHECK(g3s2.handle.IsWeak());
3761
3762     g4s1.handle.Reset(iso, Object::New(iso));
3763     g4s2.handle.Reset(iso, Object::New(iso));
3764     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3765     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3766     CHECK(g4s1.handle.IsWeak());
3767     CHECK(g4s2.handle.IsWeak());
3768   }
3769
3770   WeakCallCounterAndPersistent<Value> root(&counter);
3771   root.handle.Reset(iso, g1s1.handle);  // make a root.
3772
3773   // Connect groups.  We're building the following cycle:
3774   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3775   // groups.
3776   {
3777     UniqueId id1 = MakeUniqueId(g1s1.handle);
3778     UniqueId id2 = MakeUniqueId(g2s1.handle);
3779     UniqueId id3 = MakeUniqueId(g3s1.handle);
3780     UniqueId id4 = MakeUniqueId(g4s1.handle);
3781     iso->SetObjectGroupId(g1s1.handle, id1);
3782     iso->SetObjectGroupId(g1s2.handle, id1);
3783     iso->SetReferenceFromGroup(id1, g2s1.handle);
3784     iso->SetObjectGroupId(g2s1.handle, id2);
3785     iso->SetObjectGroupId(g2s2.handle, id2);
3786     iso->SetReferenceFromGroup(id2, g3s1.handle);
3787     iso->SetObjectGroupId(g3s1.handle, id3);
3788     iso->SetObjectGroupId(g3s2.handle, id3);
3789     iso->SetReferenceFromGroup(id3, g4s1.handle);
3790     iso->SetObjectGroupId(g4s1.handle, id4);
3791     iso->SetObjectGroupId(g4s2.handle, id4);
3792     iso->SetReferenceFromGroup(id4, g1s1.handle);
3793   }
3794   // Do a single full GC
3795   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3796       iso)->heap();
3797   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3798
3799   // All object should be alive.
3800   CHECK_EQ(0, counter.NumberOfWeakCalls());
3801
3802   // Weaken the root.
3803   root.handle.SetWeak(&root, &WeakPointerCallback);
3804
3805   // Groups are deleted, rebuild groups.
3806   {
3807     UniqueId id1 = MakeUniqueId(g1s1.handle);
3808     UniqueId id2 = MakeUniqueId(g2s1.handle);
3809     UniqueId id3 = MakeUniqueId(g3s1.handle);
3810     UniqueId id4 = MakeUniqueId(g4s1.handle);
3811     iso->SetObjectGroupId(g1s1.handle, id1);
3812     iso->SetObjectGroupId(g1s2.handle, id1);
3813     iso->SetReferenceFromGroup(id1, g2s1.handle);
3814     iso->SetObjectGroupId(g2s1.handle, id2);
3815     iso->SetObjectGroupId(g2s2.handle, id2);
3816     iso->SetReferenceFromGroup(id2, g3s1.handle);
3817     iso->SetObjectGroupId(g3s1.handle, id3);
3818     iso->SetObjectGroupId(g3s2.handle, id3);
3819     iso->SetReferenceFromGroup(id3, g4s1.handle);
3820     iso->SetObjectGroupId(g4s1.handle, id4);
3821     iso->SetObjectGroupId(g4s2.handle, id4);
3822     iso->SetReferenceFromGroup(id4, g1s1.handle);
3823   }
3824
3825   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3826
3827   // All objects should be gone. 9 global handles in total.
3828   CHECK_EQ(9, counter.NumberOfWeakCalls());
3829 }
3830
3831
3832 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3833 // on the buildbots, so was made non-threaded for the time being.
3834 TEST(ApiObjectGroupsCycleForScavenger) {
3835   i::FLAG_stress_compaction = false;
3836   i::FLAG_gc_global = false;
3837   LocalContext env;
3838   v8::Isolate* iso = env->GetIsolate();
3839   HandleScope scope(iso);
3840
3841   WeakCallCounter counter(1234);
3842
3843   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3844   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3845   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3846   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3847   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3848   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3849
3850   {
3851     HandleScope scope(iso);
3852     g1s1.handle.Reset(iso, Object::New(iso));
3853     g1s2.handle.Reset(iso, Object::New(iso));
3854     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3855     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3856
3857     g2s1.handle.Reset(iso, Object::New(iso));
3858     g2s2.handle.Reset(iso, Object::New(iso));
3859     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3860     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3861
3862     g3s1.handle.Reset(iso, Object::New(iso));
3863     g3s2.handle.Reset(iso, Object::New(iso));
3864     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3865     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3866   }
3867
3868   // Make a root.
3869   WeakCallCounterAndPersistent<Value> root(&counter);
3870   root.handle.Reset(iso, g1s1.handle);
3871   root.handle.MarkPartiallyDependent();
3872
3873   // Connect groups.  We're building the following cycle:
3874   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3875   // groups.
3876   {
3877     HandleScope handle_scope(iso);
3878     g1s1.handle.MarkPartiallyDependent();
3879     g1s2.handle.MarkPartiallyDependent();
3880     g2s1.handle.MarkPartiallyDependent();
3881     g2s2.handle.MarkPartiallyDependent();
3882     g3s1.handle.MarkPartiallyDependent();
3883     g3s2.handle.MarkPartiallyDependent();
3884     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3885     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3886     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3887         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3888     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3889     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3890     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3891         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3892     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3893     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3894     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3895         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3896   }
3897
3898   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3899       iso)->heap();
3900   heap->CollectGarbage(i::NEW_SPACE);
3901
3902   // All objects should be alive.
3903   CHECK_EQ(0, counter.NumberOfWeakCalls());
3904
3905   // Weaken the root.
3906   root.handle.SetWeak(&root, &WeakPointerCallback);
3907   root.handle.MarkPartiallyDependent();
3908
3909   // Groups are deleted, rebuild groups.
3910   {
3911     HandleScope handle_scope(iso);
3912     g1s1.handle.MarkPartiallyDependent();
3913     g1s2.handle.MarkPartiallyDependent();
3914     g2s1.handle.MarkPartiallyDependent();
3915     g2s2.handle.MarkPartiallyDependent();
3916     g3s1.handle.MarkPartiallyDependent();
3917     g3s2.handle.MarkPartiallyDependent();
3918     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3919     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3920     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
3921         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3922     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3923     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3924     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
3925         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3926     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3927     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3928     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
3929         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3930   }
3931
3932   heap->CollectGarbage(i::NEW_SPACE);
3933
3934   // All objects should be gone. 7 global handles in total.
3935   CHECK_EQ(7, counter.NumberOfWeakCalls());
3936 }
3937
3938
3939 THREADED_TEST(ScriptException) {
3940   LocalContext env;
3941   v8::HandleScope scope(env->GetIsolate());
3942   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3943   v8::TryCatch try_catch;
3944   Local<Value> result = script->Run();
3945   CHECK(result.IsEmpty());
3946   CHECK(try_catch.HasCaught());
3947   String::Utf8Value exception_value(try_catch.Exception());
3948   CHECK_EQ(*exception_value, "panama!");
3949 }
3950
3951
3952 TEST(TryCatchCustomException) {
3953   LocalContext env;
3954   v8::HandleScope scope(env->GetIsolate());
3955   v8::TryCatch try_catch;
3956   CompileRun("function CustomError() { this.a = 'b'; }"
3957              "(function f() { throw new CustomError(); })();");
3958   CHECK(try_catch.HasCaught());
3959   CHECK(try_catch.Exception()->ToObject()->
3960             Get(v8_str("a"))->Equals(v8_str("b")));
3961 }
3962
3963
3964 bool message_received;
3965
3966
3967 static void check_message_0(v8::Handle<v8::Message> message,
3968                             v8::Handle<Value> data) {
3969   CHECK_EQ(5.76, data->NumberValue());
3970   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3971   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3972   CHECK(!message->IsSharedCrossOrigin());
3973   message_received = true;
3974 }
3975
3976
3977 THREADED_TEST(MessageHandler0) {
3978   message_received = false;
3979   v8::HandleScope scope(CcTest::isolate());
3980   CHECK(!message_received);
3981   LocalContext context;
3982   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3983   v8::ScriptOrigin origin =
3984       v8::ScriptOrigin(v8_str("6.75"));
3985   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3986                                                   &origin);
3987   script->SetData(v8_str("7.56"));
3988   script->Run();
3989   CHECK(message_received);
3990   // clear out the message listener
3991   v8::V8::RemoveMessageListeners(check_message_0);
3992 }
3993
3994
3995 static void check_message_1(v8::Handle<v8::Message> message,
3996                             v8::Handle<Value> data) {
3997   CHECK(data->IsNumber());
3998   CHECK_EQ(1337, data->Int32Value());
3999   CHECK(!message->IsSharedCrossOrigin());
4000   message_received = true;
4001 }
4002
4003
4004 TEST(MessageHandler1) {
4005   message_received = false;
4006   v8::HandleScope scope(CcTest::isolate());
4007   CHECK(!message_received);
4008   v8::V8::AddMessageListener(check_message_1);
4009   LocalContext context;
4010   CompileRun("throw 1337;");
4011   CHECK(message_received);
4012   // clear out the message listener
4013   v8::V8::RemoveMessageListeners(check_message_1);
4014 }
4015
4016
4017 static void check_message_2(v8::Handle<v8::Message> message,
4018                             v8::Handle<Value> data) {
4019   LocalContext context;
4020   CHECK(data->IsObject());
4021   v8::Local<v8::Value> hidden_property =
4022       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4023   CHECK(v8_str("hidden value")->Equals(hidden_property));
4024   CHECK(!message->IsSharedCrossOrigin());
4025   message_received = true;
4026 }
4027
4028
4029 TEST(MessageHandler2) {
4030   message_received = false;
4031   v8::HandleScope scope(CcTest::isolate());
4032   CHECK(!message_received);
4033   v8::V8::AddMessageListener(check_message_2);
4034   LocalContext context;
4035   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4036   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4037                                            v8_str("hidden value"));
4038   context->Global()->Set(v8_str("error"), error);
4039   CompileRun("throw error;");
4040   CHECK(message_received);
4041   // clear out the message listener
4042   v8::V8::RemoveMessageListeners(check_message_2);
4043 }
4044
4045
4046 static void check_message_3(v8::Handle<v8::Message> message,
4047                             v8::Handle<Value> data) {
4048   CHECK(message->IsSharedCrossOrigin());
4049   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4050   message_received = true;
4051 }
4052
4053
4054 TEST(MessageHandler3) {
4055   message_received = false;
4056   v8::Isolate* isolate = CcTest::isolate();
4057   v8::HandleScope scope(isolate);
4058   CHECK(!message_received);
4059   v8::V8::AddMessageListener(check_message_3);
4060   LocalContext context;
4061   v8::ScriptOrigin origin =
4062       v8::ScriptOrigin(v8_str("6.75"),
4063                        v8::Integer::New(isolate, 1),
4064                        v8::Integer::New(isolate, 2),
4065                        v8::True(isolate));
4066   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4067                                                   &origin);
4068   script->Run();
4069   CHECK(message_received);
4070   // clear out the message listener
4071   v8::V8::RemoveMessageListeners(check_message_3);
4072 }
4073
4074
4075 static void check_message_4(v8::Handle<v8::Message> message,
4076                             v8::Handle<Value> data) {
4077   CHECK(!message->IsSharedCrossOrigin());
4078   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4079   message_received = true;
4080 }
4081
4082
4083 TEST(MessageHandler4) {
4084   message_received = false;
4085   v8::Isolate* isolate = CcTest::isolate();
4086   v8::HandleScope scope(isolate);
4087   CHECK(!message_received);
4088   v8::V8::AddMessageListener(check_message_4);
4089   LocalContext context;
4090   v8::ScriptOrigin origin =
4091       v8::ScriptOrigin(v8_str("6.75"),
4092                        v8::Integer::New(isolate, 1),
4093                        v8::Integer::New(isolate, 2),
4094                        v8::False(isolate));
4095   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4096                                                   &origin);
4097   script->Run();
4098   CHECK(message_received);
4099   // clear out the message listener
4100   v8::V8::RemoveMessageListeners(check_message_4);
4101 }
4102
4103
4104 static void check_message_5a(v8::Handle<v8::Message> message,
4105                             v8::Handle<Value> data) {
4106   CHECK(message->IsSharedCrossOrigin());
4107   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4108   message_received = true;
4109 }
4110
4111
4112 static void check_message_5b(v8::Handle<v8::Message> message,
4113                             v8::Handle<Value> data) {
4114   CHECK(!message->IsSharedCrossOrigin());
4115   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
4116   message_received = true;
4117 }
4118
4119
4120 TEST(MessageHandler5) {
4121   message_received = false;
4122   v8::Isolate* isolate = CcTest::isolate();
4123   v8::HandleScope scope(isolate);
4124   CHECK(!message_received);
4125   v8::V8::AddMessageListener(check_message_5a);
4126   LocalContext context;
4127   v8::ScriptOrigin origin =
4128       v8::ScriptOrigin(v8_str("6.75"),
4129                        v8::Integer::New(isolate, 1),
4130                        v8::Integer::New(isolate, 2),
4131                        v8::True(isolate));
4132   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4133                                                   &origin);
4134   script->Run();
4135   CHECK(message_received);
4136   // clear out the message listener
4137   v8::V8::RemoveMessageListeners(check_message_5a);
4138
4139   message_received = false;
4140   v8::V8::AddMessageListener(check_message_5b);
4141   origin =
4142       v8::ScriptOrigin(v8_str("6.75"),
4143                        v8::Integer::New(isolate, 1),
4144                        v8::Integer::New(isolate, 2),
4145                        v8::False(isolate));
4146   script = Script::Compile(v8_str("throw 'error'"),
4147                            &origin);
4148   script->Run();
4149   CHECK(message_received);
4150   // clear out the message listener
4151   v8::V8::RemoveMessageListeners(check_message_5b);
4152 }
4153
4154
4155 THREADED_TEST(GetSetProperty) {
4156   LocalContext context;
4157   v8::Isolate* isolate = context->GetIsolate();
4158   v8::HandleScope scope(isolate);
4159   context->Global()->Set(v8_str("foo"), v8_num(14));
4160   context->Global()->Set(v8_str("12"), v8_num(92));
4161   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4162   context->Global()->Set(v8_num(13), v8_num(56));
4163   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
4164   CHECK_EQ(14, foo->Int32Value());
4165   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
4166   CHECK_EQ(92, twelve->Int32Value());
4167   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
4168   CHECK_EQ(32, sixteen->Int32Value());
4169   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
4170   CHECK_EQ(56, thirteen->Int32Value());
4171   CHECK_EQ(92,
4172            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4173   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4174   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4175   CHECK_EQ(32,
4176            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4177   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4178   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4179   CHECK_EQ(56,
4180            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4181   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4182   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4183 }
4184
4185
4186 THREADED_TEST(PropertyAttributes) {
4187   LocalContext context;
4188   v8::HandleScope scope(context->GetIsolate());
4189   // none
4190   Local<String> prop = v8_str("none");
4191   context->Global()->Set(prop, v8_num(7));
4192   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4193   // read-only
4194   prop = v8_str("read_only");
4195   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
4196   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4197   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4198   Script::Compile(v8_str("read_only = 9"))->Run();
4199   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4200   context->Global()->Set(prop, v8_num(10));
4201   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4202   // dont-delete
4203   prop = v8_str("dont_delete");
4204   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
4205   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4206   Script::Compile(v8_str("delete dont_delete"))->Run();
4207   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4208   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4209   // dont-enum
4210   prop = v8_str("dont_enum");
4211   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4212   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4213   // absent
4214   prop = v8_str("absent");
4215   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4216   Local<Value> fake_prop = v8_num(1);
4217   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4218   // exception
4219   TryCatch try_catch;
4220   Local<Value> exception =
4221       CompileRun("({ toString: function() { throw 'exception';} })");
4222   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4223   CHECK(try_catch.HasCaught());
4224   String::Utf8Value exception_value(try_catch.Exception());
4225   CHECK_EQ("exception", *exception_value);
4226   try_catch.Reset();
4227 }
4228
4229
4230 THREADED_TEST(Array) {
4231   LocalContext context;
4232   v8::HandleScope scope(context->GetIsolate());
4233   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4234   CHECK_EQ(0, array->Length());
4235   CHECK(array->Get(0)->IsUndefined());
4236   CHECK(!array->Has(0));
4237   CHECK(array->Get(100)->IsUndefined());
4238   CHECK(!array->Has(100));
4239   array->Set(2, v8_num(7));
4240   CHECK_EQ(3, array->Length());
4241   CHECK(!array->Has(0));
4242   CHECK(!array->Has(1));
4243   CHECK(array->Has(2));
4244   CHECK_EQ(7, array->Get(2)->Int32Value());
4245   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
4246   Local<v8::Array> arr = obj.As<v8::Array>();
4247   CHECK_EQ(3, arr->Length());
4248   CHECK_EQ(1, arr->Get(0)->Int32Value());
4249   CHECK_EQ(2, arr->Get(1)->Int32Value());
4250   CHECK_EQ(3, arr->Get(2)->Int32Value());
4251   array = v8::Array::New(context->GetIsolate(), 27);
4252   CHECK_EQ(27, array->Length());
4253   array = v8::Array::New(context->GetIsolate(), -27);
4254   CHECK_EQ(0, array->Length());
4255 }
4256
4257
4258 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4259   v8::EscapableHandleScope scope(args.GetIsolate());
4260   ApiTestFuzzer::Fuzz();
4261   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4262   for (int i = 0; i < args.Length(); i++)
4263     result->Set(i, args[i]);
4264   args.GetReturnValue().Set(scope.Escape(result));
4265 }
4266
4267
4268 THREADED_TEST(Vector) {
4269   v8::Isolate* isolate = CcTest::isolate();
4270   v8::HandleScope scope(isolate);
4271   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4272   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4273   LocalContext context(0, global);
4274
4275   const char* fun = "f()";
4276   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4277   CHECK_EQ(0, a0->Length());
4278
4279   const char* fun2 = "f(11)";
4280   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4281   CHECK_EQ(1, a1->Length());
4282   CHECK_EQ(11, a1->Get(0)->Int32Value());
4283
4284   const char* fun3 = "f(12, 13)";
4285   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4286   CHECK_EQ(2, a2->Length());
4287   CHECK_EQ(12, a2->Get(0)->Int32Value());
4288   CHECK_EQ(13, a2->Get(1)->Int32Value());
4289
4290   const char* fun4 = "f(14, 15, 16)";
4291   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4292   CHECK_EQ(3, a3->Length());
4293   CHECK_EQ(14, a3->Get(0)->Int32Value());
4294   CHECK_EQ(15, a3->Get(1)->Int32Value());
4295   CHECK_EQ(16, a3->Get(2)->Int32Value());
4296
4297   const char* fun5 = "f(17, 18, 19, 20)";
4298   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4299   CHECK_EQ(4, a4->Length());
4300   CHECK_EQ(17, a4->Get(0)->Int32Value());
4301   CHECK_EQ(18, a4->Get(1)->Int32Value());
4302   CHECK_EQ(19, a4->Get(2)->Int32Value());
4303   CHECK_EQ(20, a4->Get(3)->Int32Value());
4304 }
4305
4306
4307 THREADED_TEST(FunctionCall) {
4308   LocalContext context;
4309   v8::Isolate* isolate = context->GetIsolate();
4310   v8::HandleScope scope(isolate);
4311   CompileRun(
4312     "function Foo() {"
4313     "  var result = [];"
4314     "  for (var i = 0; i < arguments.length; i++) {"
4315     "    result.push(arguments[i]);"
4316     "  }"
4317     "  return result;"
4318     "}"
4319     "function ReturnThisSloppy() {"
4320     "  return this;"
4321     "}"
4322     "function ReturnThisStrict() {"
4323     "  'use strict';"
4324     "  return this;"
4325     "}");
4326   Local<Function> Foo =
4327       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4328   Local<Function> ReturnThisSloppy =
4329       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4330   Local<Function> ReturnThisStrict =
4331       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4332
4333   v8::Handle<Value>* args0 = NULL;
4334   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4335   CHECK_EQ(0, a0->Length());
4336
4337   v8::Handle<Value> args1[] = { v8_num(1.1) };
4338   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4339   CHECK_EQ(1, a1->Length());
4340   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4341
4342   v8::Handle<Value> args2[] = { v8_num(2.2),
4343                                 v8_num(3.3) };
4344   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4345   CHECK_EQ(2, a2->Length());
4346   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4347   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4348
4349   v8::Handle<Value> args3[] = { v8_num(4.4),
4350                                 v8_num(5.5),
4351                                 v8_num(6.6) };
4352   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4353   CHECK_EQ(3, a3->Length());
4354   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4355   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4356   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4357
4358   v8::Handle<Value> args4[] = { v8_num(7.7),
4359                                 v8_num(8.8),
4360                                 v8_num(9.9),
4361                                 v8_num(10.11) };
4362   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4363   CHECK_EQ(4, a4->Length());
4364   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4365   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4366   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4367   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4368
4369   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4370   CHECK(r1->StrictEquals(context->Global()));
4371   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4372   CHECK(r2->StrictEquals(context->Global()));
4373   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4374   CHECK(r3->IsNumberObject());
4375   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4376   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4377   CHECK(r4->IsStringObject());
4378   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4379   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4380   CHECK(r5->IsBooleanObject());
4381   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4382
4383   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4384   CHECK(r6->IsUndefined());
4385   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4386   CHECK(r7->IsNull());
4387   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4388   CHECK(r8->StrictEquals(v8_num(42)));
4389   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4390   CHECK(r9->StrictEquals(v8_str("hello")));
4391   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4392   CHECK(r10->StrictEquals(v8::True(isolate)));
4393 }
4394
4395
4396 static const char* js_code_causing_out_of_memory =
4397     "var a = new Array(); while(true) a.push(a);";
4398
4399
4400 // These tests run for a long time and prevent us from running tests
4401 // that come after them so they cannot run in parallel.
4402 TEST(OutOfMemory) {
4403   // It's not possible to read a snapshot into a heap with different dimensions.
4404   if (i::Snapshot::IsEnabled()) return;
4405   // Set heap limits.
4406   static const int K = 1024;
4407   v8::ResourceConstraints constraints;
4408   constraints.set_max_young_space_size(256 * K);
4409   constraints.set_max_old_space_size(5 * K * K);
4410   v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4411
4412   // Execute a script that causes out of memory.
4413   LocalContext context;
4414   v8::HandleScope scope(context->GetIsolate());
4415   v8::V8::IgnoreOutOfMemoryException();
4416   Local<Script> script = Script::Compile(String::NewFromUtf8(
4417       context->GetIsolate(), js_code_causing_out_of_memory));
4418   Local<Value> result = script->Run();
4419
4420   // Check for out of memory state.
4421   CHECK(result.IsEmpty());
4422   CHECK(context->HasOutOfMemoryException());
4423 }
4424
4425
4426 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4427   ApiTestFuzzer::Fuzz();
4428
4429   LocalContext context;
4430   v8::HandleScope scope(context->GetIsolate());
4431   Local<Script> script = Script::Compile(String::NewFromUtf8(
4432       context->GetIsolate(), js_code_causing_out_of_memory));
4433   Local<Value> result = script->Run();
4434
4435   // Check for out of memory state.
4436   CHECK(result.IsEmpty());
4437   CHECK(context->HasOutOfMemoryException());
4438
4439   args.GetReturnValue().Set(result);
4440 }
4441
4442
4443 TEST(OutOfMemoryNested) {
4444   // It's not possible to read a snapshot into a heap with different dimensions.
4445   if (i::Snapshot::IsEnabled()) return;
4446   // Set heap limits.
4447   static const int K = 1024;
4448   v8::ResourceConstraints constraints;
4449   constraints.set_max_young_space_size(256 * K);
4450   constraints.set_max_old_space_size(5 * K * K);
4451   v8::Isolate* isolate = CcTest::isolate();
4452   v8::SetResourceConstraints(isolate, &constraints);
4453
4454   v8::HandleScope scope(isolate);
4455   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4456   templ->Set(v8_str("ProvokeOutOfMemory"),
4457              v8::FunctionTemplate::New(isolate, ProvokeOutOfMemory));
4458   LocalContext context(0, templ);
4459   v8::V8::IgnoreOutOfMemoryException();
4460   Local<Value> result = CompileRun(
4461     "var thrown = false;"
4462     "try {"
4463     "  ProvokeOutOfMemory();"
4464     "} catch (e) {"
4465     "  thrown = true;"
4466     "}");
4467   // Check for out of memory state.
4468   CHECK(result.IsEmpty());
4469   CHECK(context->HasOutOfMemoryException());
4470 }
4471
4472
4473 void OOMCallback(const char* location, const char* message) {
4474   exit(0);
4475 }
4476
4477
4478 TEST(HugeConsStringOutOfMemory) {
4479   // It's not possible to read a snapshot into a heap with different dimensions.
4480   if (i::Snapshot::IsEnabled()) return;
4481   // Set heap limits.
4482   static const int K = 1024;
4483   v8::ResourceConstraints constraints;
4484   constraints.set_max_young_space_size(256 * K);
4485   constraints.set_max_old_space_size(4 * K * K);
4486   v8::SetResourceConstraints(CcTest::isolate(), &constraints);
4487
4488   // Execute a script that causes out of memory.
4489   v8::V8::SetFatalErrorHandler(OOMCallback);
4490
4491   LocalContext context;
4492   v8::HandleScope scope(context->GetIsolate());
4493
4494   // Build huge string. This should fail with out of memory exception.
4495   CompileRun(
4496     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4497     "for (var i = 0; i < 22; i++) { str = str + str; }");
4498
4499   CHECK(false);  // Should not return.
4500 }
4501
4502
4503 THREADED_TEST(ConstructCall) {
4504   LocalContext context;
4505   v8::Isolate* isolate = context->GetIsolate();
4506   v8::HandleScope scope(isolate);
4507   CompileRun(
4508     "function Foo() {"
4509     "  var result = [];"
4510     "  for (var i = 0; i < arguments.length; i++) {"
4511     "    result.push(arguments[i]);"
4512     "  }"
4513     "  return result;"
4514     "}");
4515   Local<Function> Foo =
4516       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4517
4518   v8::Handle<Value>* args0 = NULL;
4519   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4520   CHECK_EQ(0, a0->Length());
4521
4522   v8::Handle<Value> args1[] = { v8_num(1.1) };
4523   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4524   CHECK_EQ(1, a1->Length());
4525   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4526
4527   v8::Handle<Value> args2[] = { v8_num(2.2),
4528                                 v8_num(3.3) };
4529   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4530   CHECK_EQ(2, a2->Length());
4531   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4532   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4533
4534   v8::Handle<Value> args3[] = { v8_num(4.4),
4535                                 v8_num(5.5),
4536                                 v8_num(6.6) };
4537   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4538   CHECK_EQ(3, a3->Length());
4539   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4540   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4541   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4542
4543   v8::Handle<Value> args4[] = { v8_num(7.7),
4544                                 v8_num(8.8),
4545                                 v8_num(9.9),
4546                                 v8_num(10.11) };
4547   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4548   CHECK_EQ(4, a4->Length());
4549   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4550   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4551   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4552   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4553 }
4554
4555
4556 static void CheckUncle(v8::TryCatch* try_catch) {
4557   CHECK(try_catch->HasCaught());
4558   String::Utf8Value str_value(try_catch->Exception());
4559   CHECK_EQ(*str_value, "uncle?");
4560   try_catch->Reset();
4561 }
4562
4563
4564 THREADED_TEST(ConversionNumber) {
4565   LocalContext env;
4566   v8::HandleScope scope(env->GetIsolate());
4567   // Very large number.
4568   CompileRun("var obj = Math.pow(2,32) * 1237;");
4569   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4570   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4571   CHECK_EQ(0, obj->ToInt32()->Value());
4572   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4573   // Large number.
4574   CompileRun("var obj = -1234567890123;");
4575   obj = env->Global()->Get(v8_str("obj"));
4576   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4577   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4578   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4579   // Small positive integer.
4580   CompileRun("var obj = 42;");
4581   obj = env->Global()->Get(v8_str("obj"));
4582   CHECK_EQ(42.0, obj->ToNumber()->Value());
4583   CHECK_EQ(42, obj->ToInt32()->Value());
4584   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4585   // Negative integer.
4586   CompileRun("var obj = -37;");
4587   obj = env->Global()->Get(v8_str("obj"));
4588   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4589   CHECK_EQ(-37, obj->ToInt32()->Value());
4590   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4591   // Positive non-int32 integer.
4592   CompileRun("var obj = 0x81234567;");
4593   obj = env->Global()->Get(v8_str("obj"));
4594   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4595   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4596   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4597   // Fraction.
4598   CompileRun("var obj = 42.3;");
4599   obj = env->Global()->Get(v8_str("obj"));
4600   CHECK_EQ(42.3, obj->ToNumber()->Value());
4601   CHECK_EQ(42, obj->ToInt32()->Value());
4602   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4603   // Large negative fraction.
4604   CompileRun("var obj = -5726623061.75;");
4605   obj = env->Global()->Get(v8_str("obj"));
4606   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4607   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4608   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4609 }
4610
4611
4612 THREADED_TEST(isNumberType) {
4613   LocalContext env;
4614   v8::HandleScope scope(env->GetIsolate());
4615   // Very large number.
4616   CompileRun("var obj = Math.pow(2,32) * 1237;");
4617   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4618   CHECK(!obj->IsInt32());
4619   CHECK(!obj->IsUint32());
4620   // Large negative number.
4621   CompileRun("var obj = -1234567890123;");
4622   obj = env->Global()->Get(v8_str("obj"));
4623   CHECK(!obj->IsInt32());
4624   CHECK(!obj->IsUint32());
4625   // Small positive integer.
4626   CompileRun("var obj = 42;");
4627   obj = env->Global()->Get(v8_str("obj"));
4628   CHECK(obj->IsInt32());
4629   CHECK(obj->IsUint32());
4630   // Negative integer.
4631   CompileRun("var obj = -37;");
4632   obj = env->Global()->Get(v8_str("obj"));
4633   CHECK(obj->IsInt32());
4634   CHECK(!obj->IsUint32());
4635   // Positive non-int32 integer.
4636   CompileRun("var obj = 0x81234567;");
4637   obj = env->Global()->Get(v8_str("obj"));
4638   CHECK(!obj->IsInt32());
4639   CHECK(obj->IsUint32());
4640   // Fraction.
4641   CompileRun("var obj = 42.3;");
4642   obj = env->Global()->Get(v8_str("obj"));
4643   CHECK(!obj->IsInt32());
4644   CHECK(!obj->IsUint32());
4645   // Large negative fraction.
4646   CompileRun("var obj = -5726623061.75;");
4647   obj = env->Global()->Get(v8_str("obj"));
4648   CHECK(!obj->IsInt32());
4649   CHECK(!obj->IsUint32());
4650   // Positive zero
4651   CompileRun("var obj = 0.0;");
4652   obj = env->Global()->Get(v8_str("obj"));
4653   CHECK(obj->IsInt32());
4654   CHECK(obj->IsUint32());
4655   // Positive zero
4656   CompileRun("var obj = -0.0;");
4657   obj = env->Global()->Get(v8_str("obj"));
4658   CHECK(!obj->IsInt32());
4659   CHECK(!obj->IsUint32());
4660 }
4661
4662
4663 THREADED_TEST(ConversionException) {
4664   LocalContext env;
4665   v8::Isolate* isolate = env->GetIsolate();
4666   v8::HandleScope scope(isolate);
4667   CompileRun(
4668     "function TestClass() { };"
4669     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4670     "var obj = new TestClass();");
4671   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4672
4673   v8::TryCatch try_catch;
4674
4675   Local<Value> to_string_result = obj->ToString();
4676   CHECK(to_string_result.IsEmpty());
4677   CheckUncle(&try_catch);
4678
4679   Local<Value> to_number_result = obj->ToNumber();
4680   CHECK(to_number_result.IsEmpty());
4681   CheckUncle(&try_catch);
4682
4683   Local<Value> to_integer_result = obj->ToInteger();
4684   CHECK(to_integer_result.IsEmpty());
4685   CheckUncle(&try_catch);
4686
4687   Local<Value> to_uint32_result = obj->ToUint32();
4688   CHECK(to_uint32_result.IsEmpty());
4689   CheckUncle(&try_catch);
4690
4691   Local<Value> to_int32_result = obj->ToInt32();
4692   CHECK(to_int32_result.IsEmpty());
4693   CheckUncle(&try_catch);
4694
4695   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4696   CHECK(to_object_result.IsEmpty());
4697   CHECK(try_catch.HasCaught());
4698   try_catch.Reset();
4699
4700   int32_t int32_value = obj->Int32Value();
4701   CHECK_EQ(0, int32_value);
4702   CheckUncle(&try_catch);
4703
4704   uint32_t uint32_value = obj->Uint32Value();
4705   CHECK_EQ(0, uint32_value);
4706   CheckUncle(&try_catch);
4707
4708   double number_value = obj->NumberValue();
4709   CHECK_NE(0, std::isnan(number_value));
4710   CheckUncle(&try_catch);
4711
4712   int64_t integer_value = obj->IntegerValue();
4713   CHECK_EQ(0.0, static_cast<double>(integer_value));
4714   CheckUncle(&try_catch);
4715 }
4716
4717
4718 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4719   ApiTestFuzzer::Fuzz();
4720   args.GetIsolate()->ThrowException(v8_str("konto"));
4721 }
4722
4723
4724 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4725   if (args.Length() < 1) {
4726     args.GetReturnValue().Set(false);
4727     return;
4728   }
4729   v8::HandleScope scope(args.GetIsolate());
4730   v8::TryCatch try_catch;
4731   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4732   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4733   args.GetReturnValue().Set(try_catch.HasCaught());
4734 }
4735
4736
4737 THREADED_TEST(APICatch) {
4738   v8::Isolate* isolate = CcTest::isolate();
4739   v8::HandleScope scope(isolate);
4740   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4741   templ->Set(v8_str("ThrowFromC"),
4742              v8::FunctionTemplate::New(isolate, ThrowFromC));
4743   LocalContext context(0, templ);
4744   CompileRun(
4745     "var thrown = false;"
4746     "try {"
4747     "  ThrowFromC();"
4748     "} catch (e) {"
4749     "  thrown = true;"
4750     "}");
4751   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4752   CHECK(thrown->BooleanValue());
4753 }
4754
4755
4756 THREADED_TEST(APIThrowTryCatch) {
4757   v8::Isolate* isolate = CcTest::isolate();
4758   v8::HandleScope scope(isolate);
4759   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4760   templ->Set(v8_str("ThrowFromC"),
4761              v8::FunctionTemplate::New(isolate, ThrowFromC));
4762   LocalContext context(0, templ);
4763   v8::TryCatch try_catch;
4764   CompileRun("ThrowFromC();");
4765   CHECK(try_catch.HasCaught());
4766 }
4767
4768
4769 // Test that a try-finally block doesn't shadow a try-catch block
4770 // when setting up an external handler.
4771 //
4772 // BUG(271): Some of the exception propagation does not work on the
4773 // ARM simulator because the simulator separates the C++ stack and the
4774 // JS stack.  This test therefore fails on the simulator.  The test is
4775 // not threaded to allow the threading tests to run on the simulator.
4776 TEST(TryCatchInTryFinally) {
4777   v8::Isolate* isolate = CcTest::isolate();
4778   v8::HandleScope scope(isolate);
4779   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4780   templ->Set(v8_str("CCatcher"),
4781              v8::FunctionTemplate::New(isolate, CCatcher));
4782   LocalContext context(0, templ);
4783   Local<Value> result = CompileRun("try {"
4784                                    "  try {"
4785                                    "    CCatcher('throw 7;');"
4786                                    "  } finally {"
4787                                    "  }"
4788                                    "} catch (e) {"
4789                                    "}");
4790   CHECK(result->IsTrue());
4791 }
4792
4793
4794 static void check_reference_error_message(
4795     v8::Handle<v8::Message> message,
4796     v8::Handle<v8::Value> data) {
4797   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4798   CHECK(message->Get()->Equals(v8_str(reference_error)));
4799 }
4800
4801
4802 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4803   ApiTestFuzzer::Fuzz();
4804   CHECK(false);
4805 }
4806
4807
4808 // Test that overwritten methods are not invoked on uncaught exception
4809 // formatting. However, they are invoked when performing normal error
4810 // string conversions.
4811 TEST(APIThrowMessageOverwrittenToString) {
4812   v8::Isolate* isolate = CcTest::isolate();
4813   v8::HandleScope scope(isolate);
4814   v8::V8::AddMessageListener(check_reference_error_message);
4815   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4816   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4817   LocalContext context(NULL, templ);
4818   CompileRun("asdf;");
4819   CompileRun("var limit = {};"
4820              "limit.valueOf = fail;"
4821              "Error.stackTraceLimit = limit;");
4822   CompileRun("asdf");
4823   CompileRun("Array.prototype.pop = fail;");
4824   CompileRun("Object.prototype.hasOwnProperty = fail;");
4825   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4826   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4827   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4828   CompileRun("ReferenceError.prototype.toString ="
4829              "  function() { return 'Whoops' }");
4830   CompileRun("asdf;");
4831   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4832   CompileRun("asdf;");
4833   CompileRun("ReferenceError.prototype.constructor = void 0;");
4834   CompileRun("asdf;");
4835   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4836   CompileRun("asdf;");
4837   CompileRun("ReferenceError.prototype = new Object();");
4838   CompileRun("asdf;");
4839   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4840   CHECK(string->Equals(v8_str("Whoops")));
4841   CompileRun("ReferenceError.prototype.constructor = new Object();"
4842              "ReferenceError.prototype.constructor.name = 1;"
4843              "Number.prototype.toString = function() { return 'Whoops'; };"
4844              "ReferenceError.prototype.toString = Object.prototype.toString;");
4845   CompileRun("asdf;");
4846   v8::V8::RemoveMessageListeners(check_reference_error_message);
4847 }
4848
4849
4850 static void check_custom_error_tostring(
4851     v8::Handle<v8::Message> message,
4852     v8::Handle<v8::Value> data) {
4853   const char* uncaught_error = "Uncaught MyError toString";
4854   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4855 }
4856
4857
4858 TEST(CustomErrorToString) {
4859   LocalContext context;
4860   v8::HandleScope scope(context->GetIsolate());
4861   v8::V8::AddMessageListener(check_custom_error_tostring);
4862   CompileRun(
4863     "function MyError(name, message) {                   "
4864     "  this.name = name;                                 "
4865     "  this.message = message;                           "
4866     "}                                                   "
4867     "MyError.prototype = Object.create(Error.prototype); "
4868     "MyError.prototype.toString = function() {           "
4869     "  return 'MyError toString';                        "
4870     "};                                                  "
4871     "throw new MyError('my name', 'my message');         ");
4872   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4873 }
4874
4875
4876 static void check_custom_error_message(
4877     v8::Handle<v8::Message> message,
4878     v8::Handle<v8::Value> data) {
4879   const char* uncaught_error = "Uncaught MyError: my message";
4880   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4881   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4882 }
4883
4884
4885 TEST(CustomErrorMessage) {
4886   LocalContext context;
4887   v8::HandleScope scope(context->GetIsolate());
4888   v8::V8::AddMessageListener(check_custom_error_message);
4889
4890   // Handlebars.
4891   CompileRun(
4892     "function MyError(msg) {                             "
4893     "  this.name = 'MyError';                            "
4894     "  this.message = msg;                               "
4895     "}                                                   "
4896     "MyError.prototype = new Error();                    "
4897     "throw new MyError('my message');                    ");
4898
4899   // Closure.
4900   CompileRun(
4901     "function MyError(msg) {                             "
4902     "  this.name = 'MyError';                            "
4903     "  this.message = msg;                               "
4904     "}                                                   "
4905     "inherits = function(childCtor, parentCtor) {        "
4906     "    function tempCtor() {};                         "
4907     "    tempCtor.prototype = parentCtor.prototype;      "
4908     "    childCtor.superClass_ = parentCtor.prototype;   "
4909     "    childCtor.prototype = new tempCtor();           "
4910     "    childCtor.prototype.constructor = childCtor;    "
4911     "};                                                  "
4912     "inherits(MyError, Error);                           "
4913     "throw new MyError('my message');                    ");
4914
4915   // Object.create.
4916   CompileRun(
4917     "function MyError(msg) {                             "
4918     "  this.name = 'MyError';                            "
4919     "  this.message = msg;                               "
4920     "}                                                   "
4921     "MyError.prototype = Object.create(Error.prototype); "
4922     "throw new MyError('my message');                    ");
4923
4924   v8::V8::RemoveMessageListeners(check_custom_error_message);
4925 }
4926
4927
4928 static void receive_message(v8::Handle<v8::Message> message,
4929                             v8::Handle<v8::Value> data) {
4930   message->Get();
4931   message_received = true;
4932 }
4933
4934
4935 TEST(APIThrowMessage) {
4936   message_received = false;
4937   v8::Isolate* isolate = CcTest::isolate();
4938   v8::HandleScope scope(isolate);
4939   v8::V8::AddMessageListener(receive_message);
4940   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4941   templ->Set(v8_str("ThrowFromC"),
4942              v8::FunctionTemplate::New(isolate, ThrowFromC));
4943   LocalContext context(0, templ);
4944   CompileRun("ThrowFromC();");
4945   CHECK(message_received);
4946   v8::V8::RemoveMessageListeners(receive_message);
4947 }
4948
4949
4950 TEST(APIThrowMessageAndVerboseTryCatch) {
4951   message_received = false;
4952   v8::Isolate* isolate = CcTest::isolate();
4953   v8::HandleScope scope(isolate);
4954   v8::V8::AddMessageListener(receive_message);
4955   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4956   templ->Set(v8_str("ThrowFromC"),
4957              v8::FunctionTemplate::New(isolate, ThrowFromC));
4958   LocalContext context(0, templ);
4959   v8::TryCatch try_catch;
4960   try_catch.SetVerbose(true);
4961   Local<Value> result = CompileRun("ThrowFromC();");
4962   CHECK(try_catch.HasCaught());
4963   CHECK(result.IsEmpty());
4964   CHECK(message_received);
4965   v8::V8::RemoveMessageListeners(receive_message);
4966 }
4967
4968
4969 TEST(APIStackOverflowAndVerboseTryCatch) {
4970   message_received = false;
4971   LocalContext context;
4972   v8::HandleScope scope(context->GetIsolate());
4973   v8::V8::AddMessageListener(receive_message);
4974   v8::TryCatch try_catch;
4975   try_catch.SetVerbose(true);
4976   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4977   CHECK(try_catch.HasCaught());
4978   CHECK(result.IsEmpty());
4979   CHECK(message_received);
4980   v8::V8::RemoveMessageListeners(receive_message);
4981 }
4982
4983
4984 THREADED_TEST(ExternalScriptException) {
4985   v8::Isolate* isolate = CcTest::isolate();
4986   v8::HandleScope scope(isolate);
4987   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4988   templ->Set(v8_str("ThrowFromC"),
4989              v8::FunctionTemplate::New(isolate, ThrowFromC));
4990   LocalContext context(0, templ);
4991
4992   v8::TryCatch try_catch;
4993   Local<Script> script
4994       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4995   Local<Value> result = script->Run();
4996   CHECK(result.IsEmpty());
4997   CHECK(try_catch.HasCaught());
4998   String::Utf8Value exception_value(try_catch.Exception());
4999   CHECK_EQ("konto", *exception_value);
5000 }
5001
5002
5003
5004 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5005   ApiTestFuzzer::Fuzz();
5006   CHECK_EQ(4, args.Length());
5007   int count = args[0]->Int32Value();
5008   int cInterval = args[2]->Int32Value();
5009   if (count == 0) {
5010     args.GetIsolate()->ThrowException(v8_str("FromC"));
5011     return;
5012   } else {
5013     Local<v8::Object> global =
5014         args.GetIsolate()->GetCurrentContext()->Global();
5015     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5016     v8::Handle<Value> argv[] = { v8_num(count - 1),
5017                                  args[1],
5018                                  args[2],
5019                                  args[3] };
5020     if (count % cInterval == 0) {
5021       v8::TryCatch try_catch;
5022       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5023       int expected = args[3]->Int32Value();
5024       if (try_catch.HasCaught()) {
5025         CHECK_EQ(expected, count);
5026         CHECK(result.IsEmpty());
5027         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5028       } else {
5029         CHECK_NE(expected, count);
5030       }
5031       args.GetReturnValue().Set(result);
5032       return;
5033     } else {
5034       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5035       return;
5036     }
5037   }
5038 }
5039
5040
5041 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5042   ApiTestFuzzer::Fuzz();
5043   CHECK_EQ(3, args.Length());
5044   bool equality = args[0]->BooleanValue();
5045   int count = args[1]->Int32Value();
5046   int expected = args[2]->Int32Value();
5047   if (equality) {
5048     CHECK_EQ(count, expected);
5049   } else {
5050     CHECK_NE(count, expected);
5051   }
5052 }
5053
5054
5055 THREADED_TEST(EvalInTryFinally) {
5056   LocalContext context;
5057   v8::HandleScope scope(context->GetIsolate());
5058   v8::TryCatch try_catch;
5059   CompileRun("(function() {"
5060              "  try {"
5061              "    eval('asldkf (*&^&*^');"
5062              "  } finally {"
5063              "    return;"
5064              "  }"
5065              "})()");
5066   CHECK(!try_catch.HasCaught());
5067 }
5068
5069
5070 // This test works by making a stack of alternating JavaScript and C
5071 // activations.  These activations set up exception handlers with regular
5072 // intervals, one interval for C activations and another for JavaScript
5073 // activations.  When enough activations have been created an exception is
5074 // thrown and we check that the right activation catches the exception and that
5075 // no other activations do.  The right activation is always the topmost one with
5076 // a handler, regardless of whether it is in JavaScript or C.
5077 //
5078 // The notation used to describe a test case looks like this:
5079 //
5080 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5081 //
5082 // Each entry is an activation, either JS or C.  The index is the count at that
5083 // level.  Stars identify activations with exception handlers, the @ identifies
5084 // the exception handler that should catch the exception.
5085 //
5086 // BUG(271): Some of the exception propagation does not work on the
5087 // ARM simulator because the simulator separates the C++ stack and the
5088 // JS stack.  This test therefore fails on the simulator.  The test is
5089 // not threaded to allow the threading tests to run on the simulator.
5090 TEST(ExceptionOrder) {
5091   v8::Isolate* isolate = CcTest::isolate();
5092   v8::HandleScope scope(isolate);
5093   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5094   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5095   templ->Set(v8_str("CThrowCountDown"),
5096              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5097   LocalContext context(0, templ);
5098   CompileRun(
5099     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5100     "  if (count == 0) throw 'FromJS';"
5101     "  if (count % jsInterval == 0) {"
5102     "    try {"
5103     "      var value = CThrowCountDown(count - 1,"
5104     "                                  jsInterval,"
5105     "                                  cInterval,"
5106     "                                  expected);"
5107     "      check(false, count, expected);"
5108     "      return value;"
5109     "    } catch (e) {"
5110     "      check(true, count, expected);"
5111     "    }"
5112     "  } else {"
5113     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5114     "  }"
5115     "}");
5116   Local<Function> fun =
5117       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5118
5119   const int argc = 4;
5120   //                             count      jsInterval cInterval  expected
5121
5122   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5123   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5124   fun->Call(fun, argc, a0);
5125
5126   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5127   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5128   fun->Call(fun, argc, a1);
5129
5130   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5131   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5132   fun->Call(fun, argc, a2);
5133
5134   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5135   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5136   fun->Call(fun, argc, a3);
5137
5138   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5139   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5140   fun->Call(fun, argc, a4);
5141
5142   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5143   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5144   fun->Call(fun, argc, a5);
5145 }
5146
5147
5148 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5149   ApiTestFuzzer::Fuzz();
5150   CHECK_EQ(1, args.Length());
5151   args.GetIsolate()->ThrowException(args[0]);
5152 }
5153
5154
5155 THREADED_TEST(ThrowValues) {
5156   v8::Isolate* isolate = CcTest::isolate();
5157   v8::HandleScope scope(isolate);
5158   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5159   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5160   LocalContext context(0, templ);
5161   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5162     "function Run(obj) {"
5163     "  try {"
5164     "    Throw(obj);"
5165     "  } catch (e) {"
5166     "    return e;"
5167     "  }"
5168     "  return 'no exception';"
5169     "}"
5170     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5171   CHECK_EQ(5, result->Length());
5172   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5173   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5174   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5175   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5176   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5177   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5178   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5179 }
5180
5181
5182 THREADED_TEST(CatchZero) {
5183   LocalContext context;
5184   v8::HandleScope scope(context->GetIsolate());
5185   v8::TryCatch try_catch;
5186   CHECK(!try_catch.HasCaught());
5187   Script::Compile(v8_str("throw 10"))->Run();
5188   CHECK(try_catch.HasCaught());
5189   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5190   try_catch.Reset();
5191   CHECK(!try_catch.HasCaught());
5192   Script::Compile(v8_str("throw 0"))->Run();
5193   CHECK(try_catch.HasCaught());
5194   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5195 }
5196
5197
5198 THREADED_TEST(CatchExceptionFromWith) {
5199   LocalContext context;
5200   v8::HandleScope scope(context->GetIsolate());
5201   v8::TryCatch try_catch;
5202   CHECK(!try_catch.HasCaught());
5203   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
5204   CHECK(try_catch.HasCaught());
5205 }
5206
5207
5208 THREADED_TEST(TryCatchAndFinallyHidingException) {
5209   LocalContext context;
5210   v8::HandleScope scope(context->GetIsolate());
5211   v8::TryCatch try_catch;
5212   CHECK(!try_catch.HasCaught());
5213   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5214   CompileRun("f({toString: function() { throw 42; }});");
5215   CHECK(!try_catch.HasCaught());
5216 }
5217
5218
5219 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5220   v8::TryCatch try_catch;
5221 }
5222
5223
5224 THREADED_TEST(TryCatchAndFinally) {
5225   LocalContext context;
5226   v8::Isolate* isolate = context->GetIsolate();
5227   v8::HandleScope scope(isolate);
5228   context->Global()->Set(
5229       v8_str("native_with_try_catch"),
5230       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5231   v8::TryCatch try_catch;
5232   CHECK(!try_catch.HasCaught());
5233   CompileRun(
5234       "try {\n"
5235       "  throw new Error('a');\n"
5236       "} finally {\n"
5237       "  native_with_try_catch();\n"
5238       "}\n");
5239   CHECK(try_catch.HasCaught());
5240 }
5241
5242
5243 static void TryCatchNestedHelper(int depth) {
5244   if (depth > 0) {
5245     v8::TryCatch try_catch;
5246     try_catch.SetVerbose(true);
5247     TryCatchNestedHelper(depth - 1);
5248     CHECK(try_catch.HasCaught());
5249     try_catch.ReThrow();
5250   } else {
5251     CcTest::isolate()->ThrowException(v8_str("back"));
5252   }
5253 }
5254
5255
5256 TEST(TryCatchNested) {
5257   v8::V8::Initialize();
5258   LocalContext context;
5259   v8::HandleScope scope(context->GetIsolate());
5260   v8::TryCatch try_catch;
5261   TryCatchNestedHelper(5);
5262   CHECK(try_catch.HasCaught());
5263   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5264 }
5265
5266
5267 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5268   CHECK(try_catch->HasCaught());
5269   Handle<Message> message = try_catch->Message();
5270   Handle<Value> resource = message->GetScriptResourceName();
5271   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5272   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5273                      "Uncaught Error: a"));
5274   CHECK_EQ(1, message->GetLineNumber());
5275   CHECK_EQ(6, message->GetStartColumn());
5276 }
5277
5278
5279 void TryCatchMixedNestingHelper(
5280     const v8::FunctionCallbackInfo<v8::Value>& args) {
5281   ApiTestFuzzer::Fuzz();
5282   v8::TryCatch try_catch;
5283   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5284   CHECK(try_catch.HasCaught());
5285   TryCatchMixedNestingCheck(&try_catch);
5286   try_catch.ReThrow();
5287 }
5288
5289
5290 // This test ensures that an outer TryCatch in the following situation:
5291 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5292 // does not clobber the Message object generated for the inner TryCatch.
5293 // This exercises the ability of TryCatch.ReThrow() to restore the
5294 // inner pending Message before throwing the exception again.
5295 TEST(TryCatchMixedNesting) {
5296   v8::Isolate* isolate = CcTest::isolate();
5297   v8::HandleScope scope(isolate);
5298   v8::V8::Initialize();
5299   v8::TryCatch try_catch;
5300   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5301   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5302              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5303   LocalContext context(0, templ);
5304   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5305   TryCatchMixedNestingCheck(&try_catch);
5306 }
5307
5308
5309 THREADED_TEST(Equality) {
5310   LocalContext context;
5311   v8::Isolate* isolate = context->GetIsolate();
5312   v8::HandleScope scope(context->GetIsolate());
5313   // Check that equality works at all before relying on CHECK_EQ
5314   CHECK(v8_str("a")->Equals(v8_str("a")));
5315   CHECK(!v8_str("a")->Equals(v8_str("b")));
5316
5317   CHECK_EQ(v8_str("a"), v8_str("a"));
5318   CHECK_NE(v8_str("a"), v8_str("b"));
5319   CHECK_EQ(v8_num(1), v8_num(1));
5320   CHECK_EQ(v8_num(1.00), v8_num(1));
5321   CHECK_NE(v8_num(1), v8_num(2));
5322
5323   // Assume String is not internalized.
5324   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5325   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5326   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5327   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5328   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5329   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5330   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5331   CHECK(!not_a_number->StrictEquals(not_a_number));
5332   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5333   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5334
5335   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5336   v8::Persistent<v8::Object> alias(isolate, obj);
5337   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5338   alias.Reset();
5339
5340   CHECK(v8_str("a")->SameValue(v8_str("a")));
5341   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5342   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5343   CHECK(v8_num(1)->SameValue(v8_num(1)));
5344   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5345   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5346   CHECK(not_a_number->SameValue(not_a_number));
5347   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5348   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5349 }
5350
5351
5352 THREADED_TEST(MultiRun) {
5353   LocalContext context;
5354   v8::HandleScope scope(context->GetIsolate());
5355   Local<Script> script = Script::Compile(v8_str("x"));
5356   for (int i = 0; i < 10; i++)
5357     script->Run();
5358 }
5359
5360
5361 static void GetXValue(Local<String> name,
5362                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5363   ApiTestFuzzer::Fuzz();
5364   CHECK_EQ(info.Data(), v8_str("donut"));
5365   CHECK_EQ(name, v8_str("x"));
5366   info.GetReturnValue().Set(name);
5367 }
5368
5369
5370 THREADED_TEST(SimplePropertyRead) {
5371   LocalContext context;
5372   v8::Isolate* isolate = context->GetIsolate();
5373   v8::HandleScope scope(isolate);
5374   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5375   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5376   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5377   Local<Script> script = Script::Compile(v8_str("obj.x"));
5378   for (int i = 0; i < 10; i++) {
5379     Local<Value> result = script->Run();
5380     CHECK_EQ(result, v8_str("x"));
5381   }
5382 }
5383
5384
5385 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5386   LocalContext context;
5387   v8::Isolate* isolate = context->GetIsolate();
5388   v8::HandleScope scope(isolate);
5389   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5390   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5391   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5392
5393   // Uses getOwnPropertyDescriptor to check the configurable status
5394   Local<Script> script_desc
5395     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5396                              "obj, 'x');"
5397                              "prop.configurable;"));
5398   Local<Value> result = script_desc->Run();
5399   CHECK_EQ(result->BooleanValue(), true);
5400
5401   // Redefine get - but still configurable
5402   Local<Script> script_define
5403     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5404                              "            configurable: true };"
5405                              "Object.defineProperty(obj, 'x', desc);"
5406                              "obj.x"));
5407   result = script_define->Run();
5408   CHECK_EQ(result, v8_num(42));
5409
5410   // Check that the accessor is still configurable
5411   result = script_desc->Run();
5412   CHECK_EQ(result->BooleanValue(), true);
5413
5414   // Redefine to a non-configurable
5415   script_define
5416     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5417                              "             configurable: false };"
5418                              "Object.defineProperty(obj, 'x', desc);"
5419                              "obj.x"));
5420   result = script_define->Run();
5421   CHECK_EQ(result, v8_num(43));
5422   result = script_desc->Run();
5423   CHECK_EQ(result->BooleanValue(), false);
5424
5425   // Make sure that it is not possible to redefine again
5426   v8::TryCatch try_catch;
5427   result = script_define->Run();
5428   CHECK(try_catch.HasCaught());
5429   String::Utf8Value exception_value(try_catch.Exception());
5430   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5431 }
5432
5433
5434 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5435   v8::Isolate* isolate = CcTest::isolate();
5436   v8::HandleScope scope(isolate);
5437   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5438   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5439   LocalContext context;
5440   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5441
5442   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5443                                     "Object.getOwnPropertyDescriptor( "
5444                                     "obj, 'x');"
5445                                     "prop.configurable;"));
5446   Local<Value> result = script_desc->Run();
5447   CHECK_EQ(result->BooleanValue(), true);
5448
5449   Local<Script> script_define =
5450     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5451                            "            configurable: true };"
5452                            "Object.defineProperty(obj, 'x', desc);"
5453                            "obj.x"));
5454   result = script_define->Run();
5455   CHECK_EQ(result, v8_num(42));
5456
5457
5458   result = script_desc->Run();
5459   CHECK_EQ(result->BooleanValue(), true);
5460
5461
5462   script_define =
5463     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5464                            "            configurable: false };"
5465                            "Object.defineProperty(obj, 'x', desc);"
5466                            "obj.x"));
5467   result = script_define->Run();
5468   CHECK_EQ(result, v8_num(43));
5469   result = script_desc->Run();
5470
5471   CHECK_EQ(result->BooleanValue(), false);
5472
5473   v8::TryCatch try_catch;
5474   result = script_define->Run();
5475   CHECK(try_catch.HasCaught());
5476   String::Utf8Value exception_value(try_catch.Exception());
5477   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5478 }
5479
5480
5481 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5482                                                 char const* name) {
5483   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5484 }
5485
5486
5487 THREADED_TEST(DefineAPIAccessorOnObject) {
5488   v8::Isolate* isolate = CcTest::isolate();
5489   v8::HandleScope scope(isolate);
5490   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5491   LocalContext context;
5492
5493   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5494   CompileRun("var obj2 = {};");
5495
5496   CHECK(CompileRun("obj1.x")->IsUndefined());
5497   CHECK(CompileRun("obj2.x")->IsUndefined());
5498
5499   CHECK(GetGlobalProperty(&context, "obj1")->
5500       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5501
5502   ExpectString("obj1.x", "x");
5503   CHECK(CompileRun("obj2.x")->IsUndefined());
5504
5505   CHECK(GetGlobalProperty(&context, "obj2")->
5506       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5507
5508   ExpectString("obj1.x", "x");
5509   ExpectString("obj2.x", "x");
5510
5511   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5512   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5513
5514   CompileRun("Object.defineProperty(obj1, 'x',"
5515              "{ get: function() { return 'y'; }, configurable: true })");
5516
5517   ExpectString("obj1.x", "y");
5518   ExpectString("obj2.x", "x");
5519
5520   CompileRun("Object.defineProperty(obj2, 'x',"
5521              "{ get: function() { return 'y'; }, configurable: true })");
5522
5523   ExpectString("obj1.x", "y");
5524   ExpectString("obj2.x", "y");
5525
5526   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5527   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5528
5529   CHECK(GetGlobalProperty(&context, "obj1")->
5530       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5531   CHECK(GetGlobalProperty(&context, "obj2")->
5532       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5533
5534   ExpectString("obj1.x", "x");
5535   ExpectString("obj2.x", "x");
5536
5537   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5538   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5539
5540   // Define getters/setters, but now make them not configurable.
5541   CompileRun("Object.defineProperty(obj1, 'x',"
5542              "{ get: function() { return 'z'; }, configurable: false })");
5543   CompileRun("Object.defineProperty(obj2, 'x',"
5544              "{ get: function() { return 'z'; }, configurable: false })");
5545
5546   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5547   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5548
5549   ExpectString("obj1.x", "z");
5550   ExpectString("obj2.x", "z");
5551
5552   CHECK(!GetGlobalProperty(&context, "obj1")->
5553       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5554   CHECK(!GetGlobalProperty(&context, "obj2")->
5555       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5556
5557   ExpectString("obj1.x", "z");
5558   ExpectString("obj2.x", "z");
5559 }
5560
5561
5562 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5563   v8::Isolate* isolate = CcTest::isolate();
5564   v8::HandleScope scope(isolate);
5565   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5566   LocalContext context;
5567
5568   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5569   CompileRun("var obj2 = {};");
5570
5571   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5572         v8_str("x"),
5573         GetXValue, NULL,
5574         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5575   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5576         v8_str("x"),
5577         GetXValue, NULL,
5578         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5579
5580   ExpectString("obj1.x", "x");
5581   ExpectString("obj2.x", "x");
5582
5583   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5584   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5585
5586   CHECK(!GetGlobalProperty(&context, "obj1")->
5587       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5588   CHECK(!GetGlobalProperty(&context, "obj2")->
5589       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5590
5591   {
5592     v8::TryCatch try_catch;
5593     CompileRun("Object.defineProperty(obj1, 'x',"
5594         "{get: function() { return 'func'; }})");
5595     CHECK(try_catch.HasCaught());
5596     String::Utf8Value exception_value(try_catch.Exception());
5597     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5598   }
5599   {
5600     v8::TryCatch try_catch;
5601     CompileRun("Object.defineProperty(obj2, 'x',"
5602         "{get: function() { return 'func'; }})");
5603     CHECK(try_catch.HasCaught());
5604     String::Utf8Value exception_value(try_catch.Exception());
5605     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5606   }
5607 }
5608
5609
5610 static void Get239Value(Local<String> name,
5611                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5612   ApiTestFuzzer::Fuzz();
5613   CHECK_EQ(info.Data(), v8_str("donut"));
5614   CHECK_EQ(name, v8_str("239"));
5615   info.GetReturnValue().Set(name);
5616 }
5617
5618
5619 THREADED_TEST(ElementAPIAccessor) {
5620   v8::Isolate* isolate = CcTest::isolate();
5621   v8::HandleScope scope(isolate);
5622   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5623   LocalContext context;
5624
5625   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5626   CompileRun("var obj2 = {};");
5627
5628   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5629         v8_str("239"),
5630         Get239Value, NULL,
5631         v8_str("donut")));
5632   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5633         v8_str("239"),
5634         Get239Value, NULL,
5635         v8_str("donut")));
5636
5637   ExpectString("obj1[239]", "239");
5638   ExpectString("obj2[239]", "239");
5639   ExpectString("obj1['239']", "239");
5640   ExpectString("obj2['239']", "239");
5641 }
5642
5643
5644 v8::Persistent<Value> xValue;
5645
5646
5647 static void SetXValue(Local<String> name,
5648                       Local<Value> value,
5649                       const v8::PropertyCallbackInfo<void>& info) {
5650   CHECK_EQ(value, v8_num(4));
5651   CHECK_EQ(info.Data(), v8_str("donut"));
5652   CHECK_EQ(name, v8_str("x"));
5653   CHECK(xValue.IsEmpty());
5654   xValue.Reset(info.GetIsolate(), value);
5655 }
5656
5657
5658 THREADED_TEST(SimplePropertyWrite) {
5659   v8::Isolate* isolate = CcTest::isolate();
5660   v8::HandleScope scope(isolate);
5661   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5662   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5663   LocalContext context;
5664   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5665   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5666   for (int i = 0; i < 10; i++) {
5667     CHECK(xValue.IsEmpty());
5668     script->Run();
5669     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5670     xValue.Reset();
5671   }
5672 }
5673
5674
5675 THREADED_TEST(SetterOnly) {
5676   v8::Isolate* isolate = CcTest::isolate();
5677   v8::HandleScope scope(isolate);
5678   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5679   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5680   LocalContext context;
5681   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5682   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5683   for (int i = 0; i < 10; i++) {
5684     CHECK(xValue.IsEmpty());
5685     script->Run();
5686     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5687     xValue.Reset();
5688   }
5689 }
5690
5691
5692 THREADED_TEST(NoAccessors) {
5693   v8::Isolate* isolate = CcTest::isolate();
5694   v8::HandleScope scope(isolate);
5695   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5696   templ->SetAccessor(v8_str("x"),
5697                      static_cast<v8::AccessorGetterCallback>(NULL),
5698                      NULL,
5699                      v8_str("donut"));
5700   LocalContext context;
5701   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5702   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5703   for (int i = 0; i < 10; i++) {
5704     script->Run();
5705   }
5706 }
5707
5708
5709 static void XPropertyGetter(Local<String> property,
5710                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5711   ApiTestFuzzer::Fuzz();
5712   CHECK(info.Data()->IsUndefined());
5713   info.GetReturnValue().Set(property);
5714 }
5715
5716
5717 THREADED_TEST(NamedInterceptorPropertyRead) {
5718   v8::Isolate* isolate = CcTest::isolate();
5719   v8::HandleScope scope(isolate);
5720   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5721   templ->SetNamedPropertyHandler(XPropertyGetter);
5722   LocalContext context;
5723   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5724   Local<Script> script = Script::Compile(v8_str("obj.x"));
5725   for (int i = 0; i < 10; i++) {
5726     Local<Value> result = script->Run();
5727     CHECK_EQ(result, v8_str("x"));
5728   }
5729 }
5730
5731
5732 THREADED_TEST(NamedInterceptorDictionaryIC) {
5733   v8::Isolate* isolate = CcTest::isolate();
5734   v8::HandleScope scope(isolate);
5735   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5736   templ->SetNamedPropertyHandler(XPropertyGetter);
5737   LocalContext context;
5738   // Create an object with a named interceptor.
5739   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5740   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5741   for (int i = 0; i < 10; i++) {
5742     Local<Value> result = script->Run();
5743     CHECK_EQ(result, v8_str("x"));
5744   }
5745   // Create a slow case object and a function accessing a property in
5746   // that slow case object (with dictionary probing in generated
5747   // code). Then force object with a named interceptor into slow-case,
5748   // pass it to the function, and check that the interceptor is called
5749   // instead of accessing the local property.
5750   Local<Value> result =
5751       CompileRun("function get_x(o) { return o.x; };"
5752                  "var obj = { x : 42, y : 0 };"
5753                  "delete obj.y;"
5754                  "for (var i = 0; i < 10; i++) get_x(obj);"
5755                  "interceptor_obj.x = 42;"
5756                  "interceptor_obj.y = 10;"
5757                  "delete interceptor_obj.y;"
5758                  "get_x(interceptor_obj)");
5759   CHECK_EQ(result, v8_str("x"));
5760 }
5761
5762
5763 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5764   v8::Isolate* isolate = CcTest::isolate();
5765   v8::HandleScope scope(isolate);
5766   v8::Local<Context> context1 = Context::New(isolate);
5767
5768   context1->Enter();
5769   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5770   templ->SetNamedPropertyHandler(XPropertyGetter);
5771   // Create an object with a named interceptor.
5772   v8::Local<v8::Object> object = templ->NewInstance();
5773   context1->Global()->Set(v8_str("interceptor_obj"), object);
5774
5775   // Force the object into the slow case.
5776   CompileRun("interceptor_obj.y = 0;"
5777              "delete interceptor_obj.y;");
5778   context1->Exit();
5779
5780   {
5781     // Introduce the object into a different context.
5782     // Repeat named loads to exercise ICs.
5783     LocalContext context2;
5784     context2->Global()->Set(v8_str("interceptor_obj"), object);
5785     Local<Value> result =
5786       CompileRun("function get_x(o) { return o.x; }"
5787                  "interceptor_obj.x = 42;"
5788                  "for (var i=0; i != 10; i++) {"
5789                  "  get_x(interceptor_obj);"
5790                  "}"
5791                  "get_x(interceptor_obj)");
5792     // Check that the interceptor was actually invoked.
5793     CHECK_EQ(result, v8_str("x"));
5794   }
5795
5796   // Return to the original context and force some object to the slow case
5797   // to cause the NormalizedMapCache to verify.
5798   context1->Enter();
5799   CompileRun("var obj = { x : 0 }; delete obj.x;");
5800   context1->Exit();
5801 }
5802
5803
5804 static void SetXOnPrototypeGetter(
5805     Local<String> property,
5806     const v8::PropertyCallbackInfo<v8::Value>& info) {
5807   // Set x on the prototype object and do not handle the get request.
5808   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5809   proto.As<v8::Object>()->Set(v8_str("x"),
5810                               v8::Integer::New(info.GetIsolate(), 23));
5811 }
5812
5813
5814 // This is a regression test for http://crbug.com/20104. Map
5815 // transitions should not interfere with post interceptor lookup.
5816 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5817   v8::Isolate* isolate = CcTest::isolate();
5818   v8::HandleScope scope(isolate);
5819   Local<v8::FunctionTemplate> function_template =
5820       v8::FunctionTemplate::New(isolate);
5821   Local<v8::ObjectTemplate> instance_template
5822       = function_template->InstanceTemplate();
5823   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5824   LocalContext context;
5825   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5826   // Create an instance of F and introduce a map transition for x.
5827   CompileRun("var o = new F(); o.x = 23;");
5828   // Create an instance of F and invoke the getter. The result should be 23.
5829   Local<Value> result = CompileRun("o = new F(); o.x");
5830   CHECK_EQ(result->Int32Value(), 23);
5831 }
5832
5833
5834 static void IndexedPropertyGetter(
5835     uint32_t index,
5836     const v8::PropertyCallbackInfo<v8::Value>& info) {
5837   ApiTestFuzzer::Fuzz();
5838   if (index == 37) {
5839     info.GetReturnValue().Set(v8_num(625));
5840   }
5841 }
5842
5843
5844 static void IndexedPropertySetter(
5845     uint32_t index,
5846     Local<Value> value,
5847     const v8::PropertyCallbackInfo<v8::Value>& info) {
5848   ApiTestFuzzer::Fuzz();
5849   if (index == 39) {
5850     info.GetReturnValue().Set(value);
5851   }
5852 }
5853
5854
5855 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5856   v8::Isolate* isolate = CcTest::isolate();
5857   v8::HandleScope scope(isolate);
5858   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5859   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5860                                    IndexedPropertySetter);
5861   LocalContext context;
5862   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5863   Local<Script> getter_script = Script::Compile(v8_str(
5864       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5865   Local<Script> setter_script = Script::Compile(v8_str(
5866       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5867       "obj[17] = 23;"
5868       "obj.foo;"));
5869   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5870       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5871       "obj[39] = 47;"
5872       "obj.foo;"));  // This setter should not run, due to the interceptor.
5873   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5874       "obj[37];"));
5875   Local<Value> result = getter_script->Run();
5876   CHECK_EQ(v8_num(5), result);
5877   result = setter_script->Run();
5878   CHECK_EQ(v8_num(23), result);
5879   result = interceptor_setter_script->Run();
5880   CHECK_EQ(v8_num(23), result);
5881   result = interceptor_getter_script->Run();
5882   CHECK_EQ(v8_num(625), result);
5883 }
5884
5885
5886 static void UnboxedDoubleIndexedPropertyGetter(
5887     uint32_t index,
5888     const v8::PropertyCallbackInfo<v8::Value>& info) {
5889   ApiTestFuzzer::Fuzz();
5890   if (index < 25) {
5891     info.GetReturnValue().Set(v8_num(index));
5892   }
5893 }
5894
5895
5896 static void UnboxedDoubleIndexedPropertySetter(
5897     uint32_t index,
5898     Local<Value> value,
5899     const v8::PropertyCallbackInfo<v8::Value>& info) {
5900   ApiTestFuzzer::Fuzz();
5901   if (index < 25) {
5902     info.GetReturnValue().Set(v8_num(index));
5903   }
5904 }
5905
5906
5907 void UnboxedDoubleIndexedPropertyEnumerator(
5908     const v8::PropertyCallbackInfo<v8::Array>& info) {
5909   // Force the list of returned keys to be stored in a FastDoubleArray.
5910   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5911       "keys = new Array(); keys[125000] = 1;"
5912       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5913       "keys.length = 25; keys;"));
5914   Local<Value> result = indexed_property_names_script->Run();
5915   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5916 }
5917
5918
5919 // Make sure that the the interceptor code in the runtime properly handles
5920 // merging property name lists for double-array-backed arrays.
5921 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5922   v8::Isolate* isolate = CcTest::isolate();
5923   v8::HandleScope scope(isolate);
5924   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5925   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5926                                    UnboxedDoubleIndexedPropertySetter,
5927                                    0,
5928                                    0,
5929                                    UnboxedDoubleIndexedPropertyEnumerator);
5930   LocalContext context;
5931   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5932   // When obj is created, force it to be Stored in a FastDoubleArray.
5933   Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5934       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5935       "key_count = 0; "
5936       "for (x in obj) {key_count++;};"
5937       "obj;"));
5938   Local<Value> result = create_unboxed_double_script->Run();
5939   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5940   Local<Script> key_count_check = Script::Compile(v8_str(
5941       "key_count;"));
5942   result = key_count_check->Run();
5943   CHECK_EQ(v8_num(40013), result);
5944 }
5945
5946
5947 void NonStrictArgsIndexedPropertyEnumerator(
5948     const v8::PropertyCallbackInfo<v8::Array>& info) {
5949   // Force the list of returned keys to be stored in a Arguments object.
5950   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5951       "function f(w,x) {"
5952       " return arguments;"
5953       "}"
5954       "keys = f(0, 1, 2, 3);"
5955       "keys;"));
5956   Local<Object> result =
5957       Local<Object>::Cast(indexed_property_names_script->Run());
5958   // Have to populate the handle manually, as it's not Cast-able.
5959   i::Handle<i::JSObject> o =
5960       v8::Utils::OpenHandle<Object, i::JSObject>(result);
5961   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5962   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5963 }
5964
5965
5966 static void NonStrictIndexedPropertyGetter(
5967     uint32_t index,
5968     const v8::PropertyCallbackInfo<v8::Value>& info) {
5969   ApiTestFuzzer::Fuzz();
5970   if (index < 4) {
5971     info.GetReturnValue().Set(v8_num(index));
5972   }
5973 }
5974
5975
5976 // Make sure that the the interceptor code in the runtime properly handles
5977 // merging property name lists for non-string arguments arrays.
5978 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5979   v8::Isolate* isolate = CcTest::isolate();
5980   v8::HandleScope scope(isolate);
5981   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5982   templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5983                                    0,
5984                                    0,
5985                                    0,
5986                                    NonStrictArgsIndexedPropertyEnumerator);
5987   LocalContext context;
5988   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5989   Local<Script> create_args_script =
5990       Script::Compile(v8_str(
5991           "var key_count = 0;"
5992           "for (x in obj) {key_count++;} key_count;"));
5993   Local<Value> result = create_args_script->Run();
5994   CHECK_EQ(v8_num(4), result);
5995 }
5996
5997
5998 static void IdentityIndexedPropertyGetter(
5999     uint32_t index,
6000     const v8::PropertyCallbackInfo<v8::Value>& info) {
6001   info.GetReturnValue().Set(index);
6002 }
6003
6004
6005 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6006   v8::Isolate* isolate = CcTest::isolate();
6007   v8::HandleScope scope(isolate);
6008   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6009   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6010
6011   LocalContext context;
6012   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6013
6014   // Check fast object case.
6015   const char* fast_case_code =
6016       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6017   ExpectString(fast_case_code, "0");
6018
6019   // Check slow case.
6020   const char* slow_case_code =
6021       "obj.x = 1; delete obj.x;"
6022       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6023   ExpectString(slow_case_code, "1");
6024 }
6025
6026
6027 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6028   v8::Isolate* isolate = CcTest::isolate();
6029   v8::HandleScope scope(isolate);
6030   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6031   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6032
6033   LocalContext context;
6034   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6035
6036   const char* code =
6037       "try {"
6038       "  obj[0] = 239;"
6039       "  for (var i = 0; i < 100; i++) {"
6040       "    var v = obj[0];"
6041       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6042       "  }"
6043       "  'PASSED'"
6044       "} catch(e) {"
6045       "  e"
6046       "}";
6047   ExpectString(code, "PASSED");
6048 }
6049
6050
6051 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6052   v8::Isolate* isolate = CcTest::isolate();
6053   v8::HandleScope scope(isolate);
6054   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6055   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6056
6057   LocalContext context;
6058   Local<v8::Object> obj = templ->NewInstance();
6059   obj->TurnOnAccessCheck();
6060   context->Global()->Set(v8_str("obj"), obj);
6061
6062   const char* code =
6063       "try {"
6064       "  for (var i = 0; i < 100; i++) {"
6065       "    var v = obj[0];"
6066       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
6067       "  }"
6068       "  'PASSED'"
6069       "} catch(e) {"
6070       "  e"
6071       "}";
6072   ExpectString(code, "PASSED");
6073 }
6074
6075
6076 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6077   i::FLAG_allow_natives_syntax = true;
6078   v8::Isolate* isolate = CcTest::isolate();
6079   v8::HandleScope scope(isolate);
6080   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6081   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6082
6083   LocalContext context;
6084   Local<v8::Object> obj = templ->NewInstance();
6085   context->Global()->Set(v8_str("obj"), obj);
6086
6087   const char* code =
6088       "try {"
6089       "  for (var i = 0; i < 100; i++) {"
6090       "    var expected = i;"
6091       "    if (i == 5) {"
6092       "      %EnableAccessChecks(obj);"
6093       "      expected = undefined;"
6094       "    }"
6095       "    var v = obj[i];"
6096       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6097       "    if (i == 5) %DisableAccessChecks(obj);"
6098       "  }"
6099       "  'PASSED'"
6100       "} catch(e) {"
6101       "  e"
6102       "}";
6103   ExpectString(code, "PASSED");
6104 }
6105
6106
6107 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6108   v8::Isolate* isolate = CcTest::isolate();
6109   v8::HandleScope scope(isolate);
6110   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6111   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6112
6113   LocalContext context;
6114   Local<v8::Object> obj = templ->NewInstance();
6115   context->Global()->Set(v8_str("obj"), obj);
6116
6117   const char* code =
6118       "try {"
6119       "  for (var i = 0; i < 100; i++) {"
6120       "    var v = obj[i];"
6121       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6122       "  }"
6123       "  'PASSED'"
6124       "} catch(e) {"
6125       "  e"
6126       "}";
6127   ExpectString(code, "PASSED");
6128 }
6129
6130
6131 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6132   v8::Isolate* isolate = CcTest::isolate();
6133   v8::HandleScope scope(isolate);
6134   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6135   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6136
6137   LocalContext context;
6138   Local<v8::Object> obj = templ->NewInstance();
6139   context->Global()->Set(v8_str("obj"), obj);
6140
6141   const char* code =
6142       "try {"
6143       "  for (var i = 0; i < 100; i++) {"
6144       "    var expected = i;"
6145       "    var key = i;"
6146       "    if (i == 25) {"
6147       "       key = -1;"
6148       "       expected = undefined;"
6149       "    }"
6150       "    if (i == 50) {"
6151       "       /* probe minimal Smi number on 32-bit platforms */"
6152       "       key = -(1 << 30);"
6153       "       expected = undefined;"
6154       "    }"
6155       "    if (i == 75) {"
6156       "       /* probe minimal Smi number on 64-bit platforms */"
6157       "       key = 1 << 31;"
6158       "       expected = undefined;"
6159       "    }"
6160       "    var v = obj[key];"
6161       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6162       "  }"
6163       "  'PASSED'"
6164       "} catch(e) {"
6165       "  e"
6166       "}";
6167   ExpectString(code, "PASSED");
6168 }
6169
6170
6171 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6172   v8::Isolate* isolate = CcTest::isolate();
6173   v8::HandleScope scope(isolate);
6174   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6175   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6176
6177   LocalContext context;
6178   Local<v8::Object> obj = templ->NewInstance();
6179   context->Global()->Set(v8_str("obj"), obj);
6180
6181   const char* code =
6182       "try {"
6183       "  for (var i = 0; i < 100; i++) {"
6184       "    var expected = i;"
6185       "    var key = i;"
6186       "    if (i == 50) {"
6187       "       key = 'foobar';"
6188       "       expected = undefined;"
6189       "    }"
6190       "    var v = obj[key];"
6191       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6192       "  }"
6193       "  'PASSED'"
6194       "} catch(e) {"
6195       "  e"
6196       "}";
6197   ExpectString(code, "PASSED");
6198 }
6199
6200
6201 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6202   v8::Isolate* isolate = CcTest::isolate();
6203   v8::HandleScope scope(isolate);
6204   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6205   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6206
6207   LocalContext context;
6208   Local<v8::Object> obj = templ->NewInstance();
6209   context->Global()->Set(v8_str("obj"), obj);
6210
6211   const char* code =
6212       "var original = obj;"
6213       "try {"
6214       "  for (var i = 0; i < 100; i++) {"
6215       "    var expected = i;"
6216       "    if (i == 50) {"
6217       "       obj = {50: 'foobar'};"
6218       "       expected = 'foobar';"
6219       "    }"
6220       "    var v = obj[i];"
6221       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6222       "    if (i == 50) obj = original;"
6223       "  }"
6224       "  'PASSED'"
6225       "} catch(e) {"
6226       "  e"
6227       "}";
6228   ExpectString(code, "PASSED");
6229 }
6230
6231
6232 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6233   v8::Isolate* isolate = CcTest::isolate();
6234   v8::HandleScope scope(isolate);
6235   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6236   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6237
6238   LocalContext context;
6239   Local<v8::Object> obj = templ->NewInstance();
6240   context->Global()->Set(v8_str("obj"), obj);
6241
6242   const char* code =
6243       "var original = obj;"
6244       "try {"
6245       "  for (var i = 0; i < 100; i++) {"
6246       "    var expected = i;"
6247       "    if (i == 5) {"
6248       "       obj = 239;"
6249       "       expected = undefined;"
6250       "    }"
6251       "    var v = obj[i];"
6252       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6253       "    if (i == 5) obj = original;"
6254       "  }"
6255       "  'PASSED'"
6256       "} catch(e) {"
6257       "  e"
6258       "}";
6259   ExpectString(code, "PASSED");
6260 }
6261
6262
6263 THREADED_TEST(IndexedInterceptorOnProto) {
6264   v8::Isolate* isolate = CcTest::isolate();
6265   v8::HandleScope scope(isolate);
6266   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6267   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6268
6269   LocalContext context;
6270   Local<v8::Object> obj = templ->NewInstance();
6271   context->Global()->Set(v8_str("obj"), obj);
6272
6273   const char* code =
6274       "var o = {__proto__: obj};"
6275       "try {"
6276       "  for (var i = 0; i < 100; i++) {"
6277       "    var v = o[i];"
6278       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6279       "  }"
6280       "  'PASSED'"
6281       "} catch(e) {"
6282       "  e"
6283       "}";
6284   ExpectString(code, "PASSED");
6285 }
6286
6287
6288 THREADED_TEST(MultiContexts) {
6289   v8::Isolate* isolate = CcTest::isolate();
6290   v8::HandleScope scope(isolate);
6291   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6292   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6293                                                         DummyCallHandler));
6294
6295   Local<String> password = v8_str("Password");
6296
6297   // Create an environment
6298   LocalContext context0(0, templ);
6299   context0->SetSecurityToken(password);
6300   v8::Handle<v8::Object> global0 = context0->Global();
6301   global0->Set(v8_str("custom"), v8_num(1234));
6302   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6303
6304   // Create an independent environment
6305   LocalContext context1(0, templ);
6306   context1->SetSecurityToken(password);
6307   v8::Handle<v8::Object> global1 = context1->Global();
6308   global1->Set(v8_str("custom"), v8_num(1234));
6309   CHECK_NE(global0, global1);
6310   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6311   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6312
6313   // Now create a new context with the old global
6314   LocalContext context2(0, templ, global1);
6315   context2->SetSecurityToken(password);
6316   v8::Handle<v8::Object> global2 = context2->Global();
6317   CHECK_EQ(global1, global2);
6318   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6319   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6320 }
6321
6322
6323 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6324   // Make sure that functions created by cloning boilerplates cannot
6325   // communicate through their __proto__ field.
6326
6327   v8::HandleScope scope(CcTest::isolate());
6328
6329   LocalContext env0;
6330   v8::Handle<v8::Object> global0 =
6331       env0->Global();
6332   v8::Handle<v8::Object> object0 =
6333       global0->Get(v8_str("Object")).As<v8::Object>();
6334   v8::Handle<v8::Object> tostring0 =
6335       object0->Get(v8_str("toString")).As<v8::Object>();
6336   v8::Handle<v8::Object> proto0 =
6337       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6338   proto0->Set(v8_str("custom"), v8_num(1234));
6339
6340   LocalContext env1;
6341   v8::Handle<v8::Object> global1 =
6342       env1->Global();
6343   v8::Handle<v8::Object> object1 =
6344       global1->Get(v8_str("Object")).As<v8::Object>();
6345   v8::Handle<v8::Object> tostring1 =
6346       object1->Get(v8_str("toString")).As<v8::Object>();
6347   v8::Handle<v8::Object> proto1 =
6348       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6349   CHECK(!proto1->Has(v8_str("custom")));
6350 }
6351
6352
6353 THREADED_TEST(Regress892105) {
6354   // Make sure that object and array literals created by cloning
6355   // boilerplates cannot communicate through their __proto__
6356   // field. This is rather difficult to check, but we try to add stuff
6357   // to Object.prototype and Array.prototype and create a new
6358   // environment. This should succeed.
6359
6360   v8::HandleScope scope(CcTest::isolate());
6361
6362   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6363                                 "Array.prototype.arr = 4567;"
6364                                 "8901");
6365
6366   LocalContext env0;
6367   Local<Script> script0 = Script::Compile(source);
6368   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6369
6370   LocalContext env1;
6371   Local<Script> script1 = Script::Compile(source);
6372   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6373 }
6374
6375
6376 THREADED_TEST(UndetectableObject) {
6377   LocalContext env;
6378   v8::HandleScope scope(env->GetIsolate());
6379
6380   Local<v8::FunctionTemplate> desc =
6381       v8::FunctionTemplate::New(env->GetIsolate());
6382   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6383
6384   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6385   env->Global()->Set(v8_str("undetectable"), obj);
6386
6387   ExpectString("undetectable.toString()", "[object Object]");
6388   ExpectString("typeof undetectable", "undefined");
6389   ExpectString("typeof(undetectable)", "undefined");
6390   ExpectBoolean("typeof undetectable == 'undefined'", true);
6391   ExpectBoolean("typeof undetectable == 'object'", false);
6392   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6393   ExpectBoolean("!undetectable", true);
6394
6395   ExpectObject("true&&undetectable", obj);
6396   ExpectBoolean("false&&undetectable", false);
6397   ExpectBoolean("true||undetectable", true);
6398   ExpectObject("false||undetectable", obj);
6399
6400   ExpectObject("undetectable&&true", obj);
6401   ExpectObject("undetectable&&false", obj);
6402   ExpectBoolean("undetectable||true", true);
6403   ExpectBoolean("undetectable||false", false);
6404
6405   ExpectBoolean("undetectable==null", true);
6406   ExpectBoolean("null==undetectable", true);
6407   ExpectBoolean("undetectable==undefined", true);
6408   ExpectBoolean("undefined==undetectable", true);
6409   ExpectBoolean("undetectable==undetectable", true);
6410
6411
6412   ExpectBoolean("undetectable===null", false);
6413   ExpectBoolean("null===undetectable", false);
6414   ExpectBoolean("undetectable===undefined", false);
6415   ExpectBoolean("undefined===undetectable", false);
6416   ExpectBoolean("undetectable===undetectable", true);
6417 }
6418
6419
6420 THREADED_TEST(VoidLiteral) {
6421   LocalContext env;
6422   v8::Isolate* isolate = env->GetIsolate();
6423   v8::HandleScope scope(isolate);
6424
6425   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6426   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6427
6428   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6429   env->Global()->Set(v8_str("undetectable"), obj);
6430
6431   ExpectBoolean("undefined == void 0", true);
6432   ExpectBoolean("undetectable == void 0", true);
6433   ExpectBoolean("null == void 0", true);
6434   ExpectBoolean("undefined === void 0", true);
6435   ExpectBoolean("undetectable === void 0", false);
6436   ExpectBoolean("null === void 0", false);
6437
6438   ExpectBoolean("void 0 == undefined", true);
6439   ExpectBoolean("void 0 == undetectable", true);
6440   ExpectBoolean("void 0 == null", true);
6441   ExpectBoolean("void 0 === undefined", true);
6442   ExpectBoolean("void 0 === undetectable", false);
6443   ExpectBoolean("void 0 === null", false);
6444
6445   ExpectString("(function() {"
6446                "  try {"
6447                "    return x === void 0;"
6448                "  } catch(e) {"
6449                "    return e.toString();"
6450                "  }"
6451                "})()",
6452                "ReferenceError: x is not defined");
6453   ExpectString("(function() {"
6454                "  try {"
6455                "    return void 0 === x;"
6456                "  } catch(e) {"
6457                "    return e.toString();"
6458                "  }"
6459                "})()",
6460                "ReferenceError: x is not defined");
6461 }
6462
6463
6464 THREADED_TEST(ExtensibleOnUndetectable) {
6465   LocalContext env;
6466   v8::Isolate* isolate = env->GetIsolate();
6467   v8::HandleScope scope(isolate);
6468
6469   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6470   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6471
6472   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6473   env->Global()->Set(v8_str("undetectable"), obj);
6474
6475   Local<String> source = v8_str("undetectable.x = 42;"
6476                                 "undetectable.x");
6477
6478   Local<Script> script = Script::Compile(source);
6479
6480   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6481
6482   ExpectBoolean("Object.isExtensible(undetectable)", true);
6483
6484   source = v8_str("Object.preventExtensions(undetectable);");
6485   script = Script::Compile(source);
6486   script->Run();
6487   ExpectBoolean("Object.isExtensible(undetectable)", false);
6488
6489   source = v8_str("undetectable.y = 2000;");
6490   script = Script::Compile(source);
6491   script->Run();
6492   ExpectBoolean("undetectable.y == undefined", true);
6493 }
6494
6495
6496
6497 THREADED_TEST(UndetectableString) {
6498   LocalContext env;
6499   v8::HandleScope scope(env->GetIsolate());
6500
6501   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6502                                           String::kUndetectableString);
6503   env->Global()->Set(v8_str("undetectable"), obj);
6504
6505   ExpectString("undetectable", "foo");
6506   ExpectString("typeof undetectable", "undefined");
6507   ExpectString("typeof(undetectable)", "undefined");
6508   ExpectBoolean("typeof undetectable == 'undefined'", true);
6509   ExpectBoolean("typeof undetectable == 'string'", false);
6510   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6511   ExpectBoolean("!undetectable", true);
6512
6513   ExpectObject("true&&undetectable", obj);
6514   ExpectBoolean("false&&undetectable", false);
6515   ExpectBoolean("true||undetectable", true);
6516   ExpectObject("false||undetectable", obj);
6517
6518   ExpectObject("undetectable&&true", obj);
6519   ExpectObject("undetectable&&false", obj);
6520   ExpectBoolean("undetectable||true", true);
6521   ExpectBoolean("undetectable||false", false);
6522
6523   ExpectBoolean("undetectable==null", true);
6524   ExpectBoolean("null==undetectable", true);
6525   ExpectBoolean("undetectable==undefined", true);
6526   ExpectBoolean("undefined==undetectable", true);
6527   ExpectBoolean("undetectable==undetectable", true);
6528
6529
6530   ExpectBoolean("undetectable===null", false);
6531   ExpectBoolean("null===undetectable", false);
6532   ExpectBoolean("undetectable===undefined", false);
6533   ExpectBoolean("undefined===undetectable", false);
6534   ExpectBoolean("undetectable===undetectable", true);
6535 }
6536
6537
6538 TEST(UndetectableOptimized) {
6539   i::FLAG_allow_natives_syntax = true;
6540   LocalContext env;
6541   v8::HandleScope scope(env->GetIsolate());
6542
6543   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6544                                           String::kUndetectableString);
6545   env->Global()->Set(v8_str("undetectable"), obj);
6546   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6547
6548   ExpectString(
6549       "function testBranch() {"
6550       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6551       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6552       "}\n"
6553       "function testBool() {"
6554       "  var b1 = !%_IsUndetectableObject(undetectable);"
6555       "  var b2 = %_IsUndetectableObject(detectable);"
6556       "  if (b1) throw 3;"
6557       "  if (b2) throw 4;"
6558       "  return b1 == b2;"
6559       "}\n"
6560       "%OptimizeFunctionOnNextCall(testBranch);"
6561       "%OptimizeFunctionOnNextCall(testBool);"
6562       "for (var i = 0; i < 10; i++) {"
6563       "  testBranch();"
6564       "  testBool();"
6565       "}\n"
6566       "\"PASS\"",
6567       "PASS");
6568 }
6569
6570
6571 template <typename T> static void USE(T) { }
6572
6573
6574 // The point of this test is type checking. We run it only so compilers
6575 // don't complain about an unused function.
6576 TEST(PersistentHandles) {
6577   LocalContext env;
6578   v8::Isolate* isolate = CcTest::isolate();
6579   v8::HandleScope scope(isolate);
6580   Local<String> str = v8_str("foo");
6581   v8::Persistent<String> p_str(isolate, str);
6582   p_str.Reset();
6583   Local<Script> scr = Script::Compile(v8_str(""));
6584   v8::Persistent<Script> p_scr(isolate, scr);
6585   p_scr.Reset();
6586   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6587   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6588   p_templ.Reset();
6589 }
6590
6591
6592 static void HandleLogDelegator(
6593     const v8::FunctionCallbackInfo<v8::Value>& args) {
6594   ApiTestFuzzer::Fuzz();
6595 }
6596
6597
6598 THREADED_TEST(GlobalObjectTemplate) {
6599   v8::Isolate* isolate = CcTest::isolate();
6600   v8::HandleScope handle_scope(isolate);
6601   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6602   global_template->Set(v8_str("JSNI_Log"),
6603                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6604   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6605   Context::Scope context_scope(context);
6606   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6607 }
6608
6609
6610 static const char* kSimpleExtensionSource =
6611   "function Foo() {"
6612   "  return 4;"
6613   "}";
6614
6615
6616 THREADED_TEST(SimpleExtensions) {
6617   v8::HandleScope handle_scope(CcTest::isolate());
6618   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6619   const char* extension_names[] = { "simpletest" };
6620   v8::ExtensionConfiguration extensions(1, extension_names);
6621   v8::Handle<Context> context =
6622       Context::New(CcTest::isolate(), &extensions);
6623   Context::Scope lock(context);
6624   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6625   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6626 }
6627
6628
6629 THREADED_TEST(NullExtensions) {
6630   v8::HandleScope handle_scope(CcTest::isolate());
6631   v8::RegisterExtension(new Extension("nulltest", NULL));
6632   const char* extension_names[] = { "nulltest" };
6633   v8::ExtensionConfiguration extensions(1, extension_names);
6634   v8::Handle<Context> context =
6635       Context::New(CcTest::isolate(), &extensions);
6636   Context::Scope lock(context);
6637   v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6638   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6639 }
6640
6641
6642 static const char* kEmbeddedExtensionSource =
6643     "function Ret54321(){return 54321;}~~@@$"
6644     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6645 static const int kEmbeddedExtensionSourceValidLen = 34;
6646
6647
6648 THREADED_TEST(ExtensionMissingSourceLength) {
6649   v8::HandleScope handle_scope(CcTest::isolate());
6650   v8::RegisterExtension(new Extension("srclentest_fail",
6651                                       kEmbeddedExtensionSource));
6652   const char* extension_names[] = { "srclentest_fail" };
6653   v8::ExtensionConfiguration extensions(1, extension_names);
6654   v8::Handle<Context> context =
6655       Context::New(CcTest::isolate(), &extensions);
6656   CHECK_EQ(0, *context);
6657 }
6658
6659
6660 THREADED_TEST(ExtensionWithSourceLength) {
6661   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6662        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6663     v8::HandleScope handle_scope(CcTest::isolate());
6664     i::ScopedVector<char> extension_name(32);
6665     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6666     v8::RegisterExtension(new Extension(extension_name.start(),
6667                                         kEmbeddedExtensionSource, 0, 0,
6668                                         source_len));
6669     const char* extension_names[1] = { extension_name.start() };
6670     v8::ExtensionConfiguration extensions(1, extension_names);
6671     v8::Handle<Context> context =
6672       Context::New(CcTest::isolate(), &extensions);
6673     if (source_len == kEmbeddedExtensionSourceValidLen) {
6674       Context::Scope lock(context);
6675       v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6676       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6677     } else {
6678       // Anything but exactly the right length should fail to compile.
6679       CHECK_EQ(0, *context);
6680     }
6681   }
6682 }
6683
6684
6685 static const char* kEvalExtensionSource1 =
6686   "function UseEval1() {"
6687   "  var x = 42;"
6688   "  return eval('x');"
6689   "}";
6690
6691
6692 static const char* kEvalExtensionSource2 =
6693   "(function() {"
6694   "  var x = 42;"
6695   "  function e() {"
6696   "    return eval('x');"
6697   "  }"
6698   "  this.UseEval2 = e;"
6699   "})()";
6700
6701
6702 THREADED_TEST(UseEvalFromExtension) {
6703   v8::HandleScope handle_scope(CcTest::isolate());
6704   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6705   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6706   const char* extension_names[] = { "evaltest1", "evaltest2" };
6707   v8::ExtensionConfiguration extensions(2, extension_names);
6708   v8::Handle<Context> context =
6709       Context::New(CcTest::isolate(), &extensions);
6710   Context::Scope lock(context);
6711   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6712   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6713   result = Script::Compile(v8_str("UseEval2()"))->Run();
6714   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6715 }
6716
6717
6718 static const char* kWithExtensionSource1 =
6719   "function UseWith1() {"
6720   "  var x = 42;"
6721   "  with({x:87}) { return x; }"
6722   "}";
6723
6724
6725
6726 static const char* kWithExtensionSource2 =
6727   "(function() {"
6728   "  var x = 42;"
6729   "  function e() {"
6730   "    with ({x:87}) { return x; }"
6731   "  }"
6732   "  this.UseWith2 = e;"
6733   "})()";
6734
6735
6736 THREADED_TEST(UseWithFromExtension) {
6737   v8::HandleScope handle_scope(CcTest::isolate());
6738   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6739   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6740   const char* extension_names[] = { "withtest1", "withtest2" };
6741   v8::ExtensionConfiguration extensions(2, extension_names);
6742   v8::Handle<Context> context =
6743       Context::New(CcTest::isolate(), &extensions);
6744   Context::Scope lock(context);
6745   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6746   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6747   result = Script::Compile(v8_str("UseWith2()"))->Run();
6748   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6749 }
6750
6751
6752 THREADED_TEST(AutoExtensions) {
6753   v8::HandleScope handle_scope(CcTest::isolate());
6754   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6755   extension->set_auto_enable(true);
6756   v8::RegisterExtension(extension);
6757   v8::Handle<Context> context =
6758       Context::New(CcTest::isolate());
6759   Context::Scope lock(context);
6760   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6761   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6762 }
6763
6764
6765 static const char* kSyntaxErrorInExtensionSource =
6766     "[";
6767
6768
6769 // Test that a syntax error in an extension does not cause a fatal
6770 // error but results in an empty context.
6771 THREADED_TEST(SyntaxErrorExtensions) {
6772   v8::HandleScope handle_scope(CcTest::isolate());
6773   v8::RegisterExtension(new Extension("syntaxerror",
6774                                       kSyntaxErrorInExtensionSource));
6775   const char* extension_names[] = { "syntaxerror" };
6776   v8::ExtensionConfiguration extensions(1, extension_names);
6777   v8::Handle<Context> context =
6778       Context::New(CcTest::isolate(), &extensions);
6779   CHECK(context.IsEmpty());
6780 }
6781
6782
6783 static const char* kExceptionInExtensionSource =
6784     "throw 42";
6785
6786
6787 // Test that an exception when installing an extension does not cause
6788 // a fatal error but results in an empty context.
6789 THREADED_TEST(ExceptionExtensions) {
6790   v8::HandleScope handle_scope(CcTest::isolate());
6791   v8::RegisterExtension(new Extension("exception",
6792                                       kExceptionInExtensionSource));
6793   const char* extension_names[] = { "exception" };
6794   v8::ExtensionConfiguration extensions(1, extension_names);
6795   v8::Handle<Context> context =
6796       Context::New(CcTest::isolate(), &extensions);
6797   CHECK(context.IsEmpty());
6798 }
6799
6800
6801 static const char* kNativeCallInExtensionSource =
6802     "function call_runtime_last_index_of(x) {"
6803     "  return %StringLastIndexOf(x, 'bob', 10);"
6804     "}";
6805
6806
6807 static const char* kNativeCallTest =
6808     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6809
6810 // Test that a native runtime calls are supported in extensions.
6811 THREADED_TEST(NativeCallInExtensions) {
6812   v8::HandleScope handle_scope(CcTest::isolate());
6813   v8::RegisterExtension(new Extension("nativecall",
6814                                       kNativeCallInExtensionSource));
6815   const char* extension_names[] = { "nativecall" };
6816   v8::ExtensionConfiguration extensions(1, extension_names);
6817   v8::Handle<Context> context =
6818       Context::New(CcTest::isolate(), &extensions);
6819   Context::Scope lock(context);
6820   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6821   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6822 }
6823
6824
6825 class NativeFunctionExtension : public Extension {
6826  public:
6827   NativeFunctionExtension(const char* name,
6828                           const char* source,
6829                           v8::FunctionCallback fun = &Echo)
6830       : Extension(name, source),
6831         function_(fun) { }
6832
6833   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6834       v8::Isolate* isolate,
6835       v8::Handle<v8::String> name) {
6836     return v8::FunctionTemplate::New(isolate, function_);
6837   }
6838
6839   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6840     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6841   }
6842  private:
6843   v8::FunctionCallback function_;
6844 };
6845
6846
6847 THREADED_TEST(NativeFunctionDeclaration) {
6848   v8::HandleScope handle_scope(CcTest::isolate());
6849   const char* name = "nativedecl";
6850   v8::RegisterExtension(new NativeFunctionExtension(name,
6851                                                     "native function foo();"));
6852   const char* extension_names[] = { name };
6853   v8::ExtensionConfiguration extensions(1, extension_names);
6854   v8::Handle<Context> context =
6855       Context::New(CcTest::isolate(), &extensions);
6856   Context::Scope lock(context);
6857   v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6858   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6859 }
6860
6861
6862 THREADED_TEST(NativeFunctionDeclarationError) {
6863   v8::HandleScope handle_scope(CcTest::isolate());
6864   const char* name = "nativedeclerr";
6865   // Syntax error in extension code.
6866   v8::RegisterExtension(new NativeFunctionExtension(name,
6867                                                     "native\nfunction foo();"));
6868   const char* extension_names[] = { name };
6869   v8::ExtensionConfiguration extensions(1, extension_names);
6870   v8::Handle<Context> context =
6871       Context::New(CcTest::isolate(), &extensions);
6872   CHECK(context.IsEmpty());
6873 }
6874
6875
6876 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6877   v8::HandleScope handle_scope(CcTest::isolate());
6878   const char* name = "nativedeclerresc";
6879   // Syntax error in extension code - escape code in "native" means that
6880   // it's not treated as a keyword.
6881   v8::RegisterExtension(new NativeFunctionExtension(
6882       name,
6883       "nativ\\u0065 function foo();"));
6884   const char* extension_names[] = { name };
6885   v8::ExtensionConfiguration extensions(1, extension_names);
6886   v8::Handle<Context> context =
6887       Context::New(CcTest::isolate(), &extensions);
6888   CHECK(context.IsEmpty());
6889 }
6890
6891
6892 static void CheckDependencies(const char* name, const char* expected) {
6893   v8::HandleScope handle_scope(CcTest::isolate());
6894   v8::ExtensionConfiguration config(1, &name);
6895   LocalContext context(&config);
6896   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
6897            context->Global()->Get(v8_str("loaded")));
6898 }
6899
6900
6901 /*
6902  * Configuration:
6903  *
6904  *     /-- B <--\
6905  * A <-          -- D <-- E
6906  *     \-- C <--/
6907  */
6908 THREADED_TEST(ExtensionDependency) {
6909   static const char* kEDeps[] = { "D" };
6910   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6911   static const char* kDDeps[] = { "B", "C" };
6912   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6913   static const char* kBCDeps[] = { "A" };
6914   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6915   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6916   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6917   CheckDependencies("A", "undefinedA");
6918   CheckDependencies("B", "undefinedAB");
6919   CheckDependencies("C", "undefinedAC");
6920   CheckDependencies("D", "undefinedABCD");
6921   CheckDependencies("E", "undefinedABCDE");
6922   v8::HandleScope handle_scope(CcTest::isolate());
6923   static const char* exts[2] = { "C", "E" };
6924   v8::ExtensionConfiguration config(2, exts);
6925   LocalContext context(&config);
6926   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6927 }
6928
6929
6930 static const char* kExtensionTestScript =
6931   "native function A();"
6932   "native function B();"
6933   "native function C();"
6934   "function Foo(i) {"
6935   "  if (i == 0) return A();"
6936   "  if (i == 1) return B();"
6937   "  if (i == 2) return C();"
6938   "}";
6939
6940
6941 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6942   ApiTestFuzzer::Fuzz();
6943   if (args.IsConstructCall()) {
6944     args.This()->Set(v8_str("data"), args.Data());
6945     args.GetReturnValue().SetNull();
6946     return;
6947   }
6948   args.GetReturnValue().Set(args.Data());
6949 }
6950
6951
6952 class FunctionExtension : public Extension {
6953  public:
6954   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6955   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6956       v8::Isolate* isolate,
6957       v8::Handle<String> name);
6958 };
6959
6960
6961 static int lookup_count = 0;
6962 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6963     v8::Isolate* isolate, v8::Handle<String> name) {
6964   lookup_count++;
6965   if (name->Equals(v8_str("A"))) {
6966     return v8::FunctionTemplate::New(
6967         isolate, CallFun, v8::Integer::New(isolate, 8));
6968   } else if (name->Equals(v8_str("B"))) {
6969     return v8::FunctionTemplate::New(
6970         isolate, CallFun, v8::Integer::New(isolate, 7));
6971   } else if (name->Equals(v8_str("C"))) {
6972     return v8::FunctionTemplate::New(
6973         isolate, CallFun, v8::Integer::New(isolate, 6));
6974   } else {
6975     return v8::Handle<v8::FunctionTemplate>();
6976   }
6977 }
6978
6979
6980 THREADED_TEST(FunctionLookup) {
6981   v8::RegisterExtension(new FunctionExtension());
6982   v8::HandleScope handle_scope(CcTest::isolate());
6983   static const char* exts[1] = { "functiontest" };
6984   v8::ExtensionConfiguration config(1, exts);
6985   LocalContext context(&config);
6986   CHECK_EQ(3, lookup_count);
6987   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
6988            Script::Compile(v8_str("Foo(0)"))->Run());
6989   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
6990            Script::Compile(v8_str("Foo(1)"))->Run());
6991   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
6992            Script::Compile(v8_str("Foo(2)"))->Run());
6993 }
6994
6995
6996 THREADED_TEST(NativeFunctionConstructCall) {
6997   v8::RegisterExtension(new FunctionExtension());
6998   v8::HandleScope handle_scope(CcTest::isolate());
6999   static const char* exts[1] = { "functiontest" };
7000   v8::ExtensionConfiguration config(1, exts);
7001   LocalContext context(&config);
7002   for (int i = 0; i < 10; i++) {
7003     // Run a few times to ensure that allocation of objects doesn't
7004     // change behavior of a constructor function.
7005     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7006              Script::Compile(v8_str("(new A()).data"))->Run());
7007     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7008              Script::Compile(v8_str("(new B()).data"))->Run());
7009     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7010              Script::Compile(v8_str("(new C()).data"))->Run());
7011   }
7012 }
7013
7014
7015 static const char* last_location;
7016 static const char* last_message;
7017 void StoringErrorCallback(const char* location, const char* message) {
7018   if (last_location == NULL) {
7019     last_location = location;
7020     last_message = message;
7021   }
7022 }
7023
7024
7025 // ErrorReporting creates a circular extensions configuration and
7026 // tests that the fatal error handler gets called.  This renders V8
7027 // unusable and therefore this test cannot be run in parallel.
7028 TEST(ErrorReporting) {
7029   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7030   static const char* aDeps[] = { "B" };
7031   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7032   static const char* bDeps[] = { "A" };
7033   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7034   last_location = NULL;
7035   v8::ExtensionConfiguration config(1, bDeps);
7036   v8::Handle<Context> context =
7037       Context::New(CcTest::isolate(), &config);
7038   CHECK(context.IsEmpty());
7039   CHECK_NE(last_location, NULL);
7040 }
7041
7042
7043 static const char* js_code_causing_huge_string_flattening =
7044     "var str = 'X';"
7045     "for (var i = 0; i < 30; i++) {"
7046     "  str = str + str;"
7047     "}"
7048     "str.match(/X/);";
7049
7050
7051 TEST(RegexpOutOfMemory) {
7052   // Execute a script that causes out of memory when flattening a string.
7053   v8::HandleScope scope(CcTest::isolate());
7054   v8::V8::SetFatalErrorHandler(OOMCallback);
7055   LocalContext context;
7056   Local<Script> script = Script::Compile(String::NewFromUtf8(
7057       CcTest::isolate(), js_code_causing_huge_string_flattening));
7058   last_location = NULL;
7059   script->Run();
7060
7061   CHECK(false);  // Should not return.
7062 }
7063
7064
7065 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7066                                              v8::Handle<Value> data) {
7067   CHECK(message->GetScriptResourceName()->IsUndefined());
7068   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
7069   message->GetLineNumber();
7070   message->GetSourceLine();
7071 }
7072
7073
7074 THREADED_TEST(ErrorWithMissingScriptInfo) {
7075   LocalContext context;
7076   v8::HandleScope scope(context->GetIsolate());
7077   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7078   Script::Compile(v8_str("throw Error()"))->Run();
7079   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7080 }
7081
7082
7083 int global_index = 0;
7084
7085 template<typename T>
7086 class Snorkel {
7087  public:
7088   explicit Snorkel(v8::Persistent<T>* handle) : handle_(handle) {
7089     index_ = global_index++;
7090   }
7091   v8::Persistent<T>* handle_;
7092   int index_;
7093 };
7094
7095 class Whammy {
7096  public:
7097   explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
7098   ~Whammy() { script_.Reset(); }
7099   v8::Handle<Script> getScript() {
7100     if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
7101     return Local<Script>::New(isolate_, script_);
7102   }
7103
7104  public:
7105   static const int kObjectCount = 256;
7106   int cursor_;
7107   v8::Isolate* isolate_;
7108   v8::Persistent<v8::Object> objects_[kObjectCount];
7109   v8::Persistent<Script> script_;
7110 };
7111
7112 static void HandleWeakReference(
7113     const v8::WeakCallbackData<v8::Value, Snorkel<v8::Value> >& data) {
7114   data.GetParameter()->handle_->ClearWeak();
7115   delete data.GetParameter();
7116 }
7117
7118 void WhammyPropertyGetter(Local<String> name,
7119                           const v8::PropertyCallbackInfo<v8::Value>& info) {
7120   Whammy* whammy =
7121     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
7122
7123   v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
7124
7125   v8::Handle<v8::Object> obj = v8::Object::New(info.GetIsolate());
7126   if (!prev.IsEmpty()) {
7127     v8::Local<v8::Object>::New(info.GetIsolate(), prev)
7128         ->Set(v8_str("next"), obj);
7129     prev.SetWeak<Value, Snorkel<Value> >(new Snorkel<Value>(&prev.As<Value>()),
7130                                          &HandleWeakReference);
7131   }
7132   whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
7133   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
7134   info.GetReturnValue().Set(whammy->getScript()->Run());
7135 }
7136
7137
7138 THREADED_TEST(WeakReference) {
7139   i::FLAG_expose_gc = true;
7140   v8::Isolate* isolate = CcTest::isolate();
7141   v8::HandleScope handle_scope(isolate);
7142   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(isolate);
7143   Whammy* whammy = new Whammy(CcTest::isolate());
7144   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
7145                                  0, 0, 0, 0,
7146                                  v8::External::New(CcTest::isolate(), whammy));
7147   const char* extension_list[] = { "v8/gc" };
7148   v8::ExtensionConfiguration extensions(1, extension_list);
7149   v8::Handle<Context> context =
7150       Context::New(CcTest::isolate(), &extensions);
7151   Context::Scope context_scope(context);
7152
7153   v8::Handle<v8::Object> interceptor = templ->NewInstance();
7154   context->Global()->Set(v8_str("whammy"), interceptor);
7155   const char* code =
7156       "var last;"
7157       "for (var i = 0; i < 10000; i++) {"
7158       "  var obj = whammy.length;"
7159       "  if (last) last.next = obj;"
7160       "  last = obj;"
7161       "}"
7162       "gc();"
7163       "4";
7164   v8::Handle<Value> result = CompileRun(code);
7165   CHECK_EQ(4.0, result->NumberValue());
7166   delete whammy;
7167 }
7168
7169
7170 struct FlagAndPersistent {
7171   bool flag;
7172   v8::Persistent<v8::Object> handle;
7173 };
7174
7175
7176 static void DisposeAndSetFlag(
7177     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7178   data.GetParameter()->handle.Reset();
7179   data.GetParameter()->flag = true;
7180 }
7181
7182
7183 THREADED_TEST(IndependentWeakHandle) {
7184   v8::Isolate* iso = CcTest::isolate();
7185   v8::HandleScope scope(iso);
7186   v8::Handle<Context> context = Context::New(iso);
7187   Context::Scope context_scope(context);
7188
7189   FlagAndPersistent object_a, object_b;
7190
7191   {
7192     v8::HandleScope handle_scope(iso);
7193     object_a.handle.Reset(iso, v8::Object::New(iso));
7194     object_b.handle.Reset(iso, v8::Object::New(iso));
7195   }
7196
7197   object_a.flag = false;
7198   object_b.flag = false;
7199   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7200   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7201   CHECK(!object_b.handle.IsIndependent());
7202   object_a.handle.MarkIndependent();
7203   object_b.handle.MarkIndependent();
7204   CHECK(object_b.handle.IsIndependent());
7205   CcTest::heap()->PerformScavenge();
7206   CHECK(object_a.flag);
7207   CHECK(object_b.flag);
7208 }
7209
7210
7211 static void InvokeScavenge() {
7212   CcTest::heap()->PerformScavenge();
7213 }
7214
7215
7216 static void InvokeMarkSweep() {
7217   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7218 }
7219
7220
7221 static void ForceScavenge(
7222     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7223   data.GetParameter()->handle.Reset();
7224   data.GetParameter()->flag = true;
7225   InvokeScavenge();
7226 }
7227
7228
7229 static void ForceMarkSweep(
7230     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7231   data.GetParameter()->handle.Reset();
7232   data.GetParameter()->flag = true;
7233   InvokeMarkSweep();
7234 }
7235
7236
7237 THREADED_TEST(GCFromWeakCallbacks) {
7238   v8::Isolate* isolate = CcTest::isolate();
7239   v8::HandleScope scope(isolate);
7240   v8::Handle<Context> context = Context::New(isolate);
7241   Context::Scope context_scope(context);
7242
7243   static const int kNumberOfGCTypes = 2;
7244   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7245       Callback;
7246   Callback gc_forcing_callback[kNumberOfGCTypes] =
7247       {&ForceScavenge, &ForceMarkSweep};
7248
7249   typedef void (*GCInvoker)();
7250   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7251
7252   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7253     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7254       FlagAndPersistent object;
7255       {
7256         v8::HandleScope handle_scope(isolate);
7257         object.handle.Reset(isolate, v8::Object::New(isolate));
7258       }
7259       object.flag = false;
7260       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7261       object.handle.MarkIndependent();
7262       invoke_gc[outer_gc]();
7263       CHECK(object.flag);
7264     }
7265   }
7266 }
7267
7268
7269 static void RevivingCallback(
7270     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7271   data.GetParameter()->handle.ClearWeak();
7272   data.GetParameter()->flag = true;
7273 }
7274
7275
7276 THREADED_TEST(IndependentHandleRevival) {
7277   v8::Isolate* isolate = CcTest::isolate();
7278   v8::HandleScope scope(isolate);
7279   v8::Handle<Context> context = Context::New(isolate);
7280   Context::Scope context_scope(context);
7281
7282   FlagAndPersistent object;
7283   {
7284     v8::HandleScope handle_scope(isolate);
7285     v8::Local<v8::Object> o = v8::Object::New(isolate);
7286     object.handle.Reset(isolate, o);
7287     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7288     v8::Local<String> y_str = v8_str("y");
7289     o->Set(y_str, y_str);
7290   }
7291   object.flag = false;
7292   object.handle.SetWeak(&object, &RevivingCallback);
7293   object.handle.MarkIndependent();
7294   CcTest::heap()->PerformScavenge();
7295   CHECK(object.flag);
7296   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7297   {
7298     v8::HandleScope handle_scope(isolate);
7299     v8::Local<v8::Object> o =
7300         v8::Local<v8::Object>::New(isolate, object.handle);
7301     v8::Local<String> y_str = v8_str("y");
7302     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7303     CHECK(o->Get(y_str)->Equals(y_str));
7304   }
7305 }
7306
7307
7308 v8::Handle<Function> args_fun;
7309
7310
7311 static void ArgumentsTestCallback(
7312     const v8::FunctionCallbackInfo<v8::Value>& args) {
7313   ApiTestFuzzer::Fuzz();
7314   v8::Isolate* isolate = args.GetIsolate();
7315   CHECK_EQ(args_fun, args.Callee());
7316   CHECK_EQ(3, args.Length());
7317   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7318   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7319   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7320   CHECK_EQ(v8::Undefined(isolate), args[3]);
7321   v8::HandleScope scope(args.GetIsolate());
7322   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7323 }
7324
7325
7326 THREADED_TEST(Arguments) {
7327   v8::Isolate* isolate = CcTest::isolate();
7328   v8::HandleScope scope(isolate);
7329   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7330   global->Set(v8_str("f"),
7331               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7332   LocalContext context(NULL, global);
7333   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7334   v8_compile("f(1, 2, 3)")->Run();
7335 }
7336
7337
7338 static void NoBlockGetterX(Local<String> name,
7339                            const v8::PropertyCallbackInfo<v8::Value>&) {
7340 }
7341
7342
7343 static void NoBlockGetterI(uint32_t index,
7344                            const v8::PropertyCallbackInfo<v8::Value>&) {
7345 }
7346
7347
7348 static void PDeleter(Local<String> name,
7349                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7350   if (!name->Equals(v8_str("foo"))) {
7351     return;  // not intercepted
7352   }
7353
7354   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7355 }
7356
7357
7358 static void IDeleter(uint32_t index,
7359                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7360   if (index != 2) {
7361     return;  // not intercepted
7362   }
7363
7364   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7365 }
7366
7367
7368 THREADED_TEST(Deleter) {
7369   v8::Isolate* isolate = CcTest::isolate();
7370   v8::HandleScope scope(isolate);
7371   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7372   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7373   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7374   LocalContext context;
7375   context->Global()->Set(v8_str("k"), obj->NewInstance());
7376   CompileRun(
7377     "k.foo = 'foo';"
7378     "k.bar = 'bar';"
7379     "k[2] = 2;"
7380     "k[4] = 4;");
7381   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7382   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7383
7384   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7385   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7386
7387   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7388   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7389
7390   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7391   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7392 }
7393
7394
7395 static void GetK(Local<String> name,
7396                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7397   ApiTestFuzzer::Fuzz();
7398   if (name->Equals(v8_str("foo")) ||
7399       name->Equals(v8_str("bar")) ||
7400       name->Equals(v8_str("baz"))) {
7401     info.GetReturnValue().SetUndefined();
7402   }
7403 }
7404
7405
7406 static void IndexedGetK(uint32_t index,
7407                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7408   ApiTestFuzzer::Fuzz();
7409   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7410 }
7411
7412
7413 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7414   ApiTestFuzzer::Fuzz();
7415   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7416   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7417   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7418   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7419   info.GetReturnValue().Set(result);
7420 }
7421
7422
7423 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7424   ApiTestFuzzer::Fuzz();
7425   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7426   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7427   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7428   info.GetReturnValue().Set(result);
7429 }
7430
7431
7432 THREADED_TEST(Enumerators) {
7433   v8::Isolate* isolate = CcTest::isolate();
7434   v8::HandleScope scope(isolate);
7435   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7436   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7437   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7438   LocalContext context;
7439   context->Global()->Set(v8_str("k"), obj->NewInstance());
7440   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7441     "k[10] = 0;"
7442     "k.a = 0;"
7443     "k[5] = 0;"
7444     "k.b = 0;"
7445     "k[4294967295] = 0;"
7446     "k.c = 0;"
7447     "k[4294967296] = 0;"
7448     "k.d = 0;"
7449     "k[140000] = 0;"
7450     "k.e = 0;"
7451     "k[30000000000] = 0;"
7452     "k.f = 0;"
7453     "var result = [];"
7454     "for (var prop in k) {"
7455     "  result.push(prop);"
7456     "}"
7457     "result"));
7458   // Check that we get all the property names returned including the
7459   // ones from the enumerators in the right order: indexed properties
7460   // in numerical order, indexed interceptor properties, named
7461   // properties in insertion order, named interceptor properties.
7462   // This order is not mandated by the spec, so this test is just
7463   // documenting our behavior.
7464   CHECK_EQ(17, result->Length());
7465   // Indexed properties in numerical order.
7466   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7467   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7468   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7469   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7470   // Indexed interceptor properties in the order they are returned
7471   // from the enumerator interceptor.
7472   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7473   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7474   // Named properties in insertion order.
7475   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7476   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7477   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7478   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7479   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7480   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7481   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7482   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7483   // Named interceptor properties.
7484   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7485   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7486   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7487 }
7488
7489
7490 int p_getter_count;
7491 int p_getter_count2;
7492
7493
7494 static void PGetter(Local<String> name,
7495                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7496   ApiTestFuzzer::Fuzz();
7497   p_getter_count++;
7498   v8::Handle<v8::Object> global =
7499       info.GetIsolate()->GetCurrentContext()->Global();
7500   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7501   if (name->Equals(v8_str("p1"))) {
7502     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7503   } else if (name->Equals(v8_str("p2"))) {
7504     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7505   } else if (name->Equals(v8_str("p3"))) {
7506     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7507   } else if (name->Equals(v8_str("p4"))) {
7508     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7509   }
7510 }
7511
7512
7513 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7514   ApiTestFuzzer::Fuzz();
7515   LocalContext context;
7516   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7517   CompileRun(
7518     "o1.__proto__ = { };"
7519     "var o2 = { __proto__: o1 };"
7520     "var o3 = { __proto__: o2 };"
7521     "var o4 = { __proto__: o3 };"
7522     "for (var i = 0; i < 10; i++) o4.p4;"
7523     "for (var i = 0; i < 10; i++) o3.p3;"
7524     "for (var i = 0; i < 10; i++) o2.p2;"
7525     "for (var i = 0; i < 10; i++) o1.p1;");
7526 }
7527
7528
7529 static void PGetter2(Local<String> name,
7530                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7531   ApiTestFuzzer::Fuzz();
7532   p_getter_count2++;
7533   v8::Handle<v8::Object> global =
7534       info.GetIsolate()->GetCurrentContext()->Global();
7535   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7536   if (name->Equals(v8_str("p1"))) {
7537     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7538   } else if (name->Equals(v8_str("p2"))) {
7539     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7540   } else if (name->Equals(v8_str("p3"))) {
7541     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7542   } else if (name->Equals(v8_str("p4"))) {
7543     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7544   }
7545 }
7546
7547
7548 THREADED_TEST(GetterHolders) {
7549   v8::Isolate* isolate = CcTest::isolate();
7550   v8::HandleScope scope(isolate);
7551   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7552   obj->SetAccessor(v8_str("p1"), PGetter);
7553   obj->SetAccessor(v8_str("p2"), PGetter);
7554   obj->SetAccessor(v8_str("p3"), PGetter);
7555   obj->SetAccessor(v8_str("p4"), PGetter);
7556   p_getter_count = 0;
7557   RunHolderTest(obj);
7558   CHECK_EQ(40, p_getter_count);
7559 }
7560
7561
7562 THREADED_TEST(PreInterceptorHolders) {
7563   v8::Isolate* isolate = CcTest::isolate();
7564   v8::HandleScope scope(isolate);
7565   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7566   obj->SetNamedPropertyHandler(PGetter2);
7567   p_getter_count2 = 0;
7568   RunHolderTest(obj);
7569   CHECK_EQ(40, p_getter_count2);
7570 }
7571
7572
7573 THREADED_TEST(ObjectInstantiation) {
7574   v8::Isolate* isolate = CcTest::isolate();
7575   v8::HandleScope scope(isolate);
7576   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7577   templ->SetAccessor(v8_str("t"), PGetter2);
7578   LocalContext context;
7579   context->Global()->Set(v8_str("o"), templ->NewInstance());
7580   for (int i = 0; i < 100; i++) {
7581     v8::HandleScope inner_scope(CcTest::isolate());
7582     v8::Handle<v8::Object> obj = templ->NewInstance();
7583     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7584     context->Global()->Set(v8_str("o2"), obj);
7585     v8::Handle<Value> value =
7586         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7587     CHECK_EQ(v8::True(isolate), value);
7588     context->Global()->Set(v8_str("o"), obj);
7589   }
7590 }
7591
7592
7593 static int StrCmp16(uint16_t* a, uint16_t* b) {
7594   while (true) {
7595     if (*a == 0 && *b == 0) return 0;
7596     if (*a != *b) return 0 + *a - *b;
7597     a++;
7598     b++;
7599   }
7600 }
7601
7602
7603 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7604   while (true) {
7605     if (n-- == 0) return 0;
7606     if (*a == 0 && *b == 0) return 0;
7607     if (*a != *b) return 0 + *a - *b;
7608     a++;
7609     b++;
7610   }
7611 }
7612
7613
7614 int GetUtf8Length(Handle<String> str) {
7615   int len = str->Utf8Length();
7616   if (len < 0) {
7617     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7618     i::FlattenString(istr);
7619     len = str->Utf8Length();
7620   }
7621   return len;
7622 }
7623
7624
7625 THREADED_TEST(StringWrite) {
7626   LocalContext context;
7627   v8::HandleScope scope(context->GetIsolate());
7628   v8::Handle<String> str = v8_str("abcde");
7629   // abc<Icelandic eth><Unicode snowman>.
7630   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7631   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7632       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7633   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7634   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7635   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7636       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7637   // single lead surrogate
7638   uint16_t lead[1] = { 0xd800 };
7639   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7640       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7641   // single trail surrogate
7642   uint16_t trail[1] = { 0xdc00 };
7643   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7644       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7645   // surrogate pair
7646   uint16_t pair[2] = { 0xd800,  0xdc00 };
7647   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7648       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7649   const int kStride = 4;  // Must match stride in for loops in JS below.
7650   CompileRun(
7651       "var left = '';"
7652       "for (var i = 0; i < 0xd800; i += 4) {"
7653       "  left = left + String.fromCharCode(i);"
7654       "}");
7655   CompileRun(
7656       "var right = '';"
7657       "for (var i = 0; i < 0xd800; i += 4) {"
7658       "  right = String.fromCharCode(i) + right;"
7659       "}");
7660   v8::Handle<v8::Object> global = context->Global();
7661   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7662   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7663
7664   CHECK_EQ(5, str2->Length());
7665   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7666   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7667
7668   char buf[100];
7669   char utf8buf[0xd800 * 3];
7670   uint16_t wbuf[100];
7671   int len;
7672   int charlen;
7673
7674   memset(utf8buf, 0x1, 1000);
7675   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7676   CHECK_EQ(9, len);
7677   CHECK_EQ(5, charlen);
7678   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7679
7680   memset(utf8buf, 0x1, 1000);
7681   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7682   CHECK_EQ(8, len);
7683   CHECK_EQ(5, charlen);
7684   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7685
7686   memset(utf8buf, 0x1, 1000);
7687   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7688   CHECK_EQ(5, len);
7689   CHECK_EQ(4, charlen);
7690   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7691
7692   memset(utf8buf, 0x1, 1000);
7693   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7694   CHECK_EQ(5, len);
7695   CHECK_EQ(4, charlen);
7696   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7697
7698   memset(utf8buf, 0x1, 1000);
7699   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7700   CHECK_EQ(5, len);
7701   CHECK_EQ(4, charlen);
7702   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7703
7704   memset(utf8buf, 0x1, 1000);
7705   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7706   CHECK_EQ(3, len);
7707   CHECK_EQ(3, charlen);
7708   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7709
7710   memset(utf8buf, 0x1, 1000);
7711   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7712   CHECK_EQ(3, len);
7713   CHECK_EQ(3, charlen);
7714   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7715
7716   memset(utf8buf, 0x1, 1000);
7717   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7718   CHECK_EQ(2, len);
7719   CHECK_EQ(2, charlen);
7720   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7721
7722   // allow orphan surrogates by default
7723   memset(utf8buf, 0x1, 1000);
7724   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7725   CHECK_EQ(13, len);
7726   CHECK_EQ(8, charlen);
7727   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7728
7729   // replace orphan surrogates with unicode replacement character
7730   memset(utf8buf, 0x1, 1000);
7731   len = orphans_str->WriteUtf8(utf8buf,
7732                                sizeof(utf8buf),
7733                                &charlen,
7734                                String::REPLACE_INVALID_UTF8);
7735   CHECK_EQ(13, len);
7736   CHECK_EQ(8, charlen);
7737   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7738
7739   // replace single lead surrogate with unicode replacement character
7740   memset(utf8buf, 0x1, 1000);
7741   len = lead_str->WriteUtf8(utf8buf,
7742                             sizeof(utf8buf),
7743                             &charlen,
7744                             String::REPLACE_INVALID_UTF8);
7745   CHECK_EQ(4, len);
7746   CHECK_EQ(1, charlen);
7747   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7748
7749   // replace single trail surrogate with unicode replacement character
7750   memset(utf8buf, 0x1, 1000);
7751   len = trail_str->WriteUtf8(utf8buf,
7752                              sizeof(utf8buf),
7753                              &charlen,
7754                              String::REPLACE_INVALID_UTF8);
7755   CHECK_EQ(4, len);
7756   CHECK_EQ(1, charlen);
7757   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7758
7759   // do not replace / write anything if surrogate pair does not fit the buffer
7760   // space
7761   memset(utf8buf, 0x1, 1000);
7762   len = pair_str->WriteUtf8(utf8buf,
7763                              3,
7764                              &charlen,
7765                              String::REPLACE_INVALID_UTF8);
7766   CHECK_EQ(0, len);
7767   CHECK_EQ(0, charlen);
7768
7769   memset(utf8buf, 0x1, sizeof(utf8buf));
7770   len = GetUtf8Length(left_tree);
7771   int utf8_expected =
7772       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7773   CHECK_EQ(utf8_expected, len);
7774   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7775   CHECK_EQ(utf8_expected, len);
7776   CHECK_EQ(0xd800 / kStride, charlen);
7777   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7778   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7779   CHECK_EQ(0xc0 - kStride,
7780            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7781   CHECK_EQ(1, utf8buf[utf8_expected]);
7782
7783   memset(utf8buf, 0x1, sizeof(utf8buf));
7784   len = GetUtf8Length(right_tree);
7785   CHECK_EQ(utf8_expected, len);
7786   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7787   CHECK_EQ(utf8_expected, len);
7788   CHECK_EQ(0xd800 / kStride, charlen);
7789   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7790   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7791   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7792   CHECK_EQ(1, utf8buf[utf8_expected]);
7793
7794   memset(buf, 0x1, sizeof(buf));
7795   memset(wbuf, 0x1, sizeof(wbuf));
7796   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7797   CHECK_EQ(5, len);
7798   len = str->Write(wbuf);
7799   CHECK_EQ(5, len);
7800   CHECK_EQ(0, strcmp("abcde", buf));
7801   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7802   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7803
7804   memset(buf, 0x1, sizeof(buf));
7805   memset(wbuf, 0x1, sizeof(wbuf));
7806   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7807   CHECK_EQ(4, len);
7808   len = str->Write(wbuf, 0, 4);
7809   CHECK_EQ(4, len);
7810   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7811   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7812   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7813
7814   memset(buf, 0x1, sizeof(buf));
7815   memset(wbuf, 0x1, sizeof(wbuf));
7816   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7817   CHECK_EQ(5, len);
7818   len = str->Write(wbuf, 0, 5);
7819   CHECK_EQ(5, len);
7820   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7821   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7822   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7823
7824   memset(buf, 0x1, sizeof(buf));
7825   memset(wbuf, 0x1, sizeof(wbuf));
7826   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7827   CHECK_EQ(5, len);
7828   len = str->Write(wbuf, 0, 6);
7829   CHECK_EQ(5, len);
7830   CHECK_EQ(0, strcmp("abcde", buf));
7831   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7832   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7833
7834   memset(buf, 0x1, sizeof(buf));
7835   memset(wbuf, 0x1, sizeof(wbuf));
7836   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7837   CHECK_EQ(1, len);
7838   len = str->Write(wbuf, 4, -1);
7839   CHECK_EQ(1, len);
7840   CHECK_EQ(0, strcmp("e", buf));
7841   uint16_t answer5[] = {'e', '\0'};
7842   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7843
7844   memset(buf, 0x1, sizeof(buf));
7845   memset(wbuf, 0x1, sizeof(wbuf));
7846   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7847   CHECK_EQ(1, len);
7848   len = str->Write(wbuf, 4, 6);
7849   CHECK_EQ(1, len);
7850   CHECK_EQ(0, strcmp("e", buf));
7851   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7852
7853   memset(buf, 0x1, sizeof(buf));
7854   memset(wbuf, 0x1, sizeof(wbuf));
7855   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7856   CHECK_EQ(1, len);
7857   len = str->Write(wbuf, 4, 1);
7858   CHECK_EQ(1, len);
7859   CHECK_EQ(0, strncmp("e\1", buf, 2));
7860   uint16_t answer6[] = {'e', 0x101};
7861   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7862
7863   memset(buf, 0x1, sizeof(buf));
7864   memset(wbuf, 0x1, sizeof(wbuf));
7865   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7866   CHECK_EQ(1, len);
7867   len = str->Write(wbuf, 3, 1);
7868   CHECK_EQ(1, len);
7869   CHECK_EQ(0, strncmp("d\1", buf, 2));
7870   uint16_t answer7[] = {'d', 0x101};
7871   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7872
7873   memset(wbuf, 0x1, sizeof(wbuf));
7874   wbuf[5] = 'X';
7875   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7876   CHECK_EQ(5, len);
7877   CHECK_EQ('X', wbuf[5]);
7878   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7879   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7880   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7881   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7882   wbuf[5] = '\0';
7883   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7884
7885   memset(buf, 0x1, sizeof(buf));
7886   buf[5] = 'X';
7887   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7888                           0,
7889                           6,
7890                           String::NO_NULL_TERMINATION);
7891   CHECK_EQ(5, len);
7892   CHECK_EQ('X', buf[5]);
7893   CHECK_EQ(0, strncmp("abcde", buf, 5));
7894   CHECK_NE(0, strcmp("abcde", buf));
7895   buf[5] = '\0';
7896   CHECK_EQ(0, strcmp("abcde", buf));
7897
7898   memset(utf8buf, 0x1, sizeof(utf8buf));
7899   utf8buf[8] = 'X';
7900   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7901                         String::NO_NULL_TERMINATION);
7902   CHECK_EQ(8, len);
7903   CHECK_EQ('X', utf8buf[8]);
7904   CHECK_EQ(5, charlen);
7905   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7906   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7907   utf8buf[8] = '\0';
7908   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7909
7910   memset(utf8buf, 0x1, sizeof(utf8buf));
7911   utf8buf[5] = 'X';
7912   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7913                         String::NO_NULL_TERMINATION);
7914   CHECK_EQ(5, len);
7915   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7916   CHECK_EQ(5, charlen);
7917   utf8buf[5] = '\0';
7918   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7919
7920   memset(buf, 0x1, sizeof(buf));
7921   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7922   CHECK_EQ(7, len);
7923   CHECK_EQ(0, strcmp("abc", buf));
7924   CHECK_EQ(0, buf[3]);
7925   CHECK_EQ(0, strcmp("def", buf + 4));
7926
7927   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7928   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7929   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7930 }
7931
7932
7933 static void Utf16Helper(
7934     LocalContext& context,
7935     const char* name,
7936     const char* lengths_name,
7937     int len) {
7938   Local<v8::Array> a =
7939       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7940   Local<v8::Array> alens =
7941       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7942   for (int i = 0; i < len; i++) {
7943     Local<v8::String> string =
7944       Local<v8::String>::Cast(a->Get(i));
7945     Local<v8::Number> expected_len =
7946       Local<v8::Number>::Cast(alens->Get(i));
7947     int length = GetUtf8Length(string);
7948     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7949   }
7950 }
7951
7952
7953 static uint16_t StringGet(Handle<String> str, int index) {
7954   i::Handle<i::String> istring =
7955       v8::Utils::OpenHandle(String::Cast(*str));
7956   return istring->Get(index);
7957 }
7958
7959
7960 static void WriteUtf8Helper(
7961     LocalContext& context,
7962     const char* name,
7963     const char* lengths_name,
7964     int len) {
7965   Local<v8::Array> b =
7966       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7967   Local<v8::Array> alens =
7968       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7969   char buffer[1000];
7970   char buffer2[1000];
7971   for (int i = 0; i < len; i++) {
7972     Local<v8::String> string =
7973       Local<v8::String>::Cast(b->Get(i));
7974     Local<v8::Number> expected_len =
7975       Local<v8::Number>::Cast(alens->Get(i));
7976     int utf8_length = static_cast<int>(expected_len->Value());
7977     for (int j = utf8_length + 1; j >= 0; j--) {
7978       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7979       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7980       int nchars;
7981       int utf8_written =
7982           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7983       int utf8_written2 =
7984           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7985       CHECK_GE(utf8_length + 1, utf8_written);
7986       CHECK_GE(utf8_length, utf8_written2);
7987       for (int k = 0; k < utf8_written2; k++) {
7988         CHECK_EQ(buffer[k], buffer2[k]);
7989       }
7990       CHECK(nchars * 3 >= utf8_written - 1);
7991       CHECK(nchars <= utf8_written);
7992       if (j == utf8_length + 1) {
7993         CHECK_EQ(utf8_written2, utf8_length);
7994         CHECK_EQ(utf8_written2 + 1, utf8_written);
7995       }
7996       CHECK_EQ(buffer[utf8_written], 42);
7997       if (j > utf8_length) {
7998         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7999         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8000         Handle<String> roundtrip = v8_str(buffer);
8001         CHECK(roundtrip->Equals(string));
8002       } else {
8003         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8004       }
8005       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8006       if (nchars >= 2) {
8007         uint16_t trail = StringGet(string, nchars - 1);
8008         uint16_t lead = StringGet(string, nchars - 2);
8009         if (((lead & 0xfc00) == 0xd800) &&
8010             ((trail & 0xfc00) == 0xdc00)) {
8011           unsigned char u1 = buffer2[utf8_written2 - 4];
8012           unsigned char u2 = buffer2[utf8_written2 - 3];
8013           unsigned char u3 = buffer2[utf8_written2 - 2];
8014           unsigned char u4 = buffer2[utf8_written2 - 1];
8015           CHECK_EQ((u1 & 0xf8), 0xf0);
8016           CHECK_EQ((u2 & 0xc0), 0x80);
8017           CHECK_EQ((u3 & 0xc0), 0x80);
8018           CHECK_EQ((u4 & 0xc0), 0x80);
8019           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8020           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8021           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8022           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8023           CHECK_EQ((u1 & 0x3), c >> 18);
8024         }
8025       }
8026     }
8027   }
8028 }
8029
8030
8031 THREADED_TEST(Utf16) {
8032   LocalContext context;
8033   v8::HandleScope scope(context->GetIsolate());
8034   CompileRun(
8035       "var pad = '01234567890123456789';"
8036       "var p = [];"
8037       "var plens = [20, 3, 3];"
8038       "p.push('01234567890123456789');"
8039       "var lead = 0xd800;"
8040       "var trail = 0xdc00;"
8041       "p.push(String.fromCharCode(0xd800));"
8042       "p.push(String.fromCharCode(0xdc00));"
8043       "var a = [];"
8044       "var b = [];"
8045       "var c = [];"
8046       "var alens = [];"
8047       "for (var i = 0; i < 3; i++) {"
8048       "  p[1] = String.fromCharCode(lead++);"
8049       "  for (var j = 0; j < 3; j++) {"
8050       "    p[2] = String.fromCharCode(trail++);"
8051       "    a.push(p[i] + p[j]);"
8052       "    b.push(p[i] + p[j]);"
8053       "    c.push(p[i] + p[j]);"
8054       "    alens.push(plens[i] + plens[j]);"
8055       "  }"
8056       "}"
8057       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8058       "var a2 = [];"
8059       "var b2 = [];"
8060       "var c2 = [];"
8061       "var a2lens = [];"
8062       "for (var m = 0; m < 9; m++) {"
8063       "  for (var n = 0; n < 9; n++) {"
8064       "    a2.push(a[m] + a[n]);"
8065       "    b2.push(b[m] + b[n]);"
8066       "    var newc = 'x' + c[m] + c[n] + 'y';"
8067       "    c2.push(newc.substring(1, newc.length - 1));"
8068       "    var utf = alens[m] + alens[n];"  // And here.
8069            // The 'n's that start with 0xdc.. are 6-8
8070            // The 'm's that end with 0xd8.. are 1, 4 and 7
8071       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8072       "    a2lens.push(utf);"
8073       "  }"
8074       "}");
8075   Utf16Helper(context, "a", "alens", 9);
8076   Utf16Helper(context, "a2", "a2lens", 81);
8077   WriteUtf8Helper(context, "b", "alens", 9);
8078   WriteUtf8Helper(context, "b2", "a2lens", 81);
8079   WriteUtf8Helper(context, "c2", "a2lens", 81);
8080 }
8081
8082
8083 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8084   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8085   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8086   return *is1 == *is2;
8087 }
8088
8089 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8090                              const char* b) {
8091   Handle<String> symbol1 =
8092       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8093   Handle<String> symbol2 =
8094       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8095   CHECK(SameSymbol(symbol1, symbol2));
8096 }
8097
8098
8099 THREADED_TEST(Utf16Symbol) {
8100   LocalContext context;
8101   v8::HandleScope scope(context->GetIsolate());
8102
8103   Handle<String> symbol1 = v8::String::NewFromUtf8(
8104       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8105   Handle<String> symbol2 = v8::String::NewFromUtf8(
8106       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8107   CHECK(SameSymbol(symbol1, symbol2));
8108
8109   SameSymbolHelper(context->GetIsolate(),
8110                    "\360\220\220\205",  // 4 byte encoding.
8111                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8112   SameSymbolHelper(context->GetIsolate(),
8113                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8114                    "\360\220\220\206");  // 4 byte encoding.
8115   SameSymbolHelper(context->GetIsolate(),
8116                    "x\360\220\220\205",  // 4 byte encoding.
8117                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8118   SameSymbolHelper(context->GetIsolate(),
8119                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8120                    "x\360\220\220\206");  // 4 byte encoding.
8121   CompileRun(
8122       "var sym0 = 'benedictus';"
8123       "var sym0b = 'S\303\270ren';"
8124       "var sym1 = '\355\240\201\355\260\207';"
8125       "var sym2 = '\360\220\220\210';"
8126       "var sym3 = 'x\355\240\201\355\260\207';"
8127       "var sym4 = 'x\360\220\220\210';"
8128       "if (sym1.length != 2) throw sym1;"
8129       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8130       "if (sym2.length != 2) throw sym2;"
8131       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8132       "if (sym3.length != 3) throw sym3;"
8133       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8134       "if (sym4.length != 3) throw sym4;"
8135       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8136   Handle<String> sym0 = v8::String::NewFromUtf8(
8137       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8138   Handle<String> sym0b = v8::String::NewFromUtf8(
8139       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8140   Handle<String> sym1 =
8141       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8142                               v8::String::kInternalizedString);
8143   Handle<String> sym2 =
8144       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8145                               v8::String::kInternalizedString);
8146   Handle<String> sym3 = v8::String::NewFromUtf8(
8147       context->GetIsolate(), "x\355\240\201\355\260\207",
8148       v8::String::kInternalizedString);
8149   Handle<String> sym4 =
8150       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8151                               v8::String::kInternalizedString);
8152   v8::Local<v8::Object> global = context->Global();
8153   Local<Value> s0 = global->Get(v8_str("sym0"));
8154   Local<Value> s0b = global->Get(v8_str("sym0b"));
8155   Local<Value> s1 = global->Get(v8_str("sym1"));
8156   Local<Value> s2 = global->Get(v8_str("sym2"));
8157   Local<Value> s3 = global->Get(v8_str("sym3"));
8158   Local<Value> s4 = global->Get(v8_str("sym4"));
8159   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8160   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8161   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8162   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8163   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8164   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8165 }
8166
8167
8168 THREADED_TEST(ToArrayIndex) {
8169   LocalContext context;
8170   v8::Isolate* isolate = context->GetIsolate();
8171   v8::HandleScope scope(isolate);
8172
8173   v8::Handle<String> str = v8_str("42");
8174   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8175   CHECK(!index.IsEmpty());
8176   CHECK_EQ(42.0, index->Uint32Value());
8177   str = v8_str("42asdf");
8178   index = str->ToArrayIndex();
8179   CHECK(index.IsEmpty());
8180   str = v8_str("-42");
8181   index = str->ToArrayIndex();
8182   CHECK(index.IsEmpty());
8183   str = v8_str("4294967295");
8184   index = str->ToArrayIndex();
8185   CHECK(!index.IsEmpty());
8186   CHECK_EQ(4294967295.0, index->Uint32Value());
8187   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8188   index = num->ToArrayIndex();
8189   CHECK(!index.IsEmpty());
8190   CHECK_EQ(1.0, index->Uint32Value());
8191   num = v8::Number::New(isolate, -1);
8192   index = num->ToArrayIndex();
8193   CHECK(index.IsEmpty());
8194   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8195   index = obj->ToArrayIndex();
8196   CHECK(index.IsEmpty());
8197 }
8198
8199
8200 THREADED_TEST(ErrorConstruction) {
8201   LocalContext context;
8202   v8::HandleScope scope(context->GetIsolate());
8203
8204   v8::Handle<String> foo = v8_str("foo");
8205   v8::Handle<String> message = v8_str("message");
8206   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8207   CHECK(range_error->IsObject());
8208   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8209   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8210   CHECK(reference_error->IsObject());
8211   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8212   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8213   CHECK(syntax_error->IsObject());
8214   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8215   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8216   CHECK(type_error->IsObject());
8217   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8218   v8::Handle<Value> error = v8::Exception::Error(foo);
8219   CHECK(error->IsObject());
8220   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8221 }
8222
8223
8224 static void YGetter(Local<String> name,
8225                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8226   ApiTestFuzzer::Fuzz();
8227   info.GetReturnValue().Set(v8_num(10));
8228 }
8229
8230
8231 static void YSetter(Local<String> name,
8232                     Local<Value> value,
8233                     const v8::PropertyCallbackInfo<void>& info) {
8234   if (info.This()->Has(name)) {
8235     info.This()->Delete(name);
8236   }
8237   info.This()->Set(name, value);
8238 }
8239
8240
8241 THREADED_TEST(DeleteAccessor) {
8242   v8::Isolate* isolate = CcTest::isolate();
8243   v8::HandleScope scope(isolate);
8244   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8245   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8246   LocalContext context;
8247   v8::Handle<v8::Object> holder = obj->NewInstance();
8248   context->Global()->Set(v8_str("holder"), holder);
8249   v8::Handle<Value> result = CompileRun(
8250       "holder.y = 11; holder.y = 12; holder.y");
8251   CHECK_EQ(12, result->Uint32Value());
8252 }
8253
8254
8255 THREADED_TEST(TypeSwitch) {
8256   v8::Isolate* isolate = CcTest::isolate();
8257   v8::HandleScope scope(isolate);
8258   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8259   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8260   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8261   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8262   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8263   LocalContext context;
8264   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8265   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8266   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8267   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8268   for (int i = 0; i < 10; i++) {
8269     CHECK_EQ(0, type_switch->match(obj0));
8270     CHECK_EQ(1, type_switch->match(obj1));
8271     CHECK_EQ(2, type_switch->match(obj2));
8272     CHECK_EQ(3, type_switch->match(obj3));
8273     CHECK_EQ(3, type_switch->match(obj3));
8274     CHECK_EQ(2, type_switch->match(obj2));
8275     CHECK_EQ(1, type_switch->match(obj1));
8276     CHECK_EQ(0, type_switch->match(obj0));
8277   }
8278 }
8279
8280
8281 // For use within the TestSecurityHandler() test.
8282 static bool g_security_callback_result = false;
8283 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8284                                       Local<Value> name,
8285                                       v8::AccessType type,
8286                                       Local<Value> data) {
8287   // Always allow read access.
8288   if (type == v8::ACCESS_GET)
8289     return true;
8290
8291   // Sometimes allow other access.
8292   return g_security_callback_result;
8293 }
8294
8295
8296 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8297                                         uint32_t key,
8298                                         v8::AccessType type,
8299                                         Local<Value> data) {
8300   // Always allow read access.
8301   if (type == v8::ACCESS_GET)
8302     return true;
8303
8304   // Sometimes allow other access.
8305   return g_security_callback_result;
8306 }
8307
8308
8309 static int trouble_nesting = 0;
8310 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8311   ApiTestFuzzer::Fuzz();
8312   trouble_nesting++;
8313
8314   // Call a JS function that throws an uncaught exception.
8315   Local<v8::Object> arg_this =
8316       args.GetIsolate()->GetCurrentContext()->Global();
8317   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8318     arg_this->Get(v8_str("trouble_callee")) :
8319     arg_this->Get(v8_str("trouble_caller"));
8320   CHECK(trouble_callee->IsFunction());
8321   args.GetReturnValue().Set(
8322       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8323 }
8324
8325
8326 static int report_count = 0;
8327 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8328                                              v8::Handle<Value>) {
8329   report_count++;
8330 }
8331
8332
8333 // Counts uncaught exceptions, but other tests running in parallel
8334 // also have uncaught exceptions.
8335 TEST(ApiUncaughtException) {
8336   report_count = 0;
8337   LocalContext env;
8338   v8::Isolate* isolate = env->GetIsolate();
8339   v8::HandleScope scope(isolate);
8340   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8341
8342   Local<v8::FunctionTemplate> fun =
8343       v8::FunctionTemplate::New(isolate, TroubleCallback);
8344   v8::Local<v8::Object> global = env->Global();
8345   global->Set(v8_str("trouble"), fun->GetFunction());
8346
8347   Script::Compile(v8_str("function trouble_callee() {"
8348                          "  var x = null;"
8349                          "  return x.foo;"
8350                          "};"
8351                          "function trouble_caller() {"
8352                          "  trouble();"
8353                          "};"))->Run();
8354   Local<Value> trouble = global->Get(v8_str("trouble"));
8355   CHECK(trouble->IsFunction());
8356   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8357   CHECK(trouble_callee->IsFunction());
8358   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8359   CHECK(trouble_caller->IsFunction());
8360   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8361   CHECK_EQ(1, report_count);
8362   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8363 }
8364
8365 static const char* script_resource_name = "ExceptionInNativeScript.js";
8366 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8367                                                 v8::Handle<Value>) {
8368   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8369   CHECK(!name_val.IsEmpty() && name_val->IsString());
8370   v8::String::Utf8Value name(message->GetScriptResourceName());
8371   CHECK_EQ(script_resource_name, *name);
8372   CHECK_EQ(3, message->GetLineNumber());
8373   v8::String::Utf8Value source_line(message->GetSourceLine());
8374   CHECK_EQ("  new o.foo();", *source_line);
8375 }
8376
8377
8378 TEST(ExceptionInNativeScript) {
8379   LocalContext env;
8380   v8::Isolate* isolate = env->GetIsolate();
8381   v8::HandleScope scope(isolate);
8382   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8383
8384   Local<v8::FunctionTemplate> fun =
8385       v8::FunctionTemplate::New(isolate, TroubleCallback);
8386   v8::Local<v8::Object> global = env->Global();
8387   global->Set(v8_str("trouble"), fun->GetFunction());
8388
8389   Script::Compile(
8390       v8_str(
8391           "function trouble() {\n"
8392           "  var o = {};\n"
8393           "  new o.foo();\n"
8394           "};"),
8395       v8::String::NewFromUtf8(isolate, script_resource_name))->Run();
8396   Local<Value> trouble = global->Get(v8_str("trouble"));
8397   CHECK(trouble->IsFunction());
8398   Function::Cast(*trouble)->Call(global, 0, NULL);
8399   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8400 }
8401
8402
8403 TEST(CompilationErrorUsingTryCatchHandler) {
8404   LocalContext env;
8405   v8::HandleScope scope(env->GetIsolate());
8406   v8::TryCatch try_catch;
8407   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
8408   CHECK_NE(NULL, *try_catch.Exception());
8409   CHECK(try_catch.HasCaught());
8410 }
8411
8412
8413 TEST(TryCatchFinallyUsingTryCatchHandler) {
8414   LocalContext env;
8415   v8::HandleScope scope(env->GetIsolate());
8416   v8::TryCatch try_catch;
8417   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
8418   CHECK(!try_catch.HasCaught());
8419   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
8420   CHECK(try_catch.HasCaught());
8421   try_catch.Reset();
8422   Script::Compile(v8_str("(function() {"
8423                          "try { throw ''; } finally { return; }"
8424                          "})()"))->Run();
8425   CHECK(!try_catch.HasCaught());
8426   Script::Compile(v8_str("(function()"
8427                          "  { try { throw ''; } finally { throw 0; }"
8428                          "})()"))->Run();
8429   CHECK(try_catch.HasCaught());
8430 }
8431
8432
8433 // SecurityHandler can't be run twice
8434 TEST(SecurityHandler) {
8435   v8::Isolate* isolate = CcTest::isolate();
8436   v8::HandleScope scope0(isolate);
8437   v8::Handle<v8::ObjectTemplate> global_template =
8438       v8::ObjectTemplate::New(isolate);
8439   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8440                                            IndexedSecurityTestCallback);
8441   // Create an environment
8442   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8443   context0->Enter();
8444
8445   v8::Handle<v8::Object> global0 = context0->Global();
8446   v8::Handle<Script> script0 = v8_compile("foo = 111");
8447   script0->Run();
8448   global0->Set(v8_str("0"), v8_num(999));
8449   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8450   CHECK_EQ(111, foo0->Int32Value());
8451   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8452   CHECK_EQ(999, z0->Int32Value());
8453
8454   // Create another environment, should fail security checks.
8455   v8::HandleScope scope1(isolate);
8456
8457   v8::Handle<Context> context1 =
8458     Context::New(isolate, NULL, global_template);
8459   context1->Enter();
8460
8461   v8::Handle<v8::Object> global1 = context1->Global();
8462   global1->Set(v8_str("othercontext"), global0);
8463   // This set will fail the security check.
8464   v8::Handle<Script> script1 =
8465     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8466   script1->Run();
8467   // This read will pass the security check.
8468   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8469   CHECK_EQ(111, foo1->Int32Value());
8470   // This read will pass the security check.
8471   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8472   CHECK_EQ(999, z1->Int32Value());
8473
8474   // Create another environment, should pass security checks.
8475   { g_security_callback_result = true;  // allow security handler to pass.
8476     v8::HandleScope scope2(isolate);
8477     LocalContext context2;
8478     v8::Handle<v8::Object> global2 = context2->Global();
8479     global2->Set(v8_str("othercontext"), global0);
8480     v8::Handle<Script> script2 =
8481         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8482     script2->Run();
8483     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8484     CHECK_EQ(333, foo2->Int32Value());
8485     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8486     CHECK_EQ(888, z2->Int32Value());
8487   }
8488
8489   context1->Exit();
8490   context0->Exit();
8491 }
8492
8493
8494 THREADED_TEST(SecurityChecks) {
8495   LocalContext env1;
8496   v8::HandleScope handle_scope(env1->GetIsolate());
8497   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8498
8499   Local<Value> foo = v8_str("foo");
8500   Local<Value> bar = v8_str("bar");
8501
8502   // Set to the same domain.
8503   env1->SetSecurityToken(foo);
8504
8505   // Create a function in env1.
8506   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
8507   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8508   CHECK(spy->IsFunction());
8509
8510   // Create another function accessing global objects.
8511   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
8512   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8513   CHECK(spy2->IsFunction());
8514
8515   // Switch to env2 in the same domain and invoke spy on env2.
8516   {
8517     env2->SetSecurityToken(foo);
8518     // Enter env2
8519     Context::Scope scope_env2(env2);
8520     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8521     CHECK(result->IsFunction());
8522   }
8523
8524   {
8525     env2->SetSecurityToken(bar);
8526     Context::Scope scope_env2(env2);
8527
8528     // Call cross_domain_call, it should throw an exception
8529     v8::TryCatch try_catch;
8530     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8531     CHECK(try_catch.HasCaught());
8532   }
8533 }
8534
8535
8536 // Regression test case for issue 1183439.
8537 THREADED_TEST(SecurityChecksForPrototypeChain) {
8538   LocalContext current;
8539   v8::HandleScope scope(current->GetIsolate());
8540   v8::Handle<Context> other = Context::New(current->GetIsolate());
8541
8542   // Change context to be able to get to the Object function in the
8543   // other context without hitting the security checks.
8544   v8::Local<Value> other_object;
8545   { Context::Scope scope(other);
8546     other_object = other->Global()->Get(v8_str("Object"));
8547     other->Global()->Set(v8_num(42), v8_num(87));
8548   }
8549
8550   current->Global()->Set(v8_str("other"), other->Global());
8551   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8552
8553   // Make sure the security check fails here and we get an undefined
8554   // result instead of getting the Object function. Repeat in a loop
8555   // to make sure to exercise the IC code.
8556   v8::Local<Script> access_other0 = v8_compile("other.Object");
8557   v8::Local<Script> access_other1 = v8_compile("other[42]");
8558   for (int i = 0; i < 5; i++) {
8559     CHECK(!access_other0->Run()->Equals(other_object));
8560     CHECK(access_other0->Run()->IsUndefined());
8561     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8562     CHECK(access_other1->Run()->IsUndefined());
8563   }
8564
8565   // Create an object that has 'other' in its prototype chain and make
8566   // sure we cannot access the Object function indirectly through
8567   // that. Repeat in a loop to make sure to exercise the IC code.
8568   v8_compile("function F() { };"
8569              "F.prototype = other;"
8570              "var f = new F();")->Run();
8571   v8::Local<Script> access_f0 = v8_compile("f.Object");
8572   v8::Local<Script> access_f1 = v8_compile("f[42]");
8573   for (int j = 0; j < 5; j++) {
8574     CHECK(!access_f0->Run()->Equals(other_object));
8575     CHECK(access_f0->Run()->IsUndefined());
8576     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8577     CHECK(access_f1->Run()->IsUndefined());
8578   }
8579
8580   // Now it gets hairy: Set the prototype for the other global object
8581   // to be the current global object. The prototype chain for 'f' now
8582   // goes through 'other' but ends up in the current global object.
8583   { Context::Scope scope(other);
8584     other->Global()->Set(v8_str("__proto__"), current->Global());
8585   }
8586   // Set a named and an index property on the current global
8587   // object. To force the lookup to go through the other global object,
8588   // the properties must not exist in the other global object.
8589   current->Global()->Set(v8_str("foo"), v8_num(100));
8590   current->Global()->Set(v8_num(99), v8_num(101));
8591   // Try to read the properties from f and make sure that the access
8592   // gets stopped by the security checks on the other global object.
8593   Local<Script> access_f2 = v8_compile("f.foo");
8594   Local<Script> access_f3 = v8_compile("f[99]");
8595   for (int k = 0; k < 5; k++) {
8596     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8597     CHECK(access_f2->Run()->IsUndefined());
8598     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8599     CHECK(access_f3->Run()->IsUndefined());
8600   }
8601 }
8602
8603
8604 THREADED_TEST(CrossDomainDelete) {
8605   LocalContext env1;
8606   v8::HandleScope handle_scope(env1->GetIsolate());
8607   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8608
8609   Local<Value> foo = v8_str("foo");
8610   Local<Value> bar = v8_str("bar");
8611
8612   // Set to the same domain.
8613   env1->SetSecurityToken(foo);
8614   env2->SetSecurityToken(foo);
8615
8616   env1->Global()->Set(v8_str("prop"), v8_num(3));
8617   env2->Global()->Set(v8_str("env1"), env1->Global());
8618
8619   // Change env2 to a different domain and delete env1.prop.
8620   env2->SetSecurityToken(bar);
8621   {
8622     Context::Scope scope_env2(env2);
8623     Local<Value> result =
8624         Script::Compile(v8_str("delete env1.prop"))->Run();
8625     CHECK(result->IsFalse());
8626   }
8627
8628   // Check that env1.prop still exists.
8629   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8630   CHECK(v->IsNumber());
8631   CHECK_EQ(3, v->Int32Value());
8632 }
8633
8634
8635 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8636   LocalContext env1;
8637   v8::HandleScope handle_scope(env1->GetIsolate());
8638   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8639
8640   Local<Value> foo = v8_str("foo");
8641   Local<Value> bar = v8_str("bar");
8642
8643   // Set to the same domain.
8644   env1->SetSecurityToken(foo);
8645   env2->SetSecurityToken(foo);
8646
8647   env1->Global()->Set(v8_str("prop"), v8_num(3));
8648   env2->Global()->Set(v8_str("env1"), env1->Global());
8649
8650   // env1.prop is enumerable in env2.
8651   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8652   {
8653     Context::Scope scope_env2(env2);
8654     Local<Value> result = Script::Compile(test)->Run();
8655     CHECK(result->IsTrue());
8656   }
8657
8658   // Change env2 to a different domain and test again.
8659   env2->SetSecurityToken(bar);
8660   {
8661     Context::Scope scope_env2(env2);
8662     Local<Value> result = Script::Compile(test)->Run();
8663     CHECK(result->IsFalse());
8664   }
8665 }
8666
8667
8668 THREADED_TEST(CrossDomainForIn) {
8669   LocalContext env1;
8670   v8::HandleScope handle_scope(env1->GetIsolate());
8671   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8672
8673   Local<Value> foo = v8_str("foo");
8674   Local<Value> bar = v8_str("bar");
8675
8676   // Set to the same domain.
8677   env1->SetSecurityToken(foo);
8678   env2->SetSecurityToken(foo);
8679
8680   env1->Global()->Set(v8_str("prop"), v8_num(3));
8681   env2->Global()->Set(v8_str("env1"), env1->Global());
8682
8683   // Change env2 to a different domain and set env1's global object
8684   // as the __proto__ of an object in env2 and enumerate properties
8685   // in for-in. It shouldn't enumerate properties on env1's global
8686   // object.
8687   env2->SetSecurityToken(bar);
8688   {
8689     Context::Scope scope_env2(env2);
8690     Local<Value> result =
8691         CompileRun("(function(){var obj = {'__proto__':env1};"
8692                    "for (var p in obj)"
8693                    "   if (p == 'prop') return false;"
8694                    "return true;})()");
8695     CHECK(result->IsTrue());
8696   }
8697 }
8698
8699
8700 TEST(ContextDetachGlobal) {
8701   LocalContext env1;
8702   v8::HandleScope handle_scope(env1->GetIsolate());
8703   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8704
8705   Local<v8::Object> global1 = env1->Global();
8706
8707   Local<Value> foo = v8_str("foo");
8708
8709   // Set to the same domain.
8710   env1->SetSecurityToken(foo);
8711   env2->SetSecurityToken(foo);
8712
8713   // Enter env2
8714   env2->Enter();
8715
8716   // Create a function in env2 and add a reference to it in env1.
8717   Local<v8::Object> global2 = env2->Global();
8718   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8719   CompileRun("function getProp() {return prop;}");
8720
8721   env1->Global()->Set(v8_str("getProp"),
8722                       global2->Get(v8_str("getProp")));
8723
8724   // Detach env2's global, and reuse the global object of env2
8725   env2->Exit();
8726   env2->DetachGlobal();
8727
8728   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8729                                           0,
8730                                           v8::Handle<v8::ObjectTemplate>(),
8731                                           global2);
8732   env3->SetSecurityToken(v8_str("bar"));
8733   env3->Enter();
8734
8735   Local<v8::Object> global3 = env3->Global();
8736   CHECK_EQ(global2, global3);
8737   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8738   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8739   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8740   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8741   env3->Exit();
8742
8743   // Call getProp in env1, and it should return the value 1
8744   {
8745     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8746     CHECK(get_prop->IsFunction());
8747     v8::TryCatch try_catch;
8748     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8749     CHECK(!try_catch.HasCaught());
8750     CHECK_EQ(1, r->Int32Value());
8751   }
8752
8753   // Check that env3 is not accessible from env1
8754   {
8755     Local<Value> r = global3->Get(v8_str("prop2"));
8756     CHECK(r->IsUndefined());
8757   }
8758 }
8759
8760
8761 TEST(DetachGlobal) {
8762   LocalContext env1;
8763   v8::HandleScope scope(env1->GetIsolate());
8764
8765   // Create second environment.
8766   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8767
8768   Local<Value> foo = v8_str("foo");
8769
8770   // Set same security token for env1 and env2.
8771   env1->SetSecurityToken(foo);
8772   env2->SetSecurityToken(foo);
8773
8774   // Create a property on the global object in env2.
8775   {
8776     v8::Context::Scope scope(env2);
8777     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8778   }
8779
8780   // Create a reference to env2 global from env1 global.
8781   env1->Global()->Set(v8_str("other"), env2->Global());
8782
8783   // Check that we have access to other.p in env2 from env1.
8784   Local<Value> result = CompileRun("other.p");
8785   CHECK(result->IsInt32());
8786   CHECK_EQ(42, result->Int32Value());
8787
8788   // Hold on to global from env2 and detach global from env2.
8789   Local<v8::Object> global2 = env2->Global();
8790   env2->DetachGlobal();
8791
8792   // Check that the global has been detached. No other.p property can
8793   // be found.
8794   result = CompileRun("other.p");
8795   CHECK(result->IsUndefined());
8796
8797   // Reuse global2 for env3.
8798   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8799                                           0,
8800                                           v8::Handle<v8::ObjectTemplate>(),
8801                                           global2);
8802   CHECK_EQ(global2, env3->Global());
8803
8804   // Start by using the same security token for env3 as for env1 and env2.
8805   env3->SetSecurityToken(foo);
8806
8807   // Create a property on the global object in env3.
8808   {
8809     v8::Context::Scope scope(env3);
8810     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8811   }
8812
8813   // Check that other.p is now the property in env3 and that we have access.
8814   result = CompileRun("other.p");
8815   CHECK(result->IsInt32());
8816   CHECK_EQ(24, result->Int32Value());
8817
8818   // Change security token for env3 to something different from env1 and env2.
8819   env3->SetSecurityToken(v8_str("bar"));
8820
8821   // Check that we do not have access to other.p in env1. |other| is now
8822   // the global object for env3 which has a different security token,
8823   // so access should be blocked.
8824   result = CompileRun("other.p");
8825   CHECK(result->IsUndefined());
8826 }
8827
8828
8829 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8830   info.GetReturnValue().Set(
8831       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8832 }
8833
8834
8835 TEST(DetachedAccesses) {
8836   LocalContext env1;
8837   v8::HandleScope scope(env1->GetIsolate());
8838
8839   // Create second environment.
8840   Local<ObjectTemplate> inner_global_template =
8841       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8842   inner_global_template ->SetAccessorProperty(
8843       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8844   v8::Local<Context> env2 =
8845       Context::New(env1->GetIsolate(), NULL, inner_global_template);
8846
8847   Local<Value> foo = v8_str("foo");
8848
8849   // Set same security token for env1 and env2.
8850   env1->SetSecurityToken(foo);
8851   env2->SetSecurityToken(foo);
8852
8853   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8854
8855   {
8856     v8::Context::Scope scope(env2);
8857     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8858     CompileRun(
8859         "function bound_x() { return x; }"
8860         "function get_x()   { return this.x; }"
8861         "function get_x_w() { return (function() {return this.x;})(); }");
8862     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8863     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8864     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8865     env1->Global()->Set(
8866         v8_str("this_x"),
8867         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8868   }
8869
8870   Local<Object> env2_global = env2->Global();
8871   env2_global->TurnOnAccessCheck();
8872   env2->DetachGlobal();
8873
8874   Local<Value> result;
8875   result = CompileRun("bound_x()");
8876   CHECK_EQ(v8_str("env2_x"), result);
8877   result = CompileRun("get_x()");
8878   CHECK(result->IsUndefined());
8879   result = CompileRun("get_x_w()");
8880   CHECK(result->IsUndefined());
8881   result = CompileRun("this_x()");
8882   CHECK_EQ(v8_str("env2_x"), result);
8883
8884   // Reattach env2's proxy
8885   env2 = Context::New(env1->GetIsolate(),
8886                       0,
8887                       v8::Handle<v8::ObjectTemplate>(),
8888                       env2_global);
8889   env2->SetSecurityToken(foo);
8890   {
8891     v8::Context::Scope scope(env2);
8892     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8893     env2->Global()->Set(v8_str("env1"), env1->Global());
8894     result = CompileRun(
8895         "results = [];"
8896         "for (var i = 0; i < 4; i++ ) {"
8897         "  results.push(env1.bound_x());"
8898         "  results.push(env1.get_x());"
8899         "  results.push(env1.get_x_w());"
8900         "  results.push(env1.this_x());"
8901         "}"
8902         "results");
8903     Local<v8::Array> results = Local<v8::Array>::Cast(result);
8904     CHECK_EQ(16, results->Length());
8905     for (int i = 0; i < 16; i += 4) {
8906       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8907       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8908       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8909       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8910     }
8911   }
8912
8913   result = CompileRun(
8914       "results = [];"
8915       "for (var i = 0; i < 4; i++ ) {"
8916       "  results.push(bound_x());"
8917       "  results.push(get_x());"
8918       "  results.push(get_x_w());"
8919       "  results.push(this_x());"
8920       "}"
8921       "results");
8922   Local<v8::Array> results = Local<v8::Array>::Cast(result);
8923   CHECK_EQ(16, results->Length());
8924   for (int i = 0; i < 16; i += 4) {
8925     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8926     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
8927     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8928     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8929   }
8930
8931   result = CompileRun(
8932       "results = [];"
8933       "for (var i = 0; i < 4; i++ ) {"
8934       "  results.push(this.bound_x());"
8935       "  results.push(this.get_x());"
8936       "  results.push(this.get_x_w());"
8937       "  results.push(this.this_x());"
8938       "}"
8939       "results");
8940   results = Local<v8::Array>::Cast(result);
8941   CHECK_EQ(16, results->Length());
8942   for (int i = 0; i < 16; i += 4) {
8943     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
8944     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
8945     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
8946     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
8947   }
8948 }
8949
8950
8951 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8952 static bool NamedAccessBlocker(Local<v8::Object> global,
8953                                Local<Value> name,
8954                                v8::AccessType type,
8955                                Local<Value> data) {
8956   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8957       allowed_access_type[type];
8958 }
8959
8960
8961 static bool IndexedAccessBlocker(Local<v8::Object> global,
8962                                  uint32_t key,
8963                                  v8::AccessType type,
8964                                  Local<Value> data) {
8965   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8966       allowed_access_type[type];
8967 }
8968
8969
8970 static int g_echo_value_1 = -1;
8971 static int g_echo_value_2 = -1;
8972
8973
8974 static void EchoGetter(
8975     Local<String> name,
8976     const v8::PropertyCallbackInfo<v8::Value>& info) {
8977   info.GetReturnValue().Set(v8_num(g_echo_value_1));
8978 }
8979
8980
8981 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8982   info.GetReturnValue().Set(v8_num(g_echo_value_2));
8983 }
8984
8985
8986 static void EchoSetter(Local<String> name,
8987                        Local<Value> value,
8988                        const v8::PropertyCallbackInfo<void>&) {
8989   if (value->IsNumber())
8990     g_echo_value_1 = value->Int32Value();
8991 }
8992
8993
8994 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8995   v8::Handle<v8::Value> value = info[0];
8996   if (value->IsNumber())
8997     g_echo_value_2 = value->Int32Value();
8998 }
8999
9000
9001 static void UnreachableGetter(
9002     Local<String> name,
9003     const v8::PropertyCallbackInfo<v8::Value>& info) {
9004   CHECK(false);  // This function should not be called..
9005 }
9006
9007
9008 static void UnreachableSetter(Local<String>,
9009                               Local<Value>,
9010                               const v8::PropertyCallbackInfo<void>&) {
9011   CHECK(false);  // This function should nto be called.
9012 }
9013
9014
9015 static void UnreachableFunction(
9016     const v8::FunctionCallbackInfo<v8::Value>& info) {
9017   CHECK(false);  // This function should not be called..
9018 }
9019
9020
9021 TEST(AccessControl) {
9022   v8::Isolate* isolate = CcTest::isolate();
9023   v8::HandleScope handle_scope(isolate);
9024   v8::Handle<v8::ObjectTemplate> global_template =
9025       v8::ObjectTemplate::New(isolate);
9026
9027   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9028                                            IndexedAccessBlocker);
9029
9030   // Add an accessor accessible by cross-domain JS code.
9031   global_template->SetAccessor(
9032       v8_str("accessible_prop"),
9033       EchoGetter, EchoSetter,
9034       v8::Handle<Value>(),
9035       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9036
9037
9038   global_template->SetAccessorProperty(
9039       v8_str("accessible_js_prop"),
9040       v8::FunctionTemplate::New(isolate, EchoGetter),
9041       v8::FunctionTemplate::New(isolate, EchoSetter),
9042       v8::None,
9043       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9044
9045   // Add an accessor that is not accessible by cross-domain JS code.
9046   global_template->SetAccessor(v8_str("blocked_prop"),
9047                                UnreachableGetter, UnreachableSetter,
9048                                v8::Handle<Value>(),
9049                                v8::DEFAULT);
9050
9051   global_template->SetAccessorProperty(
9052       v8_str("blocked_js_prop"),
9053       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9054       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9055       v8::None,
9056       v8::DEFAULT);
9057
9058   // Create an environment
9059   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9060   context0->Enter();
9061
9062   v8::Handle<v8::Object> global0 = context0->Global();
9063
9064   // Define a property with JS getter and setter.
9065   CompileRun(
9066       "function getter() { return 'getter'; };\n"
9067       "function setter() { return 'setter'; }\n"
9068       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9069
9070   Local<Value> getter = global0->Get(v8_str("getter"));
9071   Local<Value> setter = global0->Get(v8_str("setter"));
9072
9073   // And define normal element.
9074   global0->Set(239, v8_str("239"));
9075
9076   // Define an element with JS getter and setter.
9077   CompileRun(
9078       "function el_getter() { return 'el_getter'; };\n"
9079       "function el_setter() { return 'el_setter'; };\n"
9080       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9081
9082   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9083   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9084
9085   v8::HandleScope scope1(isolate);
9086
9087   v8::Local<Context> context1 = Context::New(isolate);
9088   context1->Enter();
9089
9090   v8::Handle<v8::Object> global1 = context1->Global();
9091   global1->Set(v8_str("other"), global0);
9092
9093   // Access blocked property.
9094   CompileRun("other.blocked_prop = 1");
9095
9096   ExpectUndefined("other.blocked_prop");
9097   ExpectUndefined(
9098       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9099   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
9100
9101   // Enable ACCESS_HAS
9102   allowed_access_type[v8::ACCESS_HAS] = true;
9103   ExpectUndefined("other.blocked_prop");
9104   // ... and now we can get the descriptor...
9105   ExpectUndefined(
9106       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
9107   // ... and enumerate the property.
9108   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
9109   allowed_access_type[v8::ACCESS_HAS] = false;
9110
9111   // Access blocked element.
9112   CompileRun("other[239] = 1");
9113
9114   ExpectUndefined("other[239]");
9115   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
9116   ExpectFalse("propertyIsEnumerable.call(other, '239')");
9117
9118   // Enable ACCESS_HAS
9119   allowed_access_type[v8::ACCESS_HAS] = true;
9120   ExpectUndefined("other[239]");
9121   // ... and now we can get the descriptor...
9122   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
9123   // ... and enumerate the property.
9124   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9125   allowed_access_type[v8::ACCESS_HAS] = false;
9126
9127   // Access a property with JS accessor.
9128   CompileRun("other.js_accessor_p = 2");
9129
9130   ExpectUndefined("other.js_accessor_p");
9131   ExpectUndefined(
9132       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
9133
9134   // Enable ACCESS_HAS.
9135   allowed_access_type[v8::ACCESS_HAS] = true;
9136   ExpectUndefined("other.js_accessor_p");
9137   ExpectUndefined(
9138       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9139   ExpectUndefined(
9140       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9141   ExpectUndefined(
9142       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9143   allowed_access_type[v8::ACCESS_HAS] = false;
9144
9145   // Enable both ACCESS_HAS and ACCESS_GET.
9146   allowed_access_type[v8::ACCESS_HAS] = true;
9147   allowed_access_type[v8::ACCESS_GET] = true;
9148
9149   ExpectString("other.js_accessor_p", "getter");
9150   ExpectObject(
9151       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9152   ExpectUndefined(
9153       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
9154   ExpectUndefined(
9155       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9156
9157   allowed_access_type[v8::ACCESS_GET] = false;
9158   allowed_access_type[v8::ACCESS_HAS] = false;
9159
9160   // Enable both ACCESS_HAS and ACCESS_SET.
9161   allowed_access_type[v8::ACCESS_HAS] = true;
9162   allowed_access_type[v8::ACCESS_SET] = true;
9163
9164   ExpectUndefined("other.js_accessor_p");
9165   ExpectUndefined(
9166       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
9167   ExpectObject(
9168       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9169   ExpectUndefined(
9170       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9171
9172   allowed_access_type[v8::ACCESS_SET] = false;
9173   allowed_access_type[v8::ACCESS_HAS] = false;
9174
9175   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9176   allowed_access_type[v8::ACCESS_HAS] = true;
9177   allowed_access_type[v8::ACCESS_GET] = true;
9178   allowed_access_type[v8::ACCESS_SET] = true;
9179
9180   ExpectString("other.js_accessor_p", "getter");
9181   ExpectObject(
9182       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9183   ExpectObject(
9184       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9185   ExpectUndefined(
9186       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9187
9188   allowed_access_type[v8::ACCESS_SET] = false;
9189   allowed_access_type[v8::ACCESS_GET] = false;
9190   allowed_access_type[v8::ACCESS_HAS] = false;
9191
9192   // Access an element with JS accessor.
9193   CompileRun("other[42] = 2");
9194
9195   ExpectUndefined("other[42]");
9196   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
9197
9198   // Enable ACCESS_HAS.
9199   allowed_access_type[v8::ACCESS_HAS] = true;
9200   ExpectUndefined("other[42]");
9201   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9202   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9203   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9204   allowed_access_type[v8::ACCESS_HAS] = false;
9205
9206   // Enable both ACCESS_HAS and ACCESS_GET.
9207   allowed_access_type[v8::ACCESS_HAS] = true;
9208   allowed_access_type[v8::ACCESS_GET] = true;
9209
9210   ExpectString("other[42]", "el_getter");
9211   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9212   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
9213   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9214
9215   allowed_access_type[v8::ACCESS_GET] = false;
9216   allowed_access_type[v8::ACCESS_HAS] = false;
9217
9218   // Enable both ACCESS_HAS and ACCESS_SET.
9219   allowed_access_type[v8::ACCESS_HAS] = true;
9220   allowed_access_type[v8::ACCESS_SET] = true;
9221
9222   ExpectUndefined("other[42]");
9223   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
9224   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9225   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9226
9227   allowed_access_type[v8::ACCESS_SET] = false;
9228   allowed_access_type[v8::ACCESS_HAS] = false;
9229
9230   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
9231   allowed_access_type[v8::ACCESS_HAS] = true;
9232   allowed_access_type[v8::ACCESS_GET] = true;
9233   allowed_access_type[v8::ACCESS_SET] = true;
9234
9235   ExpectString("other[42]", "el_getter");
9236   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9237   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9238   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9239
9240   allowed_access_type[v8::ACCESS_SET] = false;
9241   allowed_access_type[v8::ACCESS_GET] = false;
9242   allowed_access_type[v8::ACCESS_HAS] = false;
9243
9244   v8::Handle<Value> value;
9245
9246   // Access accessible property
9247   value = CompileRun("other.accessible_prop = 3");
9248   CHECK(value->IsNumber());
9249   CHECK_EQ(3, value->Int32Value());
9250   CHECK_EQ(3, g_echo_value_1);
9251
9252   // Access accessible js property
9253   value = CompileRun("other.accessible_js_prop = 3");
9254   CHECK(value->IsNumber());
9255   CHECK_EQ(3, value->Int32Value());
9256   CHECK_EQ(3, g_echo_value_2);
9257
9258   value = CompileRun("other.accessible_prop");
9259   CHECK(value->IsNumber());
9260   CHECK_EQ(3, value->Int32Value());
9261
9262   value = CompileRun("other.accessible_js_prop");
9263   CHECK(value->IsNumber());
9264   CHECK_EQ(3, value->Int32Value());
9265
9266   value = CompileRun(
9267       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9268   CHECK(value->IsNumber());
9269   CHECK_EQ(3, value->Int32Value());
9270
9271   value = CompileRun(
9272       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
9273   CHECK(value->IsNumber());
9274   CHECK_EQ(3, value->Int32Value());
9275
9276   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9277   CHECK(value->IsTrue());
9278
9279   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
9280   CHECK(value->IsTrue());
9281
9282   // Enumeration doesn't enumerate accessors from inaccessible objects in
9283   // the prototype chain even if the accessors are in themselves accessible.
9284   value =
9285       CompileRun("(function(){var obj = {'__proto__':other};"
9286                  "for (var p in obj)"
9287                  "   if (p == 'accessible_prop' ||"
9288                  "       p == 'accessible_js_prop' ||"
9289                  "       p == 'blocked_js_prop' ||"
9290                  "       p == 'blocked_js_prop') {"
9291                  "     return false;"
9292                  "   }"
9293                  "return true;})()");
9294   CHECK(value->IsTrue());
9295
9296   context1->Exit();
9297   context0->Exit();
9298 }
9299
9300
9301 TEST(AccessControlES5) {
9302   v8::Isolate* isolate = CcTest::isolate();
9303   v8::HandleScope handle_scope(isolate);
9304   v8::Handle<v8::ObjectTemplate> global_template =
9305       v8::ObjectTemplate::New(isolate);
9306
9307   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9308                                            IndexedAccessBlocker);
9309
9310   // Add accessible accessor.
9311   global_template->SetAccessor(
9312       v8_str("accessible_prop"),
9313       EchoGetter, EchoSetter,
9314       v8::Handle<Value>(),
9315       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9316
9317
9318   // Add an accessor that is not accessible by cross-domain JS code.
9319   global_template->SetAccessor(v8_str("blocked_prop"),
9320                                UnreachableGetter, UnreachableSetter,
9321                                v8::Handle<Value>(),
9322                                v8::DEFAULT);
9323
9324   // Create an environment
9325   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9326   context0->Enter();
9327
9328   v8::Handle<v8::Object> global0 = context0->Global();
9329
9330   v8::Local<Context> context1 = Context::New(isolate);
9331   context1->Enter();
9332   v8::Handle<v8::Object> global1 = context1->Global();
9333   global1->Set(v8_str("other"), global0);
9334
9335   // Regression test for issue 1154.
9336   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
9337
9338   ExpectUndefined("other.blocked_prop");
9339
9340   // Regression test for issue 1027.
9341   CompileRun("Object.defineProperty(\n"
9342              "  other, 'blocked_prop', {configurable: false})");
9343   ExpectUndefined("other.blocked_prop");
9344   ExpectUndefined(
9345       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
9346
9347   // Regression test for issue 1171.
9348   ExpectTrue("Object.isExtensible(other)");
9349   CompileRun("Object.preventExtensions(other)");
9350   ExpectTrue("Object.isExtensible(other)");
9351
9352   // Object.seal and Object.freeze.
9353   CompileRun("Object.freeze(other)");
9354   ExpectTrue("Object.isExtensible(other)");
9355
9356   CompileRun("Object.seal(other)");
9357   ExpectTrue("Object.isExtensible(other)");
9358
9359   // Regression test for issue 1250.
9360   // Make sure that we can set the accessible accessors value using normal
9361   // assignment.
9362   CompileRun("other.accessible_prop = 42");
9363   CHECK_EQ(42, g_echo_value_1);
9364
9365   v8::Handle<Value> value;
9366   // We follow Safari in ignoring assignments to host object accessors.
9367   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9368   value = CompileRun("other.accessible_prop == 42");
9369   CHECK(value->IsTrue());
9370 }
9371
9372
9373 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9374                                             Local<Value> name,
9375                                             v8::AccessType type,
9376                                             Local<Value> data) {
9377   return false;
9378 }
9379
9380
9381 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9382                                               uint32_t key,
9383                                               v8::AccessType type,
9384                                               Local<Value> data) {
9385   return false;
9386 }
9387
9388
9389 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9390   v8::Isolate* isolate = CcTest::isolate();
9391   v8::HandleScope handle_scope(isolate);
9392   v8::Handle<v8::ObjectTemplate> obj_template =
9393       v8::ObjectTemplate::New(isolate);
9394
9395   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9396   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9397                                         GetOwnPropertyNamesIndexedBlocker);
9398
9399   // Create an environment
9400   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9401   context0->Enter();
9402
9403   v8::Handle<v8::Object> global0 = context0->Global();
9404
9405   v8::HandleScope scope1(CcTest::isolate());
9406
9407   v8::Local<Context> context1 = Context::New(isolate);
9408   context1->Enter();
9409
9410   v8::Handle<v8::Object> global1 = context1->Global();
9411   global1->Set(v8_str("other"), global0);
9412   global1->Set(v8_str("object"), obj_template->NewInstance());
9413
9414   v8::Handle<Value> value;
9415
9416   // Attempt to get the property names of the other global object and
9417   // of an object that requires access checks.  Accessing the other
9418   // global object should be blocked by access checks on the global
9419   // proxy object.  Accessing the object that requires access checks
9420   // is blocked by the access checks on the object itself.
9421   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9422   CHECK(value->IsTrue());
9423
9424   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9425   CHECK(value->IsTrue());
9426
9427   context1->Exit();
9428   context0->Exit();
9429 }
9430
9431
9432 static void IndexedPropertyEnumerator(
9433     const v8::PropertyCallbackInfo<v8::Array>& info) {
9434   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9435   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9436   result->Set(1, v8::Object::New(info.GetIsolate()));
9437   info.GetReturnValue().Set(result);
9438 }
9439
9440
9441 static void NamedPropertyEnumerator(
9442     const v8::PropertyCallbackInfo<v8::Array>& info) {
9443   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9444   result->Set(0, v8_str("x"));
9445   result->Set(1, v8::Object::New(info.GetIsolate()));
9446   info.GetReturnValue().Set(result);
9447 }
9448
9449
9450 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9451   v8::Isolate* isolate = CcTest::isolate();
9452   v8::HandleScope handle_scope(isolate);
9453   v8::Handle<v8::ObjectTemplate> obj_template =
9454       v8::ObjectTemplate::New(isolate);
9455
9456   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9457   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9458   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9459                                           IndexedPropertyEnumerator);
9460   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9461                                         NamedPropertyEnumerator);
9462
9463   LocalContext context;
9464   v8::Handle<v8::Object> global = context->Global();
9465   global->Set(v8_str("object"), obj_template->NewInstance());
9466
9467   v8::Handle<v8::Value> result =
9468       CompileRun("Object.getOwnPropertyNames(object)");
9469   CHECK(result->IsArray());
9470   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9471   CHECK_EQ(3, result_array->Length());
9472   CHECK(result_array->Get(0)->IsString());
9473   CHECK(result_array->Get(1)->IsString());
9474   CHECK(result_array->Get(2)->IsString());
9475   CHECK_EQ(v8_str("7"), result_array->Get(0));
9476   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9477   CHECK_EQ(v8_str("x"), result_array->Get(2));
9478 }
9479
9480
9481 static void ConstTenGetter(Local<String> name,
9482                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9483   info.GetReturnValue().Set(v8_num(10));
9484 }
9485
9486
9487 THREADED_TEST(CrossDomainAccessors) {
9488   v8::Isolate* isolate = CcTest::isolate();
9489   v8::HandleScope handle_scope(isolate);
9490
9491   v8::Handle<v8::FunctionTemplate> func_template =
9492       v8::FunctionTemplate::New(isolate);
9493
9494   v8::Handle<v8::ObjectTemplate> global_template =
9495       func_template->InstanceTemplate();
9496
9497   v8::Handle<v8::ObjectTemplate> proto_template =
9498       func_template->PrototypeTemplate();
9499
9500   // Add an accessor to proto that's accessible by cross-domain JS code.
9501   proto_template->SetAccessor(v8_str("accessible"),
9502                               ConstTenGetter, 0,
9503                               v8::Handle<Value>(),
9504                               v8::ALL_CAN_READ);
9505
9506   // Add an accessor that is not accessible by cross-domain JS code.
9507   global_template->SetAccessor(v8_str("unreachable"),
9508                                UnreachableGetter, 0,
9509                                v8::Handle<Value>(),
9510                                v8::DEFAULT);
9511
9512   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9513   context0->Enter();
9514
9515   Local<v8::Object> global = context0->Global();
9516   // Add a normal property that shadows 'accessible'
9517   global->Set(v8_str("accessible"), v8_num(11));
9518
9519   // Enter a new context.
9520   v8::HandleScope scope1(CcTest::isolate());
9521   v8::Local<Context> context1 = Context::New(isolate);
9522   context1->Enter();
9523
9524   v8::Handle<v8::Object> global1 = context1->Global();
9525   global1->Set(v8_str("other"), global);
9526
9527   // Should return 10, instead of 11
9528   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9529   CHECK(value->IsNumber());
9530   CHECK_EQ(10, value->Int32Value());
9531
9532   value = v8_compile("other.unreachable")->Run();
9533   CHECK(value->IsUndefined());
9534
9535   context1->Exit();
9536   context0->Exit();
9537 }
9538
9539
9540 static int named_access_count = 0;
9541 static int indexed_access_count = 0;
9542
9543 static bool NamedAccessCounter(Local<v8::Object> global,
9544                                Local<Value> name,
9545                                v8::AccessType type,
9546                                Local<Value> data) {
9547   named_access_count++;
9548   return true;
9549 }
9550
9551
9552 static bool IndexedAccessCounter(Local<v8::Object> global,
9553                                  uint32_t key,
9554                                  v8::AccessType type,
9555                                  Local<Value> data) {
9556   indexed_access_count++;
9557   return true;
9558 }
9559
9560
9561 // This one is too easily disturbed by other tests.
9562 TEST(AccessControlIC) {
9563   named_access_count = 0;
9564   indexed_access_count = 0;
9565
9566   v8::Isolate* isolate = CcTest::isolate();
9567   v8::HandleScope handle_scope(isolate);
9568
9569   // Create an environment.
9570   v8::Local<Context> context0 = Context::New(isolate);
9571   context0->Enter();
9572
9573   // Create an object that requires access-check functions to be
9574   // called for cross-domain access.
9575   v8::Handle<v8::ObjectTemplate> object_template =
9576       v8::ObjectTemplate::New(isolate);
9577   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9578                                            IndexedAccessCounter);
9579   Local<v8::Object> object = object_template->NewInstance();
9580
9581   v8::HandleScope scope1(isolate);
9582
9583   // Create another environment.
9584   v8::Local<Context> context1 = Context::New(isolate);
9585   context1->Enter();
9586
9587   // Make easy access to the object from the other environment.
9588   v8::Handle<v8::Object> global1 = context1->Global();
9589   global1->Set(v8_str("obj"), object);
9590
9591   v8::Handle<Value> value;
9592
9593   // Check that the named access-control function is called every time.
9594   CompileRun("function testProp(obj) {"
9595              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9596              "  for (var j = 0; j < 10; j++) obj.prop;"
9597              "  return obj.prop"
9598              "}");
9599   value = CompileRun("testProp(obj)");
9600   CHECK(value->IsNumber());
9601   CHECK_EQ(1, value->Int32Value());
9602   CHECK_EQ(21, named_access_count);
9603
9604   // Check that the named access-control function is called every time.
9605   CompileRun("var p = 'prop';"
9606              "function testKeyed(obj) {"
9607              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9608              "  for (var j = 0; j < 10; j++) obj[p];"
9609              "  return obj[p];"
9610              "}");
9611   // Use obj which requires access checks.  No inline caching is used
9612   // in that case.
9613   value = CompileRun("testKeyed(obj)");
9614   CHECK(value->IsNumber());
9615   CHECK_EQ(1, value->Int32Value());
9616   CHECK_EQ(42, named_access_count);
9617   // Force the inline caches into generic state and try again.
9618   CompileRun("testKeyed({ a: 0 })");
9619   CompileRun("testKeyed({ b: 0 })");
9620   value = CompileRun("testKeyed(obj)");
9621   CHECK(value->IsNumber());
9622   CHECK_EQ(1, value->Int32Value());
9623   CHECK_EQ(63, named_access_count);
9624
9625   // Check that the indexed access-control function is called every time.
9626   CompileRun("function testIndexed(obj) {"
9627              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9628              "  for (var j = 0; j < 10; j++) obj[0];"
9629              "  return obj[0]"
9630              "}");
9631   value = CompileRun("testIndexed(obj)");
9632   CHECK(value->IsNumber());
9633   CHECK_EQ(1, value->Int32Value());
9634   CHECK_EQ(21, indexed_access_count);
9635   // Force the inline caches into generic state.
9636   CompileRun("testIndexed(new Array(1))");
9637   // Test that the indexed access check is called.
9638   value = CompileRun("testIndexed(obj)");
9639   CHECK(value->IsNumber());
9640   CHECK_EQ(1, value->Int32Value());
9641   CHECK_EQ(42, indexed_access_count);
9642
9643   // Check that the named access check is called when invoking
9644   // functions on an object that requires access checks.
9645   CompileRun("obj.f = function() {}");
9646   CompileRun("function testCallNormal(obj) {"
9647              "  for (var i = 0; i < 10; i++) obj.f();"
9648              "}");
9649   CompileRun("testCallNormal(obj)");
9650   CHECK_EQ(74, named_access_count);
9651
9652   // Force obj into slow case.
9653   value = CompileRun("delete obj.prop");
9654   CHECK(value->BooleanValue());
9655   // Force inline caches into dictionary probing mode.
9656   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9657   // Test that the named access check is called.
9658   value = CompileRun("testProp(obj);");
9659   CHECK(value->IsNumber());
9660   CHECK_EQ(1, value->Int32Value());
9661   CHECK_EQ(96, named_access_count);
9662
9663   // Force the call inline cache into dictionary probing mode.
9664   CompileRun("o.f = function() {}; testCallNormal(o)");
9665   // Test that the named access check is still called for each
9666   // invocation of the function.
9667   value = CompileRun("testCallNormal(obj)");
9668   CHECK_EQ(106, named_access_count);
9669
9670   context1->Exit();
9671   context0->Exit();
9672 }
9673
9674
9675 static bool NamedAccessFlatten(Local<v8::Object> global,
9676                                Local<Value> name,
9677                                v8::AccessType type,
9678                                Local<Value> data) {
9679   char buf[100];
9680   int len;
9681
9682   CHECK(name->IsString());
9683
9684   memset(buf, 0x1, sizeof(buf));
9685   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9686   CHECK_EQ(4, len);
9687
9688   uint16_t buf2[100];
9689
9690   memset(buf, 0x1, sizeof(buf));
9691   len = name.As<String>()->Write(buf2);
9692   CHECK_EQ(4, len);
9693
9694   return true;
9695 }
9696
9697
9698 static bool IndexedAccessFlatten(Local<v8::Object> global,
9699                                  uint32_t key,
9700                                  v8::AccessType type,
9701                                  Local<Value> data) {
9702   return true;
9703 }
9704
9705
9706 // Regression test.  In access checks, operations that may cause
9707 // garbage collection are not allowed.  It used to be the case that
9708 // using the Write operation on a string could cause a garbage
9709 // collection due to flattening of the string.  This is no longer the
9710 // case.
9711 THREADED_TEST(AccessControlFlatten) {
9712   named_access_count = 0;
9713   indexed_access_count = 0;
9714
9715   v8::Isolate* isolate = CcTest::isolate();
9716   v8::HandleScope handle_scope(isolate);
9717
9718   // Create an environment.
9719   v8::Local<Context> context0 = Context::New(isolate);
9720   context0->Enter();
9721
9722   // Create an object that requires access-check functions to be
9723   // called for cross-domain access.
9724   v8::Handle<v8::ObjectTemplate> object_template =
9725       v8::ObjectTemplate::New(isolate);
9726   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9727                                            IndexedAccessFlatten);
9728   Local<v8::Object> object = object_template->NewInstance();
9729
9730   v8::HandleScope scope1(isolate);
9731
9732   // Create another environment.
9733   v8::Local<Context> context1 = Context::New(isolate);
9734   context1->Enter();
9735
9736   // Make easy access to the object from the other environment.
9737   v8::Handle<v8::Object> global1 = context1->Global();
9738   global1->Set(v8_str("obj"), object);
9739
9740   v8::Handle<Value> value;
9741
9742   value = v8_compile("var p = 'as' + 'df';")->Run();
9743   value = v8_compile("obj[p];")->Run();
9744
9745   context1->Exit();
9746   context0->Exit();
9747 }
9748
9749
9750 static void AccessControlNamedGetter(
9751     Local<String>,
9752     const v8::PropertyCallbackInfo<v8::Value>& info) {
9753   info.GetReturnValue().Set(42);
9754 }
9755
9756
9757 static void AccessControlNamedSetter(
9758     Local<String>,
9759     Local<Value> value,
9760     const v8::PropertyCallbackInfo<v8::Value>& info) {
9761   info.GetReturnValue().Set(value);
9762 }
9763
9764
9765 static void AccessControlIndexedGetter(
9766       uint32_t index,
9767       const v8::PropertyCallbackInfo<v8::Value>& info) {
9768   info.GetReturnValue().Set(v8_num(42));
9769 }
9770
9771
9772 static void AccessControlIndexedSetter(
9773     uint32_t,
9774     Local<Value> value,
9775     const v8::PropertyCallbackInfo<v8::Value>& info) {
9776   info.GetReturnValue().Set(value);
9777 }
9778
9779
9780 THREADED_TEST(AccessControlInterceptorIC) {
9781   named_access_count = 0;
9782   indexed_access_count = 0;
9783
9784   v8::Isolate* isolate = CcTest::isolate();
9785   v8::HandleScope handle_scope(isolate);
9786
9787   // Create an environment.
9788   v8::Local<Context> context0 = Context::New(isolate);
9789   context0->Enter();
9790
9791   // Create an object that requires access-check functions to be
9792   // called for cross-domain access.  The object also has interceptors
9793   // interceptor.
9794   v8::Handle<v8::ObjectTemplate> object_template =
9795       v8::ObjectTemplate::New(isolate);
9796   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9797                                            IndexedAccessCounter);
9798   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9799                                            AccessControlNamedSetter);
9800   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9801                                              AccessControlIndexedSetter);
9802   Local<v8::Object> object = object_template->NewInstance();
9803
9804   v8::HandleScope scope1(isolate);
9805
9806   // Create another environment.
9807   v8::Local<Context> context1 = Context::New(isolate);
9808   context1->Enter();
9809
9810   // Make easy access to the object from the other environment.
9811   v8::Handle<v8::Object> global1 = context1->Global();
9812   global1->Set(v8_str("obj"), object);
9813
9814   v8::Handle<Value> value;
9815
9816   // Check that the named access-control function is called every time
9817   // eventhough there is an interceptor on the object.
9818   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9819   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9820                      "obj.x")->Run();
9821   CHECK(value->IsNumber());
9822   CHECK_EQ(42, value->Int32Value());
9823   CHECK_EQ(21, named_access_count);
9824
9825   value = v8_compile("var p = 'x';")->Run();
9826   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9827   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9828                      "obj[p]")->Run();
9829   CHECK(value->IsNumber());
9830   CHECK_EQ(42, value->Int32Value());
9831   CHECK_EQ(42, named_access_count);
9832
9833   // Check that the indexed access-control function is called every
9834   // time eventhough there is an interceptor on the object.
9835   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9836   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9837                      "obj[0]")->Run();
9838   CHECK(value->IsNumber());
9839   CHECK_EQ(42, value->Int32Value());
9840   CHECK_EQ(21, indexed_access_count);
9841
9842   context1->Exit();
9843   context0->Exit();
9844 }
9845
9846
9847 THREADED_TEST(Version) {
9848   v8::V8::GetVersion();
9849 }
9850
9851
9852 static void InstanceFunctionCallback(
9853     const v8::FunctionCallbackInfo<v8::Value>& args) {
9854   ApiTestFuzzer::Fuzz();
9855   args.GetReturnValue().Set(v8_num(12));
9856 }
9857
9858
9859 THREADED_TEST(InstanceProperties) {
9860   LocalContext context;
9861   v8::Isolate* isolate = context->GetIsolate();
9862   v8::HandleScope handle_scope(isolate);
9863
9864   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9865   Local<ObjectTemplate> instance = t->InstanceTemplate();
9866
9867   instance->Set(v8_str("x"), v8_num(42));
9868   instance->Set(v8_str("f"),
9869                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9870
9871   Local<Value> o = t->GetFunction()->NewInstance();
9872
9873   context->Global()->Set(v8_str("i"), o);
9874   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9875   CHECK_EQ(42, value->Int32Value());
9876
9877   value = Script::Compile(v8_str("i.f()"))->Run();
9878   CHECK_EQ(12, value->Int32Value());
9879 }
9880
9881
9882 static void GlobalObjectInstancePropertiesGet(
9883     Local<String> key,
9884     const v8::PropertyCallbackInfo<v8::Value>&) {
9885   ApiTestFuzzer::Fuzz();
9886 }
9887
9888
9889 THREADED_TEST(GlobalObjectInstanceProperties) {
9890   v8::Isolate* isolate = CcTest::isolate();
9891   v8::HandleScope handle_scope(isolate);
9892
9893   Local<Value> global_object;
9894
9895   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9896   t->InstanceTemplate()->SetNamedPropertyHandler(
9897       GlobalObjectInstancePropertiesGet);
9898   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9899   instance_template->Set(v8_str("x"), v8_num(42));
9900   instance_template->Set(v8_str("f"),
9901                          v8::FunctionTemplate::New(isolate,
9902                                                    InstanceFunctionCallback));
9903
9904   // The script to check how Crankshaft compiles missing global function
9905   // invocations.  function g is not defined and should throw on call.
9906   const char* script =
9907       "function wrapper(call) {"
9908       "  var x = 0, y = 1;"
9909       "  for (var i = 0; i < 1000; i++) {"
9910       "    x += i * 100;"
9911       "    y += i * 100;"
9912       "  }"
9913       "  if (call) g();"
9914       "}"
9915       "for (var i = 0; i < 17; i++) wrapper(false);"
9916       "var thrown = 0;"
9917       "try { wrapper(true); } catch (e) { thrown = 1; };"
9918       "thrown";
9919
9920   {
9921     LocalContext env(NULL, instance_template);
9922     // Hold on to the global object so it can be used again in another
9923     // environment initialization.
9924     global_object = env->Global();
9925
9926     Local<Value> value = Script::Compile(v8_str("x"))->Run();
9927     CHECK_EQ(42, value->Int32Value());
9928     value = Script::Compile(v8_str("f()"))->Run();
9929     CHECK_EQ(12, value->Int32Value());
9930     value = Script::Compile(v8_str(script))->Run();
9931     CHECK_EQ(1, value->Int32Value());
9932   }
9933
9934   {
9935     // Create new environment reusing the global object.
9936     LocalContext env(NULL, instance_template, global_object);
9937     Local<Value> value = Script::Compile(v8_str("x"))->Run();
9938     CHECK_EQ(42, value->Int32Value());
9939     value = Script::Compile(v8_str("f()"))->Run();
9940     CHECK_EQ(12, value->Int32Value());
9941     value = Script::Compile(v8_str(script))->Run();
9942     CHECK_EQ(1, value->Int32Value());
9943   }
9944 }
9945
9946
9947 THREADED_TEST(CallKnownGlobalReceiver) {
9948   v8::Isolate* isolate = CcTest::isolate();
9949   v8::HandleScope handle_scope(isolate);
9950
9951   Local<Value> global_object;
9952
9953   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9954   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9955
9956   // The script to check that we leave global object not
9957   // global object proxy on stack when we deoptimize from inside
9958   // arguments evaluation.
9959   // To provoke error we need to both force deoptimization
9960   // from arguments evaluation and to force CallIC to take
9961   // CallIC_Miss code path that can't cope with global proxy.
9962   const char* script =
9963       "function bar(x, y) { try { } finally { } }"
9964       "function baz(x) { try { } finally { } }"
9965       "function bom(x) { try { } finally { } }"
9966       "function foo(x) { bar([x], bom(2)); }"
9967       "for (var i = 0; i < 10000; i++) foo(1);"
9968       "foo";
9969
9970   Local<Value> foo;
9971   {
9972     LocalContext env(NULL, instance_template);
9973     // Hold on to the global object so it can be used again in another
9974     // environment initialization.
9975     global_object = env->Global();
9976     foo = Script::Compile(v8_str(script))->Run();
9977   }
9978
9979   {
9980     // Create new environment reusing the global object.
9981     LocalContext env(NULL, instance_template, global_object);
9982     env->Global()->Set(v8_str("foo"), foo);
9983     Script::Compile(v8_str("foo()"))->Run();
9984   }
9985 }
9986
9987
9988 static void ShadowFunctionCallback(
9989     const v8::FunctionCallbackInfo<v8::Value>& args) {
9990   ApiTestFuzzer::Fuzz();
9991   args.GetReturnValue().Set(v8_num(42));
9992 }
9993
9994
9995 static int shadow_y;
9996 static int shadow_y_setter_call_count;
9997 static int shadow_y_getter_call_count;
9998
9999
10000 static void ShadowYSetter(Local<String>,
10001                           Local<Value>,
10002                           const v8::PropertyCallbackInfo<void>&) {
10003   shadow_y_setter_call_count++;
10004   shadow_y = 42;
10005 }
10006
10007
10008 static void ShadowYGetter(Local<String> name,
10009                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10010   ApiTestFuzzer::Fuzz();
10011   shadow_y_getter_call_count++;
10012   info.GetReturnValue().Set(v8_num(shadow_y));
10013 }
10014
10015
10016 static void ShadowIndexedGet(uint32_t index,
10017                              const v8::PropertyCallbackInfo<v8::Value>&) {
10018 }
10019
10020
10021 static void ShadowNamedGet(Local<String> key,
10022                            const v8::PropertyCallbackInfo<v8::Value>&) {
10023 }
10024
10025
10026 THREADED_TEST(ShadowObject) {
10027   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10028   v8::Isolate* isolate = CcTest::isolate();
10029   v8::HandleScope handle_scope(isolate);
10030
10031   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10032   LocalContext context(NULL, global_template);
10033
10034   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10035   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10036   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10037   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10038   Local<ObjectTemplate> instance = t->InstanceTemplate();
10039
10040   proto->Set(v8_str("f"),
10041              v8::FunctionTemplate::New(isolate,
10042                                        ShadowFunctionCallback,
10043                                        Local<Value>()));
10044   proto->Set(v8_str("x"), v8_num(12));
10045
10046   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10047
10048   Local<Value> o = t->GetFunction()->NewInstance();
10049   context->Global()->Set(v8_str("__proto__"), o);
10050
10051   Local<Value> value =
10052       Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
10053   CHECK(value->IsBoolean());
10054   CHECK(!value->BooleanValue());
10055
10056   value = Script::Compile(v8_str("x"))->Run();
10057   CHECK_EQ(12, value->Int32Value());
10058
10059   value = Script::Compile(v8_str("f()"))->Run();
10060   CHECK_EQ(42, value->Int32Value());
10061
10062   Script::Compile(v8_str("y = 43"))->Run();
10063   CHECK_EQ(1, shadow_y_setter_call_count);
10064   value = Script::Compile(v8_str("y"))->Run();
10065   CHECK_EQ(1, shadow_y_getter_call_count);
10066   CHECK_EQ(42, value->Int32Value());
10067 }
10068
10069
10070 THREADED_TEST(HiddenPrototype) {
10071   LocalContext context;
10072   v8::Isolate* isolate = context->GetIsolate();
10073   v8::HandleScope handle_scope(isolate);
10074
10075   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10076   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10077   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10078   t1->SetHiddenPrototype(true);
10079   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10080   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10081   t2->SetHiddenPrototype(true);
10082   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10083   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10084   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10085
10086   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10087   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10088   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10089   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10090
10091   // Setting the prototype on an object skips hidden prototypes.
10092   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10093   o0->Set(v8_str("__proto__"), o1);
10094   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10095   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10096   o0->Set(v8_str("__proto__"), o2);
10097   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10098   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10099   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10100   o0->Set(v8_str("__proto__"), o3);
10101   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10102   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10103   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10104   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10105
10106   // Getting the prototype of o0 should get the first visible one
10107   // which is o3.  Therefore, z should not be defined on the prototype
10108   // object.
10109   Local<Value> proto = o0->Get(v8_str("__proto__"));
10110   CHECK(proto->IsObject());
10111   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10112 }
10113
10114
10115 THREADED_TEST(HiddenPrototypeSet) {
10116   LocalContext context;
10117   v8::Isolate* isolate = context->GetIsolate();
10118   v8::HandleScope handle_scope(isolate);
10119
10120   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10121   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10122   ht->SetHiddenPrototype(true);
10123   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10124   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10125
10126   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10127   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10128   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10129   o->Set(v8_str("__proto__"), h);
10130   h->Set(v8_str("__proto__"), p);
10131
10132   // Setting a property that exists on the hidden prototype goes there.
10133   o->Set(v8_str("x"), v8_num(7));
10134   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10135   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10136   CHECK(p->Get(v8_str("x"))->IsUndefined());
10137
10138   // Setting a new property should not be forwarded to the hidden prototype.
10139   o->Set(v8_str("y"), v8_num(6));
10140   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10141   CHECK(h->Get(v8_str("y"))->IsUndefined());
10142   CHECK(p->Get(v8_str("y"))->IsUndefined());
10143
10144   // Setting a property that only exists on a prototype of the hidden prototype
10145   // is treated normally again.
10146   p->Set(v8_str("z"), v8_num(8));
10147   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10148   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10149   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10150   o->Set(v8_str("z"), v8_num(9));
10151   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10152   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10153   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10154 }
10155
10156
10157 // Regression test for issue 2457.
10158 THREADED_TEST(HiddenPrototypeIdentityHash) {
10159   LocalContext context;
10160   v8::HandleScope handle_scope(context->GetIsolate());
10161
10162   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10163   t->SetHiddenPrototype(true);
10164   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10165   Handle<Object> p = t->GetFunction()->NewInstance();
10166   Handle<Object> o = Object::New(context->GetIsolate());
10167   o->SetPrototype(p);
10168
10169   int hash = o->GetIdentityHash();
10170   USE(hash);
10171   o->Set(v8_str("foo"), v8_num(42));
10172   ASSERT_EQ(hash, o->GetIdentityHash());
10173 }
10174
10175
10176 THREADED_TEST(SetPrototype) {
10177   LocalContext context;
10178   v8::Isolate* isolate = context->GetIsolate();
10179   v8::HandleScope handle_scope(isolate);
10180
10181   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10182   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10183   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10184   t1->SetHiddenPrototype(true);
10185   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10186   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10187   t2->SetHiddenPrototype(true);
10188   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10189   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10190   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10191
10192   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10193   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10194   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10195   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10196
10197   // Setting the prototype on an object does not skip hidden prototypes.
10198   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10199   CHECK(o0->SetPrototype(o1));
10200   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10201   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10202   CHECK(o1->SetPrototype(o2));
10203   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10204   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10205   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10206   CHECK(o2->SetPrototype(o3));
10207   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10208   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10209   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10210   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10211
10212   // Getting the prototype of o0 should get the first visible one
10213   // which is o3.  Therefore, z should not be defined on the prototype
10214   // object.
10215   Local<Value> proto = o0->Get(v8_str("__proto__"));
10216   CHECK(proto->IsObject());
10217   CHECK_EQ(proto.As<v8::Object>(), o3);
10218
10219   // However, Object::GetPrototype ignores hidden prototype.
10220   Local<Value> proto0 = o0->GetPrototype();
10221   CHECK(proto0->IsObject());
10222   CHECK_EQ(proto0.As<v8::Object>(), o1);
10223
10224   Local<Value> proto1 = o1->GetPrototype();
10225   CHECK(proto1->IsObject());
10226   CHECK_EQ(proto1.As<v8::Object>(), o2);
10227
10228   Local<Value> proto2 = o2->GetPrototype();
10229   CHECK(proto2->IsObject());
10230   CHECK_EQ(proto2.As<v8::Object>(), o3);
10231 }
10232
10233
10234 // Getting property names of an object with a prototype chain that
10235 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
10236 // crash the runtime.
10237 THREADED_TEST(Regress91517) {
10238   i::FLAG_allow_natives_syntax = true;
10239   LocalContext context;
10240   v8::Isolate* isolate = context->GetIsolate();
10241   v8::HandleScope handle_scope(isolate);
10242
10243   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10244   t1->SetHiddenPrototype(true);
10245   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10246   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10247   t2->SetHiddenPrototype(true);
10248   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10249   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10250   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10251   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10252   t3->SetHiddenPrototype(true);
10253   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10254   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10255   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10256
10257   // Force dictionary-based properties.
10258   i::ScopedVector<char> name_buf(1024);
10259   for (int i = 1; i <= 1000; i++) {
10260     i::OS::SNPrintF(name_buf, "sdf%d", i);
10261     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10262   }
10263
10264   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10265   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10266   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10267   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10268
10269   // Create prototype chain of hidden prototypes.
10270   CHECK(o4->SetPrototype(o3));
10271   CHECK(o3->SetPrototype(o2));
10272   CHECK(o2->SetPrototype(o1));
10273
10274   // Call the runtime version of GetLocalPropertyNames() on the natively
10275   // created object through JavaScript.
10276   context->Global()->Set(v8_str("obj"), o4);
10277   // PROPERTY_ATTRIBUTES_NONE = 0
10278   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10279
10280   ExpectInt32("names.length", 1006);
10281   ExpectTrue("names.indexOf(\"baz\") >= 0");
10282   ExpectTrue("names.indexOf(\"boo\") >= 0");
10283   ExpectTrue("names.indexOf(\"foo\") >= 0");
10284   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10285   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10286   ExpectFalse("names[1005] == undefined");
10287 }
10288
10289
10290 // Getting property names of an object with a hidden and inherited
10291 // prototype should not duplicate the accessor properties inherited.
10292 THREADED_TEST(Regress269562) {
10293   i::FLAG_allow_natives_syntax = true;
10294   LocalContext context;
10295   v8::HandleScope handle_scope(context->GetIsolate());
10296
10297   Local<v8::FunctionTemplate> t1 =
10298       v8::FunctionTemplate::New(context->GetIsolate());
10299   t1->SetHiddenPrototype(true);
10300
10301   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10302   i1->SetAccessor(v8_str("foo"),
10303                   SimpleAccessorGetter, SimpleAccessorSetter);
10304   i1->SetAccessor(v8_str("bar"),
10305                   SimpleAccessorGetter, SimpleAccessorSetter);
10306   i1->SetAccessor(v8_str("baz"),
10307                   SimpleAccessorGetter, SimpleAccessorSetter);
10308   i1->Set(v8_str("n1"), v8_num(1));
10309   i1->Set(v8_str("n2"), v8_num(2));
10310
10311   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10312   Local<v8::FunctionTemplate> t2 =
10313       v8::FunctionTemplate::New(context->GetIsolate());
10314   t2->SetHiddenPrototype(true);
10315
10316   // Inherit from t1 and mark prototype as hidden.
10317   t2->Inherit(t1);
10318   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10319
10320   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10321   CHECK(o2->SetPrototype(o1));
10322
10323   v8::Local<v8::Symbol> sym = v8::Symbol::New(context->GetIsolate(), "s1");
10324   o1->Set(sym, v8_num(3));
10325   o1->SetHiddenValue(v8_str("h1"),
10326                      v8::Integer::New(context->GetIsolate(), 2013));
10327
10328   // Call the runtime version of GetLocalPropertyNames() on
10329   // the natively created object through JavaScript.
10330   context->Global()->Set(v8_str("obj"), o2);
10331   context->Global()->Set(v8_str("sym"), sym);
10332   // PROPERTY_ATTRIBUTES_NONE = 0
10333   CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
10334
10335   ExpectInt32("names.length", 7);
10336   ExpectTrue("names.indexOf(\"foo\") >= 0");
10337   ExpectTrue("names.indexOf(\"bar\") >= 0");
10338   ExpectTrue("names.indexOf(\"baz\") >= 0");
10339   ExpectTrue("names.indexOf(\"n1\") >= 0");
10340   ExpectTrue("names.indexOf(\"n2\") >= 0");
10341   ExpectTrue("names.indexOf(sym) >= 0");
10342   ExpectTrue("names.indexOf(\"mine\") >= 0");
10343 }
10344
10345
10346 THREADED_TEST(FunctionReadOnlyPrototype) {
10347   LocalContext context;
10348   v8::Isolate* isolate = context->GetIsolate();
10349   v8::HandleScope handle_scope(isolate);
10350
10351   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10352   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10353   t1->ReadOnlyPrototype();
10354   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10355   // Configured value of ReadOnly flag.
10356   CHECK(CompileRun(
10357       "(function() {"
10358       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10359       "  return (descriptor['writable'] == false);"
10360       "})()")->BooleanValue());
10361   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10362   CHECK_EQ(42,
10363            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10364
10365   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10366   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10367   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10368   // Default value of ReadOnly flag.
10369   CHECK(CompileRun(
10370       "(function() {"
10371       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10372       "  return (descriptor['writable'] == true);"
10373       "})()")->BooleanValue());
10374   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10375 }
10376
10377
10378 THREADED_TEST(SetPrototypeThrows) {
10379   LocalContext context;
10380   v8::Isolate* isolate = context->GetIsolate();
10381   v8::HandleScope handle_scope(isolate);
10382
10383   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10384
10385   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10386   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10387
10388   CHECK(o0->SetPrototype(o1));
10389   // If setting the prototype leads to the cycle, SetPrototype should
10390   // return false and keep VM in sane state.
10391   v8::TryCatch try_catch;
10392   CHECK(!o1->SetPrototype(o0));
10393   CHECK(!try_catch.HasCaught());
10394   ASSERT(!CcTest::i_isolate()->has_pending_exception());
10395
10396   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10397 }
10398
10399
10400 THREADED_TEST(FunctionRemovePrototype) {
10401   LocalContext context;
10402   v8::Isolate* isolate = context->GetIsolate();
10403   v8::HandleScope handle_scope(isolate);
10404
10405   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10406   t1->RemovePrototype();
10407   Local<v8::Function> fun = t1->GetFunction();
10408   context->Global()->Set(v8_str("fun"), fun);
10409   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10410
10411   v8::TryCatch try_catch;
10412   CompileRun("new fun()");
10413   CHECK(try_catch.HasCaught());
10414
10415   try_catch.Reset();
10416   fun->NewInstance();
10417   CHECK(try_catch.HasCaught());
10418 }
10419
10420
10421 THREADED_TEST(GetterSetterExceptions) {
10422   LocalContext context;
10423   v8::Isolate* isolate = context->GetIsolate();
10424   v8::HandleScope handle_scope(isolate);
10425   CompileRun(
10426     "function Foo() { };"
10427     "function Throw() { throw 5; };"
10428     "var x = { };"
10429     "x.__defineSetter__('set', Throw);"
10430     "x.__defineGetter__('get', Throw);");
10431   Local<v8::Object> x =
10432       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10433   v8::TryCatch try_catch;
10434   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10435   x->Get(v8_str("get"));
10436   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10437   x->Get(v8_str("get"));
10438   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10439   x->Get(v8_str("get"));
10440   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10441   x->Get(v8_str("get"));
10442 }
10443
10444
10445 THREADED_TEST(Constructor) {
10446   LocalContext context;
10447   v8::Isolate* isolate = context->GetIsolate();
10448   v8::HandleScope handle_scope(isolate);
10449   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10450   templ->SetClassName(v8_str("Fun"));
10451   Local<Function> cons = templ->GetFunction();
10452   context->Global()->Set(v8_str("Fun"), cons);
10453   Local<v8::Object> inst = cons->NewInstance();
10454   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10455   CHECK(obj->IsJSObject());
10456   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10457   CHECK(value->BooleanValue());
10458 }
10459
10460
10461 static void ConstructorCallback(
10462     const v8::FunctionCallbackInfo<v8::Value>& args) {
10463   ApiTestFuzzer::Fuzz();
10464   Local<Object> This;
10465
10466   if (args.IsConstructCall()) {
10467     Local<Object> Holder = args.Holder();
10468     This = Object::New(args.GetIsolate());
10469     Local<Value> proto = Holder->GetPrototype();
10470     if (proto->IsObject()) {
10471       This->SetPrototype(proto);
10472     }
10473   } else {
10474     This = args.This();
10475   }
10476
10477   This->Set(v8_str("a"), args[0]);
10478   args.GetReturnValue().Set(This);
10479 }
10480
10481
10482 static void FakeConstructorCallback(
10483     const v8::FunctionCallbackInfo<v8::Value>& args) {
10484   ApiTestFuzzer::Fuzz();
10485   args.GetReturnValue().Set(args[0]);
10486 }
10487
10488
10489 THREADED_TEST(ConstructorForObject) {
10490   LocalContext context;
10491   v8::Isolate* isolate = context->GetIsolate();
10492   v8::HandleScope handle_scope(isolate);
10493
10494   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10495     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10496     Local<Object> instance = instance_template->NewInstance();
10497     context->Global()->Set(v8_str("obj"), instance);
10498     v8::TryCatch try_catch;
10499     Local<Value> value;
10500     CHECK(!try_catch.HasCaught());
10501
10502     // Call the Object's constructor with a 32-bit signed integer.
10503     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10504     CHECK(!try_catch.HasCaught());
10505     CHECK(value->IsInt32());
10506     CHECK_EQ(28, value->Int32Value());
10507
10508     Local<Value> args1[] = { v8_num(28) };
10509     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10510     CHECK(value_obj1->IsObject());
10511     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10512     value = object1->Get(v8_str("a"));
10513     CHECK(value->IsInt32());
10514     CHECK(!try_catch.HasCaught());
10515     CHECK_EQ(28, value->Int32Value());
10516
10517     // Call the Object's constructor with a String.
10518     value = CompileRun(
10519         "(function() { var o = new obj('tipli'); return o.a; })()");
10520     CHECK(!try_catch.HasCaught());
10521     CHECK(value->IsString());
10522     String::Utf8Value string_value1(value->ToString());
10523     CHECK_EQ("tipli", *string_value1);
10524
10525     Local<Value> args2[] = { v8_str("tipli") };
10526     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10527     CHECK(value_obj2->IsObject());
10528     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10529     value = object2->Get(v8_str("a"));
10530     CHECK(!try_catch.HasCaught());
10531     CHECK(value->IsString());
10532     String::Utf8Value string_value2(value->ToString());
10533     CHECK_EQ("tipli", *string_value2);
10534
10535     // Call the Object's constructor with a Boolean.
10536     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10537     CHECK(!try_catch.HasCaught());
10538     CHECK(value->IsBoolean());
10539     CHECK_EQ(true, value->BooleanValue());
10540
10541     Handle<Value> args3[] = { v8::True(isolate) };
10542     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10543     CHECK(value_obj3->IsObject());
10544     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10545     value = object3->Get(v8_str("a"));
10546     CHECK(!try_catch.HasCaught());
10547     CHECK(value->IsBoolean());
10548     CHECK_EQ(true, value->BooleanValue());
10549
10550     // Call the Object's constructor with undefined.
10551     Handle<Value> args4[] = { v8::Undefined(isolate) };
10552     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10553     CHECK(value_obj4->IsObject());
10554     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10555     value = object4->Get(v8_str("a"));
10556     CHECK(!try_catch.HasCaught());
10557     CHECK(value->IsUndefined());
10558
10559     // Call the Object's constructor with null.
10560     Handle<Value> args5[] = { v8::Null(isolate) };
10561     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10562     CHECK(value_obj5->IsObject());
10563     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10564     value = object5->Get(v8_str("a"));
10565     CHECK(!try_catch.HasCaught());
10566     CHECK(value->IsNull());
10567   }
10568
10569   // Check exception handling when there is no constructor set for the Object.
10570   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10571     Local<Object> instance = instance_template->NewInstance();
10572     context->Global()->Set(v8_str("obj2"), instance);
10573     v8::TryCatch try_catch;
10574     Local<Value> value;
10575     CHECK(!try_catch.HasCaught());
10576
10577     value = CompileRun("new obj2(28)");
10578     CHECK(try_catch.HasCaught());
10579     String::Utf8Value exception_value1(try_catch.Exception());
10580     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10581     try_catch.Reset();
10582
10583     Local<Value> args[] = { v8_num(29) };
10584     value = instance->CallAsConstructor(1, args);
10585     CHECK(try_catch.HasCaught());
10586     String::Utf8Value exception_value2(try_catch.Exception());
10587     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10588     try_catch.Reset();
10589   }
10590
10591   // Check the case when constructor throws exception.
10592   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10593     instance_template->SetCallAsFunctionHandler(ThrowValue);
10594     Local<Object> instance = instance_template->NewInstance();
10595     context->Global()->Set(v8_str("obj3"), instance);
10596     v8::TryCatch try_catch;
10597     Local<Value> value;
10598     CHECK(!try_catch.HasCaught());
10599
10600     value = CompileRun("new obj3(22)");
10601     CHECK(try_catch.HasCaught());
10602     String::Utf8Value exception_value1(try_catch.Exception());
10603     CHECK_EQ("22", *exception_value1);
10604     try_catch.Reset();
10605
10606     Local<Value> args[] = { v8_num(23) };
10607     value = instance->CallAsConstructor(1, args);
10608     CHECK(try_catch.HasCaught());
10609     String::Utf8Value exception_value2(try_catch.Exception());
10610     CHECK_EQ("23", *exception_value2);
10611     try_catch.Reset();
10612   }
10613
10614   // Check whether constructor returns with an object or non-object.
10615   { Local<FunctionTemplate> function_template =
10616         FunctionTemplate::New(isolate, FakeConstructorCallback);
10617     Local<Function> function = function_template->GetFunction();
10618     Local<Object> instance1 = function;
10619     context->Global()->Set(v8_str("obj4"), instance1);
10620     v8::TryCatch try_catch;
10621     Local<Value> value;
10622     CHECK(!try_catch.HasCaught());
10623
10624     CHECK(instance1->IsObject());
10625     CHECK(instance1->IsFunction());
10626
10627     value = CompileRun("new obj4(28)");
10628     CHECK(!try_catch.HasCaught());
10629     CHECK(value->IsObject());
10630
10631     Local<Value> args1[] = { v8_num(28) };
10632     value = instance1->CallAsConstructor(1, args1);
10633     CHECK(!try_catch.HasCaught());
10634     CHECK(value->IsObject());
10635
10636     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10637     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10638     Local<Object> instance2 = instance_template->NewInstance();
10639     context->Global()->Set(v8_str("obj5"), instance2);
10640     CHECK(!try_catch.HasCaught());
10641
10642     CHECK(instance2->IsObject());
10643     CHECK(!instance2->IsFunction());
10644
10645     value = CompileRun("new obj5(28)");
10646     CHECK(!try_catch.HasCaught());
10647     CHECK(!value->IsObject());
10648
10649     Local<Value> args2[] = { v8_num(28) };
10650     value = instance2->CallAsConstructor(1, args2);
10651     CHECK(!try_catch.HasCaught());
10652     CHECK(!value->IsObject());
10653   }
10654 }
10655
10656
10657 THREADED_TEST(FunctionDescriptorException) {
10658   LocalContext context;
10659   v8::Isolate* isolate = context->GetIsolate();
10660   v8::HandleScope handle_scope(isolate);
10661   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10662   templ->SetClassName(v8_str("Fun"));
10663   Local<Function> cons = templ->GetFunction();
10664   context->Global()->Set(v8_str("Fun"), cons);
10665   Local<Value> value = CompileRun(
10666     "function test() {"
10667     "  try {"
10668     "    (new Fun()).blah()"
10669     "  } catch (e) {"
10670     "    var str = String(e);"
10671     "    if (str.indexOf('TypeError') == -1) return 1;"
10672     "    if (str.indexOf('[object Fun]') != -1) return 2;"
10673     "    if (str.indexOf('#<Fun>') == -1) return 3;"
10674     "    return 0;"
10675     "  }"
10676     "  return 4;"
10677     "}"
10678     "test();");
10679   CHECK_EQ(0, value->Int32Value());
10680 }
10681
10682
10683 THREADED_TEST(EvalAliasedDynamic) {
10684   LocalContext current;
10685   v8::HandleScope scope(current->GetIsolate());
10686
10687   // Tests where aliased eval can only be resolved dynamically.
10688   Local<Script> script =
10689       Script::Compile(v8_str("function f(x) { "
10690                              "  var foo = 2;"
10691                              "  with (x) { return eval('foo'); }"
10692                              "}"
10693                              "foo = 0;"
10694                              "result1 = f(new Object());"
10695                              "result2 = f(this);"
10696                              "var x = new Object();"
10697                              "x.eval = function(x) { return 1; };"
10698                              "result3 = f(x);"));
10699   script->Run();
10700   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10701   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10702   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10703
10704   v8::TryCatch try_catch;
10705   script =
10706     Script::Compile(v8_str("function f(x) { "
10707                            "  var bar = 2;"
10708                            "  with (x) { return eval('bar'); }"
10709                            "}"
10710                            "result4 = f(this)"));
10711   script->Run();
10712   CHECK(!try_catch.HasCaught());
10713   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10714
10715   try_catch.Reset();
10716 }
10717
10718
10719 THREADED_TEST(CrossEval) {
10720   v8::HandleScope scope(CcTest::isolate());
10721   LocalContext other;
10722   LocalContext current;
10723
10724   Local<String> token = v8_str("<security token>");
10725   other->SetSecurityToken(token);
10726   current->SetSecurityToken(token);
10727
10728   // Set up reference from current to other.
10729   current->Global()->Set(v8_str("other"), other->Global());
10730
10731   // Check that new variables are introduced in other context.
10732   Local<Script> script =
10733       Script::Compile(v8_str("other.eval('var foo = 1234')"));
10734   script->Run();
10735   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10736   CHECK_EQ(1234, foo->Int32Value());
10737   CHECK(!current->Global()->Has(v8_str("foo")));
10738
10739   // Check that writing to non-existing properties introduces them in
10740   // the other context.
10741   script =
10742       Script::Compile(v8_str("other.eval('na = 1234')"));
10743   script->Run();
10744   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10745   CHECK(!current->Global()->Has(v8_str("na")));
10746
10747   // Check that global variables in current context are not visible in other
10748   // context.
10749   v8::TryCatch try_catch;
10750   script =
10751       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10752   Local<Value> result = script->Run();
10753   CHECK(try_catch.HasCaught());
10754   try_catch.Reset();
10755
10756   // Check that local variables in current context are not visible in other
10757   // context.
10758   script =
10759       Script::Compile(v8_str("(function() { "
10760                              "  var baz = 87;"
10761                              "  return other.eval('baz');"
10762                              "})();"));
10763   result = script->Run();
10764   CHECK(try_catch.HasCaught());
10765   try_catch.Reset();
10766
10767   // Check that global variables in the other environment are visible
10768   // when evaluting code.
10769   other->Global()->Set(v8_str("bis"), v8_num(1234));
10770   script = Script::Compile(v8_str("other.eval('bis')"));
10771   CHECK_EQ(1234, script->Run()->Int32Value());
10772   CHECK(!try_catch.HasCaught());
10773
10774   // Check that the 'this' pointer points to the global object evaluating
10775   // code.
10776   other->Global()->Set(v8_str("t"), other->Global());
10777   script = Script::Compile(v8_str("other.eval('this == t')"));
10778   result = script->Run();
10779   CHECK(result->IsTrue());
10780   CHECK(!try_catch.HasCaught());
10781
10782   // Check that variables introduced in with-statement are not visible in
10783   // other context.
10784   script =
10785       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10786   result = script->Run();
10787   CHECK(try_catch.HasCaught());
10788   try_catch.Reset();
10789
10790   // Check that you cannot use 'eval.call' with another object than the
10791   // current global object.
10792   script =
10793       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10794   result = script->Run();
10795   CHECK(try_catch.HasCaught());
10796 }
10797
10798
10799 // Test that calling eval in a context which has been detached from
10800 // its global throws an exception.  This behavior is consistent with
10801 // other JavaScript implementations.
10802 THREADED_TEST(EvalInDetachedGlobal) {
10803   v8::Isolate* isolate = CcTest::isolate();
10804   v8::HandleScope scope(isolate);
10805
10806   v8::Local<Context> context0 = Context::New(isolate);
10807   v8::Local<Context> context1 = Context::New(isolate);
10808
10809   // Set up function in context0 that uses eval from context0.
10810   context0->Enter();
10811   v8::Handle<v8::Value> fun =
10812       CompileRun("var x = 42;"
10813                  "(function() {"
10814                  "  var e = eval;"
10815                  "  return function(s) { return e(s); }"
10816                  "})()");
10817   context0->Exit();
10818
10819   // Put the function into context1 and call it before and after
10820   // detaching the global.  Before detaching, the call succeeds and
10821   // after detaching and exception is thrown.
10822   context1->Enter();
10823   context1->Global()->Set(v8_str("fun"), fun);
10824   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10825   CHECK_EQ(42, x_value->Int32Value());
10826   context0->DetachGlobal();
10827   v8::TryCatch catcher;
10828   x_value = CompileRun("fun('x')");
10829   CHECK(x_value.IsEmpty());
10830   CHECK(catcher.HasCaught());
10831   context1->Exit();
10832 }
10833
10834
10835 THREADED_TEST(CrossLazyLoad) {
10836   v8::HandleScope scope(CcTest::isolate());
10837   LocalContext other;
10838   LocalContext current;
10839
10840   Local<String> token = v8_str("<security token>");
10841   other->SetSecurityToken(token);
10842   current->SetSecurityToken(token);
10843
10844   // Set up reference from current to other.
10845   current->Global()->Set(v8_str("other"), other->Global());
10846
10847   // Trigger lazy loading in other context.
10848   Local<Script> script =
10849       Script::Compile(v8_str("other.eval('new Date(42)')"));
10850   Local<Value> value = script->Run();
10851   CHECK_EQ(42.0, value->NumberValue());
10852 }
10853
10854
10855 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10856   ApiTestFuzzer::Fuzz();
10857   if (args.IsConstructCall()) {
10858     if (args[0]->IsInt32()) {
10859       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10860       return;
10861     }
10862   }
10863
10864   args.GetReturnValue().Set(args[0]);
10865 }
10866
10867
10868 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10869   args.GetReturnValue().Set(args.This());
10870 }
10871
10872
10873 // Test that a call handler can be set for objects which will allow
10874 // non-function objects created through the API to be called as
10875 // functions.
10876 THREADED_TEST(CallAsFunction) {
10877   LocalContext context;
10878   v8::Isolate* isolate = context->GetIsolate();
10879   v8::HandleScope scope(isolate);
10880
10881   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10882     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10883     instance_template->SetCallAsFunctionHandler(call_as_function);
10884     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10885     context->Global()->Set(v8_str("obj"), instance);
10886     v8::TryCatch try_catch;
10887     Local<Value> value;
10888     CHECK(!try_catch.HasCaught());
10889
10890     value = CompileRun("obj(42)");
10891     CHECK(!try_catch.HasCaught());
10892     CHECK_EQ(42, value->Int32Value());
10893
10894     value = CompileRun("(function(o){return o(49)})(obj)");
10895     CHECK(!try_catch.HasCaught());
10896     CHECK_EQ(49, value->Int32Value());
10897
10898     // test special case of call as function
10899     value = CompileRun("[obj]['0'](45)");
10900     CHECK(!try_catch.HasCaught());
10901     CHECK_EQ(45, value->Int32Value());
10902
10903     value = CompileRun("obj.call = Function.prototype.call;"
10904                        "obj.call(null, 87)");
10905     CHECK(!try_catch.HasCaught());
10906     CHECK_EQ(87, value->Int32Value());
10907
10908     // Regression tests for bug #1116356: Calling call through call/apply
10909     // must work for non-function receivers.
10910     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10911     value = CompileRun(apply_99);
10912     CHECK(!try_catch.HasCaught());
10913     CHECK_EQ(99, value->Int32Value());
10914
10915     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10916     value = CompileRun(call_17);
10917     CHECK(!try_catch.HasCaught());
10918     CHECK_EQ(17, value->Int32Value());
10919
10920     // Check that the call-as-function handler can be called through
10921     // new.
10922     value = CompileRun("new obj(43)");
10923     CHECK(!try_catch.HasCaught());
10924     CHECK_EQ(-43, value->Int32Value());
10925
10926     // Check that the call-as-function handler can be called through
10927     // the API.
10928     v8::Handle<Value> args[] = { v8_num(28) };
10929     value = instance->CallAsFunction(instance, 1, args);
10930     CHECK(!try_catch.HasCaught());
10931     CHECK_EQ(28, value->Int32Value());
10932   }
10933
10934   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10935     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10936     USE(instance_template);
10937     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10938     context->Global()->Set(v8_str("obj2"), instance);
10939     v8::TryCatch try_catch;
10940     Local<Value> value;
10941     CHECK(!try_catch.HasCaught());
10942
10943     // Call an object without call-as-function handler through the JS
10944     value = CompileRun("obj2(28)");
10945     CHECK(value.IsEmpty());
10946     CHECK(try_catch.HasCaught());
10947     String::Utf8Value exception_value1(try_catch.Exception());
10948     CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
10949              *exception_value1);
10950     try_catch.Reset();
10951
10952     // Call an object without call-as-function handler through the API
10953     value = CompileRun("obj2(28)");
10954     v8::Handle<Value> args[] = { v8_num(28) };
10955     value = instance->CallAsFunction(instance, 1, args);
10956     CHECK(value.IsEmpty());
10957     CHECK(try_catch.HasCaught());
10958     String::Utf8Value exception_value2(try_catch.Exception());
10959     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10960     try_catch.Reset();
10961   }
10962
10963   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10964     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10965     instance_template->SetCallAsFunctionHandler(ThrowValue);
10966     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10967     context->Global()->Set(v8_str("obj3"), instance);
10968     v8::TryCatch try_catch;
10969     Local<Value> value;
10970     CHECK(!try_catch.HasCaught());
10971
10972     // Catch the exception which is thrown by call-as-function handler
10973     value = CompileRun("obj3(22)");
10974     CHECK(try_catch.HasCaught());
10975     String::Utf8Value exception_value1(try_catch.Exception());
10976     CHECK_EQ("22", *exception_value1);
10977     try_catch.Reset();
10978
10979     v8::Handle<Value> args[] = { v8_num(23) };
10980     value = instance->CallAsFunction(instance, 1, args);
10981     CHECK(try_catch.HasCaught());
10982     String::Utf8Value exception_value2(try_catch.Exception());
10983     CHECK_EQ("23", *exception_value2);
10984     try_catch.Reset();
10985   }
10986
10987   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10988     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10989     instance_template->SetCallAsFunctionHandler(ReturnThis);
10990     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10991
10992     Local<v8::Value> a1 =
10993         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10994     CHECK(a1->StrictEquals(instance));
10995     Local<v8::Value> a2 =
10996         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10997     CHECK(a2->StrictEquals(instance));
10998     Local<v8::Value> a3 =
10999         instance->CallAsFunction(v8_num(42), 0, NULL);
11000     CHECK(a3->StrictEquals(instance));
11001     Local<v8::Value> a4 =
11002         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11003     CHECK(a4->StrictEquals(instance));
11004     Local<v8::Value> a5 =
11005         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11006     CHECK(a5->StrictEquals(instance));
11007   }
11008
11009   { CompileRun(
11010       "function ReturnThisSloppy() {"
11011       "  return this;"
11012       "}"
11013       "function ReturnThisStrict() {"
11014       "  'use strict';"
11015       "  return this;"
11016       "}");
11017     Local<Function> ReturnThisSloppy =
11018         Local<Function>::Cast(
11019             context->Global()->Get(v8_str("ReturnThisSloppy")));
11020     Local<Function> ReturnThisStrict =
11021         Local<Function>::Cast(
11022             context->Global()->Get(v8_str("ReturnThisStrict")));
11023
11024     Local<v8::Value> a1 =
11025         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11026     CHECK(a1->StrictEquals(context->Global()));
11027     Local<v8::Value> a2 =
11028         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11029     CHECK(a2->StrictEquals(context->Global()));
11030     Local<v8::Value> a3 =
11031         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11032     CHECK(a3->IsNumberObject());
11033     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11034     Local<v8::Value> a4 =
11035         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11036     CHECK(a4->IsStringObject());
11037     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11038     Local<v8::Value> a5 =
11039         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11040     CHECK(a5->IsBooleanObject());
11041     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11042
11043     Local<v8::Value> a6 =
11044         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11045     CHECK(a6->IsUndefined());
11046     Local<v8::Value> a7 =
11047         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11048     CHECK(a7->IsNull());
11049     Local<v8::Value> a8 =
11050         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11051     CHECK(a8->StrictEquals(v8_num(42)));
11052     Local<v8::Value> a9 =
11053         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11054     CHECK(a9->StrictEquals(v8_str("hello")));
11055     Local<v8::Value> a10 =
11056         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11057     CHECK(a10->StrictEquals(v8::True(isolate)));
11058   }
11059 }
11060
11061
11062 // Check whether a non-function object is callable.
11063 THREADED_TEST(CallableObject) {
11064   LocalContext context;
11065   v8::Isolate* isolate = context->GetIsolate();
11066   v8::HandleScope scope(isolate);
11067
11068   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11069     instance_template->SetCallAsFunctionHandler(call_as_function);
11070     Local<Object> instance = instance_template->NewInstance();
11071     v8::TryCatch try_catch;
11072
11073     CHECK(instance->IsCallable());
11074     CHECK(!try_catch.HasCaught());
11075   }
11076
11077   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11078     Local<Object> instance = instance_template->NewInstance();
11079     v8::TryCatch try_catch;
11080
11081     CHECK(!instance->IsCallable());
11082     CHECK(!try_catch.HasCaught());
11083   }
11084
11085   { Local<FunctionTemplate> function_template =
11086         FunctionTemplate::New(isolate, call_as_function);
11087     Local<Function> function = function_template->GetFunction();
11088     Local<Object> instance = function;
11089     v8::TryCatch try_catch;
11090
11091     CHECK(instance->IsCallable());
11092     CHECK(!try_catch.HasCaught());
11093   }
11094
11095   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11096     Local<Function> function = function_template->GetFunction();
11097     Local<Object> instance = function;
11098     v8::TryCatch try_catch;
11099
11100     CHECK(instance->IsCallable());
11101     CHECK(!try_catch.HasCaught());
11102   }
11103 }
11104
11105
11106 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11107   v8::HandleScope scope(isolate);
11108   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11109   for (int i = 0; i < iterations; i++) {
11110     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11111   }
11112   return Recurse(isolate, depth - 1, iterations);
11113 }
11114
11115
11116 THREADED_TEST(HandleIteration) {
11117   static const int kIterations = 500;
11118   static const int kNesting = 200;
11119   LocalContext context;
11120   v8::Isolate* isolate = context->GetIsolate();
11121   v8::HandleScope scope0(isolate);
11122   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11123   {
11124     v8::HandleScope scope1(isolate);
11125     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11126     for (int i = 0; i < kIterations; i++) {
11127       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11128       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11129     }
11130
11131     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11132     {
11133       v8::HandleScope scope2(CcTest::isolate());
11134       for (int j = 0; j < kIterations; j++) {
11135         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11136         CHECK_EQ(j + 1 + kIterations,
11137                  v8::HandleScope::NumberOfHandles(isolate));
11138       }
11139     }
11140     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11141   }
11142   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11143   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11144 }
11145
11146
11147 static void InterceptorHasOwnPropertyGetter(
11148     Local<String> name,
11149     const v8::PropertyCallbackInfo<v8::Value>& info) {
11150   ApiTestFuzzer::Fuzz();
11151 }
11152
11153
11154 THREADED_TEST(InterceptorHasOwnProperty) {
11155   LocalContext context;
11156   v8::Isolate* isolate = context->GetIsolate();
11157   v8::HandleScope scope(isolate);
11158   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11159   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11160   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11161   Local<Function> function = fun_templ->GetFunction();
11162   context->Global()->Set(v8_str("constructor"), function);
11163   v8::Handle<Value> value = CompileRun(
11164       "var o = new constructor();"
11165       "o.hasOwnProperty('ostehaps');");
11166   CHECK_EQ(false, value->BooleanValue());
11167   value = CompileRun(
11168       "o.ostehaps = 42;"
11169       "o.hasOwnProperty('ostehaps');");
11170   CHECK_EQ(true, value->BooleanValue());
11171   value = CompileRun(
11172       "var p = new constructor();"
11173       "p.hasOwnProperty('ostehaps');");
11174   CHECK_EQ(false, value->BooleanValue());
11175 }
11176
11177
11178 static void InterceptorHasOwnPropertyGetterGC(
11179     Local<String> name,
11180     const v8::PropertyCallbackInfo<v8::Value>& info) {
11181   ApiTestFuzzer::Fuzz();
11182   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11183 }
11184
11185
11186 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11187   LocalContext context;
11188   v8::Isolate* isolate = context->GetIsolate();
11189   v8::HandleScope scope(isolate);
11190   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11191   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11192   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11193   Local<Function> function = fun_templ->GetFunction();
11194   context->Global()->Set(v8_str("constructor"), function);
11195   // Let's first make some stuff so we can be sure to get a good GC.
11196   CompileRun(
11197       "function makestr(size) {"
11198       "  switch (size) {"
11199       "    case 1: return 'f';"
11200       "    case 2: return 'fo';"
11201       "    case 3: return 'foo';"
11202       "  }"
11203       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11204       "}"
11205       "var x = makestr(12345);"
11206       "x = makestr(31415);"
11207       "x = makestr(23456);");
11208   v8::Handle<Value> value = CompileRun(
11209       "var o = new constructor();"
11210       "o.__proto__ = new String(x);"
11211       "o.hasOwnProperty('ostehaps');");
11212   CHECK_EQ(false, value->BooleanValue());
11213 }
11214
11215
11216 typedef void (*NamedPropertyGetter)(
11217     Local<String> property,
11218     const v8::PropertyCallbackInfo<v8::Value>& info);
11219
11220
11221 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11222                                    const char* source,
11223                                    int expected) {
11224   v8::Isolate* isolate = CcTest::isolate();
11225   v8::HandleScope scope(isolate);
11226   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11227   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11228   LocalContext context;
11229   context->Global()->Set(v8_str("o"), templ->NewInstance());
11230   v8::Handle<Value> value = CompileRun(source);
11231   CHECK_EQ(expected, value->Int32Value());
11232 }
11233
11234
11235 static void InterceptorLoadICGetter(
11236     Local<String> name,
11237     const v8::PropertyCallbackInfo<v8::Value>& info) {
11238   ApiTestFuzzer::Fuzz();
11239   v8::Isolate* isolate = CcTest::isolate();
11240   CHECK_EQ(isolate, info.GetIsolate());
11241   CHECK_EQ(v8_str("data"), info.Data());
11242   CHECK_EQ(v8_str("x"), name);
11243   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11244 }
11245
11246
11247 // This test should hit the load IC for the interceptor case.
11248 THREADED_TEST(InterceptorLoadIC) {
11249   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11250     "var result = 0;"
11251     "for (var i = 0; i < 1000; i++) {"
11252     "  result = o.x;"
11253     "}",
11254     42);
11255 }
11256
11257
11258 // Below go several tests which verify that JITing for various
11259 // configurations of interceptor and explicit fields works fine
11260 // (those cases are special cased to get better performance).
11261
11262 static void InterceptorLoadXICGetter(
11263     Local<String> name,
11264     const v8::PropertyCallbackInfo<v8::Value>& info) {
11265   ApiTestFuzzer::Fuzz();
11266   info.GetReturnValue().Set(
11267       v8_str("x")->Equals(name) ?
11268           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11269           v8::Handle<v8::Value>());
11270 }
11271
11272
11273 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11274   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11275     "var result = 0;"
11276     "o.y = 239;"
11277     "for (var i = 0; i < 1000; i++) {"
11278     "  result = o.y;"
11279     "}",
11280     239);
11281 }
11282
11283
11284 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11285   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11286     "var result = 0;"
11287     "o.__proto__ = { 'y': 239 };"
11288     "for (var i = 0; i < 1000; i++) {"
11289     "  result = o.y + o.x;"
11290     "}",
11291     239 + 42);
11292 }
11293
11294
11295 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11296   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11297     "var result = 0;"
11298     "o.__proto__.y = 239;"
11299     "for (var i = 0; i < 1000; i++) {"
11300     "  result = o.y + o.x;"
11301     "}",
11302     239 + 42);
11303 }
11304
11305
11306 THREADED_TEST(InterceptorLoadICUndefined) {
11307   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11308     "var result = 0;"
11309     "for (var i = 0; i < 1000; i++) {"
11310     "  result = (o.y == undefined) ? 239 : 42;"
11311     "}",
11312     239);
11313 }
11314
11315
11316 THREADED_TEST(InterceptorLoadICWithOverride) {
11317   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11318     "fst = new Object();  fst.__proto__ = o;"
11319     "snd = new Object();  snd.__proto__ = fst;"
11320     "var result1 = 0;"
11321     "for (var i = 0; i < 1000;  i++) {"
11322     "  result1 = snd.x;"
11323     "}"
11324     "fst.x = 239;"
11325     "var result = 0;"
11326     "for (var i = 0; i < 1000; i++) {"
11327     "  result = snd.x;"
11328     "}"
11329     "result + result1",
11330     239 + 42);
11331 }
11332
11333
11334 // Test the case when we stored field into
11335 // a stub, but interceptor produced value on its own.
11336 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11337   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11338     "proto = new Object();"
11339     "o.__proto__ = proto;"
11340     "proto.x = 239;"
11341     "for (var i = 0; i < 1000; i++) {"
11342     "  o.x;"
11343     // Now it should be ICed and keep a reference to x defined on proto
11344     "}"
11345     "var result = 0;"
11346     "for (var i = 0; i < 1000; i++) {"
11347     "  result += o.x;"
11348     "}"
11349     "result;",
11350     42 * 1000);
11351 }
11352
11353
11354 // Test the case when we stored field into
11355 // a stub, but it got invalidated later on.
11356 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11357   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11358     "proto1 = new Object();"
11359     "proto2 = new Object();"
11360     "o.__proto__ = proto1;"
11361     "proto1.__proto__ = proto2;"
11362     "proto2.y = 239;"
11363     "for (var i = 0; i < 1000; i++) {"
11364     "  o.y;"
11365     // Now it should be ICed and keep a reference to y defined on proto2
11366     "}"
11367     "proto1.y = 42;"
11368     "var result = 0;"
11369     "for (var i = 0; i < 1000; i++) {"
11370     "  result += o.y;"
11371     "}"
11372     "result;",
11373     42 * 1000);
11374 }
11375
11376
11377 static int interceptor_load_not_handled_calls = 0;
11378 static void InterceptorLoadNotHandled(
11379     Local<String> name,
11380     const v8::PropertyCallbackInfo<v8::Value>& info) {
11381   ++interceptor_load_not_handled_calls;
11382 }
11383
11384
11385 // Test how post-interceptor lookups are done in the non-cacheable
11386 // case: the interceptor should not be invoked during this lookup.
11387 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11388   interceptor_load_not_handled_calls = 0;
11389   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11390     "receiver = new Object();"
11391     "receiver.__proto__ = o;"
11392     "proto = new Object();"
11393     "/* Make proto a slow-case object. */"
11394     "for (var i = 0; i < 1000; i++) {"
11395     "  proto[\"xxxxxxxx\" + i] = [];"
11396     "}"
11397     "proto.x = 17;"
11398     "o.__proto__ = proto;"
11399     "var result = 0;"
11400     "for (var i = 0; i < 1000; i++) {"
11401     "  result += receiver.x;"
11402     "}"
11403     "result;",
11404     17 * 1000);
11405   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11406 }
11407
11408
11409 // Test the case when we stored field into
11410 // a stub, but it got invalidated later on due to override on
11411 // global object which is between interceptor and fields' holders.
11412 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11413   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11414     "o.__proto__ = this;"  // set a global to be a proto of o.
11415     "this.__proto__.y = 239;"
11416     "for (var i = 0; i < 10; i++) {"
11417     "  if (o.y != 239) throw 'oops: ' + o.y;"
11418     // Now it should be ICed and keep a reference to y defined on field_holder.
11419     "}"
11420     "this.y = 42;"  // Assign on a global.
11421     "var result = 0;"
11422     "for (var i = 0; i < 10; i++) {"
11423     "  result += o.y;"
11424     "}"
11425     "result;",
11426     42 * 10);
11427 }
11428
11429
11430 static void SetOnThis(Local<String> name,
11431                       Local<Value> value,
11432                       const v8::PropertyCallbackInfo<void>& info) {
11433   info.This()->ForceSet(name, value);
11434 }
11435
11436
11437 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11438   v8::Isolate* isolate = CcTest::isolate();
11439   v8::HandleScope scope(isolate);
11440   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11441   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11442   templ->SetAccessor(v8_str("y"), Return239Callback);
11443   LocalContext context;
11444   context->Global()->Set(v8_str("o"), templ->NewInstance());
11445
11446   // Check the case when receiver and interceptor's holder
11447   // are the same objects.
11448   v8::Handle<Value> value = CompileRun(
11449       "var result = 0;"
11450       "for (var i = 0; i < 7; i++) {"
11451       "  result = o.y;"
11452       "}");
11453   CHECK_EQ(239, value->Int32Value());
11454
11455   // Check the case when interceptor's holder is in proto chain
11456   // of receiver.
11457   value = CompileRun(
11458       "r = { __proto__: o };"
11459       "var result = 0;"
11460       "for (var i = 0; i < 7; i++) {"
11461       "  result = r.y;"
11462       "}");
11463   CHECK_EQ(239, value->Int32Value());
11464 }
11465
11466
11467 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11468   v8::Isolate* isolate = CcTest::isolate();
11469   v8::HandleScope scope(isolate);
11470   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11471   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11472   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11473   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11474
11475   LocalContext context;
11476   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11477   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11478
11479   // Check the case when receiver and interceptor's holder
11480   // are the same objects.
11481   v8::Handle<Value> value = CompileRun(
11482       "o.__proto__ = p;"
11483       "var result = 0;"
11484       "for (var i = 0; i < 7; i++) {"
11485       "  result = o.x + o.y;"
11486       "}");
11487   CHECK_EQ(239 + 42, value->Int32Value());
11488
11489   // Check the case when interceptor's holder is in proto chain
11490   // of receiver.
11491   value = CompileRun(
11492       "r = { __proto__: o };"
11493       "var result = 0;"
11494       "for (var i = 0; i < 7; i++) {"
11495       "  result = r.x + r.y;"
11496       "}");
11497   CHECK_EQ(239 + 42, value->Int32Value());
11498 }
11499
11500
11501 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11502   v8::Isolate* isolate = CcTest::isolate();
11503   v8::HandleScope scope(isolate);
11504   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11505   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11506   templ->SetAccessor(v8_str("y"), Return239Callback);
11507
11508   LocalContext context;
11509   context->Global()->Set(v8_str("o"), templ->NewInstance());
11510
11511   v8::Handle<Value> value = CompileRun(
11512     "fst = new Object();  fst.__proto__ = o;"
11513     "snd = new Object();  snd.__proto__ = fst;"
11514     "var result1 = 0;"
11515     "for (var i = 0; i < 7;  i++) {"
11516     "  result1 = snd.x;"
11517     "}"
11518     "fst.x = 239;"
11519     "var result = 0;"
11520     "for (var i = 0; i < 7; i++) {"
11521     "  result = snd.x;"
11522     "}"
11523     "result + result1");
11524   CHECK_EQ(239 + 42, value->Int32Value());
11525 }
11526
11527
11528 // Test the case when we stored callback into
11529 // a stub, but interceptor produced value on its own.
11530 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11531   v8::Isolate* isolate = CcTest::isolate();
11532   v8::HandleScope scope(isolate);
11533   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11534   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11535   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11536   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11537
11538   LocalContext context;
11539   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11540   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11541
11542   v8::Handle<Value> value = CompileRun(
11543     "o.__proto__ = p;"
11544     "for (var i = 0; i < 7; i++) {"
11545     "  o.x;"
11546     // Now it should be ICed and keep a reference to x defined on p
11547     "}"
11548     "var result = 0;"
11549     "for (var i = 0; i < 7; i++) {"
11550     "  result += o.x;"
11551     "}"
11552     "result");
11553   CHECK_EQ(42 * 7, value->Int32Value());
11554 }
11555
11556
11557 // Test the case when we stored callback into
11558 // a stub, but it got invalidated later on.
11559 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11560   v8::Isolate* isolate = CcTest::isolate();
11561   v8::HandleScope scope(isolate);
11562   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11563   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11564   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11565   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11566
11567   LocalContext context;
11568   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11569   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11570
11571   v8::Handle<Value> value = CompileRun(
11572     "inbetween = new Object();"
11573     "o.__proto__ = inbetween;"
11574     "inbetween.__proto__ = p;"
11575     "for (var i = 0; i < 10; i++) {"
11576     "  o.y;"
11577     // Now it should be ICed and keep a reference to y defined on p
11578     "}"
11579     "inbetween.y = 42;"
11580     "var result = 0;"
11581     "for (var i = 0; i < 10; i++) {"
11582     "  result += o.y;"
11583     "}"
11584     "result");
11585   CHECK_EQ(42 * 10, value->Int32Value());
11586 }
11587
11588
11589 // Test the case when we stored callback into
11590 // a stub, but it got invalidated later on due to override on
11591 // global object which is between interceptor and callbacks' holders.
11592 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11593   v8::Isolate* isolate = CcTest::isolate();
11594   v8::HandleScope scope(isolate);
11595   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11596   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11597   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11598   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11599
11600   LocalContext context;
11601   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11602   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11603
11604   v8::Handle<Value> value = CompileRun(
11605     "o.__proto__ = this;"
11606     "this.__proto__ = p;"
11607     "for (var i = 0; i < 10; i++) {"
11608     "  if (o.y != 239) throw 'oops: ' + o.y;"
11609     // Now it should be ICed and keep a reference to y defined on p
11610     "}"
11611     "this.y = 42;"
11612     "var result = 0;"
11613     "for (var i = 0; i < 10; i++) {"
11614     "  result += o.y;"
11615     "}"
11616     "result");
11617   CHECK_EQ(42 * 10, value->Int32Value());
11618 }
11619
11620
11621 static void InterceptorLoadICGetter0(
11622     Local<String> name,
11623     const v8::PropertyCallbackInfo<v8::Value>& info) {
11624   ApiTestFuzzer::Fuzz();
11625   CHECK(v8_str("x")->Equals(name));
11626   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11627 }
11628
11629
11630 THREADED_TEST(InterceptorReturningZero) {
11631   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11632      "o.x == undefined ? 1 : 0",
11633      0);
11634 }
11635
11636
11637 static void InterceptorStoreICSetter(
11638     Local<String> key,
11639     Local<Value> value,
11640     const v8::PropertyCallbackInfo<v8::Value>& info) {
11641   CHECK(v8_str("x")->Equals(key));
11642   CHECK_EQ(42, value->Int32Value());
11643   info.GetReturnValue().Set(value);
11644 }
11645
11646
11647 // This test should hit the store IC for the interceptor case.
11648 THREADED_TEST(InterceptorStoreIC) {
11649   v8::Isolate* isolate = CcTest::isolate();
11650   v8::HandleScope scope(isolate);
11651   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11652   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11653                                  InterceptorStoreICSetter,
11654                                  0, 0, 0, v8_str("data"));
11655   LocalContext context;
11656   context->Global()->Set(v8_str("o"), templ->NewInstance());
11657   CompileRun(
11658       "for (var i = 0; i < 1000; i++) {"
11659       "  o.x = 42;"
11660       "}");
11661 }
11662
11663
11664 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11665   v8::Isolate* isolate = CcTest::isolate();
11666   v8::HandleScope scope(isolate);
11667   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11668   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11669   LocalContext context;
11670   context->Global()->Set(v8_str("o"), templ->NewInstance());
11671   v8::Handle<Value> value = CompileRun(
11672     "for (var i = 0; i < 1000; i++) {"
11673     "  o.y = 239;"
11674     "}"
11675     "42 + o.y");
11676   CHECK_EQ(239 + 42, value->Int32Value());
11677 }
11678
11679
11680
11681
11682 v8::Handle<Value> call_ic_function;
11683 v8::Handle<Value> call_ic_function2;
11684 v8::Handle<Value> call_ic_function3;
11685
11686 static void InterceptorCallICGetter(
11687     Local<String> name,
11688     const v8::PropertyCallbackInfo<v8::Value>& info) {
11689   ApiTestFuzzer::Fuzz();
11690   CHECK(v8_str("x")->Equals(name));
11691   info.GetReturnValue().Set(call_ic_function);
11692 }
11693
11694
11695 // This test should hit the call IC for the interceptor case.
11696 THREADED_TEST(InterceptorCallIC) {
11697   v8::Isolate* isolate = CcTest::isolate();
11698   v8::HandleScope scope(isolate);
11699   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11700   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11701   LocalContext context;
11702   context->Global()->Set(v8_str("o"), templ->NewInstance());
11703   call_ic_function =
11704       v8_compile("function f(x) { return x + 1; }; f")->Run();
11705   v8::Handle<Value> value = CompileRun(
11706     "var result = 0;"
11707     "for (var i = 0; i < 1000; i++) {"
11708     "  result = o.x(41);"
11709     "}");
11710   CHECK_EQ(42, value->Int32Value());
11711 }
11712
11713
11714 // This test checks that if interceptor doesn't provide
11715 // a value, we can fetch regular value.
11716 THREADED_TEST(InterceptorCallICSeesOthers) {
11717   v8::Isolate* isolate = CcTest::isolate();
11718   v8::HandleScope scope(isolate);
11719   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11720   templ->SetNamedPropertyHandler(NoBlockGetterX);
11721   LocalContext context;
11722   context->Global()->Set(v8_str("o"), templ->NewInstance());
11723   v8::Handle<Value> value = CompileRun(
11724     "o.x = function f(x) { return x + 1; };"
11725     "var result = 0;"
11726     "for (var i = 0; i < 7; i++) {"
11727     "  result = o.x(41);"
11728     "}");
11729   CHECK_EQ(42, value->Int32Value());
11730 }
11731
11732
11733 static v8::Handle<Value> call_ic_function4;
11734 static void InterceptorCallICGetter4(
11735     Local<String> name,
11736     const v8::PropertyCallbackInfo<v8::Value>& info) {
11737   ApiTestFuzzer::Fuzz();
11738   CHECK(v8_str("x")->Equals(name));
11739   info.GetReturnValue().Set(call_ic_function4);
11740 }
11741
11742
11743 // This test checks that if interceptor provides a function,
11744 // even if we cached shadowed variant, interceptor's function
11745 // is invoked
11746 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11747   v8::Isolate* isolate = CcTest::isolate();
11748   v8::HandleScope scope(isolate);
11749   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11750   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11751   LocalContext context;
11752   context->Global()->Set(v8_str("o"), templ->NewInstance());
11753   call_ic_function4 =
11754       v8_compile("function f(x) { return x - 1; }; f")->Run();
11755   v8::Handle<Value> value = CompileRun(
11756     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11757     "var result = 0;"
11758     "for (var i = 0; i < 1000; i++) {"
11759     "  result = o.x(42);"
11760     "}");
11761   CHECK_EQ(41, value->Int32Value());
11762 }
11763
11764
11765 // Test the case when we stored cacheable lookup into
11766 // a stub, but it got invalidated later on
11767 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11768   v8::Isolate* isolate = CcTest::isolate();
11769   v8::HandleScope scope(isolate);
11770   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11771   templ->SetNamedPropertyHandler(NoBlockGetterX);
11772   LocalContext context;
11773   context->Global()->Set(v8_str("o"), templ->NewInstance());
11774   v8::Handle<Value> value = CompileRun(
11775     "proto1 = new Object();"
11776     "proto2 = new Object();"
11777     "o.__proto__ = proto1;"
11778     "proto1.__proto__ = proto2;"
11779     "proto2.y = function(x) { return x + 1; };"
11780     // Invoke it many times to compile a stub
11781     "for (var i = 0; i < 7; i++) {"
11782     "  o.y(42);"
11783     "}"
11784     "proto1.y = function(x) { return x - 1; };"
11785     "var result = 0;"
11786     "for (var i = 0; i < 7; i++) {"
11787     "  result += o.y(42);"
11788     "}");
11789   CHECK_EQ(41 * 7, value->Int32Value());
11790 }
11791
11792
11793 // This test checks that if interceptor doesn't provide a function,
11794 // cached constant function is used
11795 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11796   v8::Isolate* isolate = CcTest::isolate();
11797   v8::HandleScope scope(isolate);
11798   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11799   templ->SetNamedPropertyHandler(NoBlockGetterX);
11800   LocalContext context;
11801   context->Global()->Set(v8_str("o"), templ->NewInstance());
11802   v8::Handle<Value> value = CompileRun(
11803     "function inc(x) { return x + 1; };"
11804     "inc(1);"
11805     "o.x = inc;"
11806     "var result = 0;"
11807     "for (var i = 0; i < 1000; i++) {"
11808     "  result = o.x(42);"
11809     "}");
11810   CHECK_EQ(43, value->Int32Value());
11811 }
11812
11813
11814 static v8::Handle<Value> call_ic_function5;
11815 static void InterceptorCallICGetter5(
11816     Local<String> name,
11817     const v8::PropertyCallbackInfo<v8::Value>& info) {
11818   ApiTestFuzzer::Fuzz();
11819   if (v8_str("x")->Equals(name))
11820     info.GetReturnValue().Set(call_ic_function5);
11821 }
11822
11823
11824 // This test checks that if interceptor provides a function,
11825 // even if we cached constant function, interceptor's function
11826 // is invoked
11827 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11828   v8::Isolate* isolate = CcTest::isolate();
11829   v8::HandleScope scope(isolate);
11830   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11831   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11832   LocalContext context;
11833   context->Global()->Set(v8_str("o"), templ->NewInstance());
11834   call_ic_function5 =
11835       v8_compile("function f(x) { return x - 1; }; f")->Run();
11836   v8::Handle<Value> value = CompileRun(
11837     "function inc(x) { return x + 1; };"
11838     "inc(1);"
11839     "o.x = inc;"
11840     "var result = 0;"
11841     "for (var i = 0; i < 1000; i++) {"
11842     "  result = o.x(42);"
11843     "}");
11844   CHECK_EQ(41, value->Int32Value());
11845 }
11846
11847
11848 static v8::Handle<Value> call_ic_function6;
11849 static void InterceptorCallICGetter6(
11850     Local<String> name,
11851     const v8::PropertyCallbackInfo<v8::Value>& info) {
11852   ApiTestFuzzer::Fuzz();
11853   if (v8_str("x")->Equals(name))
11854     info.GetReturnValue().Set(call_ic_function6);
11855 }
11856
11857
11858 // Same test as above, except the code is wrapped in a function
11859 // to test the optimized compiler.
11860 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11861   i::FLAG_allow_natives_syntax = true;
11862   v8::Isolate* isolate = CcTest::isolate();
11863   v8::HandleScope scope(isolate);
11864   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11865   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11866   LocalContext context;
11867   context->Global()->Set(v8_str("o"), templ->NewInstance());
11868   call_ic_function6 =
11869       v8_compile("function f(x) { return x - 1; }; f")->Run();
11870   v8::Handle<Value> value = CompileRun(
11871     "function inc(x) { return x + 1; };"
11872     "inc(1);"
11873     "o.x = inc;"
11874     "function test() {"
11875     "  var result = 0;"
11876     "  for (var i = 0; i < 1000; i++) {"
11877     "    result = o.x(42);"
11878     "  }"
11879     "  return result;"
11880     "};"
11881     "test();"
11882     "test();"
11883     "test();"
11884     "%OptimizeFunctionOnNextCall(test);"
11885     "test()");
11886   CHECK_EQ(41, value->Int32Value());
11887 }
11888
11889
11890 // Test the case when we stored constant function into
11891 // a stub, but it got invalidated later on
11892 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11893   v8::Isolate* isolate = CcTest::isolate();
11894   v8::HandleScope scope(isolate);
11895   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11896   templ->SetNamedPropertyHandler(NoBlockGetterX);
11897   LocalContext context;
11898   context->Global()->Set(v8_str("o"), templ->NewInstance());
11899   v8::Handle<Value> value = CompileRun(
11900     "function inc(x) { return x + 1; };"
11901     "inc(1);"
11902     "proto1 = new Object();"
11903     "proto2 = new Object();"
11904     "o.__proto__ = proto1;"
11905     "proto1.__proto__ = proto2;"
11906     "proto2.y = inc;"
11907     // Invoke it many times to compile a stub
11908     "for (var i = 0; i < 7; i++) {"
11909     "  o.y(42);"
11910     "}"
11911     "proto1.y = function(x) { return x - 1; };"
11912     "var result = 0;"
11913     "for (var i = 0; i < 7; i++) {"
11914     "  result += o.y(42);"
11915     "}");
11916   CHECK_EQ(41 * 7, value->Int32Value());
11917 }
11918
11919
11920 // Test the case when we stored constant function into
11921 // a stub, but it got invalidated later on due to override on
11922 // global object which is between interceptor and constant function' holders.
11923 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11924   v8::Isolate* isolate = CcTest::isolate();
11925   v8::HandleScope scope(isolate);
11926   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11927   templ->SetNamedPropertyHandler(NoBlockGetterX);
11928   LocalContext context;
11929   context->Global()->Set(v8_str("o"), templ->NewInstance());
11930   v8::Handle<Value> value = CompileRun(
11931     "function inc(x) { return x + 1; };"
11932     "inc(1);"
11933     "o.__proto__ = this;"
11934     "this.__proto__.y = inc;"
11935     // Invoke it many times to compile a stub
11936     "for (var i = 0; i < 7; i++) {"
11937     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11938     "}"
11939     "this.y = function(x) { return x - 1; };"
11940     "var result = 0;"
11941     "for (var i = 0; i < 7; i++) {"
11942     "  result += o.y(42);"
11943     "}");
11944   CHECK_EQ(41 * 7, value->Int32Value());
11945 }
11946
11947
11948 // Test the case when actual function to call sits on global object.
11949 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11950   v8::Isolate* isolate = CcTest::isolate();
11951   v8::HandleScope scope(isolate);
11952   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11953   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11954
11955   LocalContext context;
11956   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11957
11958   v8::Handle<Value> value = CompileRun(
11959     "try {"
11960     "  o.__proto__ = this;"
11961     "  for (var i = 0; i < 10; i++) {"
11962     "    var v = o.parseFloat('239');"
11963     "    if (v != 239) throw v;"
11964       // Now it should be ICed and keep a reference to parseFloat.
11965     "  }"
11966     "  var result = 0;"
11967     "  for (var i = 0; i < 10; i++) {"
11968     "    result += o.parseFloat('239');"
11969     "  }"
11970     "  result"
11971     "} catch(e) {"
11972     "  e"
11973     "};");
11974   CHECK_EQ(239 * 10, value->Int32Value());
11975 }
11976
11977 static void InterceptorCallICFastApi(
11978     Local<String> name,
11979     const v8::PropertyCallbackInfo<v8::Value>& info) {
11980   ApiTestFuzzer::Fuzz();
11981   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11982   int* call_count =
11983       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11984   ++(*call_count);
11985   if ((*call_count) % 20 == 0) {
11986     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11987   }
11988 }
11989
11990 static void FastApiCallback_TrivialSignature(
11991     const v8::FunctionCallbackInfo<v8::Value>& args) {
11992   ApiTestFuzzer::Fuzz();
11993   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11994   v8::Isolate* isolate = CcTest::isolate();
11995   CHECK_EQ(isolate, args.GetIsolate());
11996   CHECK_EQ(args.This(), args.Holder());
11997   CHECK(args.Data()->Equals(v8_str("method_data")));
11998   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11999 }
12000
12001 static void FastApiCallback_SimpleSignature(
12002     const v8::FunctionCallbackInfo<v8::Value>& args) {
12003   ApiTestFuzzer::Fuzz();
12004   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12005   v8::Isolate* isolate = CcTest::isolate();
12006   CHECK_EQ(isolate, args.GetIsolate());
12007   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12008   CHECK(args.Data()->Equals(v8_str("method_data")));
12009   // Note, we're using HasRealNamedProperty instead of Has to avoid
12010   // invoking the interceptor again.
12011   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12012   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12013 }
12014
12015
12016 // Helper to maximize the odds of object moving.
12017 static void GenerateSomeGarbage() {
12018   CompileRun(
12019       "var garbage;"
12020       "for (var i = 0; i < 1000; i++) {"
12021       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12022       "}"
12023       "garbage = undefined;");
12024 }
12025
12026
12027 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12028   static int count = 0;
12029   if (count++ % 3 == 0) {
12030     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12031         // This should move the stub
12032     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12033   }
12034 }
12035
12036
12037 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12038   LocalContext context;
12039   v8::Isolate* isolate = context->GetIsolate();
12040   v8::HandleScope scope(isolate);
12041   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12042       v8::ObjectTemplate::New(isolate);
12043   nativeobject_templ->Set(isolate, "callback",
12044                           v8::FunctionTemplate::New(isolate,
12045                                                     DirectApiCallback));
12046   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12047   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12048   // call the api function multiple times to ensure direct call stub creation.
12049   CompileRun(
12050         "function f() {"
12051         "  for (var i = 1; i <= 30; i++) {"
12052         "    nativeobject.callback();"
12053         "  }"
12054         "}"
12055         "f();");
12056 }
12057
12058
12059 void ThrowingDirectApiCallback(
12060     const v8::FunctionCallbackInfo<v8::Value>& args) {
12061   args.GetIsolate()->ThrowException(v8_str("g"));
12062 }
12063
12064
12065 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12066   LocalContext context;
12067   v8::Isolate* isolate = context->GetIsolate();
12068   v8::HandleScope scope(isolate);
12069   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12070       v8::ObjectTemplate::New(isolate);
12071   nativeobject_templ->Set(isolate, "callback",
12072                           v8::FunctionTemplate::New(isolate,
12073                                                     ThrowingDirectApiCallback));
12074   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12075   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12076   // call the api function multiple times to ensure direct call stub creation.
12077   v8::Handle<Value> result = CompileRun(
12078       "var result = '';"
12079       "function f() {"
12080       "  for (var i = 1; i <= 5; i++) {"
12081       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12082       "  }"
12083       "}"
12084       "f(); result;");
12085   CHECK_EQ(v8_str("ggggg"), result);
12086 }
12087
12088
12089 static Handle<Value> DoDirectGetter() {
12090   if (++p_getter_count % 3 == 0) {
12091     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12092     GenerateSomeGarbage();
12093   }
12094   return v8_str("Direct Getter Result");
12095 }
12096
12097 static void DirectGetterCallback(
12098     Local<String> name,
12099     const v8::PropertyCallbackInfo<v8::Value>& info) {
12100   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12101   info.GetReturnValue().Set(DoDirectGetter());
12102 }
12103
12104
12105 template<typename Accessor>
12106 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12107   LocalContext context;
12108   v8::Isolate* isolate = context->GetIsolate();
12109   v8::HandleScope scope(isolate);
12110   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12111   obj->SetAccessor(v8_str("p1"), accessor);
12112   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12113   p_getter_count = 0;
12114   v8::Handle<v8::Value> result = CompileRun(
12115       "function f() {"
12116       "  for (var i = 0; i < 30; i++) o1.p1;"
12117       "  return o1.p1"
12118       "}"
12119       "f();");
12120   CHECK_EQ(v8_str("Direct Getter Result"), result);
12121   CHECK_EQ(31, p_getter_count);
12122 }
12123
12124
12125 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12126   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12127 }
12128
12129
12130 void ThrowingDirectGetterCallback(
12131     Local<String> name,
12132     const v8::PropertyCallbackInfo<v8::Value>& info) {
12133   info.GetIsolate()->ThrowException(v8_str("g"));
12134 }
12135
12136
12137 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12138   LocalContext context;
12139   v8::Isolate* isolate = context->GetIsolate();
12140   v8::HandleScope scope(isolate);
12141   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12142   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12143   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12144   v8::Handle<Value> result = CompileRun(
12145       "var result = '';"
12146       "for (var i = 0; i < 5; i++) {"
12147       "    try { o1.p1; } catch (e) { result += e; }"
12148       "}"
12149       "result;");
12150   CHECK_EQ(v8_str("ggggg"), result);
12151 }
12152
12153
12154 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12155   int interceptor_call_count = 0;
12156   v8::Isolate* isolate = CcTest::isolate();
12157   v8::HandleScope scope(isolate);
12158   v8::Handle<v8::FunctionTemplate> fun_templ =
12159       v8::FunctionTemplate::New(isolate);
12160   v8::Handle<v8::FunctionTemplate> method_templ =
12161       v8::FunctionTemplate::New(isolate,
12162                                 FastApiCallback_TrivialSignature,
12163                                 v8_str("method_data"),
12164                                 v8::Handle<v8::Signature>());
12165   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12166   proto_templ->Set(v8_str("method"), method_templ);
12167   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12168   templ->SetNamedPropertyHandler(
12169       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12170       v8::External::New(isolate, &interceptor_call_count));
12171   LocalContext context;
12172   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12173   GenerateSomeGarbage();
12174   context->Global()->Set(v8_str("o"), fun->NewInstance());
12175   CompileRun(
12176       "var result = 0;"
12177       "for (var i = 0; i < 100; i++) {"
12178       "  result = o.method(41);"
12179       "}");
12180   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12181   CHECK_EQ(100, interceptor_call_count);
12182 }
12183
12184
12185 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12186   int interceptor_call_count = 0;
12187   v8::Isolate* isolate = CcTest::isolate();
12188   v8::HandleScope scope(isolate);
12189   v8::Handle<v8::FunctionTemplate> fun_templ =
12190       v8::FunctionTemplate::New(isolate);
12191   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12192       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12193       v8::Signature::New(isolate, fun_templ));
12194   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12195   proto_templ->Set(v8_str("method"), method_templ);
12196   fun_templ->SetHiddenPrototype(true);
12197   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12198   templ->SetNamedPropertyHandler(
12199       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12200       v8::External::New(isolate, &interceptor_call_count));
12201   LocalContext context;
12202   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12203   GenerateSomeGarbage();
12204   context->Global()->Set(v8_str("o"), fun->NewInstance());
12205   CompileRun(
12206       "o.foo = 17;"
12207       "var receiver = {};"
12208       "receiver.__proto__ = o;"
12209       "var result = 0;"
12210       "for (var i = 0; i < 100; i++) {"
12211       "  result = receiver.method(41);"
12212       "}");
12213   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12214   CHECK_EQ(100, interceptor_call_count);
12215 }
12216
12217
12218 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12219   int interceptor_call_count = 0;
12220   v8::Isolate* isolate = CcTest::isolate();
12221   v8::HandleScope scope(isolate);
12222   v8::Handle<v8::FunctionTemplate> fun_templ =
12223       v8::FunctionTemplate::New(isolate);
12224   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12225       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12226       v8::Signature::New(isolate, fun_templ));
12227   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12228   proto_templ->Set(v8_str("method"), method_templ);
12229   fun_templ->SetHiddenPrototype(true);
12230   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12231   templ->SetNamedPropertyHandler(
12232       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12233       v8::External::New(isolate, &interceptor_call_count));
12234   LocalContext context;
12235   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12236   GenerateSomeGarbage();
12237   context->Global()->Set(v8_str("o"), fun->NewInstance());
12238   CompileRun(
12239       "o.foo = 17;"
12240       "var receiver = {};"
12241       "receiver.__proto__ = o;"
12242       "var result = 0;"
12243       "var saved_result = 0;"
12244       "for (var i = 0; i < 100; i++) {"
12245       "  result = receiver.method(41);"
12246       "  if (i == 50) {"
12247       "    saved_result = result;"
12248       "    receiver = {method: function(x) { return x - 1 }};"
12249       "  }"
12250       "}");
12251   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12252   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12253   CHECK_GE(interceptor_call_count, 50);
12254 }
12255
12256
12257 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12258   int interceptor_call_count = 0;
12259   v8::Isolate* isolate = CcTest::isolate();
12260   v8::HandleScope scope(isolate);
12261   v8::Handle<v8::FunctionTemplate> fun_templ =
12262       v8::FunctionTemplate::New(isolate);
12263   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12264       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12265       v8::Signature::New(isolate, fun_templ));
12266   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12267   proto_templ->Set(v8_str("method"), method_templ);
12268   fun_templ->SetHiddenPrototype(true);
12269   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12270   templ->SetNamedPropertyHandler(
12271       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12272       v8::External::New(isolate, &interceptor_call_count));
12273   LocalContext context;
12274   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12275   GenerateSomeGarbage();
12276   context->Global()->Set(v8_str("o"), fun->NewInstance());
12277   CompileRun(
12278       "o.foo = 17;"
12279       "var receiver = {};"
12280       "receiver.__proto__ = o;"
12281       "var result = 0;"
12282       "var saved_result = 0;"
12283       "for (var i = 0; i < 100; i++) {"
12284       "  result = receiver.method(41);"
12285       "  if (i == 50) {"
12286       "    saved_result = result;"
12287       "    o.method = function(x) { return x - 1 };"
12288       "  }"
12289       "}");
12290   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12291   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12292   CHECK_GE(interceptor_call_count, 50);
12293 }
12294
12295
12296 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12297   int interceptor_call_count = 0;
12298   v8::Isolate* isolate = CcTest::isolate();
12299   v8::HandleScope scope(isolate);
12300   v8::Handle<v8::FunctionTemplate> fun_templ =
12301       v8::FunctionTemplate::New(isolate);
12302   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12303       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12304       v8::Signature::New(isolate, fun_templ));
12305   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12306   proto_templ->Set(v8_str("method"), method_templ);
12307   fun_templ->SetHiddenPrototype(true);
12308   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12309   templ->SetNamedPropertyHandler(
12310       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12311       v8::External::New(isolate, &interceptor_call_count));
12312   LocalContext context;
12313   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12314   GenerateSomeGarbage();
12315   context->Global()->Set(v8_str("o"), fun->NewInstance());
12316   v8::TryCatch try_catch;
12317   CompileRun(
12318       "o.foo = 17;"
12319       "var receiver = {};"
12320       "receiver.__proto__ = o;"
12321       "var result = 0;"
12322       "var saved_result = 0;"
12323       "for (var i = 0; i < 100; i++) {"
12324       "  result = receiver.method(41);"
12325       "  if (i == 50) {"
12326       "    saved_result = result;"
12327       "    receiver = 333;"
12328       "  }"
12329       "}");
12330   CHECK(try_catch.HasCaught());
12331   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
12332            try_catch.Exception()->ToString());
12333   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12334   CHECK_GE(interceptor_call_count, 50);
12335 }
12336
12337
12338 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12339   int interceptor_call_count = 0;
12340   v8::Isolate* isolate = CcTest::isolate();
12341   v8::HandleScope scope(isolate);
12342   v8::Handle<v8::FunctionTemplate> fun_templ =
12343       v8::FunctionTemplate::New(isolate);
12344   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12345       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12346       v8::Signature::New(isolate, fun_templ));
12347   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12348   proto_templ->Set(v8_str("method"), method_templ);
12349   fun_templ->SetHiddenPrototype(true);
12350   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12351   templ->SetNamedPropertyHandler(
12352       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12353       v8::External::New(isolate, &interceptor_call_count));
12354   LocalContext context;
12355   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12356   GenerateSomeGarbage();
12357   context->Global()->Set(v8_str("o"), fun->NewInstance());
12358   v8::TryCatch try_catch;
12359   CompileRun(
12360       "o.foo = 17;"
12361       "var receiver = {};"
12362       "receiver.__proto__ = o;"
12363       "var result = 0;"
12364       "var saved_result = 0;"
12365       "for (var i = 0; i < 100; i++) {"
12366       "  result = receiver.method(41);"
12367       "  if (i == 50) {"
12368       "    saved_result = result;"
12369       "    receiver = {method: receiver.method};"
12370       "  }"
12371       "}");
12372   CHECK(try_catch.HasCaught());
12373   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12374            try_catch.Exception()->ToString());
12375   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12376   CHECK_GE(interceptor_call_count, 50);
12377 }
12378
12379
12380 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12381   v8::Isolate* isolate = CcTest::isolate();
12382   v8::HandleScope scope(isolate);
12383   v8::Handle<v8::FunctionTemplate> fun_templ =
12384       v8::FunctionTemplate::New(isolate);
12385   v8::Handle<v8::FunctionTemplate> method_templ =
12386       v8::FunctionTemplate::New(isolate,
12387                                 FastApiCallback_TrivialSignature,
12388                                 v8_str("method_data"),
12389                                 v8::Handle<v8::Signature>());
12390   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12391   proto_templ->Set(v8_str("method"), method_templ);
12392   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12393   USE(templ);
12394   LocalContext context;
12395   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12396   GenerateSomeGarbage();
12397   context->Global()->Set(v8_str("o"), fun->NewInstance());
12398   CompileRun(
12399       "var result = 0;"
12400       "for (var i = 0; i < 100; i++) {"
12401       "  result = o.method(41);"
12402       "}");
12403
12404   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12405 }
12406
12407
12408 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
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 = v8::FunctionTemplate::New(
12414       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12415       v8::Signature::New(isolate, fun_templ));
12416   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12417   proto_templ->Set(v8_str("method"), method_templ);
12418   fun_templ->SetHiddenPrototype(true);
12419   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12420   CHECK(!templ.IsEmpty());
12421   LocalContext context;
12422   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12423   GenerateSomeGarbage();
12424   context->Global()->Set(v8_str("o"), fun->NewInstance());
12425   CompileRun(
12426       "o.foo = 17;"
12427       "var receiver = {};"
12428       "receiver.__proto__ = o;"
12429       "var result = 0;"
12430       "for (var i = 0; i < 100; i++) {"
12431       "  result = receiver.method(41);"
12432       "}");
12433
12434   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12435 }
12436
12437
12438 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12439   v8::Isolate* isolate = CcTest::isolate();
12440   v8::HandleScope scope(isolate);
12441   v8::Handle<v8::FunctionTemplate> fun_templ =
12442       v8::FunctionTemplate::New(isolate);
12443   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12444       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12445       v8::Signature::New(isolate, fun_templ));
12446   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12447   proto_templ->Set(v8_str("method"), method_templ);
12448   fun_templ->SetHiddenPrototype(true);
12449   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12450   CHECK(!templ.IsEmpty());
12451   LocalContext context;
12452   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12453   GenerateSomeGarbage();
12454   context->Global()->Set(v8_str("o"), fun->NewInstance());
12455   CompileRun(
12456       "o.foo = 17;"
12457       "var receiver = {};"
12458       "receiver.__proto__ = o;"
12459       "var result = 0;"
12460       "var saved_result = 0;"
12461       "for (var i = 0; i < 100; i++) {"
12462       "  result = receiver.method(41);"
12463       "  if (i == 50) {"
12464       "    saved_result = result;"
12465       "    receiver = {method: function(x) { return x - 1 }};"
12466       "  }"
12467       "}");
12468   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12469   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12470 }
12471
12472
12473 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12474   v8::Isolate* isolate = CcTest::isolate();
12475   v8::HandleScope scope(isolate);
12476   v8::Handle<v8::FunctionTemplate> fun_templ =
12477       v8::FunctionTemplate::New(isolate);
12478   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12479       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12480       v8::Signature::New(isolate, fun_templ));
12481   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12482   proto_templ->Set(v8_str("method"), method_templ);
12483   fun_templ->SetHiddenPrototype(true);
12484   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12485   CHECK(!templ.IsEmpty());
12486   LocalContext context;
12487   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12488   GenerateSomeGarbage();
12489   context->Global()->Set(v8_str("o"), fun->NewInstance());
12490   v8::TryCatch try_catch;
12491   CompileRun(
12492       "o.foo = 17;"
12493       "var receiver = {};"
12494       "receiver.__proto__ = o;"
12495       "var result = 0;"
12496       "var saved_result = 0;"
12497       "for (var i = 0; i < 100; i++) {"
12498       "  result = receiver.method(41);"
12499       "  if (i == 50) {"
12500       "    saved_result = result;"
12501       "    receiver = 333;"
12502       "  }"
12503       "}");
12504   CHECK(try_catch.HasCaught());
12505   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
12506            try_catch.Exception()->ToString());
12507   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12508 }
12509
12510
12511 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12512   v8::Isolate* isolate = CcTest::isolate();
12513   v8::HandleScope scope(isolate);
12514   v8::Handle<v8::FunctionTemplate> fun_templ =
12515       v8::FunctionTemplate::New(isolate);
12516   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12517       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12518       v8::Signature::New(isolate, fun_templ));
12519   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12520   proto_templ->Set(v8_str("method"), method_templ);
12521   fun_templ->SetHiddenPrototype(true);
12522   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12523   CHECK(!templ.IsEmpty());
12524   LocalContext context;
12525   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12526   GenerateSomeGarbage();
12527   context->Global()->Set(v8_str("o"), fun->NewInstance());
12528   v8::TryCatch try_catch;
12529   CompileRun(
12530       "o.foo = 17;"
12531       "var receiver = {};"
12532       "receiver.__proto__ = o;"
12533       "var result = 0;"
12534       "var saved_result = 0;"
12535       "for (var i = 0; i < 100; i++) {"
12536       "  result = receiver.method(41);"
12537       "  if (i == 50) {"
12538       "    saved_result = result;"
12539       "    receiver = Object.create(receiver);"
12540       "  }"
12541       "}");
12542   CHECK(try_catch.HasCaught());
12543   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12544            try_catch.Exception()->ToString());
12545   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12546 }
12547
12548
12549 v8::Handle<Value> keyed_call_ic_function;
12550
12551 static void InterceptorKeyedCallICGetter(
12552     Local<String> name,
12553     const v8::PropertyCallbackInfo<v8::Value>& info) {
12554   ApiTestFuzzer::Fuzz();
12555   if (v8_str("x")->Equals(name)) {
12556     info.GetReturnValue().Set(keyed_call_ic_function);
12557   }
12558 }
12559
12560
12561 // Test the case when we stored cacheable lookup into
12562 // a stub, but the function name changed (to another cacheable function).
12563 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12564   v8::Isolate* isolate = CcTest::isolate();
12565   v8::HandleScope scope(isolate);
12566   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12567   templ->SetNamedPropertyHandler(NoBlockGetterX);
12568   LocalContext context;
12569   context->Global()->Set(v8_str("o"), templ->NewInstance());
12570   CompileRun(
12571     "proto = new Object();"
12572     "proto.y = function(x) { return x + 1; };"
12573     "proto.z = function(x) { return x - 1; };"
12574     "o.__proto__ = proto;"
12575     "var result = 0;"
12576     "var method = 'y';"
12577     "for (var i = 0; i < 10; i++) {"
12578     "  if (i == 5) { method = 'z'; };"
12579     "  result += o[method](41);"
12580     "}");
12581   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12582 }
12583
12584
12585 // Test the case when we stored cacheable lookup into
12586 // a stub, but the function name changed (and the new function is present
12587 // both before and after the interceptor in the prototype chain).
12588 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12589   v8::Isolate* isolate = CcTest::isolate();
12590   v8::HandleScope scope(isolate);
12591   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12592   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12593   LocalContext context;
12594   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12595   keyed_call_ic_function =
12596       v8_compile("function f(x) { return x - 1; }; f")->Run();
12597   CompileRun(
12598     "o = new Object();"
12599     "proto2 = new Object();"
12600     "o.y = function(x) { return x + 1; };"
12601     "proto2.y = function(x) { return x + 2; };"
12602     "o.__proto__ = proto1;"
12603     "proto1.__proto__ = proto2;"
12604     "var result = 0;"
12605     "var method = 'x';"
12606     "for (var i = 0; i < 10; i++) {"
12607     "  if (i == 5) { method = 'y'; };"
12608     "  result += o[method](41);"
12609     "}");
12610   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12611 }
12612
12613
12614 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12615 // on the global object.
12616 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12617   v8::Isolate* isolate = CcTest::isolate();
12618   v8::HandleScope scope(isolate);
12619   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12620   templ->SetNamedPropertyHandler(NoBlockGetterX);
12621   LocalContext context;
12622   context->Global()->Set(v8_str("o"), templ->NewInstance());
12623   CompileRun(
12624     "function inc(x) { return x + 1; };"
12625     "inc(1);"
12626     "function dec(x) { return x - 1; };"
12627     "dec(1);"
12628     "o.__proto__ = this;"
12629     "this.__proto__.x = inc;"
12630     "this.__proto__.y = dec;"
12631     "var result = 0;"
12632     "var method = 'x';"
12633     "for (var i = 0; i < 10; i++) {"
12634     "  if (i == 5) { method = 'y'; };"
12635     "  result += o[method](41);"
12636     "}");
12637   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12638 }
12639
12640
12641 // Test the case when actual function to call sits on global object.
12642 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12643   v8::Isolate* isolate = CcTest::isolate();
12644   v8::HandleScope scope(isolate);
12645   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12646   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12647   LocalContext context;
12648   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12649
12650   CompileRun(
12651     "function len(x) { return x.length; };"
12652     "o.__proto__ = this;"
12653     "var m = 'parseFloat';"
12654     "var result = 0;"
12655     "for (var i = 0; i < 10; i++) {"
12656     "  if (i == 5) {"
12657     "    m = 'len';"
12658     "    saved_result = result;"
12659     "  };"
12660     "  result = o[m]('239');"
12661     "}");
12662   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12663   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12664 }
12665
12666
12667 // Test the map transition before the interceptor.
12668 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12669   v8::Isolate* isolate = CcTest::isolate();
12670   v8::HandleScope scope(isolate);
12671   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12672   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12673   LocalContext context;
12674   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12675
12676   CompileRun(
12677     "var o = new Object();"
12678     "o.__proto__ = proto;"
12679     "o.method = function(x) { return x + 1; };"
12680     "var m = 'method';"
12681     "var result = 0;"
12682     "for (var i = 0; i < 10; i++) {"
12683     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12684     "  result += o[m](41);"
12685     "}");
12686   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12687 }
12688
12689
12690 // Test the map transition after the interceptor.
12691 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12692   v8::Isolate* isolate = CcTest::isolate();
12693   v8::HandleScope scope(isolate);
12694   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12695   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12696   LocalContext context;
12697   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12698
12699   CompileRun(
12700     "var proto = new Object();"
12701     "o.__proto__ = proto;"
12702     "proto.method = function(x) { return x + 1; };"
12703     "var m = 'method';"
12704     "var result = 0;"
12705     "for (var i = 0; i < 10; i++) {"
12706     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12707     "  result += o[m](41);"
12708     "}");
12709   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12710 }
12711
12712
12713 static int interceptor_call_count = 0;
12714
12715 static void InterceptorICRefErrorGetter(
12716     Local<String> name,
12717     const v8::PropertyCallbackInfo<v8::Value>& info) {
12718   ApiTestFuzzer::Fuzz();
12719   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12720     info.GetReturnValue().Set(call_ic_function2);
12721   }
12722 }
12723
12724
12725 // This test should hit load and call ICs for the interceptor case.
12726 // Once in a while, the interceptor will reply that a property was not
12727 // found in which case we should get a reference error.
12728 THREADED_TEST(InterceptorICReferenceErrors) {
12729   v8::Isolate* isolate = CcTest::isolate();
12730   v8::HandleScope scope(isolate);
12731   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12732   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12733   LocalContext context(0, templ, v8::Handle<Value>());
12734   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12735   v8::Handle<Value> value = CompileRun(
12736     "function f() {"
12737     "  for (var i = 0; i < 1000; i++) {"
12738     "    try { x; } catch(e) { return true; }"
12739     "  }"
12740     "  return false;"
12741     "};"
12742     "f();");
12743   CHECK_EQ(true, value->BooleanValue());
12744   interceptor_call_count = 0;
12745   value = CompileRun(
12746     "function g() {"
12747     "  for (var i = 0; i < 1000; i++) {"
12748     "    try { x(42); } catch(e) { return true; }"
12749     "  }"
12750     "  return false;"
12751     "};"
12752     "g();");
12753   CHECK_EQ(true, value->BooleanValue());
12754 }
12755
12756
12757 static int interceptor_ic_exception_get_count = 0;
12758
12759 static void InterceptorICExceptionGetter(
12760     Local<String> name,
12761     const v8::PropertyCallbackInfo<v8::Value>& info) {
12762   ApiTestFuzzer::Fuzz();
12763   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12764     info.GetReturnValue().Set(call_ic_function3);
12765   }
12766   if (interceptor_ic_exception_get_count == 20) {
12767     info.GetIsolate()->ThrowException(v8_num(42));
12768     return;
12769   }
12770 }
12771
12772
12773 // Test interceptor load/call IC where the interceptor throws an
12774 // exception once in a while.
12775 THREADED_TEST(InterceptorICGetterExceptions) {
12776   interceptor_ic_exception_get_count = 0;
12777   v8::Isolate* isolate = CcTest::isolate();
12778   v8::HandleScope scope(isolate);
12779   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12780   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12781   LocalContext context(0, templ, v8::Handle<Value>());
12782   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12783   v8::Handle<Value> value = CompileRun(
12784     "function f() {"
12785     "  for (var i = 0; i < 100; i++) {"
12786     "    try { x; } catch(e) { return true; }"
12787     "  }"
12788     "  return false;"
12789     "};"
12790     "f();");
12791   CHECK_EQ(true, value->BooleanValue());
12792   interceptor_ic_exception_get_count = 0;
12793   value = CompileRun(
12794     "function f() {"
12795     "  for (var i = 0; i < 100; i++) {"
12796     "    try { x(42); } catch(e) { return true; }"
12797     "  }"
12798     "  return false;"
12799     "};"
12800     "f();");
12801   CHECK_EQ(true, value->BooleanValue());
12802 }
12803
12804
12805 static int interceptor_ic_exception_set_count = 0;
12806
12807 static void InterceptorICExceptionSetter(
12808       Local<String> key,
12809       Local<Value> value,
12810       const v8::PropertyCallbackInfo<v8::Value>& info) {
12811   ApiTestFuzzer::Fuzz();
12812   if (++interceptor_ic_exception_set_count > 20) {
12813     info.GetIsolate()->ThrowException(v8_num(42));
12814   }
12815 }
12816
12817
12818 // Test interceptor store IC where the interceptor throws an exception
12819 // once in a while.
12820 THREADED_TEST(InterceptorICSetterExceptions) {
12821   interceptor_ic_exception_set_count = 0;
12822   v8::Isolate* isolate = CcTest::isolate();
12823   v8::HandleScope scope(isolate);
12824   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12825   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12826   LocalContext context(0, templ, v8::Handle<Value>());
12827   v8::Handle<Value> value = CompileRun(
12828     "function f() {"
12829     "  for (var i = 0; i < 100; i++) {"
12830     "    try { x = 42; } catch(e) { return true; }"
12831     "  }"
12832     "  return false;"
12833     "};"
12834     "f();");
12835   CHECK_EQ(true, value->BooleanValue());
12836 }
12837
12838
12839 // Test that we ignore null interceptors.
12840 THREADED_TEST(NullNamedInterceptor) {
12841   v8::Isolate* isolate = CcTest::isolate();
12842   v8::HandleScope scope(isolate);
12843   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12844   templ->SetNamedPropertyHandler(
12845       static_cast<v8::NamedPropertyGetterCallback>(0));
12846   LocalContext context;
12847   templ->Set(CcTest::isolate(), "x", v8_num(42));
12848   v8::Handle<v8::Object> obj = templ->NewInstance();
12849   context->Global()->Set(v8_str("obj"), obj);
12850   v8::Handle<Value> value = CompileRun("obj.x");
12851   CHECK(value->IsInt32());
12852   CHECK_EQ(42, value->Int32Value());
12853 }
12854
12855
12856 // Test that we ignore null interceptors.
12857 THREADED_TEST(NullIndexedInterceptor) {
12858   v8::Isolate* isolate = CcTest::isolate();
12859   v8::HandleScope scope(isolate);
12860   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12861   templ->SetIndexedPropertyHandler(
12862       static_cast<v8::IndexedPropertyGetterCallback>(0));
12863   LocalContext context;
12864   templ->Set(CcTest::isolate(), "42", v8_num(42));
12865   v8::Handle<v8::Object> obj = templ->NewInstance();
12866   context->Global()->Set(v8_str("obj"), obj);
12867   v8::Handle<Value> value = CompileRun("obj[42]");
12868   CHECK(value->IsInt32());
12869   CHECK_EQ(42, value->Int32Value());
12870 }
12871
12872
12873 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12874   v8::Isolate* isolate = CcTest::isolate();
12875   v8::HandleScope scope(isolate);
12876   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12877   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12878   LocalContext env;
12879   env->Global()->Set(v8_str("obj"),
12880                      templ->GetFunction()->NewInstance());
12881   ExpectTrue("obj.x === 42");
12882   ExpectTrue("!obj.propertyIsEnumerable('x')");
12883 }
12884
12885
12886 static void ThrowingGetter(Local<String> name,
12887                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12888   ApiTestFuzzer::Fuzz();
12889   info.GetIsolate()->ThrowException(Handle<Value>());
12890   info.GetReturnValue().SetUndefined();
12891 }
12892
12893
12894 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12895   LocalContext context;
12896   HandleScope scope(context->GetIsolate());
12897
12898   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12899   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12900   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12901
12902   Local<Object> instance = templ->GetFunction()->NewInstance();
12903
12904   Local<Object> another = Object::New(context->GetIsolate());
12905   another->SetPrototype(instance);
12906
12907   Local<Object> with_js_getter = CompileRun(
12908       "o = {};\n"
12909       "o.__defineGetter__('f', function() { throw undefined; });\n"
12910       "o\n").As<Object>();
12911   CHECK(!with_js_getter.IsEmpty());
12912
12913   TryCatch try_catch;
12914
12915   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12916   CHECK(try_catch.HasCaught());
12917   try_catch.Reset();
12918   CHECK(result.IsEmpty());
12919
12920   result = another->GetRealNamedProperty(v8_str("f"));
12921   CHECK(try_catch.HasCaught());
12922   try_catch.Reset();
12923   CHECK(result.IsEmpty());
12924
12925   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12926   CHECK(try_catch.HasCaught());
12927   try_catch.Reset();
12928   CHECK(result.IsEmpty());
12929
12930   result = another->Get(v8_str("f"));
12931   CHECK(try_catch.HasCaught());
12932   try_catch.Reset();
12933   CHECK(result.IsEmpty());
12934
12935   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12936   CHECK(try_catch.HasCaught());
12937   try_catch.Reset();
12938   CHECK(result.IsEmpty());
12939
12940   result = with_js_getter->Get(v8_str("f"));
12941   CHECK(try_catch.HasCaught());
12942   try_catch.Reset();
12943   CHECK(result.IsEmpty());
12944 }
12945
12946
12947 static void ThrowingCallbackWithTryCatch(
12948     const v8::FunctionCallbackInfo<v8::Value>& args) {
12949   TryCatch try_catch;
12950   // Verboseness is important: it triggers message delivery which can call into
12951   // external code.
12952   try_catch.SetVerbose(true);
12953   CompileRun("throw 'from JS';");
12954   CHECK(try_catch.HasCaught());
12955   CHECK(!CcTest::i_isolate()->has_pending_exception());
12956   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12957 }
12958
12959
12960 static int call_depth;
12961
12962
12963 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12964   TryCatch try_catch;
12965 }
12966
12967
12968 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12969   if (--call_depth) CompileRun("throw 'ThrowInJS';");
12970 }
12971
12972
12973 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12974   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12975 }
12976
12977
12978 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12979   Handle<String> errorMessageString = message->Get();
12980   CHECK(!errorMessageString.IsEmpty());
12981   message->GetStackTrace();
12982   message->GetScriptResourceName();
12983 }
12984
12985
12986 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12987   LocalContext context;
12988   v8::Isolate* isolate = context->GetIsolate();
12989   HandleScope scope(isolate);
12990
12991   Local<Function> func =
12992       FunctionTemplate::New(isolate,
12993                             ThrowingCallbackWithTryCatch)->GetFunction();
12994   context->Global()->Set(v8_str("func"), func);
12995
12996   MessageCallback callbacks[] =
12997       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12998   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12999     MessageCallback callback = callbacks[i];
13000     if (callback != NULL) {
13001       V8::AddMessageListener(callback);
13002     }
13003     // Some small number to control number of times message handler should
13004     // throw an exception.
13005     call_depth = 5;
13006     ExpectFalse(
13007         "var thrown = false;\n"
13008         "try { func(); } catch(e) { thrown = true; }\n"
13009         "thrown\n");
13010     if (callback != NULL) {
13011       V8::RemoveMessageListeners(callback);
13012     }
13013   }
13014 }
13015
13016
13017 static void ParentGetter(Local<String> name,
13018                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13019   ApiTestFuzzer::Fuzz();
13020   info.GetReturnValue().Set(v8_num(1));
13021 }
13022
13023
13024 static void ChildGetter(Local<String> name,
13025                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13026   ApiTestFuzzer::Fuzz();
13027   info.GetReturnValue().Set(v8_num(42));
13028 }
13029
13030
13031 THREADED_TEST(Overriding) {
13032   i::FLAG_es5_readonly = true;
13033   LocalContext context;
13034   v8::Isolate* isolate = context->GetIsolate();
13035   v8::HandleScope scope(isolate);
13036
13037   // Parent template.
13038   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13039   Local<ObjectTemplate> parent_instance_templ =
13040       parent_templ->InstanceTemplate();
13041   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13042
13043   // Template that inherits from the parent template.
13044   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13045   Local<ObjectTemplate> child_instance_templ =
13046       child_templ->InstanceTemplate();
13047   child_templ->Inherit(parent_templ);
13048   // Override 'f'.  The child version of 'f' should get called for child
13049   // instances.
13050   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13051   // Add 'g' twice.  The 'g' added last should get called for instances.
13052   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13053   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13054
13055   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13056   // so 'h' can be shadowed on the instance object.
13057   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13058   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13059       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13060
13061   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13062   // but the attribute does not have effect because it is duplicated with
13063   // NULL setter.
13064   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13065       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13066
13067
13068
13069   // Instantiate the child template.
13070   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13071
13072   // Check that the child function overrides the parent one.
13073   context->Global()->Set(v8_str("o"), instance);
13074   Local<Value> value = v8_compile("o.f")->Run();
13075   // Check that the 'g' that was added last is hit.
13076   CHECK_EQ(42, value->Int32Value());
13077   value = v8_compile("o.g")->Run();
13078   CHECK_EQ(42, value->Int32Value());
13079
13080   // Check that 'h' cannot be shadowed.
13081   value = v8_compile("o.h = 3; o.h")->Run();
13082   CHECK_EQ(1, value->Int32Value());
13083
13084   // Check that 'i' cannot be shadowed or changed.
13085   value = v8_compile("o.i = 3; o.i")->Run();
13086   CHECK_EQ(42, value->Int32Value());
13087 }
13088
13089
13090 static void IsConstructHandler(
13091     const v8::FunctionCallbackInfo<v8::Value>& args) {
13092   ApiTestFuzzer::Fuzz();
13093   args.GetReturnValue().Set(args.IsConstructCall());
13094 }
13095
13096
13097 THREADED_TEST(IsConstructCall) {
13098   v8::Isolate* isolate = CcTest::isolate();
13099   v8::HandleScope scope(isolate);
13100
13101   // Function template with call handler.
13102   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13103   templ->SetCallHandler(IsConstructHandler);
13104
13105   LocalContext context;
13106
13107   context->Global()->Set(v8_str("f"), templ->GetFunction());
13108   Local<Value> value = v8_compile("f()")->Run();
13109   CHECK(!value->BooleanValue());
13110   value = v8_compile("new f()")->Run();
13111   CHECK(value->BooleanValue());
13112 }
13113
13114
13115 THREADED_TEST(ObjectProtoToString) {
13116   v8::Isolate* isolate = CcTest::isolate();
13117   v8::HandleScope scope(isolate);
13118   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13119   templ->SetClassName(v8_str("MyClass"));
13120
13121   LocalContext context;
13122
13123   Local<String> customized_tostring = v8_str("customized toString");
13124
13125   // Replace Object.prototype.toString
13126   v8_compile("Object.prototype.toString = function() {"
13127                   "  return 'customized toString';"
13128                   "}")->Run();
13129
13130   // Normal ToString call should call replaced Object.prototype.toString
13131   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13132   Local<String> value = instance->ToString();
13133   CHECK(value->IsString() && value->Equals(customized_tostring));
13134
13135   // ObjectProtoToString should not call replace toString function.
13136   value = instance->ObjectProtoToString();
13137   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13138
13139   // Check global
13140   value = context->Global()->ObjectProtoToString();
13141   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13142
13143   // Check ordinary object
13144   Local<Value> object = v8_compile("new Object()")->Run();
13145   value = object.As<v8::Object>()->ObjectProtoToString();
13146   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13147 }
13148
13149
13150 THREADED_TEST(ObjectGetConstructorName) {
13151   LocalContext context;
13152   v8::HandleScope scope(context->GetIsolate());
13153   v8_compile("function Parent() {};"
13154              "function Child() {};"
13155              "Child.prototype = new Parent();"
13156              "var outer = { inner: function() { } };"
13157              "var p = new Parent();"
13158              "var c = new Child();"
13159              "var x = new outer.inner();")->Run();
13160
13161   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13162   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13163       v8_str("Parent")));
13164
13165   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13166   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13167       v8_str("Child")));
13168
13169   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13170   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13171       v8_str("outer.inner")));
13172 }
13173
13174
13175 bool ApiTestFuzzer::fuzzing_ = false;
13176 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
13177 int ApiTestFuzzer::active_tests_;
13178 int ApiTestFuzzer::tests_being_run_;
13179 int ApiTestFuzzer::current_;
13180
13181
13182 // We are in a callback and want to switch to another thread (if we
13183 // are currently running the thread fuzzing test).
13184 void ApiTestFuzzer::Fuzz() {
13185   if (!fuzzing_) return;
13186   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13187   test->ContextSwitch();
13188 }
13189
13190
13191 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13192 // not start immediately.
13193 bool ApiTestFuzzer::NextThread() {
13194   int test_position = GetNextTestNumber();
13195   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13196   if (test_position == current_) {
13197     if (kLogThreading)
13198       printf("Stay with %s\n", test_name);
13199     return false;
13200   }
13201   if (kLogThreading) {
13202     printf("Switch from %s to %s\n",
13203            test_name,
13204            RegisterThreadedTest::nth(test_position)->name());
13205   }
13206   current_ = test_position;
13207   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13208   return true;
13209 }
13210
13211
13212 void ApiTestFuzzer::Run() {
13213   // When it is our turn...
13214   gate_.Wait();
13215   {
13216     // ... get the V8 lock and start running the test.
13217     v8::Locker locker(CcTest::isolate());
13218     CallTest();
13219   }
13220   // This test finished.
13221   active_ = false;
13222   active_tests_--;
13223   // If it was the last then signal that fact.
13224   if (active_tests_ == 0) {
13225     all_tests_done_.Signal();
13226   } else {
13227     // Otherwise select a new test and start that.
13228     NextThread();
13229   }
13230 }
13231
13232
13233 static unsigned linear_congruential_generator;
13234
13235
13236 void ApiTestFuzzer::SetUp(PartOfTest part) {
13237   linear_congruential_generator = i::FLAG_testing_prng_seed;
13238   fuzzing_ = true;
13239   int count = RegisterThreadedTest::count();
13240   int start =  count * part / (LAST_PART + 1);
13241   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13242   active_tests_ = tests_being_run_ = end - start + 1;
13243   for (int i = 0; i < tests_being_run_; i++) {
13244     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13245   }
13246   for (int i = 0; i < active_tests_; i++) {
13247     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13248   }
13249 }
13250
13251
13252 static void CallTestNumber(int test_number) {
13253   (RegisterThreadedTest::nth(test_number)->callback())();
13254 }
13255
13256
13257 void ApiTestFuzzer::RunAllTests() {
13258   // Set off the first test.
13259   current_ = -1;
13260   NextThread();
13261   // Wait till they are all done.
13262   all_tests_done_.Wait();
13263 }
13264
13265
13266 int ApiTestFuzzer::GetNextTestNumber() {
13267   int next_test;
13268   do {
13269     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13270     linear_congruential_generator *= 1664525u;
13271     linear_congruential_generator += 1013904223u;
13272   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13273   return next_test;
13274 }
13275
13276
13277 void ApiTestFuzzer::ContextSwitch() {
13278   // If the new thread is the same as the current thread there is nothing to do.
13279   if (NextThread()) {
13280     // Now it can start.
13281     v8::Unlocker unlocker(CcTest::isolate());
13282     // Wait till someone starts us again.
13283     gate_.Wait();
13284     // And we're off.
13285   }
13286 }
13287
13288
13289 void ApiTestFuzzer::TearDown() {
13290   fuzzing_ = false;
13291   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13292     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13293     if (fuzzer != NULL) fuzzer->Join();
13294   }
13295 }
13296
13297
13298 // Lets not be needlessly self-referential.
13299 TEST(Threading1) {
13300   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13301   ApiTestFuzzer::RunAllTests();
13302   ApiTestFuzzer::TearDown();
13303 }
13304
13305
13306 TEST(Threading2) {
13307   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13308   ApiTestFuzzer::RunAllTests();
13309   ApiTestFuzzer::TearDown();
13310 }
13311
13312
13313 TEST(Threading3) {
13314   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13315   ApiTestFuzzer::RunAllTests();
13316   ApiTestFuzzer::TearDown();
13317 }
13318
13319
13320 TEST(Threading4) {
13321   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13322   ApiTestFuzzer::RunAllTests();
13323   ApiTestFuzzer::TearDown();
13324 }
13325
13326
13327 void ApiTestFuzzer::CallTest() {
13328   v8::Isolate::Scope scope(CcTest::isolate());
13329   if (kLogThreading)
13330     printf("Start test %d\n", test_number_);
13331   CallTestNumber(test_number_);
13332   if (kLogThreading)
13333     printf("End test %d\n", test_number_);
13334 }
13335
13336
13337 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13338   v8::Isolate* isolate = args.GetIsolate();
13339   CHECK(v8::Locker::IsLocked(isolate));
13340   ApiTestFuzzer::Fuzz();
13341   v8::Unlocker unlocker(isolate);
13342   const char* code = "throw 7;";
13343   {
13344     v8::Locker nested_locker(isolate);
13345     v8::HandleScope scope(isolate);
13346     v8::Handle<Value> exception;
13347     { v8::TryCatch try_catch;
13348       v8::Handle<Value> value = CompileRun(code);
13349       CHECK(value.IsEmpty());
13350       CHECK(try_catch.HasCaught());
13351       // Make sure to wrap the exception in a new handle because
13352       // the handle returned from the TryCatch is destroyed
13353       // when the TryCatch is destroyed.
13354       exception = Local<Value>::New(isolate, try_catch.Exception());
13355     }
13356     args.GetIsolate()->ThrowException(exception);
13357   }
13358 }
13359
13360
13361 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13362   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13363   ApiTestFuzzer::Fuzz();
13364   v8::Unlocker unlocker(CcTest::isolate());
13365   const char* code = "throw 7;";
13366   {
13367     v8::Locker nested_locker(CcTest::isolate());
13368     v8::HandleScope scope(args.GetIsolate());
13369     v8::Handle<Value> value = CompileRun(code);
13370     CHECK(value.IsEmpty());
13371     args.GetReturnValue().Set(v8_str("foo"));
13372   }
13373 }
13374
13375
13376 // These are locking tests that don't need to be run again
13377 // as part of the locking aggregation tests.
13378 TEST(NestedLockers) {
13379   v8::Isolate* isolate = CcTest::isolate();
13380   v8::Locker locker(isolate);
13381   CHECK(v8::Locker::IsLocked(isolate));
13382   LocalContext env;
13383   v8::HandleScope scope(env->GetIsolate());
13384   Local<v8::FunctionTemplate> fun_templ =
13385       v8::FunctionTemplate::New(isolate, ThrowInJS);
13386   Local<Function> fun = fun_templ->GetFunction();
13387   env->Global()->Set(v8_str("throw_in_js"), fun);
13388   Local<Script> script = v8_compile("(function () {"
13389                                     "  try {"
13390                                     "    throw_in_js();"
13391                                     "    return 42;"
13392                                     "  } catch (e) {"
13393                                     "    return e * 13;"
13394                                     "  }"
13395                                     "})();");
13396   CHECK_EQ(91, script->Run()->Int32Value());
13397 }
13398
13399
13400 // These are locking tests that don't need to be run again
13401 // as part of the locking aggregation tests.
13402 TEST(NestedLockersNoTryCatch) {
13403   v8::Locker locker(CcTest::isolate());
13404   LocalContext env;
13405   v8::HandleScope scope(env->GetIsolate());
13406   Local<v8::FunctionTemplate> fun_templ =
13407       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13408   Local<Function> fun = fun_templ->GetFunction();
13409   env->Global()->Set(v8_str("throw_in_js"), fun);
13410   Local<Script> script = v8_compile("(function () {"
13411                                     "  try {"
13412                                     "    throw_in_js();"
13413                                     "    return 42;"
13414                                     "  } catch (e) {"
13415                                     "    return e * 13;"
13416                                     "  }"
13417                                     "})();");
13418   CHECK_EQ(91, script->Run()->Int32Value());
13419 }
13420
13421
13422 THREADED_TEST(RecursiveLocking) {
13423   v8::Locker locker(CcTest::isolate());
13424   {
13425     v8::Locker locker2(CcTest::isolate());
13426     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13427   }
13428 }
13429
13430
13431 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13432   ApiTestFuzzer::Fuzz();
13433   v8::Unlocker unlocker(CcTest::isolate());
13434 }
13435
13436
13437 THREADED_TEST(LockUnlockLock) {
13438   {
13439     v8::Locker locker(CcTest::isolate());
13440     v8::HandleScope scope(CcTest::isolate());
13441     LocalContext env;
13442     Local<v8::FunctionTemplate> fun_templ =
13443         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13444     Local<Function> fun = fun_templ->GetFunction();
13445     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13446     Local<Script> script = v8_compile("(function () {"
13447                                       "  unlock_for_a_moment();"
13448                                       "  return 42;"
13449                                       "})();");
13450     CHECK_EQ(42, script->Run()->Int32Value());
13451   }
13452   {
13453     v8::Locker locker(CcTest::isolate());
13454     v8::HandleScope scope(CcTest::isolate());
13455     LocalContext env;
13456     Local<v8::FunctionTemplate> fun_templ =
13457         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13458     Local<Function> fun = fun_templ->GetFunction();
13459     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13460     Local<Script> script = v8_compile("(function () {"
13461                                       "  unlock_for_a_moment();"
13462                                       "  return 42;"
13463                                       "})();");
13464     CHECK_EQ(42, script->Run()->Int32Value());
13465   }
13466 }
13467
13468
13469 static int GetGlobalObjectsCount() {
13470   CcTest::heap()->EnsureHeapIsIterable();
13471   int count = 0;
13472   i::HeapIterator it(CcTest::heap());
13473   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13474     if (object->IsJSGlobalObject()) count++;
13475   return count;
13476 }
13477
13478
13479 static void CheckSurvivingGlobalObjectsCount(int expected) {
13480   // We need to collect all garbage twice to be sure that everything
13481   // has been collected.  This is because inline caches are cleared in
13482   // the first garbage collection but some of the maps have already
13483   // been marked at that point.  Therefore some of the maps are not
13484   // collected until the second garbage collection.
13485   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13486   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13487   int count = GetGlobalObjectsCount();
13488 #ifdef DEBUG
13489   if (count != expected) CcTest::heap()->TracePathToGlobal();
13490 #endif
13491   CHECK_EQ(expected, count);
13492 }
13493
13494
13495 TEST(DontLeakGlobalObjects) {
13496   // Regression test for issues 1139850 and 1174891.
13497
13498   i::FLAG_expose_gc = true;
13499   v8::V8::Initialize();
13500
13501   for (int i = 0; i < 5; i++) {
13502     { v8::HandleScope scope(CcTest::isolate());
13503       LocalContext context;
13504     }
13505     v8::V8::ContextDisposedNotification();
13506     CheckSurvivingGlobalObjectsCount(0);
13507
13508     { v8::HandleScope scope(CcTest::isolate());
13509       LocalContext context;
13510       v8_compile("Date")->Run();
13511     }
13512     v8::V8::ContextDisposedNotification();
13513     CheckSurvivingGlobalObjectsCount(0);
13514
13515     { v8::HandleScope scope(CcTest::isolate());
13516       LocalContext context;
13517       v8_compile("/aaa/")->Run();
13518     }
13519     v8::V8::ContextDisposedNotification();
13520     CheckSurvivingGlobalObjectsCount(0);
13521
13522     { v8::HandleScope scope(CcTest::isolate());
13523       const char* extension_list[] = { "v8/gc" };
13524       v8::ExtensionConfiguration extensions(1, extension_list);
13525       LocalContext context(&extensions);
13526       v8_compile("gc();")->Run();
13527     }
13528     v8::V8::ContextDisposedNotification();
13529     CheckSurvivingGlobalObjectsCount(0);
13530   }
13531 }
13532
13533
13534 TEST(CopyablePersistent) {
13535   LocalContext context;
13536   v8::Isolate* isolate = context->GetIsolate();
13537   i::GlobalHandles* globals =
13538       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13539   int initial_handles = globals->global_handles_count();
13540   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13541       CopyableObject;
13542   {
13543     CopyableObject handle1;
13544     {
13545       v8::HandleScope scope(isolate);
13546       handle1.Reset(isolate, v8::Object::New(isolate));
13547     }
13548     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13549     CopyableObject  handle2;
13550     handle2 = handle1;
13551     CHECK(handle1 == handle2);
13552     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13553     CopyableObject handle3(handle2);
13554     CHECK(handle1 == handle3);
13555     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13556   }
13557   // Verify autodispose
13558   CHECK_EQ(initial_handles, globals->global_handles_count());
13559 }
13560
13561
13562 static void WeakApiCallback(
13563     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13564   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13565   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13566   data.GetParameter()->Reset();
13567   delete data.GetParameter();
13568 }
13569
13570
13571 TEST(WeakCallbackApi) {
13572   LocalContext context;
13573   v8::Isolate* isolate = context->GetIsolate();
13574   i::GlobalHandles* globals =
13575       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13576   int initial_handles = globals->global_handles_count();
13577   {
13578     v8::HandleScope scope(isolate);
13579     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13580     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13581     v8::Persistent<v8::Object>* handle =
13582         new v8::Persistent<v8::Object>(isolate, obj);
13583     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13584                                                              WeakApiCallback);
13585   }
13586   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13587       CollectAllGarbage(i::Heap::kNoGCFlags);
13588   // Verify disposed.
13589   CHECK_EQ(initial_handles, globals->global_handles_count());
13590 }
13591
13592
13593 v8::Persistent<v8::Object> some_object;
13594 v8::Persistent<v8::Object> bad_handle;
13595
13596 void NewPersistentHandleCallback(
13597     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13598   v8::HandleScope scope(data.GetIsolate());
13599   bad_handle.Reset(data.GetIsolate(), some_object);
13600   data.GetParameter()->Reset();
13601 }
13602
13603
13604 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13605   LocalContext context;
13606   v8::Isolate* isolate = context->GetIsolate();
13607
13608   v8::Persistent<v8::Object> handle1, handle2;
13609   {
13610     v8::HandleScope scope(isolate);
13611     some_object.Reset(isolate, v8::Object::New(isolate));
13612     handle1.Reset(isolate, v8::Object::New(isolate));
13613     handle2.Reset(isolate, v8::Object::New(isolate));
13614   }
13615   // Note: order is implementation dependent alas: currently
13616   // global handle nodes are processed by PostGarbageCollectionProcessing
13617   // in reverse allocation order, so if second allocated handle is deleted,
13618   // weak callback of the first handle would be able to 'reallocate' it.
13619   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13620   handle2.Reset();
13621   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13622 }
13623
13624
13625 v8::Persistent<v8::Object> to_be_disposed;
13626
13627 void DisposeAndForceGcCallback(
13628     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13629   to_be_disposed.Reset();
13630   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13631   data.GetParameter()->Reset();
13632 }
13633
13634
13635 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13636   LocalContext context;
13637   v8::Isolate* isolate = context->GetIsolate();
13638
13639   v8::Persistent<v8::Object> handle1, handle2;
13640   {
13641     v8::HandleScope scope(isolate);
13642     handle1.Reset(isolate, v8::Object::New(isolate));
13643     handle2.Reset(isolate, v8::Object::New(isolate));
13644   }
13645   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13646   to_be_disposed.Reset(isolate, handle2);
13647   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13648 }
13649
13650 void DisposingCallback(
13651     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13652   data.GetParameter()->Reset();
13653 }
13654
13655 void HandleCreatingCallback(
13656     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13657   v8::HandleScope scope(data.GetIsolate());
13658   v8::Persistent<v8::Object>(data.GetIsolate(),
13659                              v8::Object::New(data.GetIsolate()));
13660   data.GetParameter()->Reset();
13661 }
13662
13663
13664 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13665   LocalContext context;
13666   v8::Isolate* isolate = context->GetIsolate();
13667
13668   v8::Persistent<v8::Object> handle1, handle2, handle3;
13669   {
13670     v8::HandleScope scope(isolate);
13671     handle3.Reset(isolate, v8::Object::New(isolate));
13672     handle2.Reset(isolate, v8::Object::New(isolate));
13673     handle1.Reset(isolate, v8::Object::New(isolate));
13674   }
13675   handle2.SetWeak(&handle2, DisposingCallback);
13676   handle3.SetWeak(&handle3, HandleCreatingCallback);
13677   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13678 }
13679
13680
13681 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13682   v8::V8::Initialize();
13683
13684   const int nof = 2;
13685   const char* sources[nof] = {
13686     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13687     "Object()"
13688   };
13689
13690   for (int i = 0; i < nof; i++) {
13691     const char* source = sources[i];
13692     { v8::HandleScope scope(CcTest::isolate());
13693       LocalContext context;
13694       CompileRun(source);
13695     }
13696     { v8::HandleScope scope(CcTest::isolate());
13697       LocalContext context;
13698       CompileRun(source);
13699     }
13700   }
13701 }
13702
13703
13704 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13705   v8::EscapableHandleScope inner(env->GetIsolate());
13706   env->Enter();
13707   v8::Local<Value> three = v8_num(3);
13708   v8::Local<Value> value = inner.Escape(three);
13709   env->Exit();
13710   return value;
13711 }
13712
13713
13714 THREADED_TEST(NestedHandleScopeAndContexts) {
13715   v8::Isolate* isolate = CcTest::isolate();
13716   v8::HandleScope outer(isolate);
13717   v8::Local<Context> env = Context::New(isolate);
13718   env->Enter();
13719   v8::Handle<Value> value = NestedScope(env);
13720   v8::Handle<String> str(value->ToString());
13721   CHECK(!str.IsEmpty());
13722   env->Exit();
13723 }
13724
13725
13726 static bool MatchPointers(void* key1, void* key2) {
13727   return key1 == key2;
13728 }
13729
13730
13731 struct SymbolInfo {
13732   size_t id;
13733   size_t size;
13734   std::string name;
13735 };
13736
13737
13738 class SetFunctionEntryHookTest {
13739  public:
13740   SetFunctionEntryHookTest() {
13741     CHECK(instance_ == NULL);
13742     instance_ = this;
13743   }
13744   ~SetFunctionEntryHookTest() {
13745     CHECK(instance_ == this);
13746     instance_ = NULL;
13747   }
13748   void Reset() {
13749     symbols_.clear();
13750     symbol_locations_.clear();
13751     invocations_.clear();
13752   }
13753   void RunTest();
13754   void OnJitEvent(const v8::JitCodeEvent* event);
13755   static void JitEvent(const v8::JitCodeEvent* event) {
13756     CHECK(instance_ != NULL);
13757     instance_->OnJitEvent(event);
13758   }
13759
13760   void OnEntryHook(uintptr_t function,
13761                    uintptr_t return_addr_location);
13762   static void EntryHook(uintptr_t function,
13763                         uintptr_t return_addr_location) {
13764     CHECK(instance_ != NULL);
13765     instance_->OnEntryHook(function, return_addr_location);
13766   }
13767
13768   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13769     CHECK(instance_ != NULL);
13770     args.GetReturnValue().Set(v8_num(42));
13771   }
13772   void RunLoopInNewEnv(v8::Isolate* isolate);
13773
13774   // Records addr as location of symbol.
13775   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13776
13777   // Finds the symbol containing addr
13778   SymbolInfo* FindSymbolForAddr(i::Address addr);
13779   // Returns the number of invocations where the caller name contains
13780   // \p caller_name and the function name contains \p function_name.
13781   int CountInvocations(const char* caller_name,
13782                        const char* function_name);
13783
13784   i::Handle<i::JSFunction> foo_func_;
13785   i::Handle<i::JSFunction> bar_func_;
13786
13787   typedef std::map<size_t, SymbolInfo> SymbolMap;
13788   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13789   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13790   SymbolMap symbols_;
13791   SymbolLocationMap symbol_locations_;
13792   InvocationMap invocations_;
13793
13794   static SetFunctionEntryHookTest* instance_;
13795 };
13796 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13797
13798
13799 // Returns true if addr is in the range [start, start+len).
13800 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13801   if (start <= addr && start + len > addr)
13802     return true;
13803
13804   return false;
13805 }
13806
13807 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13808                                               SymbolInfo* symbol) {
13809   // Insert the symbol at the new location.
13810   SymbolLocationMap::iterator it =
13811       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13812   // Now erase symbols to the left and right that overlap this one.
13813   while (it != symbol_locations_.begin()) {
13814     SymbolLocationMap::iterator left = it;
13815     --left;
13816     if (!Overlaps(left->first, left->second->size, addr))
13817       break;
13818     symbol_locations_.erase(left);
13819   }
13820
13821   // Now erase symbols to the left and right that overlap this one.
13822   while (true) {
13823     SymbolLocationMap::iterator right = it;
13824     ++right;
13825     if (right == symbol_locations_.end())
13826         break;
13827     if (!Overlaps(addr, symbol->size, right->first))
13828       break;
13829     symbol_locations_.erase(right);
13830   }
13831 }
13832
13833
13834 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13835   switch (event->type) {
13836     case v8::JitCodeEvent::CODE_ADDED: {
13837         CHECK(event->code_start != NULL);
13838         CHECK_NE(0, static_cast<int>(event->code_len));
13839         CHECK(event->name.str != NULL);
13840         size_t symbol_id = symbols_.size();
13841
13842         // Record the new symbol.
13843         SymbolInfo& info = symbols_[symbol_id];
13844         info.id = symbol_id;
13845         info.size = event->code_len;
13846         info.name.assign(event->name.str, event->name.str + event->name.len);
13847
13848         // And record it's location.
13849         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13850       }
13851       break;
13852
13853     case v8::JitCodeEvent::CODE_MOVED: {
13854         // We would like to never see code move that we haven't seen before,
13855         // but the code creation event does not happen until the line endings
13856         // have been calculated (this is so that we can report the line in the
13857         // script at which the function source is found, see
13858         // Compiler::RecordFunctionCompilation) and the line endings
13859         // calculations can cause a GC, which can move the newly created code
13860         // before its existence can be logged.
13861         SymbolLocationMap::iterator it(
13862             symbol_locations_.find(
13863                 reinterpret_cast<i::Address>(event->code_start)));
13864         if (it != symbol_locations_.end()) {
13865           // Found a symbol at this location, move it.
13866           SymbolInfo* info = it->second;
13867           symbol_locations_.erase(it);
13868           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13869                          info);
13870         }
13871       }
13872     default:
13873       break;
13874   }
13875 }
13876
13877 void SetFunctionEntryHookTest::OnEntryHook(
13878     uintptr_t function, uintptr_t return_addr_location) {
13879   // Get the function's code object.
13880   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13881       reinterpret_cast<i::Address>(function));
13882   CHECK(function_code != NULL);
13883
13884   // Then try and look up the caller's code object.
13885   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13886
13887   // Count the invocation.
13888   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13889   SymbolInfo* function_symbol =
13890       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13891   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13892
13893   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13894     // Check that we have a symbol for the "bar" function at the right location.
13895     SymbolLocationMap::iterator it(
13896         symbol_locations_.find(function_code->instruction_start()));
13897     CHECK(it != symbol_locations_.end());
13898   }
13899
13900   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13901     // Check that we have a symbol for "foo" at the right location.
13902     SymbolLocationMap::iterator it(
13903         symbol_locations_.find(function_code->instruction_start()));
13904     CHECK(it != symbol_locations_.end());
13905   }
13906 }
13907
13908
13909 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13910   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13911   // Do we have a direct hit on a symbol?
13912   if (it != symbol_locations_.end()) {
13913     if (it->first == addr)
13914       return it->second;
13915   }
13916
13917   // If not a direct hit, it'll have to be the previous symbol.
13918   if (it == symbol_locations_.begin())
13919     return NULL;
13920
13921   --it;
13922   size_t offs = addr - it->first;
13923   if (offs < it->second->size)
13924     return it->second;
13925
13926   return NULL;
13927 }
13928
13929
13930 int SetFunctionEntryHookTest::CountInvocations(
13931     const char* caller_name, const char* function_name) {
13932   InvocationMap::iterator it(invocations_.begin());
13933   int invocations = 0;
13934   for (; it != invocations_.end(); ++it) {
13935     SymbolInfo* caller = it->first.first;
13936     SymbolInfo* function = it->first.second;
13937
13938     // Filter out non-matching functions.
13939     if (function_name != NULL) {
13940       if (function->name.find(function_name) == std::string::npos)
13941         continue;
13942     }
13943
13944     // Filter out non-matching callers.
13945     if (caller_name != NULL) {
13946       if (caller == NULL)
13947         continue;
13948       if (caller->name.find(caller_name) == std::string::npos)
13949         continue;
13950     }
13951
13952     // It matches add the invocation count to the tally.
13953     invocations += it->second;
13954   }
13955
13956   return invocations;
13957 }
13958
13959
13960 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13961   v8::HandleScope outer(isolate);
13962   v8::Local<Context> env = Context::New(isolate);
13963   env->Enter();
13964
13965   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
13966   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
13967   env->Global()->Set(v8_str("obj"), t->NewInstance());
13968
13969   const char* script =
13970       "function bar() {\n"
13971       "  var sum = 0;\n"
13972       "  for (i = 0; i < 100; ++i)\n"
13973       "    sum = foo(i);\n"
13974       "  return sum;\n"
13975       "}\n"
13976       "function foo(i) { return i * i; }\n"
13977       "// Invoke on the runtime function.\n"
13978       "obj.asdf()";
13979   CompileRun(script);
13980   bar_func_ = i::Handle<i::JSFunction>::cast(
13981           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13982   ASSERT(!bar_func_.is_null());
13983
13984   foo_func_ =
13985       i::Handle<i::JSFunction>::cast(
13986            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13987   ASSERT(!foo_func_.is_null());
13988
13989   v8::Handle<v8::Value> value = CompileRun("bar();");
13990   CHECK(value->IsNumber());
13991   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13992
13993   // Test the optimized codegen path.
13994   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13995                      "bar();");
13996   CHECK(value->IsNumber());
13997   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13998
13999   env->Exit();
14000 }
14001
14002
14003 void SetFunctionEntryHookTest::RunTest() {
14004   // Work in a new isolate throughout.
14005   v8::Isolate* isolate = v8::Isolate::New();
14006
14007   // Test setting the entry hook on the new isolate.
14008   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14009
14010   // Replacing the hook, once set should fail.
14011   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14012
14013   {
14014     v8::Isolate::Scope scope(isolate);
14015
14016     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14017
14018     RunLoopInNewEnv(isolate);
14019
14020     // Check the exepected invocation counts.
14021     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14022     CHECK_EQ(200, CountInvocations("bar", "foo"));
14023     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14024
14025     // Verify that we have an entry hook on some specific stubs.
14026     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14027     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14028     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14029   }
14030   isolate->Dispose();
14031
14032   Reset();
14033
14034   // Make sure a second isolate is unaffected by the previous entry hook.
14035   isolate = v8::Isolate::New();
14036   {
14037     v8::Isolate::Scope scope(isolate);
14038
14039     // Reset the entry count to zero and set the entry hook.
14040     RunLoopInNewEnv(isolate);
14041
14042     // We should record no invocations in this isolate.
14043     CHECK_EQ(0, static_cast<int>(invocations_.size()));
14044   }
14045   // Since the isolate has been used, we shouldn't be able to set an entry
14046   // hook anymore.
14047   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14048
14049   isolate->Dispose();
14050 }
14051
14052
14053 TEST(SetFunctionEntryHook) {
14054   // FunctionEntryHook does not work well with experimental natives.
14055   // Experimental natives are compiled during snapshot deserialization.
14056   // This test breaks because InstallGetter (function from snapshot that
14057   // only gets called from experimental natives) is compiled with entry hooks.
14058   i::FLAG_allow_natives_syntax = true;
14059   i::FLAG_use_inlining = false;
14060
14061   SetFunctionEntryHookTest test;
14062   test.RunTest();
14063 }
14064
14065
14066 static i::HashMap* code_map = NULL;
14067 static i::HashMap* jitcode_line_info = NULL;
14068 static int saw_bar = 0;
14069 static int move_events = 0;
14070
14071
14072 static bool FunctionNameIs(const char* expected,
14073                            const v8::JitCodeEvent* event) {
14074   // Log lines for functions are of the general form:
14075   // "LazyCompile:<type><function_name>", where the type is one of
14076   // "*", "~" or "".
14077   static const char kPreamble[] = "LazyCompile:";
14078   static size_t kPreambleLen = sizeof(kPreamble) - 1;
14079
14080   if (event->name.len < sizeof(kPreamble) - 1 ||
14081       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14082     return false;
14083   }
14084
14085   const char* tail = event->name.str + kPreambleLen;
14086   size_t tail_len = event->name.len - kPreambleLen;
14087   size_t expected_len = strlen(expected);
14088   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14089     --tail_len;
14090     ++tail;
14091   }
14092
14093   // Check for tails like 'bar :1'.
14094   if (tail_len > expected_len + 2 &&
14095       tail[expected_len] == ' ' &&
14096       tail[expected_len + 1] == ':' &&
14097       tail[expected_len + 2] &&
14098       !strncmp(tail, expected, expected_len)) {
14099     return true;
14100   }
14101
14102   if (tail_len != expected_len)
14103     return false;
14104
14105   return strncmp(tail, expected, expected_len) == 0;
14106 }
14107
14108
14109 static void event_handler(const v8::JitCodeEvent* event) {
14110   CHECK(event != NULL);
14111   CHECK(code_map != NULL);
14112   CHECK(jitcode_line_info != NULL);
14113
14114   class DummyJitCodeLineInfo {
14115   };
14116
14117   switch (event->type) {
14118     case v8::JitCodeEvent::CODE_ADDED: {
14119         CHECK(event->code_start != NULL);
14120         CHECK_NE(0, static_cast<int>(event->code_len));
14121         CHECK(event->name.str != NULL);
14122         i::HashMap::Entry* entry =
14123             code_map->Lookup(event->code_start,
14124                              i::ComputePointerHash(event->code_start),
14125                              true);
14126         entry->value = reinterpret_cast<void*>(event->code_len);
14127
14128         if (FunctionNameIs("bar", event)) {
14129           ++saw_bar;
14130         }
14131       }
14132       break;
14133
14134     case v8::JitCodeEvent::CODE_MOVED: {
14135         uint32_t hash = i::ComputePointerHash(event->code_start);
14136         // We would like to never see code move that we haven't seen before,
14137         // but the code creation event does not happen until the line endings
14138         // have been calculated (this is so that we can report the line in the
14139         // script at which the function source is found, see
14140         // Compiler::RecordFunctionCompilation) and the line endings
14141         // calculations can cause a GC, which can move the newly created code
14142         // before its existence can be logged.
14143         i::HashMap::Entry* entry =
14144             code_map->Lookup(event->code_start, hash, false);
14145         if (entry != NULL) {
14146           ++move_events;
14147
14148           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14149           code_map->Remove(event->code_start, hash);
14150
14151           entry = code_map->Lookup(event->new_code_start,
14152                                    i::ComputePointerHash(event->new_code_start),
14153                                    true);
14154           CHECK(entry != NULL);
14155           entry->value = reinterpret_cast<void*>(event->code_len);
14156         }
14157       }
14158       break;
14159
14160     case v8::JitCodeEvent::CODE_REMOVED:
14161       // Object/code removal events are currently not dispatched from the GC.
14162       CHECK(false);
14163       break;
14164
14165     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14166     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14167     // record it in jitcode_line_info.
14168     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14169         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14170         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14171         temp_event->user_data = line_info;
14172         i::HashMap::Entry* entry =
14173             jitcode_line_info->Lookup(line_info,
14174                                       i::ComputePointerHash(line_info),
14175                                       true);
14176         entry->value = reinterpret_cast<void*>(line_info);
14177       }
14178       break;
14179     // For these two events, we will check whether the event->user_data
14180     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14181     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14182     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14183         CHECK(event->user_data != NULL);
14184         uint32_t hash = i::ComputePointerHash(event->user_data);
14185         i::HashMap::Entry* entry =
14186             jitcode_line_info->Lookup(event->user_data, hash, false);
14187         CHECK(entry != NULL);
14188         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14189       }
14190       break;
14191
14192     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14193         CHECK(event->user_data != NULL);
14194         uint32_t hash = i::ComputePointerHash(event->user_data);
14195         i::HashMap::Entry* entry =
14196             jitcode_line_info->Lookup(event->user_data, hash, false);
14197         CHECK(entry != NULL);
14198       }
14199       break;
14200
14201     default:
14202       // Impossible event.
14203       CHECK(false);
14204       break;
14205   }
14206 }
14207
14208
14209 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14210   i::FLAG_stress_compaction = true;
14211   i::FLAG_incremental_marking = false;
14212   const char* script =
14213     "function bar() {"
14214     "  var sum = 0;"
14215     "  for (i = 0; i < 100; ++i)"
14216     "    sum = foo(i);"
14217     "  return sum;"
14218     "}"
14219     "function foo(i) { return i * i; };"
14220     "bar();";
14221
14222   // Run this test in a new isolate to make sure we don't
14223   // have remnants of state from other code.
14224   v8::Isolate* isolate = v8::Isolate::New();
14225   isolate->Enter();
14226   i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
14227
14228   {
14229     v8::HandleScope scope(isolate);
14230     i::HashMap code(MatchPointers);
14231     code_map = &code;
14232
14233     i::HashMap lineinfo(MatchPointers);
14234     jitcode_line_info = &lineinfo;
14235
14236     saw_bar = 0;
14237     move_events = 0;
14238
14239     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14240
14241     // Generate new code objects sparsely distributed across several
14242     // different fragmented code-space pages.
14243     const int kIterations = 10;
14244     for (int i = 0; i < kIterations; ++i) {
14245       LocalContext env(isolate);
14246       i::AlwaysAllocateScope always_allocate;
14247       SimulateFullSpace(heap->code_space());
14248       CompileRun(script);
14249
14250       // Keep a strong reference to the code object in the handle scope.
14251       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14252           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14253       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14254           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14255
14256       // Clear the compilation cache to get more wastage.
14257       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14258     }
14259
14260     // Force code movement.
14261     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14262
14263     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14264
14265     CHECK_LE(kIterations, saw_bar);
14266     CHECK_LT(0, move_events);
14267
14268     code_map = NULL;
14269     jitcode_line_info = NULL;
14270   }
14271
14272   isolate->Exit();
14273   isolate->Dispose();
14274
14275   // Do this in a new isolate.
14276   isolate = v8::Isolate::New();
14277   isolate->Enter();
14278
14279   // Verify that we get callbacks for existing code objects when we
14280   // request enumeration of existing code.
14281   {
14282     v8::HandleScope scope(isolate);
14283     LocalContext env(isolate);
14284     CompileRun(script);
14285
14286     // Now get code through initial iteration.
14287     i::HashMap code(MatchPointers);
14288     code_map = &code;
14289
14290     i::HashMap lineinfo(MatchPointers);
14291     jitcode_line_info = &lineinfo;
14292
14293     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14294     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14295
14296     jitcode_line_info = NULL;
14297     // We expect that we got some events. Note that if we could get code removal
14298     // notifications, we could compare two collections, one created by listening
14299     // from the time of creation of an isolate, and the other by subscribing
14300     // with EnumExisting.
14301     CHECK_LT(0, code.occupancy());
14302
14303     code_map = NULL;
14304   }
14305
14306   isolate->Exit();
14307   isolate->Dispose();
14308 }
14309
14310
14311 THREADED_TEST(ExternalAllocatedMemory) {
14312   v8::Isolate* isolate = CcTest::isolate();
14313   v8::HandleScope outer(isolate);
14314   v8::Local<Context> env(Context::New(isolate));
14315   CHECK(!env.IsEmpty());
14316   const int64_t kSize = 1024*1024;
14317   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14318   CHECK_EQ(baseline + kSize,
14319            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14320   CHECK_EQ(baseline,
14321            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14322 }
14323
14324
14325 // Regression test for issue 54, object templates with internal fields
14326 // but no accessors or interceptors did not get their internal field
14327 // count set on instances.
14328 THREADED_TEST(Regress54) {
14329   LocalContext context;
14330   v8::Isolate* isolate = context->GetIsolate();
14331   v8::HandleScope outer(isolate);
14332   static v8::Persistent<v8::ObjectTemplate> templ;
14333   if (templ.IsEmpty()) {
14334     v8::EscapableHandleScope inner(isolate);
14335     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14336     local->SetInternalFieldCount(1);
14337     templ.Reset(isolate, inner.Escape(local));
14338   }
14339   v8::Handle<v8::Object> result =
14340       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14341   CHECK_EQ(1, result->InternalFieldCount());
14342 }
14343
14344
14345 // If part of the threaded tests, this test makes ThreadingTest fail
14346 // on mac.
14347 TEST(CatchStackOverflow) {
14348   LocalContext context;
14349   v8::HandleScope scope(context->GetIsolate());
14350   v8::TryCatch try_catch;
14351   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::NewFromUtf8(
14352     context->GetIsolate(),
14353     "function f() {"
14354     "  return f();"
14355     "}"
14356     ""
14357     "f();"));
14358   v8::Handle<v8::Value> result = script->Run();
14359   CHECK(result.IsEmpty());
14360 }
14361
14362
14363 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14364                                     const char* resource_name,
14365                                     int line_offset) {
14366   v8::HandleScope scope(CcTest::isolate());
14367   v8::TryCatch try_catch;
14368   v8::Handle<v8::Value> result = script->Run();
14369   CHECK(result.IsEmpty());
14370   CHECK(try_catch.HasCaught());
14371   v8::Handle<v8::Message> message = try_catch.Message();
14372   CHECK(!message.IsEmpty());
14373   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14374   CHECK_EQ(91, message->GetStartPosition());
14375   CHECK_EQ(92, message->GetEndPosition());
14376   CHECK_EQ(2, message->GetStartColumn());
14377   CHECK_EQ(3, message->GetEndColumn());
14378   v8::String::Utf8Value line(message->GetSourceLine());
14379   CHECK_EQ("  throw 'nirk';", *line);
14380   v8::String::Utf8Value name(message->GetScriptResourceName());
14381   CHECK_EQ(resource_name, *name);
14382 }
14383
14384
14385 THREADED_TEST(TryCatchSourceInfo) {
14386   LocalContext context;
14387   v8::HandleScope scope(context->GetIsolate());
14388   v8::Handle<v8::String> source = v8::String::NewFromUtf8(
14389       context->GetIsolate(),
14390       "function Foo() {\n"
14391       "  return Bar();\n"
14392       "}\n"
14393       "\n"
14394       "function Bar() {\n"
14395       "  return Baz();\n"
14396       "}\n"
14397       "\n"
14398       "function Baz() {\n"
14399       "  throw 'nirk';\n"
14400       "}\n"
14401       "\n"
14402       "Foo();\n");
14403
14404   const char* resource_name;
14405   v8::Handle<v8::Script> script;
14406   resource_name = "test.js";
14407   script = v8::Script::Compile(
14408       source, v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14409   CheckTryCatchSourceInfo(script, resource_name, 0);
14410
14411   resource_name = "test1.js";
14412   v8::ScriptOrigin origin1(
14413       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14414   script = v8::Script::Compile(source, &origin1);
14415   CheckTryCatchSourceInfo(script, resource_name, 0);
14416
14417   resource_name = "test2.js";
14418   v8::ScriptOrigin origin2(
14419       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14420       v8::Integer::New(context->GetIsolate(), 7));
14421   script = v8::Script::Compile(source, &origin2);
14422   CheckTryCatchSourceInfo(script, resource_name, 7);
14423 }
14424
14425
14426 THREADED_TEST(CompilationCache) {
14427   LocalContext context;
14428   v8::HandleScope scope(context->GetIsolate());
14429   v8::Handle<v8::String> source0 =
14430       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14431   v8::Handle<v8::String> source1 =
14432       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14433   v8::Handle<v8::Script> script0 = v8::Script::Compile(
14434       source0, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14435   v8::Handle<v8::Script> script1 = v8::Script::Compile(
14436       source1, v8::String::NewFromUtf8(context->GetIsolate(), "test.js"));
14437   v8::Handle<v8::Script> script2 =
14438       v8::Script::Compile(source0);  // different origin
14439   CHECK_EQ(1234, script0->Run()->Int32Value());
14440   CHECK_EQ(1234, script1->Run()->Int32Value());
14441   CHECK_EQ(1234, script2->Run()->Int32Value());
14442 }
14443
14444
14445 static void FunctionNameCallback(
14446     const v8::FunctionCallbackInfo<v8::Value>& args) {
14447   ApiTestFuzzer::Fuzz();
14448   args.GetReturnValue().Set(v8_num(42));
14449 }
14450
14451
14452 THREADED_TEST(CallbackFunctionName) {
14453   LocalContext context;
14454   v8::Isolate* isolate = context->GetIsolate();
14455   v8::HandleScope scope(isolate);
14456   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14457   t->Set(v8_str("asdf"),
14458          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14459   context->Global()->Set(v8_str("obj"), t->NewInstance());
14460   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14461   CHECK(value->IsString());
14462   v8::String::Utf8Value name(value);
14463   CHECK_EQ("asdf", *name);
14464 }
14465
14466
14467 THREADED_TEST(DateAccess) {
14468   LocalContext context;
14469   v8::HandleScope scope(context->GetIsolate());
14470   v8::Handle<v8::Value> date =
14471       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14472   CHECK(date->IsDate());
14473   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14474 }
14475
14476
14477 void CheckProperties(v8::Isolate* isolate,
14478                      v8::Handle<v8::Value> val,
14479                      int elmc,
14480                      const char* elmv[]) {
14481   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14482   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14483   CHECK_EQ(elmc, props->Length());
14484   for (int i = 0; i < elmc; i++) {
14485     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14486     CHECK_EQ(elmv[i], *elm);
14487   }
14488 }
14489
14490
14491 void CheckOwnProperties(v8::Isolate* isolate,
14492                         v8::Handle<v8::Value> val,
14493                         int elmc,
14494                         const char* elmv[]) {
14495   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14496   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14497   CHECK_EQ(elmc, props->Length());
14498   for (int i = 0; i < elmc; i++) {
14499     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14500     CHECK_EQ(elmv[i], *elm);
14501   }
14502 }
14503
14504
14505 THREADED_TEST(PropertyEnumeration) {
14506   LocalContext context;
14507   v8::Isolate* isolate = context->GetIsolate();
14508   v8::HandleScope scope(isolate);
14509   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14510       context->GetIsolate(),
14511       "var result = [];"
14512       "result[0] = {};"
14513       "result[1] = {a: 1, b: 2};"
14514       "result[2] = [1, 2, 3];"
14515       "var proto = {x: 1, y: 2, z: 3};"
14516       "var x = { __proto__: proto, w: 0, z: 1 };"
14517       "result[3] = x;"
14518       "result;"))->Run();
14519   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14520   CHECK_EQ(4, elms->Length());
14521   int elmc0 = 0;
14522   const char** elmv0 = NULL;
14523   CheckProperties(
14524       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14525   CheckOwnProperties(
14526       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14527   int elmc1 = 2;
14528   const char* elmv1[] = {"a", "b"};
14529   CheckProperties(
14530       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14531   CheckOwnProperties(
14532       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14533   int elmc2 = 3;
14534   const char* elmv2[] = {"0", "1", "2"};
14535   CheckProperties(
14536       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14537   CheckOwnProperties(
14538       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14539   int elmc3 = 4;
14540   const char* elmv3[] = {"w", "z", "x", "y"};
14541   CheckProperties(
14542       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14543   int elmc4 = 2;
14544   const char* elmv4[] = {"w", "z"};
14545   CheckOwnProperties(
14546       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14547 }
14548
14549
14550 THREADED_TEST(PropertyEnumeration2) {
14551   LocalContext context;
14552   v8::Isolate* isolate = context->GetIsolate();
14553   v8::HandleScope scope(isolate);
14554   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::NewFromUtf8(
14555       context->GetIsolate(),
14556       "var result = [];"
14557       "result[0] = {};"
14558       "result[1] = {a: 1, b: 2};"
14559       "result[2] = [1, 2, 3];"
14560       "var proto = {x: 1, y: 2, z: 3};"
14561       "var x = { __proto__: proto, w: 0, z: 1 };"
14562       "result[3] = x;"
14563       "result;"))->Run();
14564   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14565   CHECK_EQ(4, elms->Length());
14566   int elmc0 = 0;
14567   const char** elmv0 = NULL;
14568   CheckProperties(isolate,
14569                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14570
14571   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14572   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14573   CHECK_EQ(0, props->Length());
14574   for (uint32_t i = 0; i < props->Length(); i++) {
14575     printf("p[%d]\n", i);
14576   }
14577 }
14578
14579 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14580                                   Local<Value> name,
14581                                   v8::AccessType type,
14582                                   Local<Value> data) {
14583   return type != v8::ACCESS_SET;
14584 }
14585
14586
14587 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14588                                     uint32_t key,
14589                                     v8::AccessType type,
14590                                     Local<Value> data) {
14591   return type != v8::ACCESS_SET;
14592 }
14593
14594
14595 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14596   LocalContext context;
14597   v8::Isolate* isolate = context->GetIsolate();
14598   v8::HandleScope scope(isolate);
14599   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14600   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14601                                  IndexedSetAccessBlocker);
14602   templ->Set(v8_str("x"), v8::True(isolate));
14603   Local<v8::Object> instance = templ->NewInstance();
14604   context->Global()->Set(v8_str("obj"), instance);
14605   Local<Value> value = CompileRun("obj.x");
14606   CHECK(value->BooleanValue());
14607 }
14608
14609
14610 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14611                                   Local<Value> name,
14612                                   v8::AccessType type,
14613                                   Local<Value> data) {
14614   return false;
14615 }
14616
14617
14618 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14619                                     uint32_t key,
14620                                     v8::AccessType type,
14621                                     Local<Value> data) {
14622   return false;
14623 }
14624
14625
14626
14627 THREADED_TEST(AccessChecksReenabledCorrectly) {
14628   LocalContext context;
14629   v8::Isolate* isolate = context->GetIsolate();
14630   v8::HandleScope scope(isolate);
14631   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14632   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14633                                  IndexedGetAccessBlocker);
14634   templ->Set(v8_str("a"), v8_str("a"));
14635   // Add more than 8 (see kMaxFastProperties) properties
14636   // so that the constructor will force copying map.
14637   // Cannot sprintf, gcc complains unsafety.
14638   char buf[4];
14639   for (char i = '0'; i <= '9' ; i++) {
14640     buf[0] = i;
14641     for (char j = '0'; j <= '9'; j++) {
14642       buf[1] = j;
14643       for (char k = '0'; k <= '9'; k++) {
14644         buf[2] = k;
14645         buf[3] = 0;
14646         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14647       }
14648     }
14649   }
14650
14651   Local<v8::Object> instance_1 = templ->NewInstance();
14652   context->Global()->Set(v8_str("obj_1"), instance_1);
14653
14654   Local<Value> value_1 = CompileRun("obj_1.a");
14655   CHECK(value_1->IsUndefined());
14656
14657   Local<v8::Object> instance_2 = templ->NewInstance();
14658   context->Global()->Set(v8_str("obj_2"), instance_2);
14659
14660   Local<Value> value_2 = CompileRun("obj_2.a");
14661   CHECK(value_2->IsUndefined());
14662 }
14663
14664
14665 // This tests that access check information remains on the global
14666 // object template when creating contexts.
14667 THREADED_TEST(AccessControlRepeatedContextCreation) {
14668   v8::Isolate* isolate = CcTest::isolate();
14669   v8::HandleScope handle_scope(isolate);
14670   v8::Handle<v8::ObjectTemplate> global_template =
14671       v8::ObjectTemplate::New(isolate);
14672   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14673                                            IndexedSetAccessBlocker);
14674   i::Handle<i::ObjectTemplateInfo> internal_template =
14675       v8::Utils::OpenHandle(*global_template);
14676   CHECK(!internal_template->constructor()->IsUndefined());
14677   i::Handle<i::FunctionTemplateInfo> constructor(
14678       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14679   CHECK(!constructor->access_check_info()->IsUndefined());
14680   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14681   CHECK(!context0.IsEmpty());
14682   CHECK(!constructor->access_check_info()->IsUndefined());
14683 }
14684
14685
14686 THREADED_TEST(TurnOnAccessCheck) {
14687   v8::Isolate* isolate = CcTest::isolate();
14688   v8::HandleScope handle_scope(isolate);
14689
14690   // Create an environment with access check to the global object disabled by
14691   // default.
14692   v8::Handle<v8::ObjectTemplate> global_template =
14693       v8::ObjectTemplate::New(isolate);
14694   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14695                                            IndexedGetAccessBlocker,
14696                                            v8::Handle<v8::Value>(),
14697                                            false);
14698   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14699   Context::Scope context_scope(context);
14700
14701   // Set up a property and a number of functions.
14702   context->Global()->Set(v8_str("a"), v8_num(1));
14703   CompileRun("function f1() {return a;}"
14704              "function f2() {return a;}"
14705              "function g1() {return h();}"
14706              "function g2() {return h();}"
14707              "function h() {return 1;}");
14708   Local<Function> f1 =
14709       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14710   Local<Function> f2 =
14711       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14712   Local<Function> g1 =
14713       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14714   Local<Function> g2 =
14715       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14716   Local<Function> h =
14717       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14718
14719   // Get the global object.
14720   v8::Handle<v8::Object> global = context->Global();
14721
14722   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14723   // uses the runtime system to retreive property a whereas f2 uses global load
14724   // inline cache.
14725   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14726   for (int i = 0; i < 4; i++) {
14727     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14728   }
14729
14730   // Same for g1 and g2.
14731   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14732   for (int i = 0; i < 4; i++) {
14733     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14734   }
14735
14736   // Detach the global and turn on access check.
14737   Local<Object> hidden_global = Local<Object>::Cast(
14738       context->Global()->GetPrototype());
14739   context->DetachGlobal();
14740   hidden_global->TurnOnAccessCheck();
14741
14742   // Failing access check to property get results in undefined.
14743   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14744   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14745
14746   // Failing access check to function call results in exception.
14747   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14748   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14749
14750   // No failing access check when just returning a constant.
14751   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14752 }
14753
14754
14755 static const char* kPropertyA = "a";
14756 static const char* kPropertyH = "h";
14757
14758 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14759                                        Local<Value> name,
14760                                        v8::AccessType type,
14761                                        Local<Value> data) {
14762   if (!name->IsString()) return false;
14763   i::Handle<i::String> name_handle =
14764       v8::Utils::OpenHandle(String::Cast(*name));
14765   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14766       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14767 }
14768
14769
14770 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14771   v8::Isolate* isolate = CcTest::isolate();
14772   v8::HandleScope handle_scope(isolate);
14773
14774   // Create an environment with access check to the global object disabled by
14775   // default. When the registered access checker will block access to properties
14776   // a and h.
14777   v8::Handle<v8::ObjectTemplate> global_template =
14778      v8::ObjectTemplate::New(isolate);
14779   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14780                                            IndexedGetAccessBlocker,
14781                                            v8::Handle<v8::Value>(),
14782                                            false);
14783   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14784   Context::Scope context_scope(context);
14785
14786   // Set up a property and a number of functions.
14787   context->Global()->Set(v8_str("a"), v8_num(1));
14788   static const char* source = "function f1() {return a;}"
14789                               "function f2() {return a;}"
14790                               "function g1() {return h();}"
14791                               "function g2() {return h();}"
14792                               "function h() {return 1;}";
14793
14794   CompileRun(source);
14795   Local<Function> f1;
14796   Local<Function> f2;
14797   Local<Function> g1;
14798   Local<Function> g2;
14799   Local<Function> h;
14800   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14801   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14802   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14803   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14804   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14805
14806   // Get the global object.
14807   v8::Handle<v8::Object> global = context->Global();
14808
14809   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14810   // uses the runtime system to retreive property a whereas f2 uses global load
14811   // inline cache.
14812   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14813   for (int i = 0; i < 4; i++) {
14814     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14815   }
14816
14817   // Same for g1 and g2.
14818   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14819   for (int i = 0; i < 4; i++) {
14820     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14821   }
14822
14823   // Detach the global and turn on access check now blocking access to property
14824   // a and function h.
14825   Local<Object> hidden_global = Local<Object>::Cast(
14826       context->Global()->GetPrototype());
14827   context->DetachGlobal();
14828   hidden_global->TurnOnAccessCheck();
14829
14830   // Failing access check to property get results in undefined.
14831   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14832   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14833
14834   // Failing access check to function call results in exception.
14835   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14836   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14837
14838   // No failing access check when just returning a constant.
14839   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14840
14841   // Now compile the source again. And get the newly compiled functions, except
14842   // for h for which access is blocked.
14843   CompileRun(source);
14844   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14845   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14846   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14847   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14848   CHECK(hidden_global->Get(v8_str("h"))->IsUndefined());
14849
14850   // Failing access check to property get results in undefined.
14851   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14852   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14853
14854   // Failing access check to function call results in exception.
14855   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14856   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14857 }
14858
14859
14860 // This test verifies that pre-compilation (aka preparsing) can be called
14861 // without initializing the whole VM. Thus we cannot run this test in a
14862 // multi-threaded setup.
14863 TEST(PreCompile) {
14864   // TODO(155): This test would break without the initialization of V8. This is
14865   // a workaround for now to make this test not fail.
14866   v8::V8::Initialize();
14867   v8::Isolate* isolate = CcTest::isolate();
14868   HandleScope handle_scope(isolate);
14869   const char* script = "function foo(a) { return a+1; }";
14870   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14871       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14872   CHECK_NE(sd->Length(), 0);
14873   CHECK_NE(sd->Data(), NULL);
14874   CHECK(!sd->HasError());
14875   delete sd;
14876 }
14877
14878
14879 TEST(PreCompileWithError) {
14880   v8::V8::Initialize();
14881   v8::Isolate* isolate = CcTest::isolate();
14882   HandleScope handle_scope(isolate);
14883   const char* script = "function foo(a) { return 1 * * 2; }";
14884   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14885       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14886   CHECK(sd->HasError());
14887   delete sd;
14888 }
14889
14890
14891 TEST(Regress31661) {
14892   v8::V8::Initialize();
14893   v8::Isolate* isolate = CcTest::isolate();
14894   HandleScope handle_scope(isolate);
14895   const char* script = " The Definintive Guide";
14896   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14897       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14898   CHECK(sd->HasError());
14899   delete sd;
14900 }
14901
14902
14903 // Tests that ScriptData can be serialized and deserialized.
14904 TEST(PreCompileSerialization) {
14905   v8::V8::Initialize();
14906   v8::Isolate* isolate = CcTest::isolate();
14907   HandleScope handle_scope(isolate);
14908   const char* script = "function foo(a) { return a+1; }";
14909   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14910       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14911
14912   // Serialize.
14913   int serialized_data_length = sd->Length();
14914   char* serialized_data = i::NewArray<char>(serialized_data_length);
14915   i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14916
14917   // Deserialize.
14918   v8::ScriptData* deserialized_sd =
14919       v8::ScriptData::New(serialized_data, serialized_data_length);
14920
14921   // Verify that the original is the same as the deserialized.
14922   CHECK_EQ(sd->Length(), deserialized_sd->Length());
14923   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14924   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14925
14926   delete sd;
14927   delete deserialized_sd;
14928 }
14929
14930
14931 // Attempts to deserialize bad data.
14932 TEST(PreCompileDeserializationError) {
14933   v8::V8::Initialize();
14934   const char* data = "DONT CARE";
14935   int invalid_size = 3;
14936   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14937
14938   CHECK_EQ(0, sd->Length());
14939
14940   delete sd;
14941 }
14942
14943
14944 // Attempts to deserialize bad data.
14945 TEST(PreCompileInvalidPreparseDataError) {
14946   v8::V8::Initialize();
14947   v8::Isolate* isolate = CcTest::isolate();
14948   LocalContext context;
14949   v8::HandleScope scope(context->GetIsolate());
14950
14951   const char* script = "function foo(){ return 5;}\n"
14952       "function bar(){ return 6 + 7;}  foo();";
14953   v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14954       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14955   CHECK(!sd->HasError());
14956   // ScriptDataImpl private implementation details
14957   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14958   const int kFunctionEntrySize = i::FunctionEntry::kSize;
14959   const int kFunctionEntryStartOffset = 0;
14960   const int kFunctionEntryEndOffset = 1;
14961   unsigned* sd_data =
14962       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14963
14964   // Overwrite function bar's end position with 0.
14965   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14966   v8::TryCatch try_catch;
14967
14968   Local<String> source = String::NewFromUtf8(isolate, script);
14969   Local<Script> compiled_script = Script::New(source, NULL, sd);
14970   CHECK(try_catch.HasCaught());
14971   String::Utf8Value exception_value(try_catch.Message()->Get());
14972   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14973            *exception_value);
14974
14975   try_catch.Reset();
14976
14977   // Overwrite function bar's start position with 200.  The function entry
14978   // will not be found when searching for it by position and we should fall
14979   // back on eager compilation.
14980   sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
14981       isolate, script, v8::String::kNormalString, i::StrLength(script)));
14982   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14983   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14984       200;
14985   compiled_script = Script::New(source, NULL, sd);
14986   CHECK(!try_catch.HasCaught());
14987
14988   delete sd;
14989 }
14990
14991
14992 // This tests that we do not allow dictionary load/call inline caches
14993 // to use functions that have not yet been compiled.  The potential
14994 // problem of loading a function that has not yet been compiled can
14995 // arise because we share code between contexts via the compilation
14996 // cache.
14997 THREADED_TEST(DictionaryICLoadedFunction) {
14998   v8::HandleScope scope(CcTest::isolate());
14999   // Test LoadIC.
15000   for (int i = 0; i < 2; i++) {
15001     LocalContext context;
15002     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15003     context->Global()->Delete(v8_str("tmp"));
15004     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15005   }
15006   // Test CallIC.
15007   for (int i = 0; i < 2; i++) {
15008     LocalContext context;
15009     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15010     context->Global()->Delete(v8_str("tmp"));
15011     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15012   }
15013 }
15014
15015
15016 // Test that cross-context new calls use the context of the callee to
15017 // create the new JavaScript object.
15018 THREADED_TEST(CrossContextNew) {
15019   v8::Isolate* isolate = CcTest::isolate();
15020   v8::HandleScope scope(isolate);
15021   v8::Local<Context> context0 = Context::New(isolate);
15022   v8::Local<Context> context1 = Context::New(isolate);
15023
15024   // Allow cross-domain access.
15025   Local<String> token = v8_str("<security token>");
15026   context0->SetSecurityToken(token);
15027   context1->SetSecurityToken(token);
15028
15029   // Set an 'x' property on the Object prototype and define a
15030   // constructor function in context0.
15031   context0->Enter();
15032   CompileRun("Object.prototype.x = 42; function C() {};");
15033   context0->Exit();
15034
15035   // Call the constructor function from context0 and check that the
15036   // result has the 'x' property.
15037   context1->Enter();
15038   context1->Global()->Set(v8_str("other"), context0->Global());
15039   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15040   CHECK(value->IsInt32());
15041   CHECK_EQ(42, value->Int32Value());
15042   context1->Exit();
15043 }
15044
15045
15046 // Verify that we can clone an object
15047 TEST(ObjectClone) {
15048   LocalContext env;
15049   v8::Isolate* isolate = env->GetIsolate();
15050   v8::HandleScope scope(isolate);
15051
15052   const char* sample =
15053     "var rv = {};"      \
15054     "rv.alpha = 'hello';" \
15055     "rv.beta = 123;"     \
15056     "rv;";
15057
15058   // Create an object, verify basics.
15059   Local<Value> val = CompileRun(sample);
15060   CHECK(val->IsObject());
15061   Local<v8::Object> obj = val.As<v8::Object>();
15062   obj->Set(v8_str("gamma"), v8_str("cloneme"));
15063
15064   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15065   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15066   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15067
15068   // Clone it.
15069   Local<v8::Object> clone = obj->Clone();
15070   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15071   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15072   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15073
15074   // Set a property on the clone, verify each object.
15075   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15076   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15077   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15078 }
15079
15080
15081 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15082  public:
15083   explicit AsciiVectorResource(i::Vector<const char> vector)
15084       : data_(vector) {}
15085   virtual ~AsciiVectorResource() {}
15086   virtual size_t length() const { return data_.length(); }
15087   virtual const char* data() const { return data_.start(); }
15088  private:
15089   i::Vector<const char> data_;
15090 };
15091
15092
15093 class UC16VectorResource : public v8::String::ExternalStringResource {
15094  public:
15095   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15096       : data_(vector) {}
15097   virtual ~UC16VectorResource() {}
15098   virtual size_t length() const { return data_.length(); }
15099   virtual const i::uc16* data() const { return data_.start(); }
15100  private:
15101   i::Vector<const i::uc16> data_;
15102 };
15103
15104
15105 static void MorphAString(i::String* string,
15106                          AsciiVectorResource* ascii_resource,
15107                          UC16VectorResource* uc16_resource) {
15108   CHECK(i::StringShape(string).IsExternal());
15109   if (string->IsOneByteRepresentation()) {
15110     // Check old map is not internalized or long.
15111     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15112     // Morph external string to be TwoByte string.
15113     string->set_map(CcTest::heap()->external_string_map());
15114     i::ExternalTwoByteString* morphed =
15115          i::ExternalTwoByteString::cast(string);
15116     morphed->set_resource(uc16_resource);
15117   } else {
15118     // Check old map is not internalized or long.
15119     CHECK(string->map() == CcTest::heap()->external_string_map());
15120     // Morph external string to be ASCII string.
15121     string->set_map(CcTest::heap()->external_ascii_string_map());
15122     i::ExternalAsciiString* morphed =
15123          i::ExternalAsciiString::cast(string);
15124     morphed->set_resource(ascii_resource);
15125   }
15126 }
15127
15128
15129 // Test that we can still flatten a string if the components it is built up
15130 // from have been turned into 16 bit strings in the mean time.
15131 THREADED_TEST(MorphCompositeStringTest) {
15132   char utf_buffer[129];
15133   const char* c_string = "Now is the time for all good men"
15134                          " to come to the aid of the party";
15135   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15136   {
15137     LocalContext env;
15138     i::Factory* factory = CcTest::i_isolate()->factory();
15139     v8::HandleScope scope(env->GetIsolate());
15140     AsciiVectorResource ascii_resource(
15141         i::Vector<const char>(c_string, i::StrLength(c_string)));
15142     UC16VectorResource uc16_resource(
15143         i::Vector<const uint16_t>(two_byte_string,
15144                                   i::StrLength(c_string)));
15145
15146     Local<String> lhs(v8::Utils::ToLocal(
15147         factory->NewExternalStringFromAscii(&ascii_resource)));
15148     Local<String> rhs(v8::Utils::ToLocal(
15149         factory->NewExternalStringFromAscii(&ascii_resource)));
15150
15151     env->Global()->Set(v8_str("lhs"), lhs);
15152     env->Global()->Set(v8_str("rhs"), rhs);
15153
15154     CompileRun(
15155         "var cons = lhs + rhs;"
15156         "var slice = lhs.substring(1, lhs.length - 1);"
15157         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15158
15159     CHECK(lhs->IsOneByte());
15160     CHECK(rhs->IsOneByte());
15161
15162     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15163     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15164
15165     // This should UTF-8 without flattening, since everything is ASCII.
15166     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15167     CHECK_EQ(128, cons->Utf8Length());
15168     int nchars = -1;
15169     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15170     CHECK_EQ(128, nchars);
15171     CHECK_EQ(0, strcmp(
15172         utf_buffer,
15173         "Now is the time for all good men to come to the aid of the party"
15174         "Now is the time for all good men to come to the aid of the party"));
15175
15176     // Now do some stuff to make sure the strings are flattened, etc.
15177     CompileRun(
15178         "/[^a-z]/.test(cons);"
15179         "/[^a-z]/.test(slice);"
15180         "/[^a-z]/.test(slice_on_cons);");
15181     const char* expected_cons =
15182         "Now is the time for all good men to come to the aid of the party"
15183         "Now is the time for all good men to come to the aid of the party";
15184     const char* expected_slice =
15185         "ow is the time for all good men to come to the aid of the part";
15186     const char* expected_slice_on_cons =
15187         "ow is the time for all good men to come to the aid of the party"
15188         "Now is the time for all good men to come to the aid of the part";
15189     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15190              env->Global()->Get(v8_str("cons")));
15191     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15192              env->Global()->Get(v8_str("slice")));
15193     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15194              env->Global()->Get(v8_str("slice_on_cons")));
15195   }
15196   i::DeleteArray(two_byte_string);
15197 }
15198
15199
15200 TEST(CompileExternalTwoByteSource) {
15201   LocalContext context;
15202   v8::HandleScope scope(context->GetIsolate());
15203
15204   // This is a very short list of sources, which currently is to check for a
15205   // regression caused by r2703.
15206   const char* ascii_sources[] = {
15207     "0.5",
15208     "-0.5",   // This mainly testes PushBack in the Scanner.
15209     "--0.5",  // This mainly testes PushBack in the Scanner.
15210     NULL
15211   };
15212
15213   // Compile the sources as external two byte strings.
15214   for (int i = 0; ascii_sources[i] != NULL; i++) {
15215     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15216     UC16VectorResource uc16_resource(
15217         i::Vector<const uint16_t>(two_byte_string,
15218                                   i::StrLength(ascii_sources[i])));
15219     v8::Local<v8::String> source =
15220         v8::String::NewExternal(context->GetIsolate(), &uc16_resource);
15221     v8::Script::Compile(source);
15222     i::DeleteArray(two_byte_string);
15223   }
15224 }
15225
15226
15227 #ifndef V8_INTERPRETED_REGEXP
15228
15229 struct RegExpInterruptionData {
15230   int loop_count;
15231   UC16VectorResource* string_resource;
15232   v8::Persistent<v8::String> string;
15233 } regexp_interruption_data;
15234
15235
15236 class RegExpInterruptionThread : public i::Thread {
15237  public:
15238   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15239       : Thread("TimeoutThread"), isolate_(isolate) {}
15240
15241   virtual void Run() {
15242     for (regexp_interruption_data.loop_count = 0;
15243          regexp_interruption_data.loop_count < 7;
15244          regexp_interruption_data.loop_count++) {
15245       i::OS::Sleep(50);  // Wait a bit before requesting GC.
15246       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15247     }
15248     i::OS::Sleep(50);  // Wait a bit before terminating.
15249     v8::V8::TerminateExecution(isolate_);
15250   }
15251
15252  private:
15253   v8::Isolate* isolate_;
15254 };
15255
15256
15257 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15258   if (regexp_interruption_data.loop_count != 2) return;
15259   v8::HandleScope scope(CcTest::isolate());
15260   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15261       CcTest::isolate(), regexp_interruption_data.string);
15262   string->MakeExternal(regexp_interruption_data.string_resource);
15263 }
15264
15265
15266 // Test that RegExp execution can be interrupted.  Specifically, we test
15267 // * interrupting with GC
15268 // * turn the subject string from one-byte internal to two-byte external string
15269 // * force termination
15270 TEST(RegExpInterruption) {
15271   v8::HandleScope scope(CcTest::isolate());
15272   LocalContext env;
15273
15274   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15275
15276   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15277   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15278   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15279   v8::Local<v8::String> string = v8_str(ascii_content);
15280
15281   CcTest::global()->Set(v8_str("a"), string);
15282   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15283   regexp_interruption_data.string_resource = new UC16VectorResource(
15284       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15285
15286   v8::TryCatch try_catch;
15287   timeout_thread.Start();
15288
15289   CompileRun("/((a*)*)*b/.exec(a)");
15290   CHECK(try_catch.HasTerminated());
15291
15292   timeout_thread.Join();
15293
15294   delete regexp_interruption_data.string_resource;
15295   regexp_interruption_data.string.Reset();
15296 }
15297
15298 #endif  // V8_INTERPRETED_REGEXP
15299
15300
15301 // Test that we cannot set a property on the global object if there
15302 // is a read-only property in the prototype chain.
15303 TEST(ReadOnlyPropertyInGlobalProto) {
15304   i::FLAG_es5_readonly = true;
15305   v8::Isolate* isolate = CcTest::isolate();
15306   v8::HandleScope scope(isolate);
15307   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15308   LocalContext context(0, templ);
15309   v8::Handle<v8::Object> global = context->Global();
15310   v8::Handle<v8::Object> global_proto =
15311       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15312   global_proto->Set(v8_str("x"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15313   global_proto->Set(v8_str("y"), v8::Integer::New(isolate, 0), v8::ReadOnly);
15314   // Check without 'eval' or 'with'.
15315   v8::Handle<v8::Value> res =
15316       CompileRun("function f() { x = 42; return x; }; f()");
15317   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15318   // Check with 'eval'.
15319   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15320   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15321   // Check with 'with'.
15322   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15323   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15324 }
15325
15326 static int force_set_set_count = 0;
15327 static int force_set_get_count = 0;
15328 bool pass_on_get = false;
15329
15330 static void ForceSetGetter(v8::Local<v8::String> name,
15331                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15332   force_set_get_count++;
15333   if (pass_on_get) {
15334     return;
15335   }
15336   info.GetReturnValue().Set(3);
15337 }
15338
15339 static void ForceSetSetter(v8::Local<v8::String> name,
15340                            v8::Local<v8::Value> value,
15341                            const v8::PropertyCallbackInfo<void>& info) {
15342   force_set_set_count++;
15343 }
15344
15345 static void ForceSetInterceptSetter(
15346     v8::Local<v8::String> name,
15347     v8::Local<v8::Value> value,
15348     const v8::PropertyCallbackInfo<v8::Value>& info) {
15349   force_set_set_count++;
15350   info.GetReturnValue().SetUndefined();
15351 }
15352
15353
15354 TEST(ForceSet) {
15355   force_set_get_count = 0;
15356   force_set_set_count = 0;
15357   pass_on_get = false;
15358
15359   v8::Isolate* isolate = CcTest::isolate();
15360   v8::HandleScope scope(isolate);
15361   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15362   v8::Handle<v8::String> access_property =
15363       v8::String::NewFromUtf8(isolate, "a");
15364   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15365   LocalContext context(NULL, templ);
15366   v8::Handle<v8::Object> global = context->Global();
15367
15368   // Ordinary properties
15369   v8::Handle<v8::String> simple_property =
15370       v8::String::NewFromUtf8(isolate, "p");
15371   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15372   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15373   // This should fail because the property is read-only
15374   global->Set(simple_property, v8::Int32::New(isolate, 5));
15375   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15376   // This should succeed even though the property is read-only
15377   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15378   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15379
15380   // Accessors
15381   CHECK_EQ(0, force_set_set_count);
15382   CHECK_EQ(0, force_set_get_count);
15383   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15384   // CHECK_EQ the property shouldn't override it, just call the setter
15385   // which in this case does nothing.
15386   global->Set(access_property, v8::Int32::New(isolate, 7));
15387   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15388   CHECK_EQ(1, force_set_set_count);
15389   CHECK_EQ(2, force_set_get_count);
15390   // Forcing the property to be set should override the accessor without
15391   // calling it
15392   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15393   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15394   CHECK_EQ(1, force_set_set_count);
15395   CHECK_EQ(2, force_set_get_count);
15396 }
15397
15398
15399 TEST(ForceSetWithInterceptor) {
15400   force_set_get_count = 0;
15401   force_set_set_count = 0;
15402   pass_on_get = false;
15403
15404   v8::Isolate* isolate = CcTest::isolate();
15405   v8::HandleScope scope(isolate);
15406   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15407   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15408   LocalContext context(NULL, templ);
15409   v8::Handle<v8::Object> global = context->Global();
15410
15411   v8::Handle<v8::String> some_property =
15412       v8::String::NewFromUtf8(isolate, "a");
15413   CHECK_EQ(0, force_set_set_count);
15414   CHECK_EQ(0, force_set_get_count);
15415   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15416   // Setting the property shouldn't override it, just call the setter
15417   // which in this case does nothing.
15418   global->Set(some_property, v8::Int32::New(isolate, 7));
15419   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15420   CHECK_EQ(1, force_set_set_count);
15421   CHECK_EQ(2, force_set_get_count);
15422   // Getting the property when the interceptor returns an empty handle
15423   // should yield undefined, since the property isn't present on the
15424   // object itself yet.
15425   pass_on_get = true;
15426   CHECK(global->Get(some_property)->IsUndefined());
15427   CHECK_EQ(1, force_set_set_count);
15428   CHECK_EQ(3, force_set_get_count);
15429   // Forcing the property to be set should cause the value to be
15430   // set locally without calling the interceptor.
15431   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15432   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15433   CHECK_EQ(1, force_set_set_count);
15434   CHECK_EQ(4, force_set_get_count);
15435   // Reenabling the interceptor should cause it to take precedence over
15436   // the property
15437   pass_on_get = false;
15438   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15439   CHECK_EQ(1, force_set_set_count);
15440   CHECK_EQ(5, force_set_get_count);
15441   // The interceptor should also work for other properties
15442   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15443                   ->Int32Value());
15444   CHECK_EQ(1, force_set_set_count);
15445   CHECK_EQ(6, force_set_get_count);
15446 }
15447
15448
15449 THREADED_TEST(ForceDelete) {
15450   v8::Isolate* isolate = CcTest::isolate();
15451   v8::HandleScope scope(isolate);
15452   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15453   LocalContext context(NULL, templ);
15454   v8::Handle<v8::Object> global = context->Global();
15455
15456   // Ordinary properties
15457   v8::Handle<v8::String> simple_property =
15458       v8::String::NewFromUtf8(isolate, "p");
15459   global->Set(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15460   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15461   // This should fail because the property is dont-delete.
15462   CHECK(!global->Delete(simple_property));
15463   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15464   // This should succeed even though the property is dont-delete.
15465   CHECK(global->ForceDelete(simple_property));
15466   CHECK(global->Get(simple_property)->IsUndefined());
15467 }
15468
15469
15470 static int force_delete_interceptor_count = 0;
15471 static bool pass_on_delete = false;
15472
15473
15474 static void ForceDeleteDeleter(
15475     v8::Local<v8::String> name,
15476     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15477   force_delete_interceptor_count++;
15478   if (pass_on_delete) return;
15479   info.GetReturnValue().Set(true);
15480 }
15481
15482
15483 THREADED_TEST(ForceDeleteWithInterceptor) {
15484   force_delete_interceptor_count = 0;
15485   pass_on_delete = false;
15486
15487   v8::Isolate* isolate = CcTest::isolate();
15488   v8::HandleScope scope(isolate);
15489   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15490   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15491   LocalContext context(NULL, templ);
15492   v8::Handle<v8::Object> global = context->Global();
15493
15494   v8::Handle<v8::String> some_property =
15495       v8::String::NewFromUtf8(isolate, "a");
15496   global->Set(some_property, v8::Integer::New(isolate, 42), v8::DontDelete);
15497
15498   // Deleting a property should get intercepted and nothing should
15499   // happen.
15500   CHECK_EQ(0, force_delete_interceptor_count);
15501   CHECK(global->Delete(some_property));
15502   CHECK_EQ(1, force_delete_interceptor_count);
15503   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15504   // Deleting the property when the interceptor returns an empty
15505   // handle should not delete the property since it is DontDelete.
15506   pass_on_delete = true;
15507   CHECK(!global->Delete(some_property));
15508   CHECK_EQ(2, force_delete_interceptor_count);
15509   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15510   // Forcing the property to be deleted should delete the value
15511   // without calling the interceptor.
15512   CHECK(global->ForceDelete(some_property));
15513   CHECK(global->Get(some_property)->IsUndefined());
15514   CHECK_EQ(2, force_delete_interceptor_count);
15515 }
15516
15517
15518 // Make sure that forcing a delete invalidates any IC stubs, so we
15519 // don't read the hole value.
15520 THREADED_TEST(ForceDeleteIC) {
15521   LocalContext context;
15522   v8::HandleScope scope(context->GetIsolate());
15523   // Create a DontDelete variable on the global object.
15524   CompileRun("this.__proto__ = { foo: 'horse' };"
15525              "var foo = 'fish';"
15526              "function f() { return foo.length; }");
15527   // Initialize the IC for foo in f.
15528   CompileRun("for (var i = 0; i < 4; i++) f();");
15529   // Make sure the value of foo is correct before the deletion.
15530   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15531   // Force the deletion of foo.
15532   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15533   // Make sure the value for foo is read from the prototype, and that
15534   // we don't get in trouble with reading the deleted cell value
15535   // sentinel.
15536   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15537 }
15538
15539
15540 TEST(InlinedFunctionAcrossContexts) {
15541   i::FLAG_allow_natives_syntax = true;
15542   v8::Isolate* isolate = CcTest::isolate();
15543   v8::HandleScope outer_scope(isolate);
15544   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15545   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15546   ctx1->Enter();
15547
15548   {
15549     v8::HandleScope inner_scope(CcTest::isolate());
15550     CompileRun("var G = 42; function foo() { return G; }");
15551     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15552     ctx2->Enter();
15553     ctx2->Global()->Set(v8_str("o"), foo);
15554     v8::Local<v8::Value> res = CompileRun(
15555         "function f() { return o(); }"
15556         "for (var i = 0; i < 10; ++i) f();"
15557         "%OptimizeFunctionOnNextCall(f);"
15558         "f();");
15559     CHECK_EQ(42, res->Int32Value());
15560     ctx2->Exit();
15561     v8::Handle<v8::String> G_property =
15562         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15563     CHECK(ctx1->Global()->ForceDelete(G_property));
15564     ctx2->Enter();
15565     ExpectString(
15566         "(function() {"
15567         "  try {"
15568         "    return f();"
15569         "  } catch(e) {"
15570         "    return e.toString();"
15571         "  }"
15572         " })()",
15573         "ReferenceError: G is not defined");
15574     ctx2->Exit();
15575     ctx1->Exit();
15576   }
15577 }
15578
15579
15580 static v8::Local<Context> calling_context0;
15581 static v8::Local<Context> calling_context1;
15582 static v8::Local<Context> calling_context2;
15583
15584
15585 // Check that the call to the callback is initiated in
15586 // calling_context2, the directly calling context is calling_context1
15587 // and the callback itself is in calling_context0.
15588 static void GetCallingContextCallback(
15589     const v8::FunctionCallbackInfo<v8::Value>& args) {
15590   ApiTestFuzzer::Fuzz();
15591   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15592   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15593   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15594   args.GetReturnValue().Set(42);
15595 }
15596
15597
15598 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15599   i::Isolate* isolate = CcTest::i_isolate();
15600   CHECK(isolate != NULL);
15601   CHECK(isolate->context() == NULL);
15602   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15603   v8::HandleScope scope(v8_isolate);
15604   // The following should not crash, but return an empty handle.
15605   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15606   CHECK(current.IsEmpty());
15607 }
15608
15609
15610 THREADED_TEST(GetCallingContext) {
15611   v8::Isolate* isolate = CcTest::isolate();
15612   v8::HandleScope scope(isolate);
15613
15614   Local<Context> calling_context0(Context::New(isolate));
15615   Local<Context> calling_context1(Context::New(isolate));
15616   Local<Context> calling_context2(Context::New(isolate));
15617   ::calling_context0 = calling_context0;
15618   ::calling_context1 = calling_context1;
15619   ::calling_context2 = calling_context2;
15620
15621   // Allow cross-domain access.
15622   Local<String> token = v8_str("<security token>");
15623   calling_context0->SetSecurityToken(token);
15624   calling_context1->SetSecurityToken(token);
15625   calling_context2->SetSecurityToken(token);
15626
15627   // Create an object with a C++ callback in context0.
15628   calling_context0->Enter();
15629   Local<v8::FunctionTemplate> callback_templ =
15630       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15631   calling_context0->Global()->Set(v8_str("callback"),
15632                                   callback_templ->GetFunction());
15633   calling_context0->Exit();
15634
15635   // Expose context0 in context1 and set up a function that calls the
15636   // callback function.
15637   calling_context1->Enter();
15638   calling_context1->Global()->Set(v8_str("context0"),
15639                                   calling_context0->Global());
15640   CompileRun("function f() { context0.callback() }");
15641   calling_context1->Exit();
15642
15643   // Expose context1 in context2 and call the callback function in
15644   // context0 indirectly through f in context1.
15645   calling_context2->Enter();
15646   calling_context2->Global()->Set(v8_str("context1"),
15647                                   calling_context1->Global());
15648   CompileRun("context1.f()");
15649   calling_context2->Exit();
15650   ::calling_context0.Clear();
15651   ::calling_context1.Clear();
15652   ::calling_context2.Clear();
15653 }
15654
15655
15656 // Check that a variable declaration with no explicit initialization
15657 // value does shadow an existing property in the prototype chain.
15658 THREADED_TEST(InitGlobalVarInProtoChain) {
15659   i::FLAG_es52_globals = true;
15660   LocalContext context;
15661   v8::HandleScope scope(context->GetIsolate());
15662   // Introduce a variable in the prototype chain.
15663   CompileRun("__proto__.x = 42");
15664   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15665   CHECK(!result->IsUndefined());
15666   CHECK_EQ(43, result->Int32Value());
15667 }
15668
15669
15670 // Regression test for issue 398.
15671 // If a function is added to an object, creating a constant function
15672 // field, and the result is cloned, replacing the constant function on the
15673 // original should not affect the clone.
15674 // See http://code.google.com/p/v8/issues/detail?id=398
15675 THREADED_TEST(ReplaceConstantFunction) {
15676   LocalContext context;
15677   v8::Isolate* isolate = context->GetIsolate();
15678   v8::HandleScope scope(isolate);
15679   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15680   v8::Handle<v8::FunctionTemplate> func_templ =
15681       v8::FunctionTemplate::New(isolate);
15682   v8::Handle<v8::String> foo_string =
15683       v8::String::NewFromUtf8(isolate, "foo");
15684   obj->Set(foo_string, func_templ->GetFunction());
15685   v8::Handle<v8::Object> obj_clone = obj->Clone();
15686   obj_clone->Set(foo_string,
15687                  v8::String::NewFromUtf8(isolate, "Hello"));
15688   CHECK(!obj->Get(foo_string)->IsUndefined());
15689 }
15690
15691
15692 static void CheckElementValue(i::Isolate* isolate,
15693                               int expected,
15694                               i::Handle<i::Object> obj,
15695                               int offset) {
15696   i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15697   CHECK_EQ(expected, i::Smi::cast(element)->value());
15698 }
15699
15700
15701 THREADED_TEST(PixelArray) {
15702   LocalContext context;
15703   i::Isolate* isolate = CcTest::i_isolate();
15704   i::Factory* factory = isolate->factory();
15705   v8::HandleScope scope(context->GetIsolate());
15706   const int kElementCount = 260;
15707   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15708   i::Handle<i::ExternalUint8ClampedArray> pixels =
15709       i::Handle<i::ExternalUint8ClampedArray>::cast(
15710           factory->NewExternalArray(kElementCount,
15711                                     v8::kExternalUint8ClampedArray,
15712                                     pixel_data));
15713   // Force GC to trigger verification.
15714   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15715   for (int i = 0; i < kElementCount; i++) {
15716     pixels->set(i, i % 256);
15717   }
15718   // Force GC to trigger verification.
15719   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15720   for (int i = 0; i < kElementCount; i++) {
15721     CHECK_EQ(i % 256, pixels->get_scalar(i));
15722     CHECK_EQ(i % 256, pixel_data[i]);
15723   }
15724
15725   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15726   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15727   // Set the elements to be the pixels.
15728   // jsobj->set_elements(*pixels);
15729   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15730   CheckElementValue(isolate, 1, jsobj, 1);
15731   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15732   context->Global()->Set(v8_str("pixels"), obj);
15733   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15734   CHECK_EQ(1503, result->Int32Value());
15735   result = CompileRun("pixels[1]");
15736   CHECK_EQ(1, result->Int32Value());
15737
15738   result = CompileRun("var sum = 0;"
15739                       "for (var i = 0; i < 8; i++) {"
15740                       "  sum += pixels[i] = pixels[i] = -i;"
15741                       "}"
15742                       "sum;");
15743   CHECK_EQ(-28, result->Int32Value());
15744
15745   result = CompileRun("var sum = 0;"
15746                       "for (var i = 0; i < 8; i++) {"
15747                       "  sum += pixels[i] = pixels[i] = 0;"
15748                       "}"
15749                       "sum;");
15750   CHECK_EQ(0, result->Int32Value());
15751
15752   result = CompileRun("var sum = 0;"
15753                       "for (var i = 0; i < 8; i++) {"
15754                       "  sum += pixels[i] = pixels[i] = 255;"
15755                       "}"
15756                       "sum;");
15757   CHECK_EQ(8 * 255, result->Int32Value());
15758
15759   result = CompileRun("var sum = 0;"
15760                       "for (var i = 0; i < 8; i++) {"
15761                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15762                       "}"
15763                       "sum;");
15764   CHECK_EQ(2076, result->Int32Value());
15765
15766   result = CompileRun("var sum = 0;"
15767                       "for (var i = 0; i < 8; i++) {"
15768                       "  sum += pixels[i] = pixels[i] = i;"
15769                       "}"
15770                       "sum;");
15771   CHECK_EQ(28, result->Int32Value());
15772
15773   result = CompileRun("var sum = 0;"
15774                       "for (var i = 0; i < 8; i++) {"
15775                       "  sum += pixels[i];"
15776                       "}"
15777                       "sum;");
15778   CHECK_EQ(28, result->Int32Value());
15779
15780   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15781                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15782   i::Handle<i::Object> no_failure;
15783   no_failure =
15784       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15785   ASSERT(!no_failure.is_null());
15786   i::USE(no_failure);
15787   CheckElementValue(isolate, 2, jsobj, 1);
15788   *value.location() = i::Smi::FromInt(256);
15789   no_failure =
15790       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15791   ASSERT(!no_failure.is_null());
15792   i::USE(no_failure);
15793   CheckElementValue(isolate, 255, jsobj, 1);
15794   *value.location() = i::Smi::FromInt(-1);
15795   no_failure =
15796       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15797   ASSERT(!no_failure.is_null());
15798   i::USE(no_failure);
15799   CheckElementValue(isolate, 0, jsobj, 1);
15800
15801   result = CompileRun("for (var i = 0; i < 8; i++) {"
15802                       "  pixels[i] = (i * 65) - 109;"
15803                       "}"
15804                       "pixels[1] + pixels[6];");
15805   CHECK_EQ(255, result->Int32Value());
15806   CheckElementValue(isolate, 0, jsobj, 0);
15807   CheckElementValue(isolate, 0, jsobj, 1);
15808   CheckElementValue(isolate, 21, jsobj, 2);
15809   CheckElementValue(isolate, 86, jsobj, 3);
15810   CheckElementValue(isolate, 151, jsobj, 4);
15811   CheckElementValue(isolate, 216, jsobj, 5);
15812   CheckElementValue(isolate, 255, jsobj, 6);
15813   CheckElementValue(isolate, 255, jsobj, 7);
15814   result = CompileRun("var sum = 0;"
15815                       "for (var i = 0; i < 8; i++) {"
15816                       "  sum += pixels[i];"
15817                       "}"
15818                       "sum;");
15819   CHECK_EQ(984, result->Int32Value());
15820
15821   result = CompileRun("for (var i = 0; i < 8; i++) {"
15822                       "  pixels[i] = (i * 1.1);"
15823                       "}"
15824                       "pixels[1] + pixels[6];");
15825   CHECK_EQ(8, result->Int32Value());
15826   CheckElementValue(isolate, 0, jsobj, 0);
15827   CheckElementValue(isolate, 1, jsobj, 1);
15828   CheckElementValue(isolate, 2, jsobj, 2);
15829   CheckElementValue(isolate, 3, jsobj, 3);
15830   CheckElementValue(isolate, 4, jsobj, 4);
15831   CheckElementValue(isolate, 6, jsobj, 5);
15832   CheckElementValue(isolate, 7, jsobj, 6);
15833   CheckElementValue(isolate, 8, jsobj, 7);
15834
15835   result = CompileRun("for (var i = 0; i < 8; i++) {"
15836                       "  pixels[7] = undefined;"
15837                       "}"
15838                       "pixels[7];");
15839   CHECK_EQ(0, result->Int32Value());
15840   CheckElementValue(isolate, 0, jsobj, 7);
15841
15842   result = CompileRun("for (var i = 0; i < 8; i++) {"
15843                       "  pixels[6] = '2.3';"
15844                       "}"
15845                       "pixels[6];");
15846   CHECK_EQ(2, result->Int32Value());
15847   CheckElementValue(isolate, 2, jsobj, 6);
15848
15849   result = CompileRun("for (var i = 0; i < 8; i++) {"
15850                       "  pixels[5] = NaN;"
15851                       "}"
15852                       "pixels[5];");
15853   CHECK_EQ(0, result->Int32Value());
15854   CheckElementValue(isolate, 0, jsobj, 5);
15855
15856   result = CompileRun("for (var i = 0; i < 8; i++) {"
15857                       "  pixels[8] = Infinity;"
15858                       "}"
15859                       "pixels[8];");
15860   CHECK_EQ(255, result->Int32Value());
15861   CheckElementValue(isolate, 255, jsobj, 8);
15862
15863   result = CompileRun("for (var i = 0; i < 8; i++) {"
15864                       "  pixels[9] = -Infinity;"
15865                       "}"
15866                       "pixels[9];");
15867   CHECK_EQ(0, result->Int32Value());
15868   CheckElementValue(isolate, 0, jsobj, 9);
15869
15870   result = CompileRun("pixels[3] = 33;"
15871                       "delete pixels[3];"
15872                       "pixels[3];");
15873   CHECK_EQ(33, result->Int32Value());
15874
15875   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15876                       "pixels[2] = 12; pixels[3] = 13;"
15877                       "pixels.__defineGetter__('2',"
15878                       "function() { return 120; });"
15879                       "pixels[2];");
15880   CHECK_EQ(12, result->Int32Value());
15881
15882   result = CompileRun("var js_array = new Array(40);"
15883                       "js_array[0] = 77;"
15884                       "js_array;");
15885   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15886
15887   result = CompileRun("pixels[1] = 23;"
15888                       "pixels.__proto__ = [];"
15889                       "js_array.__proto__ = pixels;"
15890                       "js_array.concat(pixels);");
15891   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15892   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15893
15894   result = CompileRun("pixels[1] = 23;");
15895   CHECK_EQ(23, result->Int32Value());
15896
15897   // Test for index greater than 255.  Regression test for:
15898   // http://code.google.com/p/chromium/issues/detail?id=26337.
15899   result = CompileRun("pixels[256] = 255;");
15900   CHECK_EQ(255, result->Int32Value());
15901   result = CompileRun("var i = 0;"
15902                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15903                       "i");
15904   CHECK_EQ(255, result->Int32Value());
15905
15906   // Make sure that pixel array ICs recognize when a non-pixel array
15907   // is passed to it.
15908   result = CompileRun("function pa_load(p) {"
15909                       "  var sum = 0;"
15910                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15911                       "  return sum;"
15912                       "}"
15913                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15914                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15915                       "just_ints = new Object();"
15916                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15917                       "for (var i = 0; i < 10; ++i) {"
15918                       "  result = pa_load(just_ints);"
15919                       "}"
15920                       "result");
15921   CHECK_EQ(32640, result->Int32Value());
15922
15923   // Make sure that pixel array ICs recognize out-of-bound accesses.
15924   result = CompileRun("function pa_load(p, start) {"
15925                       "  var sum = 0;"
15926                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15927                       "  return sum;"
15928                       "}"
15929                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15930                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15931                       "for (var i = 0; i < 10; ++i) {"
15932                       "  result = pa_load(pixels,-10);"
15933                       "}"
15934                       "result");
15935   CHECK_EQ(0, result->Int32Value());
15936
15937   // Make sure that generic ICs properly handles a pixel array.
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                       "just_ints = new Object();"
15945                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15946                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15947                       "for (var i = 0; i < 10; ++i) {"
15948                       "  result = pa_load(pixels);"
15949                       "}"
15950                       "result");
15951   CHECK_EQ(32640, result->Int32Value());
15952
15953   // Make sure that generic load ICs recognize out-of-bound accesses in
15954   // pixel arrays.
15955   result = CompileRun("function pa_load(p, start) {"
15956                       "  var sum = 0;"
15957                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15958                       "  return sum;"
15959                       "}"
15960                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15961                       "just_ints = new Object();"
15962                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15963                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15964                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15965                       "for (var i = 0; i < 10; ++i) {"
15966                       "  result = pa_load(pixels,-10);"
15967                       "}"
15968                       "result");
15969   CHECK_EQ(0, result->Int32Value());
15970
15971   // Make sure that generic ICs properly handles other types than pixel
15972   // arrays (that the inlined fast pixel array test leaves the right information
15973   // in the right registers).
15974   result = CompileRun("function pa_load(p) {"
15975                       "  var sum = 0;"
15976                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15977                       "  return sum;"
15978                       "}"
15979                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15980                       "just_ints = new Object();"
15981                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15982                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15983                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15984                       "sparse_array = new Object();"
15985                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15986                       "sparse_array[1000000] = 3;"
15987                       "for (var i = 0; i < 10; ++i) {"
15988                       "  result = pa_load(sparse_array);"
15989                       "}"
15990                       "result");
15991   CHECK_EQ(32640, result->Int32Value());
15992
15993   // Make sure that pixel array store ICs clamp values correctly.
15994   result = CompileRun("function pa_store(p) {"
15995                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15996                       "}"
15997                       "pa_store(pixels);"
15998                       "var sum = 0;"
15999                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16000                       "sum");
16001   CHECK_EQ(48896, result->Int32Value());
16002
16003   // Make sure that pixel array stores correctly handle accesses outside
16004   // of the pixel array..
16005   result = CompileRun("function pa_store(p,start) {"
16006                       "  for (var j = 0; j < 256; j++) {"
16007                       "    p[j+start] = j * 2;"
16008                       "  }"
16009                       "}"
16010                       "pa_store(pixels,0);"
16011                       "pa_store(pixels,-128);"
16012                       "var sum = 0;"
16013                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16014                       "sum");
16015   CHECK_EQ(65280, result->Int32Value());
16016
16017   // Make sure that the generic store stub correctly handle accesses outside
16018   // of the pixel array..
16019   result = CompileRun("function pa_store(p,start) {"
16020                       "  for (var j = 0; j < 256; j++) {"
16021                       "    p[j+start] = j * 2;"
16022                       "  }"
16023                       "}"
16024                       "pa_store(pixels,0);"
16025                       "just_ints = new Object();"
16026                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16027                       "pa_store(just_ints, 0);"
16028                       "pa_store(pixels,-128);"
16029                       "var sum = 0;"
16030                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16031                       "sum");
16032   CHECK_EQ(65280, result->Int32Value());
16033
16034   // Make sure that the generic keyed store stub clamps pixel array values
16035   // correctly.
16036   result = CompileRun("function pa_store(p) {"
16037                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16038                       "}"
16039                       "pa_store(pixels);"
16040                       "just_ints = new Object();"
16041                       "pa_store(just_ints);"
16042                       "pa_store(pixels);"
16043                       "var sum = 0;"
16044                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16045                       "sum");
16046   CHECK_EQ(48896, result->Int32Value());
16047
16048   // Make sure that pixel array loads are optimized by crankshaft.
16049   result = CompileRun("function pa_load(p) {"
16050                       "  var sum = 0;"
16051                       "  for (var i=0; i<256; ++i) {"
16052                       "    sum += p[i];"
16053                       "  }"
16054                       "  return sum; "
16055                       "}"
16056                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16057                       "for (var i = 0; i < 5000; ++i) {"
16058                       "  result = pa_load(pixels);"
16059                       "}"
16060                       "result");
16061   CHECK_EQ(32640, result->Int32Value());
16062
16063   // Make sure that pixel array stores are optimized by crankshaft.
16064   result = CompileRun("function pa_init(p) {"
16065                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16066                       "}"
16067                       "function pa_load(p) {"
16068                       "  var sum = 0;"
16069                       "  for (var i=0; i<256; ++i) {"
16070                       "    sum += p[i];"
16071                       "  }"
16072                       "  return sum; "
16073                       "}"
16074                       "for (var i = 0; i < 5000; ++i) {"
16075                       "  pa_init(pixels);"
16076                       "}"
16077                       "result = pa_load(pixels);"
16078                       "result");
16079   CHECK_EQ(32640, result->Int32Value());
16080
16081   free(pixel_data);
16082 }
16083
16084
16085 THREADED_TEST(PixelArrayInfo) {
16086   LocalContext context;
16087   v8::HandleScope scope(context->GetIsolate());
16088   for (int size = 0; size < 100; size += 10) {
16089     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16090     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16091     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16092     CHECK(obj->HasIndexedPropertiesInPixelData());
16093     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16094     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16095     free(pixel_data);
16096   }
16097 }
16098
16099
16100 static void NotHandledIndexedPropertyGetter(
16101     uint32_t index,
16102     const v8::PropertyCallbackInfo<v8::Value>& info) {
16103   ApiTestFuzzer::Fuzz();
16104 }
16105
16106
16107 static void NotHandledIndexedPropertySetter(
16108     uint32_t index,
16109     Local<Value> value,
16110     const v8::PropertyCallbackInfo<v8::Value>& info) {
16111   ApiTestFuzzer::Fuzz();
16112 }
16113
16114
16115 THREADED_TEST(PixelArrayWithInterceptor) {
16116   LocalContext context;
16117   i::Factory* factory = CcTest::i_isolate()->factory();
16118   v8::Isolate* isolate = context->GetIsolate();
16119   v8::HandleScope scope(isolate);
16120   const int kElementCount = 260;
16121   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16122   i::Handle<i::ExternalUint8ClampedArray> pixels =
16123       i::Handle<i::ExternalUint8ClampedArray>::cast(
16124           factory->NewExternalArray(kElementCount,
16125                                     v8::kExternalUint8ClampedArray,
16126                                     pixel_data));
16127   for (int i = 0; i < kElementCount; i++) {
16128     pixels->set(i, i % 256);
16129   }
16130   v8::Handle<v8::ObjectTemplate> templ =
16131       v8::ObjectTemplate::New(context->GetIsolate());
16132   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16133                                    NotHandledIndexedPropertySetter);
16134   v8::Handle<v8::Object> obj = templ->NewInstance();
16135   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16136   context->Global()->Set(v8_str("pixels"), obj);
16137   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16138   CHECK_EQ(1, result->Int32Value());
16139   result = CompileRun("var sum = 0;"
16140                       "for (var i = 0; i < 8; i++) {"
16141                       "  sum += pixels[i] = pixels[i] = -i;"
16142                       "}"
16143                       "sum;");
16144   CHECK_EQ(-28, result->Int32Value());
16145   result = CompileRun("pixels.hasOwnProperty('1')");
16146   CHECK(result->BooleanValue());
16147   free(pixel_data);
16148 }
16149
16150
16151 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16152   switch (array_type) {
16153     case v8::kExternalInt8Array:
16154     case v8::kExternalUint8Array:
16155     case v8::kExternalUint8ClampedArray:
16156       return 1;
16157       break;
16158     case v8::kExternalInt16Array:
16159     case v8::kExternalUint16Array:
16160       return 2;
16161       break;
16162     case v8::kExternalInt32Array:
16163     case v8::kExternalUint32Array:
16164     case v8::kExternalFloat32Array:
16165       return 4;
16166       break;
16167     case v8::kExternalFloat64Array:
16168       return 8;
16169       break;
16170     default:
16171       UNREACHABLE();
16172       return -1;
16173   }
16174   UNREACHABLE();
16175   return -1;
16176 }
16177
16178
16179 template <class ExternalArrayClass, class ElementType>
16180 static void ObjectWithExternalArrayTestHelper(
16181     Handle<Context> context,
16182     v8::Handle<Object> obj,
16183     int element_count,
16184     v8::ExternalArrayType array_type,
16185     int64_t low, int64_t high) {
16186   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16187   i::Isolate* isolate = jsobj->GetIsolate();
16188   obj->Set(v8_str("field"),
16189            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16190   context->Global()->Set(v8_str("ext_array"), obj);
16191   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16192   CHECK_EQ(1503, result->Int32Value());
16193   result = CompileRun("ext_array[1]");
16194   CHECK_EQ(1, result->Int32Value());
16195
16196   // Check assigned smis
16197   result = CompileRun("for (var i = 0; i < 8; i++) {"
16198                       "  ext_array[i] = i;"
16199                       "}"
16200                       "var sum = 0;"
16201                       "for (var i = 0; i < 8; i++) {"
16202                       "  sum += ext_array[i];"
16203                       "}"
16204                       "sum;");
16205
16206   CHECK_EQ(28, result->Int32Value());
16207   // Check pass through of assigned smis
16208   result = CompileRun("var sum = 0;"
16209                       "for (var i = 0; i < 8; i++) {"
16210                       "  sum += ext_array[i] = ext_array[i] = -i;"
16211                       "}"
16212                       "sum;");
16213   CHECK_EQ(-28, result->Int32Value());
16214
16215
16216   // Check assigned smis in reverse order
16217   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16218                       "  ext_array[i] = i;"
16219                       "}"
16220                       "var sum = 0;"
16221                       "for (var i = 0; i < 8; i++) {"
16222                       "  sum += ext_array[i];"
16223                       "}"
16224                       "sum;");
16225   CHECK_EQ(28, result->Int32Value());
16226
16227   // Check pass through of assigned HeapNumbers
16228   result = CompileRun("var sum = 0;"
16229                       "for (var i = 0; i < 16; i+=2) {"
16230                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16231                       "}"
16232                       "sum;");
16233   CHECK_EQ(-28, result->Int32Value());
16234
16235   // Check assigned HeapNumbers
16236   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16237                       "  ext_array[i] = (i * 0.5);"
16238                       "}"
16239                       "var sum = 0;"
16240                       "for (var i = 0; i < 16; i+=2) {"
16241                       "  sum += ext_array[i];"
16242                       "}"
16243                       "sum;");
16244   CHECK_EQ(28, result->Int32Value());
16245
16246   // Check assigned HeapNumbers in reverse order
16247   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16248                       "  ext_array[i] = (i * 0.5);"
16249                       "}"
16250                       "var sum = 0;"
16251                       "for (var i = 0; i < 16; i+=2) {"
16252                       "  sum += ext_array[i];"
16253                       "}"
16254                       "sum;");
16255   CHECK_EQ(28, result->Int32Value());
16256
16257   i::ScopedVector<char> test_buf(1024);
16258
16259   // Check legal boundary conditions.
16260   // The repeated loads and stores ensure the ICs are exercised.
16261   const char* boundary_program =
16262       "var res = 0;"
16263       "for (var i = 0; i < 16; i++) {"
16264       "  ext_array[i] = %lld;"
16265       "  if (i > 8) {"
16266       "    res = ext_array[i];"
16267       "  }"
16268       "}"
16269       "res;";
16270   i::OS::SNPrintF(test_buf,
16271                   boundary_program,
16272                   low);
16273   result = CompileRun(test_buf.start());
16274   CHECK_EQ(low, result->IntegerValue());
16275
16276   i::OS::SNPrintF(test_buf,
16277                   boundary_program,
16278                   high);
16279   result = CompileRun(test_buf.start());
16280   CHECK_EQ(high, result->IntegerValue());
16281
16282   // Check misprediction of type in IC.
16283   result = CompileRun("var tmp_array = ext_array;"
16284                       "var sum = 0;"
16285                       "for (var i = 0; i < 8; i++) {"
16286                       "  tmp_array[i] = i;"
16287                       "  sum += tmp_array[i];"
16288                       "  if (i == 4) {"
16289                       "    tmp_array = {};"
16290                       "  }"
16291                       "}"
16292                       "sum;");
16293   // Force GC to trigger verification.
16294   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16295   CHECK_EQ(28, result->Int32Value());
16296
16297   // Make sure out-of-range loads do not throw.
16298   i::OS::SNPrintF(test_buf,
16299                   "var caught_exception = false;"
16300                   "try {"
16301                   "  ext_array[%d];"
16302                   "} catch (e) {"
16303                   "  caught_exception = true;"
16304                   "}"
16305                   "caught_exception;",
16306                   element_count);
16307   result = CompileRun(test_buf.start());
16308   CHECK_EQ(false, result->BooleanValue());
16309
16310   // Make sure out-of-range stores do not throw.
16311   i::OS::SNPrintF(test_buf,
16312                   "var caught_exception = false;"
16313                   "try {"
16314                   "  ext_array[%d] = 1;"
16315                   "} catch (e) {"
16316                   "  caught_exception = true;"
16317                   "}"
16318                   "caught_exception;",
16319                   element_count);
16320   result = CompileRun(test_buf.start());
16321   CHECK_EQ(false, result->BooleanValue());
16322
16323   // Check other boundary conditions, values and operations.
16324   result = CompileRun("for (var i = 0; i < 8; i++) {"
16325                       "  ext_array[7] = undefined;"
16326                       "}"
16327                       "ext_array[7];");
16328   CHECK_EQ(0, result->Int32Value());
16329   if (array_type == v8::kExternalFloat64Array ||
16330       array_type == v8::kExternalFloat32Array) {
16331     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
16332              static_cast<int>(
16333                  jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
16334   } else {
16335     CheckElementValue(isolate, 0, jsobj, 7);
16336   }
16337
16338   result = CompileRun("for (var i = 0; i < 8; i++) {"
16339                       "  ext_array[6] = '2.3';"
16340                       "}"
16341                       "ext_array[6];");
16342   CHECK_EQ(2, result->Int32Value());
16343   CHECK_EQ(2,
16344            static_cast<int>(
16345                jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
16346
16347   if (array_type != v8::kExternalFloat32Array &&
16348       array_type != v8::kExternalFloat64Array) {
16349     // Though the specification doesn't state it, be explicit about
16350     // converting NaNs and +/-Infinity to zero.
16351     result = CompileRun("for (var i = 0; i < 8; i++) {"
16352                         "  ext_array[i] = 5;"
16353                         "}"
16354                         "for (var i = 0; i < 8; i++) {"
16355                         "  ext_array[i] = NaN;"
16356                         "}"
16357                         "ext_array[5];");
16358     CHECK_EQ(0, result->Int32Value());
16359     CheckElementValue(isolate, 0, jsobj, 5);
16360
16361     result = CompileRun("for (var i = 0; i < 8; i++) {"
16362                         "  ext_array[i] = 5;"
16363                         "}"
16364                         "for (var i = 0; i < 8; i++) {"
16365                         "  ext_array[i] = Infinity;"
16366                         "}"
16367                         "ext_array[5];");
16368     int expected_value =
16369         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16370     CHECK_EQ(expected_value, result->Int32Value());
16371     CheckElementValue(isolate, expected_value, jsobj, 5);
16372
16373     result = CompileRun("for (var i = 0; i < 8; i++) {"
16374                         "  ext_array[i] = 5;"
16375                         "}"
16376                         "for (var i = 0; i < 8; i++) {"
16377                         "  ext_array[i] = -Infinity;"
16378                         "}"
16379                         "ext_array[5];");
16380     CHECK_EQ(0, result->Int32Value());
16381     CheckElementValue(isolate, 0, jsobj, 5);
16382
16383     // Check truncation behavior of integral arrays.
16384     const char* unsigned_data =
16385         "var source_data = [0.6, 10.6];"
16386         "var expected_results = [0, 10];";
16387     const char* signed_data =
16388         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16389         "var expected_results = [0, 10, 0, -10];";
16390     const char* pixel_data =
16391         "var source_data = [0.6, 10.6];"
16392         "var expected_results = [1, 11];";
16393     bool is_unsigned =
16394         (array_type == v8::kExternalUint8Array ||
16395          array_type == v8::kExternalUint16Array ||
16396          array_type == v8::kExternalUint32Array);
16397     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16398
16399     i::OS::SNPrintF(test_buf,
16400                     "%s"
16401                     "var all_passed = true;"
16402                     "for (var i = 0; i < source_data.length; i++) {"
16403                     "  for (var j = 0; j < 8; j++) {"
16404                     "    ext_array[j] = source_data[i];"
16405                     "  }"
16406                     "  all_passed = all_passed &&"
16407                     "               (ext_array[5] == expected_results[i]);"
16408                     "}"
16409                     "all_passed;",
16410                     (is_unsigned ?
16411                          unsigned_data :
16412                          (is_pixel_data ? pixel_data : signed_data)));
16413     result = CompileRun(test_buf.start());
16414     CHECK_EQ(true, result->BooleanValue());
16415   }
16416
16417   i::Handle<ExternalArrayClass> array(
16418       ExternalArrayClass::cast(jsobj->elements()));
16419   for (int i = 0; i < element_count; i++) {
16420     array->set(i, static_cast<ElementType>(i));
16421   }
16422
16423   // Test complex assignments
16424   result = CompileRun("function ee_op_test_complex_func(sum) {"
16425                       " for (var i = 0; i < 40; ++i) {"
16426                       "   sum += (ext_array[i] += 1);"
16427                       "   sum += (ext_array[i] -= 1);"
16428                       " } "
16429                       " return sum;"
16430                       "}"
16431                       "sum=0;"
16432                       "for (var i=0;i<10000;++i) {"
16433                       "  sum=ee_op_test_complex_func(sum);"
16434                       "}"
16435                       "sum;");
16436   CHECK_EQ(16000000, result->Int32Value());
16437
16438   // Test count operations
16439   result = CompileRun("function ee_op_test_count_func(sum) {"
16440                       " for (var i = 0; i < 40; ++i) {"
16441                       "   sum += (++ext_array[i]);"
16442                       "   sum += (--ext_array[i]);"
16443                       " } "
16444                       " return sum;"
16445                       "}"
16446                       "sum=0;"
16447                       "for (var i=0;i<10000;++i) {"
16448                       "  sum=ee_op_test_count_func(sum);"
16449                       "}"
16450                       "sum;");
16451   CHECK_EQ(16000000, result->Int32Value());
16452
16453   result = CompileRun("ext_array[3] = 33;"
16454                       "delete ext_array[3];"
16455                       "ext_array[3];");
16456   CHECK_EQ(33, result->Int32Value());
16457
16458   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16459                       "ext_array[2] = 12; ext_array[3] = 13;"
16460                       "ext_array.__defineGetter__('2',"
16461                       "function() { return 120; });"
16462                       "ext_array[2];");
16463   CHECK_EQ(12, result->Int32Value());
16464
16465   result = CompileRun("var js_array = new Array(40);"
16466                       "js_array[0] = 77;"
16467                       "js_array;");
16468   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16469
16470   result = CompileRun("ext_array[1] = 23;"
16471                       "ext_array.__proto__ = [];"
16472                       "js_array.__proto__ = ext_array;"
16473                       "js_array.concat(ext_array);");
16474   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16475   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16476
16477   result = CompileRun("ext_array[1] = 23;");
16478   CHECK_EQ(23, result->Int32Value());
16479 }
16480
16481
16482 template <class FixedTypedArrayClass,
16483           i::ElementsKind elements_kind,
16484           class ElementType>
16485 static void FixedTypedArrayTestHelper(
16486     v8::ExternalArrayType array_type,
16487     ElementType low,
16488     ElementType high) {
16489   i::FLAG_allow_natives_syntax = true;
16490   LocalContext context;
16491   i::Isolate* isolate = CcTest::i_isolate();
16492   i::Factory* factory = isolate->factory();
16493   v8::HandleScope scope(context->GetIsolate());
16494   const int kElementCount = 260;
16495   i::Handle<FixedTypedArrayClass> fixed_array =
16496     i::Handle<FixedTypedArrayClass>::cast(
16497         factory->NewFixedTypedArray(kElementCount, array_type));
16498   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16499            fixed_array->map()->instance_type());
16500   CHECK_EQ(kElementCount, fixed_array->length());
16501   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16502   for (int i = 0; i < kElementCount; i++) {
16503     fixed_array->set(i, static_cast<ElementType>(i));
16504   }
16505   // Force GC to trigger verification.
16506   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16507   for (int i = 0; i < kElementCount; i++) {
16508     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16509              static_cast<int64_t>(fixed_array->get_scalar(i)));
16510   }
16511   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16512   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16513   i::Handle<i::Map> fixed_array_map =
16514       isolate->factory()->GetElementsTransitionMap(jsobj, elements_kind);
16515   jsobj->set_map(*fixed_array_map);
16516   jsobj->set_elements(*fixed_array);
16517
16518   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16519       context.local(), obj, kElementCount, array_type,
16520       static_cast<int64_t>(low),
16521       static_cast<int64_t>(high));
16522 }
16523
16524
16525 THREADED_TEST(FixedUint8Array) {
16526   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16527     v8::kExternalUint8Array,
16528     0x0, 0xFF);
16529 }
16530
16531
16532 THREADED_TEST(FixedUint8ClampedArray) {
16533   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16534                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16535     v8::kExternalUint8ClampedArray,
16536     0x0, 0xFF);
16537 }
16538
16539
16540 THREADED_TEST(FixedInt8Array) {
16541   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16542     v8::kExternalInt8Array,
16543     -0x80, 0x7F);
16544 }
16545
16546
16547 THREADED_TEST(FixedUint16Array) {
16548   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16549     v8::kExternalUint16Array,
16550     0x0, 0xFFFF);
16551 }
16552
16553
16554 THREADED_TEST(FixedInt16Array) {
16555   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16556     v8::kExternalInt16Array,
16557     -0x8000, 0x7FFF);
16558 }
16559
16560
16561 THREADED_TEST(FixedUint32Array) {
16562   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16563     v8::kExternalUint32Array,
16564     0x0, UINT_MAX);
16565 }
16566
16567
16568 THREADED_TEST(FixedInt32Array) {
16569   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16570     v8::kExternalInt32Array,
16571     INT_MIN, INT_MAX);
16572 }
16573
16574
16575 THREADED_TEST(FixedFloat32Array) {
16576   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16577     v8::kExternalFloat32Array,
16578     -500, 500);
16579 }
16580
16581
16582 THREADED_TEST(FixedFloat64Array) {
16583   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16584     v8::kExternalFloat64Array,
16585     -500, 500);
16586 }
16587
16588
16589 template <class ExternalArrayClass, class ElementType>
16590 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16591                                     int64_t low,
16592                                     int64_t high) {
16593   LocalContext context;
16594   i::Isolate* isolate = CcTest::i_isolate();
16595   i::Factory* factory = isolate->factory();
16596   v8::HandleScope scope(context->GetIsolate());
16597   const int kElementCount = 40;
16598   int element_size = ExternalArrayElementSize(array_type);
16599   ElementType* array_data =
16600       static_cast<ElementType*>(malloc(kElementCount * element_size));
16601   i::Handle<ExternalArrayClass> array =
16602       i::Handle<ExternalArrayClass>::cast(
16603           factory->NewExternalArray(kElementCount, array_type, array_data));
16604   // Force GC to trigger verification.
16605   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16606   for (int i = 0; i < kElementCount; i++) {
16607     array->set(i, static_cast<ElementType>(i));
16608   }
16609   // Force GC to trigger verification.
16610   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16611   for (int i = 0; i < kElementCount; i++) {
16612     CHECK_EQ(static_cast<int64_t>(i),
16613              static_cast<int64_t>(array->get_scalar(i)));
16614     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16615   }
16616
16617   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16618   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16619   // Set the elements to be the external array.
16620   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16621                                                array_type,
16622                                                kElementCount);
16623   CHECK_EQ(1,
16624            static_cast<int>(
16625                jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
16626
16627   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16628       context.local(), obj, kElementCount, array_type, low, high);
16629
16630   v8::Handle<v8::Value> result;
16631
16632   // Test more complex manipulations which cause eax to contain values
16633   // that won't be completely overwritten by loads from the arrays.
16634   // This catches bugs in the instructions used for the KeyedLoadIC
16635   // for byte and word types.
16636   {
16637     const int kXSize = 300;
16638     const int kYSize = 300;
16639     const int kLargeElementCount = kXSize * kYSize * 4;
16640     ElementType* large_array_data =
16641         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16642     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16643     // Set the elements to be the external array.
16644     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16645                                                        array_type,
16646                                                        kLargeElementCount);
16647     context->Global()->Set(v8_str("large_array"), large_obj);
16648     // Initialize contents of a few rows.
16649     for (int x = 0; x < 300; x++) {
16650       int row = 0;
16651       int offset = row * 300 * 4;
16652       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16653       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16654       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16655       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16656       row = 150;
16657       offset = row * 300 * 4;
16658       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16659       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16660       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16661       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16662       row = 298;
16663       offset = row * 300 * 4;
16664       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16665       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16666       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16667       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16668     }
16669     // The goal of the code below is to make "offset" large enough
16670     // that the computation of the index (which goes into eax) has
16671     // high bits set which will not be overwritten by a byte or short
16672     // load.
16673     result = CompileRun("var failed = false;"
16674                         "var offset = 0;"
16675                         "for (var i = 0; i < 300; i++) {"
16676                         "  if (large_array[4 * i] != 127 ||"
16677                         "      large_array[4 * i + 1] != 0 ||"
16678                         "      large_array[4 * i + 2] != 0 ||"
16679                         "      large_array[4 * i + 3] != 127) {"
16680                         "    failed = true;"
16681                         "  }"
16682                         "}"
16683                         "offset = 150 * 300 * 4;"
16684                         "for (var i = 0; i < 300; i++) {"
16685                         "  if (large_array[offset + 4 * i] != 127 ||"
16686                         "      large_array[offset + 4 * i + 1] != 0 ||"
16687                         "      large_array[offset + 4 * i + 2] != 0 ||"
16688                         "      large_array[offset + 4 * i + 3] != 127) {"
16689                         "    failed = true;"
16690                         "  }"
16691                         "}"
16692                         "offset = 298 * 300 * 4;"
16693                         "for (var i = 0; i < 300; i++) {"
16694                         "  if (large_array[offset + 4 * i] != 127 ||"
16695                         "      large_array[offset + 4 * i + 1] != 0 ||"
16696                         "      large_array[offset + 4 * i + 2] != 0 ||"
16697                         "      large_array[offset + 4 * i + 3] != 127) {"
16698                         "    failed = true;"
16699                         "  }"
16700                         "}"
16701                         "!failed;");
16702     CHECK_EQ(true, result->BooleanValue());
16703     free(large_array_data);
16704   }
16705
16706   // The "" property descriptor is overloaded to store information about
16707   // the external array. Ensure that setting and accessing the "" property
16708   // works (it should overwrite the information cached about the external
16709   // array in the DescriptorArray) in various situations.
16710   result = CompileRun("ext_array[''] = 23; ext_array['']");
16711   CHECK_EQ(23, result->Int32Value());
16712
16713   // Property "" set after the external array is associated with the object.
16714   {
16715     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16716     obj2->Set(v8_str("ee_test_field"),
16717               v8::Int32::New(context->GetIsolate(), 256));
16718     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16719     // Set the elements to be the external array.
16720     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16721                                                   array_type,
16722                                                   kElementCount);
16723     context->Global()->Set(v8_str("ext_array"), obj2);
16724     result = CompileRun("ext_array['']");
16725     CHECK_EQ(1503, result->Int32Value());
16726   }
16727
16728   // Property "" set after the external array is associated with the object.
16729   {
16730     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16731     obj2->Set(v8_str("ee_test_field_2"),
16732               v8::Int32::New(context->GetIsolate(), 256));
16733     // Set the elements to be the external array.
16734     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16735                                                   array_type,
16736                                                   kElementCount);
16737     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16738     context->Global()->Set(v8_str("ext_array"), obj2);
16739     result = CompileRun("ext_array['']");
16740     CHECK_EQ(1503, result->Int32Value());
16741   }
16742
16743   // Should reuse the map from previous test.
16744   {
16745     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16746     obj2->Set(v8_str("ee_test_field_2"),
16747               v8::Int32::New(context->GetIsolate(), 256));
16748     // Set the elements to be the external array. Should re-use the map
16749     // from previous test.
16750     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16751                                                   array_type,
16752                                                   kElementCount);
16753     context->Global()->Set(v8_str("ext_array"), obj2);
16754     result = CompileRun("ext_array['']");
16755   }
16756
16757   // Property "" is a constant function that shouldn't not be interfered with
16758   // when an external array is set.
16759   {
16760     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16761     // Start
16762     obj2->Set(v8_str("ee_test_field3"),
16763               v8::Int32::New(context->GetIsolate(), 256));
16764
16765     // Add a constant function to an object.
16766     context->Global()->Set(v8_str("ext_array"), obj2);
16767     result = CompileRun("ext_array[''] = function() {return 1503;};"
16768                         "ext_array['']();");
16769
16770     // Add an external array transition to the same map that
16771     // has the constant transition.
16772     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16773     obj3->Set(v8_str("ee_test_field3"),
16774               v8::Int32::New(context->GetIsolate(), 256));
16775     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16776                                                   array_type,
16777                                                   kElementCount);
16778     context->Global()->Set(v8_str("ext_array"), obj3);
16779   }
16780
16781   // If a external array transition is in the map, it should get clobbered
16782   // by a constant function.
16783   {
16784     // Add an external array transition.
16785     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16786     obj3->Set(v8_str("ee_test_field4"),
16787               v8::Int32::New(context->GetIsolate(), 256));
16788     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16789                                                   array_type,
16790                                                   kElementCount);
16791
16792     // Add a constant function to the same map that just got an external array
16793     // transition.
16794     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16795     obj2->Set(v8_str("ee_test_field4"),
16796               v8::Int32::New(context->GetIsolate(), 256));
16797     context->Global()->Set(v8_str("ext_array"), obj2);
16798     result = CompileRun("ext_array[''] = function() {return 1503;};"
16799                         "ext_array['']();");
16800   }
16801
16802   free(array_data);
16803 }
16804
16805
16806 THREADED_TEST(ExternalInt8Array) {
16807   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16808       v8::kExternalInt8Array,
16809       -128,
16810       127);
16811 }
16812
16813
16814 THREADED_TEST(ExternalUint8Array) {
16815   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16816       v8::kExternalUint8Array,
16817       0,
16818       255);
16819 }
16820
16821
16822 THREADED_TEST(ExternalUint8ClampedArray) {
16823   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16824       v8::kExternalUint8ClampedArray,
16825       0,
16826       255);
16827 }
16828
16829
16830 THREADED_TEST(ExternalInt16Array) {
16831   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16832       v8::kExternalInt16Array,
16833       -32768,
16834       32767);
16835 }
16836
16837
16838 THREADED_TEST(ExternalUint16Array) {
16839   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16840       v8::kExternalUint16Array,
16841       0,
16842       65535);
16843 }
16844
16845
16846 THREADED_TEST(ExternalInt32Array) {
16847   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16848       v8::kExternalInt32Array,
16849       INT_MIN,   // -2147483648
16850       INT_MAX);  //  2147483647
16851 }
16852
16853
16854 THREADED_TEST(ExternalUint32Array) {
16855   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16856       v8::kExternalUint32Array,
16857       0,
16858       UINT_MAX);  // 4294967295
16859 }
16860
16861
16862 THREADED_TEST(ExternalFloat32Array) {
16863   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16864       v8::kExternalFloat32Array,
16865       -500,
16866       500);
16867 }
16868
16869
16870 THREADED_TEST(ExternalFloat64Array) {
16871   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16872       v8::kExternalFloat64Array,
16873       -500,
16874       500);
16875 }
16876
16877
16878 THREADED_TEST(ExternalArrays) {
16879   TestExternalInt8Array();
16880   TestExternalUint8Array();
16881   TestExternalInt16Array();
16882   TestExternalUint16Array();
16883   TestExternalInt32Array();
16884   TestExternalUint32Array();
16885   TestExternalFloat32Array();
16886 }
16887
16888
16889 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16890   LocalContext context;
16891   v8::HandleScope scope(context->GetIsolate());
16892   for (int size = 0; size < 100; size += 10) {
16893     int element_size = ExternalArrayElementSize(array_type);
16894     void* external_data = malloc(size * element_size);
16895     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16896     obj->SetIndexedPropertiesToExternalArrayData(
16897         external_data, array_type, size);
16898     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16899     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16900     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16901     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16902     free(external_data);
16903   }
16904 }
16905
16906
16907 THREADED_TEST(ExternalArrayInfo) {
16908   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16909   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16910   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16911   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16912   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16913   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16914   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16915   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16916   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16917 }
16918
16919
16920 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16921                           v8::ExternalArrayType array_type,
16922                           int size) {
16923   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16924   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16925   last_location = last_message = NULL;
16926   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16927   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16928   CHECK_NE(NULL, last_location);
16929   CHECK_NE(NULL, last_message);
16930 }
16931
16932
16933 TEST(ExternalArrayLimits) {
16934   LocalContext context;
16935   v8::Isolate* isolate = context->GetIsolate();
16936   v8::HandleScope scope(isolate);
16937   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16938   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16939   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16940   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16941   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16942   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16943   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16944   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16945   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16946   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16947   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16948   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16949   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16950   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16951   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16952   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16953   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16954   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16955 }
16956
16957
16958 template <typename ElementType, typename TypedArray,
16959           class ExternalArrayClass>
16960 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16961                           int64_t low, int64_t high) {
16962   const int kElementCount = 50;
16963
16964   i::ScopedVector<ElementType> backing_store(kElementCount+2);
16965
16966   LocalContext env;
16967   v8::Isolate* isolate = env->GetIsolate();
16968   v8::HandleScope handle_scope(isolate);
16969
16970   Local<v8::ArrayBuffer> ab =
16971       v8::ArrayBuffer::New(isolate, backing_store.start(),
16972                            (kElementCount + 2) * sizeof(ElementType));
16973   Local<TypedArray> ta =
16974       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16975   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16976   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16977   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16978   CHECK_EQ(kElementCount*sizeof(ElementType),
16979            static_cast<int>(ta->ByteLength()));
16980   CHECK_EQ(ab, ta->Buffer());
16981
16982   ElementType* data = backing_store.start() + 2;
16983   for (int i = 0; i < kElementCount; i++) {
16984     data[i] = static_cast<ElementType>(i);
16985   }
16986
16987   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16988       env.local(), ta, kElementCount, array_type, low, high);
16989 }
16990
16991
16992 THREADED_TEST(Uint8Array) {
16993   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16994       v8::kExternalUint8Array, 0, 0xFF);
16995 }
16996
16997
16998 THREADED_TEST(Int8Array) {
16999   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17000       v8::kExternalInt8Array, -0x80, 0x7F);
17001 }
17002
17003
17004 THREADED_TEST(Uint16Array) {
17005   TypedArrayTestHelper<uint16_t,
17006                        v8::Uint16Array,
17007                        i::ExternalUint16Array>(
17008       v8::kExternalUint16Array, 0, 0xFFFF);
17009 }
17010
17011
17012 THREADED_TEST(Int16Array) {
17013   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17014       v8::kExternalInt16Array, -0x8000, 0x7FFF);
17015 }
17016
17017
17018 THREADED_TEST(Uint32Array) {
17019   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17020       v8::kExternalUint32Array, 0, UINT_MAX);
17021 }
17022
17023
17024 THREADED_TEST(Int32Array) {
17025   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17026       v8::kExternalInt32Array, INT_MIN, INT_MAX);
17027 }
17028
17029
17030 THREADED_TEST(Float32Array) {
17031   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17032       v8::kExternalFloat32Array, -500, 500);
17033 }
17034
17035
17036 THREADED_TEST(Float64Array) {
17037   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17038       v8::kExternalFloat64Array, -500, 500);
17039 }
17040
17041
17042 THREADED_TEST(Uint8ClampedArray) {
17043   TypedArrayTestHelper<uint8_t,
17044                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17045       v8::kExternalUint8ClampedArray, 0, 0xFF);
17046 }
17047
17048
17049 THREADED_TEST(DataView) {
17050   const int kSize = 50;
17051
17052   i::ScopedVector<uint8_t> backing_store(kSize+2);
17053
17054   LocalContext env;
17055   v8::Isolate* isolate = env->GetIsolate();
17056   v8::HandleScope handle_scope(isolate);
17057
17058   Local<v8::ArrayBuffer> ab =
17059       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17060   Local<v8::DataView> dv =
17061       v8::DataView::New(ab, 2, kSize);
17062   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17063   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17064   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17065   CHECK_EQ(ab, dv->Buffer());
17066 }
17067
17068
17069 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17070   THREADED_TEST(Is##View) {                                                   \
17071     LocalContext env;                                                         \
17072     v8::Isolate* isolate = env->GetIsolate();                                 \
17073     v8::HandleScope handle_scope(isolate);                                    \
17074                                                                               \
17075     Handle<Value> result = CompileRun(                                        \
17076         "var ab = new ArrayBuffer(128);"                                      \
17077         "new " #View "(ab)");                                                 \
17078     CHECK(result->IsArrayBufferView());                                       \
17079     CHECK(result->Is##View());                                                \
17080     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17081   }
17082
17083 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17084 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17085 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17086 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17087 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17088 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17089 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17090 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17091 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17092 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17093
17094 #undef IS_ARRAY_BUFFER_VIEW_TEST
17095
17096
17097
17098 THREADED_TEST(ScriptContextDependence) {
17099   LocalContext c1;
17100   v8::HandleScope scope(c1->GetIsolate());
17101   const char *source = "foo";
17102   v8::Handle<v8::Script> dep =
17103       v8::Script::Compile(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17104   v8::Handle<v8::Script> indep =
17105       v8::Script::New(v8::String::NewFromUtf8(c1->GetIsolate(), source));
17106   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17107                     v8::Integer::New(c1->GetIsolate(), 100));
17108   CHECK_EQ(dep->Run()->Int32Value(), 100);
17109   CHECK_EQ(indep->Run()->Int32Value(), 100);
17110   LocalContext c2;
17111   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17112                     v8::Integer::New(c2->GetIsolate(), 101));
17113   CHECK_EQ(dep->Run()->Int32Value(), 100);
17114   CHECK_EQ(indep->Run()->Int32Value(), 101);
17115 }
17116
17117
17118 THREADED_TEST(StackTrace) {
17119   LocalContext context;
17120   v8::HandleScope scope(context->GetIsolate());
17121   v8::TryCatch try_catch;
17122   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17123   v8::Handle<v8::String> src =
17124       v8::String::NewFromUtf8(context->GetIsolate(), source);
17125   v8::Handle<v8::String> origin =
17126       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17127   v8::Script::New(src, origin)->Run();
17128   CHECK(try_catch.HasCaught());
17129   v8::String::Utf8Value stack(try_catch.StackTrace());
17130   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17131 }
17132
17133
17134 // Checks that a StackFrame has certain expected values.
17135 void checkStackFrame(const char* expected_script_name,
17136     const char* expected_func_name, int expected_line_number,
17137     int expected_column, bool is_eval, bool is_constructor,
17138     v8::Handle<v8::StackFrame> frame) {
17139   v8::HandleScope scope(CcTest::isolate());
17140   v8::String::Utf8Value func_name(frame->GetFunctionName());
17141   v8::String::Utf8Value script_name(frame->GetScriptName());
17142   if (*script_name == NULL) {
17143     // The situation where there is no associated script, like for evals.
17144     CHECK(expected_script_name == NULL);
17145   } else {
17146     CHECK(strstr(*script_name, expected_script_name) != NULL);
17147   }
17148   CHECK(strstr(*func_name, expected_func_name) != NULL);
17149   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17150   CHECK_EQ(expected_column, frame->GetColumn());
17151   CHECK_EQ(is_eval, frame->IsEval());
17152   CHECK_EQ(is_constructor, frame->IsConstructor());
17153 }
17154
17155
17156 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17157   v8::HandleScope scope(args.GetIsolate());
17158   const char* origin = "capture-stack-trace-test";
17159   const int kOverviewTest = 1;
17160   const int kDetailedTest = 2;
17161
17162   ASSERT(args.Length() == 1);
17163
17164   int testGroup = args[0]->Int32Value();
17165   if (testGroup == kOverviewTest) {
17166     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17167         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17168     CHECK_EQ(4, stackTrace->GetFrameCount());
17169     checkStackFrame(origin, "bar", 2, 10, false, false,
17170                     stackTrace->GetFrame(0));
17171     checkStackFrame(origin, "foo", 6, 3, false, false,
17172                     stackTrace->GetFrame(1));
17173     // This is the source string inside the eval which has the call to foo.
17174     checkStackFrame(NULL, "", 1, 5, false, false,
17175                     stackTrace->GetFrame(2));
17176     // The last frame is an anonymous function which has the initial eval call.
17177     checkStackFrame(origin, "", 8, 7, false, false,
17178                     stackTrace->GetFrame(3));
17179
17180     CHECK(stackTrace->AsArray()->IsArray());
17181   } else if (testGroup == kDetailedTest) {
17182     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17183         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17184     CHECK_EQ(4, stackTrace->GetFrameCount());
17185     checkStackFrame(origin, "bat", 4, 22, false, false,
17186                     stackTrace->GetFrame(0));
17187     checkStackFrame(origin, "baz", 8, 3, false, true,
17188                     stackTrace->GetFrame(1));
17189 #ifdef ENABLE_DEBUGGER_SUPPORT
17190     bool is_eval = true;
17191 #else  // ENABLE_DEBUGGER_SUPPORT
17192     bool is_eval = false;
17193 #endif  // ENABLE_DEBUGGER_SUPPORT
17194
17195     // This is the source string inside the eval which has the call to baz.
17196     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17197                     stackTrace->GetFrame(2));
17198     // The last frame is an anonymous function which has the initial eval call.
17199     checkStackFrame(origin, "", 10, 1, false, false,
17200                     stackTrace->GetFrame(3));
17201
17202     CHECK(stackTrace->AsArray()->IsArray());
17203   }
17204 }
17205
17206
17207 // Tests the C++ StackTrace API.
17208 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17209 // THREADED_TEST(CaptureStackTrace) {
17210 TEST(CaptureStackTrace) {
17211   v8::Isolate* isolate = CcTest::isolate();
17212   v8::HandleScope scope(isolate);
17213   v8::Handle<v8::String> origin =
17214       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17215   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17216   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17217              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17218   LocalContext context(0, templ);
17219
17220   // Test getting OVERVIEW information. Should ignore information that is not
17221   // script name, function name, line number, and column offset.
17222   const char *overview_source =
17223     "function bar() {\n"
17224     "  var y; AnalyzeStackInNativeCode(1);\n"
17225     "}\n"
17226     "function foo() {\n"
17227     "\n"
17228     "  bar();\n"
17229     "}\n"
17230     "var x;eval('new foo();');";
17231   v8::Handle<v8::String> overview_src =
17232       v8::String::NewFromUtf8(isolate, overview_source);
17233   v8::Handle<Value> overview_result(
17234       v8::Script::New(overview_src, origin)->Run());
17235   CHECK(!overview_result.IsEmpty());
17236   CHECK(overview_result->IsObject());
17237
17238   // Test getting DETAILED information.
17239   const char *detailed_source =
17240     "function bat() {AnalyzeStackInNativeCode(2);\n"
17241     "}\n"
17242     "\n"
17243     "function baz() {\n"
17244     "  bat();\n"
17245     "}\n"
17246     "eval('new baz();');";
17247   v8::Handle<v8::String> detailed_src =
17248       v8::String::NewFromUtf8(isolate, detailed_source);
17249   // Make the script using a non-zero line and column offset.
17250   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17251   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17252   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17253   v8::Handle<v8::Script> detailed_script(
17254       v8::Script::New(detailed_src, &detailed_origin));
17255   v8::Handle<Value> detailed_result(detailed_script->Run());
17256   CHECK(!detailed_result.IsEmpty());
17257   CHECK(detailed_result->IsObject());
17258 }
17259
17260
17261 static void StackTraceForUncaughtExceptionListener(
17262     v8::Handle<v8::Message> message,
17263     v8::Handle<Value>) {
17264   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17265   CHECK_EQ(2, stack_trace->GetFrameCount());
17266   checkStackFrame("origin", "foo", 2, 3, false, false,
17267                   stack_trace->GetFrame(0));
17268   checkStackFrame("origin", "bar", 5, 3, false, false,
17269                   stack_trace->GetFrame(1));
17270 }
17271
17272
17273 TEST(CaptureStackTraceForUncaughtException) {
17274   report_count = 0;
17275   LocalContext env;
17276   v8::HandleScope scope(env->GetIsolate());
17277   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17278   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17279
17280   Script::Compile(v8_str("function foo() {\n"
17281                          "  throw 1;\n"
17282                          "};\n"
17283                          "function bar() {\n"
17284                          "  foo();\n"
17285                          "};"),
17286                   v8_str("origin"))->Run();
17287   v8::Local<v8::Object> global = env->Global();
17288   Local<Value> trouble = global->Get(v8_str("bar"));
17289   CHECK(trouble->IsFunction());
17290   Function::Cast(*trouble)->Call(global, 0, NULL);
17291   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17292   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17293 }
17294
17295
17296 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17297   LocalContext env;
17298   v8::HandleScope scope(env->GetIsolate());
17299   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17300                                                     1024,
17301                                                     v8::StackTrace::kDetailed);
17302
17303   CompileRun(
17304       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17305       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17306       "    'isConstructor'];\n"
17307       "for (var i = 0; i < setters.length; i++) {\n"
17308       "  var prop = setters[i];\n"
17309       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17310       "}\n");
17311   CompileRun("throw 'exception';");
17312   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17313 }
17314
17315
17316 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17317                                      v8::Handle<v8::Value> data) {
17318   // Use the frame where JavaScript is called from.
17319   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17320   CHECK(!stack_trace.IsEmpty());
17321   int frame_count = stack_trace->GetFrameCount();
17322   CHECK_EQ(3, frame_count);
17323   int line_number[] = {1, 2, 5};
17324   for (int i = 0; i < frame_count; i++) {
17325     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17326   }
17327 }
17328
17329
17330 // Test that we only return the stack trace at the site where the exception
17331 // is first thrown (not where it is rethrown).
17332 TEST(RethrowStackTrace) {
17333   LocalContext env;
17334   v8::HandleScope scope(env->GetIsolate());
17335   // We make sure that
17336   // - the stack trace of the ReferenceError in g() is reported.
17337   // - the stack trace is not overwritten when e1 is rethrown by t().
17338   // - the stack trace of e2 does not overwrite that of e1.
17339   const char* source =
17340       "function g() { error; }          \n"
17341       "function f() { g(); }            \n"
17342       "function t(e) { throw e; }       \n"
17343       "try {                            \n"
17344       "  f();                           \n"
17345       "} catch (e1) {                   \n"
17346       "  try {                          \n"
17347       "    error;                       \n"
17348       "  } catch (e2) {                 \n"
17349       "    t(e1);                       \n"
17350       "  }                              \n"
17351       "}                                \n";
17352   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17353   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17354   CompileRun(source);
17355   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17356   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17357 }
17358
17359
17360 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17361                                               v8::Handle<v8::Value> data) {
17362   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17363   CHECK(!stack_trace.IsEmpty());
17364   int frame_count = stack_trace->GetFrameCount();
17365   CHECK_EQ(2, frame_count);
17366   int line_number[] = {3, 7};
17367   for (int i = 0; i < frame_count; i++) {
17368     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17369   }
17370 }
17371
17372
17373 // Test that we do not recognize identity for primitive exceptions.
17374 TEST(RethrowPrimitiveStackTrace) {
17375   LocalContext env;
17376   v8::HandleScope scope(env->GetIsolate());
17377   // We do not capture stack trace for non Error objects on creation time.
17378   // Instead, we capture the stack trace on last throw.
17379   const char* source =
17380       "function g() { throw 404; }      \n"
17381       "function f() { g(); }            \n"
17382       "function t(e) { throw e; }       \n"
17383       "try {                            \n"
17384       "  f();                           \n"
17385       "} catch (e1) {                   \n"
17386       "  t(e1)                          \n"
17387       "}                                \n";
17388   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17389   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17390   CompileRun(source);
17391   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17392   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17393 }
17394
17395
17396 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17397                                               v8::Handle<v8::Value> data) {
17398   // Use the frame where JavaScript is called from.
17399   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17400   CHECK(!stack_trace.IsEmpty());
17401   CHECK_EQ(1, stack_trace->GetFrameCount());
17402   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17403 }
17404
17405
17406 // Test that the stack trace is captured when the error object is created and
17407 // not where it is thrown.
17408 TEST(RethrowExistingStackTrace) {
17409   LocalContext env;
17410   v8::HandleScope scope(env->GetIsolate());
17411   const char* source =
17412       "var e = new Error();           \n"
17413       "throw e;                       \n";
17414   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17415   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17416   CompileRun(source);
17417   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17418   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17419 }
17420
17421
17422 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17423                                                v8::Handle<v8::Value> data) {
17424   // Use the frame where JavaScript is called from.
17425   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17426   CHECK(!stack_trace.IsEmpty());
17427   CHECK_EQ(1, stack_trace->GetFrameCount());
17428   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17429 }
17430
17431
17432 // Test that the stack trace is captured where the bogus Error object is thrown.
17433 TEST(RethrowBogusErrorStackTrace) {
17434   LocalContext env;
17435   v8::HandleScope scope(env->GetIsolate());
17436   const char* source =
17437       "var e = {__proto__: new Error()} \n"
17438       "throw e;                         \n";
17439   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17440   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17441   CompileRun(source);
17442   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17443   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17444 }
17445
17446
17447 void AnalyzeStackOfEvalWithSourceURL(
17448     const v8::FunctionCallbackInfo<v8::Value>& args) {
17449   v8::HandleScope scope(args.GetIsolate());
17450   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17451       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17452   CHECK_EQ(5, stackTrace->GetFrameCount());
17453   v8::Handle<v8::String> url = v8_str("eval_url");
17454   for (int i = 0; i < 3; i++) {
17455     v8::Handle<v8::String> name =
17456         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17457     CHECK(!name.IsEmpty());
17458     CHECK_EQ(url, name);
17459   }
17460 }
17461
17462
17463 TEST(SourceURLInStackTrace) {
17464   v8::Isolate* isolate = CcTest::isolate();
17465   v8::HandleScope scope(isolate);
17466   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17467   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17468              v8::FunctionTemplate::New(isolate,
17469                                        AnalyzeStackOfEvalWithSourceURL));
17470   LocalContext context(0, templ);
17471
17472   const char *source =
17473     "function outer() {\n"
17474     "function bar() {\n"
17475     "  AnalyzeStackOfEvalWithSourceURL();\n"
17476     "}\n"
17477     "function foo() {\n"
17478     "\n"
17479     "  bar();\n"
17480     "}\n"
17481     "foo();\n"
17482     "}\n"
17483     "eval('(' + outer +')()%s');";
17484
17485   i::ScopedVector<char> code(1024);
17486   i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
17487   CHECK(CompileRun(code.start())->IsUndefined());
17488   i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
17489   CHECK(CompileRun(code.start())->IsUndefined());
17490 }
17491
17492
17493 static int scriptIdInStack[2];
17494
17495 void AnalyzeScriptIdInStack(
17496     const v8::FunctionCallbackInfo<v8::Value>& args) {
17497   v8::HandleScope scope(args.GetIsolate());
17498   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17499       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17500   CHECK_EQ(2, stackTrace->GetFrameCount());
17501   for (int i = 0; i < 2; i++) {
17502     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17503   }
17504 }
17505
17506
17507 TEST(ScriptIdInStackTrace) {
17508   v8::Isolate* isolate = CcTest::isolate();
17509   v8::HandleScope scope(isolate);
17510   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17511   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17512              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17513   LocalContext context(0, templ);
17514
17515   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17516     isolate,
17517     "function foo() {\n"
17518     "  AnalyzeScriptIdInStack();"
17519     "}\n"
17520     "foo();\n");
17521   v8::ScriptOrigin origin =
17522       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"));
17523   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17524   script->Run();
17525   for (int i = 0; i < 2; i++) {
17526     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17527     CHECK_EQ(scriptIdInStack[i], script->GetId());
17528   }
17529 }
17530
17531
17532 void AnalyzeStackOfInlineScriptWithSourceURL(
17533     const v8::FunctionCallbackInfo<v8::Value>& args) {
17534   v8::HandleScope scope(args.GetIsolate());
17535   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17536       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17537   CHECK_EQ(4, stackTrace->GetFrameCount());
17538   v8::Handle<v8::String> url = v8_str("url");
17539   for (int i = 0; i < 3; i++) {
17540     v8::Handle<v8::String> name =
17541         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17542     CHECK(!name.IsEmpty());
17543     CHECK_EQ(url, name);
17544   }
17545 }
17546
17547
17548 TEST(InlineScriptWithSourceURLInStackTrace) {
17549   v8::Isolate* isolate = CcTest::isolate();
17550   v8::HandleScope scope(isolate);
17551   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17552   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17553              v8::FunctionTemplate::New(
17554                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17555   LocalContext context(0, templ);
17556
17557   const char *source =
17558     "function outer() {\n"
17559     "function bar() {\n"
17560     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17561     "}\n"
17562     "function foo() {\n"
17563     "\n"
17564     "  bar();\n"
17565     "}\n"
17566     "foo();\n"
17567     "}\n"
17568     "outer()\n%s";
17569
17570   i::ScopedVector<char> code(1024);
17571   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17572   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17573   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17574   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17575 }
17576
17577
17578 void AnalyzeStackOfDynamicScriptWithSourceURL(
17579     const v8::FunctionCallbackInfo<v8::Value>& args) {
17580   v8::HandleScope scope(args.GetIsolate());
17581   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17582       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17583   CHECK_EQ(4, stackTrace->GetFrameCount());
17584   v8::Handle<v8::String> url = v8_str("source_url");
17585   for (int i = 0; i < 3; i++) {
17586     v8::Handle<v8::String> name =
17587         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17588     CHECK(!name.IsEmpty());
17589     CHECK_EQ(url, name);
17590   }
17591 }
17592
17593
17594 TEST(DynamicWithSourceURLInStackTrace) {
17595   v8::Isolate* isolate = CcTest::isolate();
17596   v8::HandleScope scope(isolate);
17597   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17598   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17599              v8::FunctionTemplate::New(
17600                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17601   LocalContext context(0, templ);
17602
17603   const char *source =
17604     "function outer() {\n"
17605     "function bar() {\n"
17606     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17607     "}\n"
17608     "function foo() {\n"
17609     "\n"
17610     "  bar();\n"
17611     "}\n"
17612     "foo();\n"
17613     "}\n"
17614     "outer()\n%s";
17615
17616   i::ScopedVector<char> code(1024);
17617   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
17618   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17619   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
17620   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17621 }
17622
17623
17624 static void CreateGarbageInOldSpace() {
17625   i::Factory* factory = CcTest::i_isolate()->factory();
17626   v8::HandleScope scope(CcTest::isolate());
17627   i::AlwaysAllocateScope always_allocate;
17628   for (int i = 0; i < 1000; i++) {
17629     factory->NewFixedArray(1000, i::TENURED);
17630   }
17631 }
17632
17633
17634 // Test that idle notification can be handled and eventually returns true.
17635 TEST(IdleNotification) {
17636   const intptr_t MB = 1024 * 1024;
17637   LocalContext env;
17638   v8::HandleScope scope(env->GetIsolate());
17639   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17640   CreateGarbageInOldSpace();
17641   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17642   CHECK_GT(size_with_garbage, initial_size + MB);
17643   bool finished = false;
17644   for (int i = 0; i < 200 && !finished; i++) {
17645     finished = v8::V8::IdleNotification();
17646   }
17647   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17648   CHECK(finished);
17649   CHECK_LT(final_size, initial_size + 1);
17650 }
17651
17652
17653 // Test that idle notification can be handled and eventually collects garbage.
17654 TEST(IdleNotificationWithSmallHint) {
17655   const intptr_t MB = 1024 * 1024;
17656   const int IdlePauseInMs = 900;
17657   LocalContext env;
17658   v8::HandleScope scope(env->GetIsolate());
17659   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17660   CreateGarbageInOldSpace();
17661   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17662   CHECK_GT(size_with_garbage, initial_size + MB);
17663   bool finished = false;
17664   for (int i = 0; i < 200 && !finished; i++) {
17665     finished = v8::V8::IdleNotification(IdlePauseInMs);
17666   }
17667   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17668   CHECK(finished);
17669   CHECK_LT(final_size, initial_size + 1);
17670 }
17671
17672
17673 // Test that idle notification can be handled and eventually collects garbage.
17674 TEST(IdleNotificationWithLargeHint) {
17675   const intptr_t MB = 1024 * 1024;
17676   const int IdlePauseInMs = 900;
17677   LocalContext env;
17678   v8::HandleScope scope(env->GetIsolate());
17679   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17680   CreateGarbageInOldSpace();
17681   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17682   CHECK_GT(size_with_garbage, initial_size + MB);
17683   bool finished = false;
17684   for (int i = 0; i < 200 && !finished; i++) {
17685     finished = v8::V8::IdleNotification(IdlePauseInMs);
17686   }
17687   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17688   CHECK(finished);
17689   CHECK_LT(final_size, initial_size + 1);
17690 }
17691
17692
17693 TEST(Regress2107) {
17694   const intptr_t MB = 1024 * 1024;
17695   const int kShortIdlePauseInMs = 100;
17696   const int kLongIdlePauseInMs = 1000;
17697   LocalContext env;
17698   v8::Isolate* isolate = env->GetIsolate();
17699   v8::HandleScope scope(env->GetIsolate());
17700   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17701   // Send idle notification to start a round of incremental GCs.
17702   v8::V8::IdleNotification(kShortIdlePauseInMs);
17703   // Emulate 7 page reloads.
17704   for (int i = 0; i < 7; i++) {
17705     {
17706       v8::HandleScope inner_scope(env->GetIsolate());
17707       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17708       ctx->Enter();
17709       CreateGarbageInOldSpace();
17710       ctx->Exit();
17711     }
17712     v8::V8::ContextDisposedNotification();
17713     v8::V8::IdleNotification(kLongIdlePauseInMs);
17714   }
17715   // Create garbage and check that idle notification still collects it.
17716   CreateGarbageInOldSpace();
17717   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17718   CHECK_GT(size_with_garbage, initial_size + MB);
17719   bool finished = false;
17720   for (int i = 0; i < 200 && !finished; i++) {
17721     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17722   }
17723   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17724   CHECK_LT(final_size, initial_size + 1);
17725 }
17726
17727
17728 TEST(Regress2333) {
17729   LocalContext env;
17730   for (int i = 0; i < 3; i++) {
17731     CcTest::heap()->PerformScavenge();
17732   }
17733 }
17734
17735 static uint32_t* stack_limit;
17736
17737 static void GetStackLimitCallback(
17738     const v8::FunctionCallbackInfo<v8::Value>& args) {
17739   stack_limit = reinterpret_cast<uint32_t*>(
17740       CcTest::i_isolate()->stack_guard()->real_climit());
17741 }
17742
17743
17744 // Uses the address of a local variable to determine the stack top now.
17745 // Given a size, returns an address that is that far from the current
17746 // top of stack.
17747 static uint32_t* ComputeStackLimit(uint32_t size) {
17748   uint32_t* answer = &size - (size / sizeof(size));
17749   // If the size is very large and the stack is very near the bottom of
17750   // memory then the calculation above may wrap around and give an address
17751   // that is above the (downwards-growing) stack.  In that case we return
17752   // a very low address.
17753   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17754   return answer;
17755 }
17756
17757
17758 // We need at least 165kB for an x64 debug build with clang and ASAN.
17759 static const int stack_breathing_room = 256 * i::KB;
17760
17761
17762 TEST(SetResourceConstraints) {
17763   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17764
17765   // Set stack limit.
17766   v8::ResourceConstraints constraints;
17767   constraints.set_stack_limit(set_limit);
17768   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17769
17770   // Execute a script.
17771   LocalContext env;
17772   v8::HandleScope scope(env->GetIsolate());
17773   Local<v8::FunctionTemplate> fun_templ =
17774       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17775   Local<Function> fun = fun_templ->GetFunction();
17776   env->Global()->Set(v8_str("get_stack_limit"), fun);
17777   CompileRun("get_stack_limit();");
17778
17779   CHECK(stack_limit == set_limit);
17780 }
17781
17782
17783 TEST(SetResourceConstraintsInThread) {
17784   uint32_t* set_limit;
17785   {
17786     v8::Locker locker(CcTest::isolate());
17787     set_limit = ComputeStackLimit(stack_breathing_room);
17788
17789     // Set stack limit.
17790     v8::ResourceConstraints constraints;
17791     constraints.set_stack_limit(set_limit);
17792     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17793
17794     // Execute a script.
17795     v8::HandleScope scope(CcTest::isolate());
17796     LocalContext env;
17797     Local<v8::FunctionTemplate> fun_templ =
17798         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17799     Local<Function> fun = fun_templ->GetFunction();
17800     env->Global()->Set(v8_str("get_stack_limit"), fun);
17801     CompileRun("get_stack_limit();");
17802
17803     CHECK(stack_limit == set_limit);
17804   }
17805   {
17806     v8::Locker locker(CcTest::isolate());
17807     CHECK(stack_limit == set_limit);
17808   }
17809 }
17810
17811
17812 THREADED_TEST(GetHeapStatistics) {
17813   LocalContext c1;
17814   v8::HandleScope scope(c1->GetIsolate());
17815   v8::HeapStatistics heap_statistics;
17816   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17817   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17818   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17819   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17820   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17821 }
17822
17823
17824 class VisitorImpl : public v8::ExternalResourceVisitor {
17825  public:
17826   explicit VisitorImpl(TestResource** resource) {
17827     for (int i = 0; i < 4; i++) {
17828       resource_[i] = resource[i];
17829       found_resource_[i] = false;
17830     }
17831   }
17832   virtual ~VisitorImpl() {}
17833   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17834     if (!string->IsExternal()) {
17835       CHECK(string->IsExternalAscii());
17836       return;
17837     }
17838     v8::String::ExternalStringResource* resource =
17839         string->GetExternalStringResource();
17840     CHECK(resource);
17841     for (int i = 0; i < 4; i++) {
17842       if (resource_[i] == resource) {
17843         CHECK(!found_resource_[i]);
17844         found_resource_[i] = true;
17845       }
17846     }
17847   }
17848   void CheckVisitedResources() {
17849     for (int i = 0; i < 4; i++) {
17850       CHECK(found_resource_[i]);
17851     }
17852   }
17853
17854  private:
17855   v8::String::ExternalStringResource* resource_[4];
17856   bool found_resource_[4];
17857 };
17858
17859
17860 TEST(VisitExternalStrings) {
17861   LocalContext env;
17862   v8::HandleScope scope(env->GetIsolate());
17863   const char* string = "Some string";
17864   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17865   TestResource* resource[4];
17866   resource[0] = new TestResource(two_byte_string);
17867   v8::Local<v8::String> string0 =
17868       v8::String::NewExternal(env->GetIsolate(), resource[0]);
17869   resource[1] = new TestResource(two_byte_string);
17870   v8::Local<v8::String> string1 =
17871       v8::String::NewExternal(env->GetIsolate(), resource[1]);
17872
17873   // Externalized symbol.
17874   resource[2] = new TestResource(two_byte_string);
17875   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17876       env->GetIsolate(), string, v8::String::kInternalizedString);
17877   CHECK(string2->MakeExternal(resource[2]));
17878
17879   // Symbolized External.
17880   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17881   v8::Local<v8::String> string3 =
17882       v8::String::NewExternal(env->GetIsolate(), resource[3]);
17883   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
17884   // Turn into a symbol.
17885   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17886   CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17887   CHECK(string3_i->IsInternalizedString());
17888
17889   // We need to add usages for string* to avoid warnings in GCC 4.7
17890   CHECK(string0->IsExternal());
17891   CHECK(string1->IsExternal());
17892   CHECK(string2->IsExternal());
17893   CHECK(string3->IsExternal());
17894
17895   VisitorImpl visitor(resource);
17896   v8::V8::VisitExternalResources(&visitor);
17897   visitor.CheckVisitedResources();
17898 }
17899
17900
17901 TEST(ExternalStringCollectedAtTearDown) {
17902   int destroyed = 0;
17903   v8::Isolate* isolate = v8::Isolate::New();
17904   { v8::Isolate::Scope isolate_scope(isolate);
17905     v8::HandleScope handle_scope(isolate);
17906     const char* s = "One string to test them all, one string to find them.";
17907     TestAsciiResource* inscription =
17908         new TestAsciiResource(i::StrDup(s), &destroyed);
17909     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17910     // Ring is still alive.  Orcs are roaming freely across our lands.
17911     CHECK_EQ(0, destroyed);
17912     USE(ring);
17913   }
17914
17915   isolate->Dispose();
17916   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17917   CHECK_EQ(1, destroyed);
17918 }
17919
17920
17921 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17922   int destroyed = 0;
17923   v8::Isolate* isolate = v8::Isolate::New();
17924   { v8::Isolate::Scope isolate_scope(isolate);
17925     LocalContext env(isolate);
17926     v8::HandleScope handle_scope(isolate);
17927     CompileRun("var ring = 'One string to test them all';");
17928     const char* s = "One string to test them all";
17929     TestAsciiResource* inscription =
17930         new TestAsciiResource(i::StrDup(s), &destroyed);
17931     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17932     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17933     ring->MakeExternal(inscription);
17934     // Ring is still alive.  Orcs are roaming freely across our lands.
17935     CHECK_EQ(0, destroyed);
17936     USE(ring);
17937   }
17938
17939   isolate->Dispose();
17940   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17941   CHECK_EQ(1, destroyed);
17942 }
17943
17944
17945 TEST(ExternalInternalizedStringCollectedAtGC) {
17946   int destroyed = 0;
17947   { LocalContext env;
17948     v8::HandleScope handle_scope(env->GetIsolate());
17949     CompileRun("var ring = 'One string to test them all';");
17950     const char* s = "One string to test them all";
17951     TestAsciiResource* inscription =
17952         new TestAsciiResource(i::StrDup(s), &destroyed);
17953     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17954     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17955     ring->MakeExternal(inscription);
17956     // Ring is still alive.  Orcs are roaming freely across our lands.
17957     CHECK_EQ(0, destroyed);
17958     USE(ring);
17959   }
17960
17961   // Garbage collector deals swift blows to evil.
17962   CcTest::i_isolate()->compilation_cache()->Clear();
17963   CcTest::heap()->CollectAllAvailableGarbage();
17964
17965   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17966   CHECK_EQ(1, destroyed);
17967 }
17968
17969
17970 static double DoubleFromBits(uint64_t value) {
17971   double target;
17972   i::OS::MemCopy(&target, &value, sizeof(target));
17973   return target;
17974 }
17975
17976
17977 static uint64_t DoubleToBits(double value) {
17978   uint64_t target;
17979   i::OS::MemCopy(&target, &value, sizeof(target));
17980   return target;
17981 }
17982
17983
17984 static double DoubleToDateTime(double input) {
17985   double date_limit = 864e13;
17986   if (std::isnan(input) || input < -date_limit || input > date_limit) {
17987     return i::OS::nan_value();
17988   }
17989   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
17990 }
17991
17992
17993 // We don't have a consistent way to write 64-bit constants syntactically, so we
17994 // split them into two 32-bit constants and combine them programmatically.
17995 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17996   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17997 }
17998
17999
18000 THREADED_TEST(QuietSignalingNaNs) {
18001   LocalContext context;
18002   v8::Isolate* isolate = context->GetIsolate();
18003   v8::HandleScope scope(isolate);
18004   v8::TryCatch try_catch;
18005
18006   // Special double values.
18007   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18008   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18009   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18010   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18011   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18012   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18013   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18014
18015   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18016   // on either side of the epoch.
18017   double date_limit = 864e13;
18018
18019   double test_values[] = {
18020       snan,
18021       qnan,
18022       infinity,
18023       max_normal,
18024       date_limit + 1,
18025       date_limit,
18026       min_normal,
18027       max_denormal,
18028       min_denormal,
18029       0,
18030       -0,
18031       -min_denormal,
18032       -max_denormal,
18033       -min_normal,
18034       -date_limit,
18035       -date_limit - 1,
18036       -max_normal,
18037       -infinity,
18038       -qnan,
18039       -snan
18040   };
18041   int num_test_values = 20;
18042
18043   for (int i = 0; i < num_test_values; i++) {
18044     double test_value = test_values[i];
18045
18046     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18047     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18048     double stored_number = number->NumberValue();
18049     if (!std::isnan(test_value)) {
18050       CHECK_EQ(test_value, stored_number);
18051     } else {
18052       uint64_t stored_bits = DoubleToBits(stored_number);
18053       // Check if quiet nan (bits 51..62 all set).
18054 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18055       // Most significant fraction bit for quiet nan is set to 0
18056       // on MIPS architecture. Allowed by IEEE-754.
18057       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18058 #else
18059       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18060 #endif
18061     }
18062
18063     // Check that Date::New preserves non-NaNs in the date range and
18064     // quiets SNaNs.
18065     v8::Handle<v8::Value> date =
18066         v8::Date::New(isolate, test_value);
18067     double expected_stored_date = DoubleToDateTime(test_value);
18068     double stored_date = date->NumberValue();
18069     if (!std::isnan(expected_stored_date)) {
18070       CHECK_EQ(expected_stored_date, stored_date);
18071     } else {
18072       uint64_t stored_bits = DoubleToBits(stored_date);
18073       // Check if quiet nan (bits 51..62 all set).
18074 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
18075       // Most significant fraction bit for quiet nan is set to 0
18076       // on MIPS architecture. Allowed by IEEE-754.
18077       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18078 #else
18079       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18080 #endif
18081     }
18082   }
18083 }
18084
18085
18086 static void SpaghettiIncident(
18087     const v8::FunctionCallbackInfo<v8::Value>& args) {
18088   v8::HandleScope scope(args.GetIsolate());
18089   v8::TryCatch tc;
18090   v8::Handle<v8::String> str(args[0]->ToString());
18091   USE(str);
18092   if (tc.HasCaught())
18093     tc.ReThrow();
18094 }
18095
18096
18097 // Test that an exception can be propagated down through a spaghetti
18098 // stack using ReThrow.
18099 THREADED_TEST(SpaghettiStackReThrow) {
18100   v8::Isolate* isolate = CcTest::isolate();
18101   v8::HandleScope scope(isolate);
18102   LocalContext context;
18103   context->Global()->Set(
18104       v8::String::NewFromUtf8(isolate, "s"),
18105       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18106   v8::TryCatch try_catch;
18107   CompileRun(
18108       "var i = 0;"
18109       "var o = {"
18110       "  toString: function () {"
18111       "    if (i == 10) {"
18112       "      throw 'Hey!';"
18113       "    } else {"
18114       "      i++;"
18115       "      return s(o);"
18116       "    }"
18117       "  }"
18118       "};"
18119       "s(o);");
18120   CHECK(try_catch.HasCaught());
18121   v8::String::Utf8Value value(try_catch.Exception());
18122   CHECK_EQ(0, strcmp(*value, "Hey!"));
18123 }
18124
18125
18126 TEST(Regress528) {
18127   v8::V8::Initialize();
18128   v8::Isolate* isolate = CcTest::isolate();
18129   v8::HandleScope scope(isolate);
18130   v8::Local<Context> other_context;
18131   int gc_count;
18132
18133   // Create a context used to keep the code from aging in the compilation
18134   // cache.
18135   other_context = Context::New(isolate);
18136
18137   // Context-dependent context data creates reference from the compilation
18138   // cache to the global object.
18139   const char* source_simple = "1";
18140   {
18141     v8::HandleScope scope(isolate);
18142     v8::Local<Context> context = Context::New(isolate);
18143
18144     context->Enter();
18145     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18146     context->SetEmbedderData(0, obj);
18147     CompileRun(source_simple);
18148     context->Exit();
18149   }
18150   v8::V8::ContextDisposedNotification();
18151   for (gc_count = 1; gc_count < 10; gc_count++) {
18152     other_context->Enter();
18153     CompileRun(source_simple);
18154     other_context->Exit();
18155     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18156     if (GetGlobalObjectsCount() == 1) break;
18157   }
18158   CHECK_GE(2, gc_count);
18159   CHECK_EQ(1, GetGlobalObjectsCount());
18160
18161   // Eval in a function creates reference from the compilation cache to the
18162   // global object.
18163   const char* source_eval = "function f(){eval('1')}; f()";
18164   {
18165     v8::HandleScope scope(isolate);
18166     v8::Local<Context> context = Context::New(isolate);
18167
18168     context->Enter();
18169     CompileRun(source_eval);
18170     context->Exit();
18171   }
18172   v8::V8::ContextDisposedNotification();
18173   for (gc_count = 1; gc_count < 10; gc_count++) {
18174     other_context->Enter();
18175     CompileRun(source_eval);
18176     other_context->Exit();
18177     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18178     if (GetGlobalObjectsCount() == 1) break;
18179   }
18180   CHECK_GE(2, gc_count);
18181   CHECK_EQ(1, GetGlobalObjectsCount());
18182
18183   // Looking up the line number for an exception creates reference from the
18184   // compilation cache to the global object.
18185   const char* source_exception = "function f(){throw 1;} f()";
18186   {
18187     v8::HandleScope scope(isolate);
18188     v8::Local<Context> context = Context::New(isolate);
18189
18190     context->Enter();
18191     v8::TryCatch try_catch;
18192     CompileRun(source_exception);
18193     CHECK(try_catch.HasCaught());
18194     v8::Handle<v8::Message> message = try_catch.Message();
18195     CHECK(!message.IsEmpty());
18196     CHECK_EQ(1, message->GetLineNumber());
18197     context->Exit();
18198   }
18199   v8::V8::ContextDisposedNotification();
18200   for (gc_count = 1; gc_count < 10; gc_count++) {
18201     other_context->Enter();
18202     CompileRun(source_exception);
18203     other_context->Exit();
18204     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18205     if (GetGlobalObjectsCount() == 1) break;
18206   }
18207   CHECK_GE(2, gc_count);
18208   CHECK_EQ(1, GetGlobalObjectsCount());
18209
18210   v8::V8::ContextDisposedNotification();
18211 }
18212
18213
18214 THREADED_TEST(ScriptOrigin) {
18215   LocalContext env;
18216   v8::HandleScope scope(env->GetIsolate());
18217   v8::ScriptOrigin origin =
18218       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18219   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18220       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18221   v8::Script::Compile(script, &origin)->Run();
18222   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18223       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18224   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18225       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18226
18227   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18228   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18229   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18230
18231   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18232   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18233   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18234 }
18235
18236
18237 THREADED_TEST(FunctionGetInferredName) {
18238   LocalContext env;
18239   v8::HandleScope scope(env->GetIsolate());
18240   v8::ScriptOrigin origin =
18241       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18242   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18243       env->GetIsolate(),
18244       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18245   v8::Script::Compile(script, &origin)->Run();
18246   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18247       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18248   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18249 }
18250
18251
18252 THREADED_TEST(FunctionGetDisplayName) {
18253   LocalContext env;
18254   v8::HandleScope scope(env->GetIsolate());
18255   const char* code = "var error = false;"
18256                      "function a() { this.x = 1; };"
18257                      "a.displayName = 'display_a';"
18258                      "var b = (function() {"
18259                      "  var f = function() { this.x = 2; };"
18260                      "  f.displayName = 'display_b';"
18261                      "  return f;"
18262                      "})();"
18263                      "var c = function() {};"
18264                      "c.__defineGetter__('displayName', function() {"
18265                      "  error = true;"
18266                      "  throw new Error();"
18267                      "});"
18268                      "function d() {};"
18269                      "d.__defineGetter__('displayName', function() {"
18270                      "  error = true;"
18271                      "  return 'wrong_display_name';"
18272                      "});"
18273                      "function e() {};"
18274                      "e.displayName = 'wrong_display_name';"
18275                      "e.__defineSetter__('displayName', function() {"
18276                      "  error = true;"
18277                      "  throw new Error();"
18278                      "});"
18279                      "function f() {};"
18280                      "f.displayName = { 'foo': 6, toString: function() {"
18281                      "  error = true;"
18282                      "  return 'wrong_display_name';"
18283                      "}};"
18284                      "var g = function() {"
18285                      "  arguments.callee.displayName = 'set_in_runtime';"
18286                      "}; g();"
18287                      ;
18288   v8::ScriptOrigin origin =
18289       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18290   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18291       ->Run();
18292   v8::Local<v8::Value> error =
18293       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18294   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18295       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18296   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18297       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18298   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18299       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18300   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18301       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18302   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18303       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18304   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18305       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18306   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18307       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18308   CHECK_EQ(false, error->BooleanValue());
18309   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18310   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18311   CHECK(c->GetDisplayName()->IsUndefined());
18312   CHECK(d->GetDisplayName()->IsUndefined());
18313   CHECK(e->GetDisplayName()->IsUndefined());
18314   CHECK(f->GetDisplayName()->IsUndefined());
18315   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18316 }
18317
18318
18319 THREADED_TEST(ScriptLineNumber) {
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   CHECK_EQ(0, f->GetScriptLineNumber());
18332   CHECK_EQ(2, g->GetScriptLineNumber());
18333 }
18334
18335
18336 THREADED_TEST(ScriptColumnNumber) {
18337   LocalContext env;
18338   v8::Isolate* isolate = env->GetIsolate();
18339   v8::HandleScope scope(isolate);
18340   v8::ScriptOrigin origin =
18341       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18342                        v8::Integer::New(isolate, 3),
18343                        v8::Integer::New(isolate, 2));
18344   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18345       isolate, "function foo() {}\n\n     function bar() {}");
18346   v8::Script::Compile(script, &origin)->Run();
18347   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18348       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18349   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18350       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18351   CHECK_EQ(14, foo->GetScriptColumnNumber());
18352   CHECK_EQ(17, bar->GetScriptColumnNumber());
18353 }
18354
18355
18356 THREADED_TEST(FunctionIsBuiltin) {
18357   LocalContext env;
18358   v8::Isolate* isolate = env->GetIsolate();
18359   v8::HandleScope scope(isolate);
18360   v8::Local<v8::Function> f;
18361   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18362   CHECK(f->IsBuiltin());
18363   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18364   CHECK(f->IsBuiltin());
18365   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18366   CHECK(f->IsBuiltin());
18367   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18368   CHECK(f->IsBuiltin());
18369   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18370   CHECK(!f->IsBuiltin());
18371 }
18372
18373
18374 THREADED_TEST(FunctionGetScriptId) {
18375   LocalContext env;
18376   v8::Isolate* isolate = env->GetIsolate();
18377   v8::HandleScope scope(isolate);
18378   v8::ScriptOrigin origin =
18379       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18380                        v8::Integer::New(isolate, 3),
18381                        v8::Integer::New(isolate, 2));
18382   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18383       isolate, "function foo() {}\n\n     function bar() {}");
18384   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18385   script->Run();
18386   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18387       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18388   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18389       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18390   CHECK_EQ(script->GetId(), foo->ScriptId());
18391   CHECK_EQ(script->GetId(), bar->ScriptId());
18392 }
18393
18394
18395 THREADED_TEST(FunctionGetBoundFunction) {
18396   LocalContext env;
18397   v8::HandleScope scope(env->GetIsolate());
18398   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18399       env->GetIsolate(), "test"));
18400   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18401       env->GetIsolate(),
18402       "var a = new Object();\n"
18403       "a.x = 1;\n"
18404       "function f () { return this.x };\n"
18405       "var g = f.bind(a);\n"
18406       "var b = g();");
18407   v8::Script::Compile(script, &origin)->Run();
18408   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18409       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18410   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18411       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18412   CHECK(g->GetBoundFunction()->IsFunction());
18413   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18414       g->GetBoundFunction());
18415   CHECK_EQ(f->GetName(), original_function->GetName());
18416   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18417   CHECK_EQ(f->GetScriptColumnNumber(),
18418            original_function->GetScriptColumnNumber());
18419 }
18420
18421
18422 static void GetterWhichReturns42(
18423     Local<String> name,
18424     const v8::PropertyCallbackInfo<v8::Value>& info) {
18425   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18426   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18427   info.GetReturnValue().Set(v8_num(42));
18428 }
18429
18430
18431 static void SetterWhichSetsYOnThisTo23(
18432     Local<String> name,
18433     Local<Value> value,
18434     const v8::PropertyCallbackInfo<void>& info) {
18435   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18436   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18437   info.This()->Set(v8_str("y"), v8_num(23));
18438 }
18439
18440
18441 void FooGetInterceptor(Local<String> name,
18442                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18443   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18444   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18445   if (!name->Equals(v8_str("foo"))) return;
18446   info.GetReturnValue().Set(v8_num(42));
18447 }
18448
18449
18450 void FooSetInterceptor(Local<String> name,
18451                        Local<Value> value,
18452                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18453   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18454   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18455   if (!name->Equals(v8_str("foo"))) return;
18456   info.This()->Set(v8_str("y"), v8_num(23));
18457   info.GetReturnValue().Set(v8_num(23));
18458 }
18459
18460
18461 TEST(SetterOnConstructorPrototype) {
18462   v8::Isolate* isolate = CcTest::isolate();
18463   v8::HandleScope scope(isolate);
18464   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18465   templ->SetAccessor(v8_str("x"),
18466                      GetterWhichReturns42,
18467                      SetterWhichSetsYOnThisTo23);
18468   LocalContext context;
18469   context->Global()->Set(v8_str("P"), templ->NewInstance());
18470   CompileRun("function C1() {"
18471              "  this.x = 23;"
18472              "};"
18473              "C1.prototype = P;"
18474              "function C2() {"
18475              "  this.x = 23"
18476              "};"
18477              "C2.prototype = { };"
18478              "C2.prototype.__proto__ = P;");
18479
18480   v8::Local<v8::Script> script;
18481   script = v8::Script::Compile(v8_str("new C1();"));
18482   for (int i = 0; i < 10; i++) {
18483     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18484     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18485     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18486   }
18487
18488   script = v8::Script::Compile(v8_str("new C2();"));
18489   for (int i = 0; i < 10; i++) {
18490     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18491     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18492     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18493   }
18494 }
18495
18496
18497 static void NamedPropertyGetterWhichReturns42(
18498     Local<String> name,
18499     const v8::PropertyCallbackInfo<v8::Value>& info) {
18500   info.GetReturnValue().Set(v8_num(42));
18501 }
18502
18503
18504 static void NamedPropertySetterWhichSetsYOnThisTo23(
18505     Local<String> name,
18506     Local<Value> value,
18507     const v8::PropertyCallbackInfo<v8::Value>& info) {
18508   if (name->Equals(v8_str("x"))) {
18509     info.This()->Set(v8_str("y"), v8_num(23));
18510   }
18511 }
18512
18513
18514 THREADED_TEST(InterceptorOnConstructorPrototype) {
18515   v8::Isolate* isolate = CcTest::isolate();
18516   v8::HandleScope scope(isolate);
18517   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18518   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18519                                  NamedPropertySetterWhichSetsYOnThisTo23);
18520   LocalContext context;
18521   context->Global()->Set(v8_str("P"), templ->NewInstance());
18522   CompileRun("function C1() {"
18523              "  this.x = 23;"
18524              "};"
18525              "C1.prototype = P;"
18526              "function C2() {"
18527              "  this.x = 23"
18528              "};"
18529              "C2.prototype = { };"
18530              "C2.prototype.__proto__ = P;");
18531
18532   v8::Local<v8::Script> script;
18533   script = v8::Script::Compile(v8_str("new C1();"));
18534   for (int i = 0; i < 10; i++) {
18535     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18536     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18537     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18538   }
18539
18540   script = v8::Script::Compile(v8_str("new C2();"));
18541   for (int i = 0; i < 10; i++) {
18542     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18543     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18544     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18545   }
18546 }
18547
18548
18549 TEST(Regress618) {
18550   const char* source = "function C1() {"
18551                        "  this.x = 23;"
18552                        "};"
18553                        "C1.prototype = P;";
18554
18555   LocalContext context;
18556   v8::Isolate* isolate = context->GetIsolate();
18557   v8::HandleScope scope(isolate);
18558   v8::Local<v8::Script> script;
18559
18560   // Use a simple object as prototype.
18561   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18562   prototype->Set(v8_str("y"), v8_num(42));
18563   context->Global()->Set(v8_str("P"), prototype);
18564
18565   // This compile will add the code to the compilation cache.
18566   CompileRun(source);
18567
18568   script = v8::Script::Compile(v8_str("new C1();"));
18569   // Allow enough iterations for the inobject slack tracking logic
18570   // to finalize instance size and install the fast construct stub.
18571   for (int i = 0; i < 256; i++) {
18572     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18573     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18574     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18575   }
18576
18577   // Use an API object with accessors as prototype.
18578   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18579   templ->SetAccessor(v8_str("x"),
18580                      GetterWhichReturns42,
18581                      SetterWhichSetsYOnThisTo23);
18582   context->Global()->Set(v8_str("P"), templ->NewInstance());
18583
18584   // This compile will get the code from the compilation cache.
18585   CompileRun(source);
18586
18587   script = v8::Script::Compile(v8_str("new C1();"));
18588   for (int i = 0; i < 10; i++) {
18589     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18590     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18591     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18592   }
18593 }
18594
18595 v8::Isolate* gc_callbacks_isolate = NULL;
18596 int prologue_call_count = 0;
18597 int epilogue_call_count = 0;
18598 int prologue_call_count_second = 0;
18599 int epilogue_call_count_second = 0;
18600
18601 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18602   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18603   ++prologue_call_count;
18604 }
18605
18606
18607 void PrologueCallback(v8::Isolate* isolate,
18608                       v8::GCType,
18609                       v8::GCCallbackFlags flags) {
18610   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18611   CHECK_EQ(gc_callbacks_isolate, isolate);
18612   ++prologue_call_count;
18613 }
18614
18615
18616 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18617   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18618   ++epilogue_call_count;
18619 }
18620
18621
18622 void EpilogueCallback(v8::Isolate* isolate,
18623                       v8::GCType,
18624                       v8::GCCallbackFlags flags) {
18625   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18626   CHECK_EQ(gc_callbacks_isolate, isolate);
18627   ++epilogue_call_count;
18628 }
18629
18630
18631 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18632   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18633   ++prologue_call_count_second;
18634 }
18635
18636
18637 void PrologueCallbackSecond(v8::Isolate* isolate,
18638                             v8::GCType,
18639                             v8::GCCallbackFlags flags) {
18640   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18641   CHECK_EQ(gc_callbacks_isolate, isolate);
18642   ++prologue_call_count_second;
18643 }
18644
18645
18646 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18647   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18648   ++epilogue_call_count_second;
18649 }
18650
18651
18652 void EpilogueCallbackSecond(v8::Isolate* isolate,
18653                             v8::GCType,
18654                             v8::GCCallbackFlags flags) {
18655   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18656   CHECK_EQ(gc_callbacks_isolate, isolate);
18657   ++epilogue_call_count_second;
18658 }
18659
18660
18661 TEST(GCCallbacksOld) {
18662   LocalContext context;
18663
18664   v8::V8::AddGCPrologueCallback(PrologueCallback);
18665   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18666   CHECK_EQ(0, prologue_call_count);
18667   CHECK_EQ(0, epilogue_call_count);
18668   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18669   CHECK_EQ(1, prologue_call_count);
18670   CHECK_EQ(1, epilogue_call_count);
18671   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18672   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18673   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18674   CHECK_EQ(2, prologue_call_count);
18675   CHECK_EQ(2, epilogue_call_count);
18676   CHECK_EQ(1, prologue_call_count_second);
18677   CHECK_EQ(1, epilogue_call_count_second);
18678   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18679   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18680   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18681   CHECK_EQ(2, prologue_call_count);
18682   CHECK_EQ(2, epilogue_call_count);
18683   CHECK_EQ(2, prologue_call_count_second);
18684   CHECK_EQ(2, epilogue_call_count_second);
18685   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18686   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18687   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18688   CHECK_EQ(2, prologue_call_count);
18689   CHECK_EQ(2, epilogue_call_count);
18690   CHECK_EQ(2, prologue_call_count_second);
18691   CHECK_EQ(2, epilogue_call_count_second);
18692 }
18693
18694
18695 TEST(GCCallbacks) {
18696   LocalContext context;
18697   v8::Isolate* isolate = context->GetIsolate();
18698   gc_callbacks_isolate = isolate;
18699   isolate->AddGCPrologueCallback(PrologueCallback);
18700   isolate->AddGCEpilogueCallback(EpilogueCallback);
18701   CHECK_EQ(0, prologue_call_count);
18702   CHECK_EQ(0, epilogue_call_count);
18703   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18704   CHECK_EQ(1, prologue_call_count);
18705   CHECK_EQ(1, epilogue_call_count);
18706   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18707   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18708   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18709   CHECK_EQ(2, prologue_call_count);
18710   CHECK_EQ(2, epilogue_call_count);
18711   CHECK_EQ(1, prologue_call_count_second);
18712   CHECK_EQ(1, epilogue_call_count_second);
18713   isolate->RemoveGCPrologueCallback(PrologueCallback);
18714   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18715   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18716   CHECK_EQ(2, prologue_call_count);
18717   CHECK_EQ(2, epilogue_call_count);
18718   CHECK_EQ(2, prologue_call_count_second);
18719   CHECK_EQ(2, epilogue_call_count_second);
18720   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18721   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18722   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18723   CHECK_EQ(2, prologue_call_count);
18724   CHECK_EQ(2, epilogue_call_count);
18725   CHECK_EQ(2, prologue_call_count_second);
18726   CHECK_EQ(2, epilogue_call_count_second);
18727 }
18728
18729
18730 THREADED_TEST(AddToJSFunctionResultCache) {
18731   i::FLAG_stress_compaction = false;
18732   i::FLAG_allow_natives_syntax = true;
18733   v8::HandleScope scope(CcTest::isolate());
18734
18735   LocalContext context;
18736
18737   const char* code =
18738       "(function() {"
18739       "  var key0 = 'a';"
18740       "  var key1 = 'b';"
18741       "  var r0 = %_GetFromCache(0, key0);"
18742       "  var r1 = %_GetFromCache(0, key1);"
18743       "  var r0_ = %_GetFromCache(0, key0);"
18744       "  if (r0 !== r0_)"
18745       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18746       "  var r1_ = %_GetFromCache(0, key1);"
18747       "  if (r1 !== r1_)"
18748       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18749       "  return 'PASSED';"
18750       "})()";
18751   CcTest::heap()->ClearJSFunctionResultCaches();
18752   ExpectString(code, "PASSED");
18753 }
18754
18755
18756 THREADED_TEST(FillJSFunctionResultCache) {
18757   i::FLAG_allow_natives_syntax = true;
18758   LocalContext context;
18759   v8::HandleScope scope(context->GetIsolate());
18760
18761   const char* code =
18762       "(function() {"
18763       "  var k = 'a';"
18764       "  var r = %_GetFromCache(0, k);"
18765       "  for (var i = 0; i < 16; i++) {"
18766       "    %_GetFromCache(0, 'a' + i);"
18767       "  };"
18768       "  if (r === %_GetFromCache(0, k))"
18769       "    return 'FAILED: k0CacheSize is too small';"
18770       "  return 'PASSED';"
18771       "})()";
18772   CcTest::heap()->ClearJSFunctionResultCaches();
18773   ExpectString(code, "PASSED");
18774 }
18775
18776
18777 THREADED_TEST(RoundRobinGetFromCache) {
18778   i::FLAG_allow_natives_syntax = true;
18779   LocalContext context;
18780   v8::HandleScope scope(context->GetIsolate());
18781
18782   const char* code =
18783       "(function() {"
18784       "  var keys = [];"
18785       "  for (var i = 0; i < 16; i++) keys.push(i);"
18786       "  var values = [];"
18787       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18788       "  for (var i = 0; i < 16; i++) {"
18789       "    var v = %_GetFromCache(0, keys[i]);"
18790       "    if (v.toString() !== values[i].toString())"
18791       "      return 'Wrong value for ' + "
18792       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18793       "  };"
18794       "  return 'PASSED';"
18795       "})()";
18796   CcTest::heap()->ClearJSFunctionResultCaches();
18797   ExpectString(code, "PASSED");
18798 }
18799
18800
18801 THREADED_TEST(ReverseGetFromCache) {
18802   i::FLAG_allow_natives_syntax = true;
18803   LocalContext context;
18804   v8::HandleScope scope(context->GetIsolate());
18805
18806   const char* code =
18807       "(function() {"
18808       "  var keys = [];"
18809       "  for (var i = 0; i < 16; i++) keys.push(i);"
18810       "  var values = [];"
18811       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18812       "  for (var i = 15; i >= 16; i--) {"
18813       "    var v = %_GetFromCache(0, keys[i]);"
18814       "    if (v !== values[i])"
18815       "      return 'Wrong value for ' + "
18816       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18817       "  };"
18818       "  return 'PASSED';"
18819       "})()";
18820   CcTest::heap()->ClearJSFunctionResultCaches();
18821   ExpectString(code, "PASSED");
18822 }
18823
18824
18825 THREADED_TEST(TestEviction) {
18826   i::FLAG_allow_natives_syntax = true;
18827   LocalContext context;
18828   v8::HandleScope scope(context->GetIsolate());
18829
18830   const char* code =
18831       "(function() {"
18832       "  for (var i = 0; i < 2*16; i++) {"
18833       "    %_GetFromCache(0, 'a' + i);"
18834       "  };"
18835       "  return 'PASSED';"
18836       "})()";
18837   CcTest::heap()->ClearJSFunctionResultCaches();
18838   ExpectString(code, "PASSED");
18839 }
18840
18841
18842 THREADED_TEST(TwoByteStringInAsciiCons) {
18843   // See Chromium issue 47824.
18844   LocalContext context;
18845   v8::HandleScope scope(context->GetIsolate());
18846
18847   const char* init_code =
18848       "var str1 = 'abelspendabel';"
18849       "var str2 = str1 + str1 + str1;"
18850       "str2;";
18851   Local<Value> result = CompileRun(init_code);
18852
18853   Local<Value> indexof = CompileRun("str2.indexOf('els')");
18854   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18855
18856   CHECK(result->IsString());
18857   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18858   int length = string->length();
18859   CHECK(string->IsOneByteRepresentation());
18860
18861   FlattenString(string);
18862   i::Handle<i::String> flat_string = FlattenGetString(string);
18863
18864   CHECK(string->IsOneByteRepresentation());
18865   CHECK(flat_string->IsOneByteRepresentation());
18866
18867   // Create external resource.
18868   uint16_t* uc16_buffer = new uint16_t[length + 1];
18869
18870   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18871   uc16_buffer[length] = 0;
18872
18873   TestResource resource(uc16_buffer);
18874
18875   flat_string->MakeExternal(&resource);
18876
18877   CHECK(flat_string->IsTwoByteRepresentation());
18878
18879   // If the cons string has been short-circuited, skip the following checks.
18880   if (!string.is_identical_to(flat_string)) {
18881     // At this point, we should have a Cons string which is flat and ASCII,
18882     // with a first half that is a two-byte string (although it only contains
18883     // ASCII characters). This is a valid sequence of steps, and it can happen
18884     // in real pages.
18885     CHECK(string->IsOneByteRepresentation());
18886     i::ConsString* cons = i::ConsString::cast(*string);
18887     CHECK_EQ(0, cons->second()->length());
18888     CHECK(cons->first()->IsTwoByteRepresentation());
18889   }
18890
18891   // Check that some string operations work.
18892
18893   // Atom RegExp.
18894   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18895   CHECK_EQ(6, reresult->Int32Value());
18896
18897   // Nonatom RegExp.
18898   reresult = CompileRun("str2.match(/abe./g).length;");
18899   CHECK_EQ(6, reresult->Int32Value());
18900
18901   reresult = CompileRun("str2.search(/bel/g);");
18902   CHECK_EQ(1, reresult->Int32Value());
18903
18904   reresult = CompileRun("str2.search(/be./g);");
18905   CHECK_EQ(1, reresult->Int32Value());
18906
18907   ExpectTrue("/bel/g.test(str2);");
18908
18909   ExpectTrue("/be./g.test(str2);");
18910
18911   reresult = CompileRun("/bel/g.exec(str2);");
18912   CHECK(!reresult->IsNull());
18913
18914   reresult = CompileRun("/be./g.exec(str2);");
18915   CHECK(!reresult->IsNull());
18916
18917   ExpectString("str2.substring(2, 10);", "elspenda");
18918
18919   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18920
18921   ExpectString("str2.charAt(2);", "e");
18922
18923   ExpectObject("str2.indexOf('els');", indexof);
18924
18925   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18926
18927   reresult = CompileRun("str2.charCodeAt(2);");
18928   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18929 }
18930
18931
18932 TEST(ContainsOnlyOneByte) {
18933   v8::V8::Initialize();
18934   v8::Isolate* isolate = CcTest::isolate();
18935   v8::HandleScope scope(isolate);
18936   // Make a buffer long enough that it won't automatically be converted.
18937   const int length = 512;
18938   // Ensure word aligned assignment.
18939   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18940   i::SmartArrayPointer<uintptr_t>
18941   aligned_contents(new uintptr_t[aligned_length]);
18942   uint16_t* string_contents =
18943       reinterpret_cast<uint16_t*>(aligned_contents.get());
18944   // Set to contain only one byte.
18945   for (int i = 0; i < length-1; i++) {
18946     string_contents[i] = 0x41;
18947   }
18948   string_contents[length-1] = 0;
18949   // Simple case.
18950   Handle<String> string;
18951   string = String::NewExternal(isolate, new TestResource(string_contents));
18952   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18953   // Counter example.
18954   string = String::NewFromTwoByte(isolate, string_contents);
18955   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18956   // Test left right and balanced cons strings.
18957   Handle<String> base = String::NewFromUtf8(isolate, "a");
18958   Handle<String> left = base;
18959   Handle<String> right = base;
18960   for (int i = 0; i < 1000; i++) {
18961     left = String::Concat(base, left);
18962     right = String::Concat(right, base);
18963   }
18964   Handle<String> balanced = String::Concat(left, base);
18965   balanced = String::Concat(balanced, right);
18966   Handle<String> cons_strings[] = {left, balanced, right};
18967   Handle<String> two_byte =
18968       String::NewExternal(isolate, new TestResource(string_contents));
18969   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
18970     // Base assumptions.
18971     string = cons_strings[i];
18972     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18973     // Test left and right concatentation.
18974     string = String::Concat(two_byte, cons_strings[i]);
18975     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18976     string = String::Concat(cons_strings[i], two_byte);
18977     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18978   }
18979   // Set bits in different positions
18980   // for strings of different lengths and alignments.
18981   for (int alignment = 0; alignment < 7; alignment++) {
18982     for (int size = 2; alignment + size < length; size *= 2) {
18983       int zero_offset = size + alignment;
18984       string_contents[zero_offset] = 0;
18985       for (int i = 0; i < size; i++) {
18986         int shift = 8 + (i % 7);
18987         string_contents[alignment + i] = 1 << shift;
18988         string = String::NewExternal(
18989             isolate, new TestResource(string_contents + alignment));
18990         CHECK_EQ(size, string->Length());
18991         CHECK(!string->ContainsOnlyOneByte());
18992         string_contents[alignment + i] = 0x41;
18993       }
18994       string_contents[zero_offset] = 0x41;
18995     }
18996   }
18997 }
18998
18999
19000 // Failed access check callback that performs a GC on each invocation.
19001 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19002                                  v8::AccessType type,
19003                                  Local<v8::Value> data) {
19004   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19005 }
19006
19007
19008 TEST(GCInFailedAccessCheckCallback) {
19009   // Install a failed access check callback that performs a GC on each
19010   // invocation. Then force the callback to be called from va
19011
19012   v8::V8::Initialize();
19013   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19014
19015   v8::Isolate* isolate = CcTest::isolate();
19016   v8::HandleScope scope(isolate);
19017
19018   // Create an ObjectTemplate for global objects and install access
19019   // check callbacks that will block access.
19020   v8::Handle<v8::ObjectTemplate> global_template =
19021       v8::ObjectTemplate::New(isolate);
19022   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19023                                            IndexedGetAccessBlocker,
19024                                            v8::Handle<v8::Value>(),
19025                                            false);
19026
19027   // Create a context and set an x property on it's global object.
19028   LocalContext context0(NULL, global_template);
19029   context0->Global()->Set(v8_str("x"), v8_num(42));
19030   v8::Handle<v8::Object> global0 = context0->Global();
19031
19032   // Create a context with a different security token so that the
19033   // failed access check callback will be called on each access.
19034   LocalContext context1(NULL, global_template);
19035   context1->Global()->Set(v8_str("other"), global0);
19036
19037   // Get property with failed access check.
19038   ExpectUndefined("other.x");
19039
19040   // Get element with failed access check.
19041   ExpectUndefined("other[0]");
19042
19043   // Set property with failed access check.
19044   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19045   CHECK(result->IsObject());
19046
19047   // Set element with failed access check.
19048   result = CompileRun("other[0] = new Object()");
19049   CHECK(result->IsObject());
19050
19051   // Get property attribute with failed access check.
19052   ExpectFalse("\'x\' in other");
19053
19054   // Get property attribute for element with failed access check.
19055   ExpectFalse("0 in other");
19056
19057   // Delete property.
19058   ExpectFalse("delete other.x");
19059
19060   // Delete element.
19061   CHECK_EQ(false, global0->Delete(0));
19062
19063   // DefineAccessor.
19064   CHECK_EQ(false,
19065            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19066
19067   // Define JavaScript accessor.
19068   ExpectUndefined("Object.prototype.__defineGetter__.call("
19069                   "    other, \'x\', function() { return 42; })");
19070
19071   // LookupAccessor.
19072   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19073                   "    other, \'x\')");
19074
19075   // HasLocalElement.
19076   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19077
19078   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19079   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19080   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19081
19082   // Reset the failed access check callback so it does not influence
19083   // the other tests.
19084   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19085 }
19086
19087
19088 TEST(IsolateNewDispose) {
19089   v8::Isolate* current_isolate = CcTest::isolate();
19090   v8::Isolate* isolate = v8::Isolate::New();
19091   CHECK(isolate != NULL);
19092   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
19093   CHECK(current_isolate != isolate);
19094   CHECK(current_isolate == CcTest::isolate());
19095
19096   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19097   last_location = last_message = NULL;
19098   isolate->Dispose();
19099   CHECK_EQ(last_location, NULL);
19100   CHECK_EQ(last_message, NULL);
19101 }
19102
19103
19104 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19105   v8::Isolate* isolate = v8::Isolate::New();
19106   CHECK(isolate);
19107   isolate->Enter();
19108   v8::HandleScope scope(isolate);
19109   LocalContext context(isolate);
19110   // Run something in this isolate.
19111   ExpectTrue("true");
19112   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19113   last_location = last_message = NULL;
19114   // Still entered, should fail.
19115   isolate->Dispose();
19116   CHECK_NE(last_location, NULL);
19117   CHECK_NE(last_message, NULL);
19118 }
19119
19120
19121 TEST(RunTwoIsolatesOnSingleThread) {
19122   // Run isolate 1.
19123   v8::Isolate* isolate1 = v8::Isolate::New();
19124   isolate1->Enter();
19125   v8::Persistent<v8::Context> context1;
19126   {
19127     v8::HandleScope scope(isolate1);
19128     context1.Reset(isolate1, Context::New(isolate1));
19129   }
19130
19131   {
19132     v8::HandleScope scope(isolate1);
19133     v8::Local<v8::Context> context =
19134         v8::Local<v8::Context>::New(isolate1, context1);
19135     v8::Context::Scope context_scope(context);
19136     // Run something in new isolate.
19137     CompileRun("var foo = 'isolate 1';");
19138     ExpectString("function f() { return foo; }; f()", "isolate 1");
19139   }
19140
19141   // Run isolate 2.
19142   v8::Isolate* isolate2 = v8::Isolate::New();
19143   v8::Persistent<v8::Context> context2;
19144
19145   {
19146     v8::Isolate::Scope iscope(isolate2);
19147     v8::HandleScope scope(isolate2);
19148     context2.Reset(isolate2, Context::New(isolate2));
19149     v8::Local<v8::Context> context =
19150         v8::Local<v8::Context>::New(isolate2, context2);
19151     v8::Context::Scope context_scope(context);
19152
19153     // Run something in new isolate.
19154     CompileRun("var foo = 'isolate 2';");
19155     ExpectString("function f() { return foo; }; f()", "isolate 2");
19156   }
19157
19158   {
19159     v8::HandleScope scope(isolate1);
19160     v8::Local<v8::Context> context =
19161         v8::Local<v8::Context>::New(isolate1, context1);
19162     v8::Context::Scope context_scope(context);
19163     // Now again in isolate 1
19164     ExpectString("function f() { return foo; }; f()", "isolate 1");
19165   }
19166
19167   isolate1->Exit();
19168
19169   // Run some stuff in default isolate.
19170   v8::Persistent<v8::Context> context_default;
19171   {
19172     v8::Isolate* isolate = CcTest::isolate();
19173     v8::Isolate::Scope iscope(isolate);
19174     v8::HandleScope scope(isolate);
19175     context_default.Reset(isolate, Context::New(isolate));
19176   }
19177
19178   {
19179     v8::HandleScope scope(CcTest::isolate());
19180     v8::Local<v8::Context> context =
19181         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19182     v8::Context::Scope context_scope(context);
19183     // Variables in other isolates should be not available, verify there
19184     // is an exception.
19185     ExpectTrue("function f() {"
19186                "  try {"
19187                "    foo;"
19188                "    return false;"
19189                "  } catch(e) {"
19190                "    return true;"
19191                "  }"
19192                "};"
19193                "var isDefaultIsolate = true;"
19194                "f()");
19195   }
19196
19197   isolate1->Enter();
19198
19199   {
19200     v8::Isolate::Scope iscope(isolate2);
19201     v8::HandleScope scope(isolate2);
19202     v8::Local<v8::Context> context =
19203         v8::Local<v8::Context>::New(isolate2, context2);
19204     v8::Context::Scope context_scope(context);
19205     ExpectString("function f() { return foo; }; f()", "isolate 2");
19206   }
19207
19208   {
19209     v8::HandleScope scope(v8::Isolate::GetCurrent());
19210     v8::Local<v8::Context> context =
19211         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19212     v8::Context::Scope context_scope(context);
19213     ExpectString("function f() { return foo; }; f()", "isolate 1");
19214   }
19215
19216   {
19217     v8::Isolate::Scope iscope(isolate2);
19218     context2.Reset();
19219   }
19220
19221   context1.Reset();
19222   isolate1->Exit();
19223
19224   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19225   last_location = last_message = NULL;
19226
19227   isolate1->Dispose();
19228   CHECK_EQ(last_location, NULL);
19229   CHECK_EQ(last_message, NULL);
19230
19231   isolate2->Dispose();
19232   CHECK_EQ(last_location, NULL);
19233   CHECK_EQ(last_message, NULL);
19234
19235   // Check that default isolate still runs.
19236   {
19237     v8::HandleScope scope(CcTest::isolate());
19238     v8::Local<v8::Context> context =
19239         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19240     v8::Context::Scope context_scope(context);
19241     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19242   }
19243 }
19244
19245
19246 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19247   v8::Isolate::Scope isolate_scope(isolate);
19248   v8::HandleScope scope(isolate);
19249   LocalContext context(isolate);
19250   i::ScopedVector<char> code(1024);
19251   i::OS::SNPrintF(code, "function fib(n) {"
19252                         "  if (n <= 2) return 1;"
19253                         "  return fib(n-1) + fib(n-2);"
19254                         "}"
19255                         "fib(%d)", limit);
19256   Local<Value> value = CompileRun(code.start());
19257   CHECK(value->IsNumber());
19258   return static_cast<int>(value->NumberValue());
19259 }
19260
19261 class IsolateThread : public v8::internal::Thread {
19262  public:
19263   IsolateThread(v8::Isolate* isolate, int fib_limit)
19264       : Thread("IsolateThread"),
19265         isolate_(isolate),
19266         fib_limit_(fib_limit),
19267         result_(0) { }
19268
19269   void Run() {
19270     result_ = CalcFibonacci(isolate_, fib_limit_);
19271   }
19272
19273   int result() { return result_; }
19274
19275  private:
19276   v8::Isolate* isolate_;
19277   int fib_limit_;
19278   int result_;
19279 };
19280
19281
19282 TEST(MultipleIsolatesOnIndividualThreads) {
19283   v8::Isolate* isolate1 = v8::Isolate::New();
19284   v8::Isolate* isolate2 = v8::Isolate::New();
19285
19286   IsolateThread thread1(isolate1, 21);
19287   IsolateThread thread2(isolate2, 12);
19288
19289   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19290   thread1.Start();
19291   thread2.Start();
19292
19293   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19294   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19295
19296   thread1.Join();
19297   thread2.Join();
19298
19299   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19300   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19301   CHECK_EQ(result1, 10946);
19302   CHECK_EQ(result2, 144);
19303   CHECK_EQ(result1, thread1.result());
19304   CHECK_EQ(result2, thread2.result());
19305
19306   isolate1->Dispose();
19307   isolate2->Dispose();
19308 }
19309
19310
19311 TEST(IsolateDifferentContexts) {
19312   v8::Isolate* isolate = v8::Isolate::New();
19313   Local<v8::Context> context;
19314   {
19315     v8::Isolate::Scope isolate_scope(isolate);
19316     v8::HandleScope handle_scope(isolate);
19317     context = v8::Context::New(isolate);
19318     v8::Context::Scope context_scope(context);
19319     Local<Value> v = CompileRun("2");
19320     CHECK(v->IsNumber());
19321     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19322   }
19323   {
19324     v8::Isolate::Scope isolate_scope(isolate);
19325     v8::HandleScope handle_scope(isolate);
19326     context = v8::Context::New(isolate);
19327     v8::Context::Scope context_scope(context);
19328     Local<Value> v = CompileRun("22");
19329     CHECK(v->IsNumber());
19330     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19331   }
19332 }
19333
19334 class InitDefaultIsolateThread : public v8::internal::Thread {
19335  public:
19336   enum TestCase {
19337     IgnoreOOM,
19338     SetResourceConstraints,
19339     SetFatalHandler,
19340     SetCounterFunction,
19341     SetCreateHistogramFunction,
19342     SetAddHistogramSampleFunction
19343   };
19344
19345   explicit InitDefaultIsolateThread(TestCase testCase)
19346       : Thread("InitDefaultIsolateThread"),
19347         testCase_(testCase),
19348         result_(false) { }
19349
19350   void Run() {
19351     v8::Isolate* isolate = v8::Isolate::New();
19352     isolate->Enter();
19353     switch (testCase_) {
19354     case IgnoreOOM:
19355       v8::V8::IgnoreOutOfMemoryException();
19356       break;
19357
19358     case SetResourceConstraints: {
19359       static const int K = 1024;
19360       v8::ResourceConstraints constraints;
19361       constraints.set_max_young_space_size(256 * K);
19362       constraints.set_max_old_space_size(4 * K * K);
19363       v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19364       break;
19365     }
19366
19367     case SetFatalHandler:
19368       v8::V8::SetFatalErrorHandler(NULL);
19369       break;
19370
19371     case SetCounterFunction:
19372       v8::V8::SetCounterFunction(NULL);
19373       break;
19374
19375     case SetCreateHistogramFunction:
19376       v8::V8::SetCreateHistogramFunction(NULL);
19377       break;
19378
19379     case SetAddHistogramSampleFunction:
19380       v8::V8::SetAddHistogramSampleFunction(NULL);
19381       break;
19382     }
19383     isolate->Exit();
19384     isolate->Dispose();
19385     result_ = true;
19386   }
19387
19388   bool result() { return result_; }
19389
19390  private:
19391   TestCase testCase_;
19392   bool result_;
19393 };
19394
19395
19396 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19397   InitDefaultIsolateThread thread(testCase);
19398   thread.Start();
19399   thread.Join();
19400   CHECK_EQ(thread.result(), true);
19401 }
19402
19403
19404 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19405   InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
19406 }
19407
19408
19409 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19410   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19411 }
19412
19413
19414 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19415   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19416 }
19417
19418
19419 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19420   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19421 }
19422
19423
19424 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19425   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19426 }
19427
19428
19429 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
19430   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19431 }
19432
19433
19434 TEST(StringCheckMultipleContexts) {
19435   const char* code =
19436       "(function() { return \"a\".charAt(0); })()";
19437
19438   {
19439     // Run the code twice in the first context to initialize the call IC.
19440     LocalContext context1;
19441     v8::HandleScope scope(context1->GetIsolate());
19442     ExpectString(code, "a");
19443     ExpectString(code, "a");
19444   }
19445
19446   {
19447     // Change the String.prototype in the second context and check
19448     // that the right function gets called.
19449     LocalContext context2;
19450     v8::HandleScope scope(context2->GetIsolate());
19451     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19452     ExpectString(code, "not a");
19453   }
19454 }
19455
19456
19457 TEST(NumberCheckMultipleContexts) {
19458   const char* code =
19459       "(function() { return (42).toString(); })()";
19460
19461   {
19462     // Run the code twice in the first context to initialize the call IC.
19463     LocalContext context1;
19464     v8::HandleScope scope(context1->GetIsolate());
19465     ExpectString(code, "42");
19466     ExpectString(code, "42");
19467   }
19468
19469   {
19470     // Change the Number.prototype in the second context and check
19471     // that the right function gets called.
19472     LocalContext context2;
19473     v8::HandleScope scope(context2->GetIsolate());
19474     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19475     ExpectString(code, "not 42");
19476   }
19477 }
19478
19479
19480 TEST(BooleanCheckMultipleContexts) {
19481   const char* code =
19482       "(function() { return true.toString(); })()";
19483
19484   {
19485     // Run the code twice in the first context to initialize the call IC.
19486     LocalContext context1;
19487     v8::HandleScope scope(context1->GetIsolate());
19488     ExpectString(code, "true");
19489     ExpectString(code, "true");
19490   }
19491
19492   {
19493     // Change the Boolean.prototype in the second context and check
19494     // that the right function gets called.
19495     LocalContext context2;
19496     v8::HandleScope scope(context2->GetIsolate());
19497     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19498     ExpectString(code, "");
19499   }
19500 }
19501
19502
19503 TEST(DontDeleteCellLoadIC) {
19504   const char* function_code =
19505       "function readCell() { while (true) { return cell; } }";
19506
19507   {
19508     // Run the code twice in the first context to initialize the load
19509     // IC for a don't delete cell.
19510     LocalContext context1;
19511     v8::HandleScope scope(context1->GetIsolate());
19512     CompileRun("var cell = \"first\";");
19513     ExpectBoolean("delete cell", false);
19514     CompileRun(function_code);
19515     ExpectString("readCell()", "first");
19516     ExpectString("readCell()", "first");
19517   }
19518
19519   {
19520     // Use a deletable cell in the second context.
19521     LocalContext context2;
19522     v8::HandleScope scope(context2->GetIsolate());
19523     CompileRun("cell = \"second\";");
19524     CompileRun(function_code);
19525     ExpectString("readCell()", "second");
19526     ExpectBoolean("delete cell", true);
19527     ExpectString("(function() {"
19528                  "  try {"
19529                  "    return readCell();"
19530                  "  } catch(e) {"
19531                  "    return e.toString();"
19532                  "  }"
19533                  "})()",
19534                  "ReferenceError: cell is not defined");
19535     CompileRun("cell = \"new_second\";");
19536     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19537     ExpectString("readCell()", "new_second");
19538     ExpectString("readCell()", "new_second");
19539   }
19540 }
19541
19542
19543 TEST(DontDeleteCellLoadICForceDelete) {
19544   const char* function_code =
19545       "function readCell() { while (true) { return cell; } }";
19546
19547   // Run the code twice to initialize the load IC for a don't delete
19548   // cell.
19549   LocalContext context;
19550   v8::HandleScope scope(context->GetIsolate());
19551   CompileRun("var cell = \"value\";");
19552   ExpectBoolean("delete cell", false);
19553   CompileRun(function_code);
19554   ExpectString("readCell()", "value");
19555   ExpectString("readCell()", "value");
19556
19557   // Delete the cell using the API and check the inlined code works
19558   // correctly.
19559   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19560   ExpectString("(function() {"
19561                "  try {"
19562                "    return readCell();"
19563                "  } catch(e) {"
19564                "    return e.toString();"
19565                "  }"
19566                "})()",
19567                "ReferenceError: cell is not defined");
19568 }
19569
19570
19571 TEST(DontDeleteCellLoadICAPI) {
19572   const char* function_code =
19573       "function readCell() { while (true) { return cell; } }";
19574
19575   // Run the code twice to initialize the load IC for a don't delete
19576   // cell created using the API.
19577   LocalContext context;
19578   v8::HandleScope scope(context->GetIsolate());
19579   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
19580   ExpectBoolean("delete cell", false);
19581   CompileRun(function_code);
19582   ExpectString("readCell()", "value");
19583   ExpectString("readCell()", "value");
19584
19585   // Delete the cell using the API and check the inlined code works
19586   // correctly.
19587   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19588   ExpectString("(function() {"
19589                "  try {"
19590                "    return readCell();"
19591                "  } catch(e) {"
19592                "    return e.toString();"
19593                "  }"
19594                "})()",
19595                "ReferenceError: cell is not defined");
19596 }
19597
19598
19599 class Visitor42 : public v8::PersistentHandleVisitor {
19600  public:
19601   explicit Visitor42(v8::Persistent<v8::Object>* object)
19602       : counter_(0), object_(object) { }
19603
19604   virtual void VisitPersistentHandle(Persistent<Value>* value,
19605                                      uint16_t class_id) {
19606     if (class_id != 42) return;
19607     CHECK_EQ(42, value->WrapperClassId());
19608     v8::Isolate* isolate = CcTest::isolate();
19609     v8::HandleScope handle_scope(isolate);
19610     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19611     v8::Handle<v8::Value> object =
19612         v8::Local<v8::Object>::New(isolate, *object_);
19613     CHECK(handle->IsObject());
19614     CHECK_EQ(Handle<Object>::Cast(handle), object);
19615     ++counter_;
19616   }
19617
19618   int counter_;
19619   v8::Persistent<v8::Object>* object_;
19620 };
19621
19622
19623 TEST(PersistentHandleVisitor) {
19624   LocalContext context;
19625   v8::Isolate* isolate = context->GetIsolate();
19626   v8::HandleScope scope(isolate);
19627   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19628   CHECK_EQ(0, object.WrapperClassId());
19629   object.SetWrapperClassId(42);
19630   CHECK_EQ(42, object.WrapperClassId());
19631
19632   Visitor42 visitor(&object);
19633   v8::V8::VisitHandlesWithClassIds(&visitor);
19634   CHECK_EQ(1, visitor.counter_);
19635
19636   object.Reset();
19637 }
19638
19639
19640 TEST(WrapperClassId) {
19641   LocalContext context;
19642   v8::Isolate* isolate = context->GetIsolate();
19643   v8::HandleScope scope(isolate);
19644   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19645   CHECK_EQ(0, object.WrapperClassId());
19646   object.SetWrapperClassId(65535);
19647   CHECK_EQ(65535, object.WrapperClassId());
19648   object.Reset();
19649 }
19650
19651
19652 TEST(PersistentHandleInNewSpaceVisitor) {
19653   LocalContext context;
19654   v8::Isolate* isolate = context->GetIsolate();
19655   v8::HandleScope scope(isolate);
19656   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19657   CHECK_EQ(0, object1.WrapperClassId());
19658   object1.SetWrapperClassId(42);
19659   CHECK_EQ(42, object1.WrapperClassId());
19660
19661   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19662
19663   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19664   CHECK_EQ(0, object2.WrapperClassId());
19665   object2.SetWrapperClassId(42);
19666   CHECK_EQ(42, object2.WrapperClassId());
19667
19668   Visitor42 visitor(&object2);
19669   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19670   CHECK_EQ(1, visitor.counter_);
19671
19672   object1.Reset();
19673   object2.Reset();
19674 }
19675
19676
19677 TEST(RegExp) {
19678   LocalContext context;
19679   v8::HandleScope scope(context->GetIsolate());
19680
19681   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19682   CHECK(re->IsRegExp());
19683   CHECK(re->GetSource()->Equals(v8_str("foo")));
19684   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19685
19686   re = v8::RegExp::New(v8_str("bar"),
19687                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19688                                                       v8::RegExp::kGlobal));
19689   CHECK(re->IsRegExp());
19690   CHECK(re->GetSource()->Equals(v8_str("bar")));
19691   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19692            static_cast<int>(re->GetFlags()));
19693
19694   re = v8::RegExp::New(v8_str("baz"),
19695                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19696                                                       v8::RegExp::kMultiline));
19697   CHECK(re->IsRegExp());
19698   CHECK(re->GetSource()->Equals(v8_str("baz")));
19699   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19700            static_cast<int>(re->GetFlags()));
19701
19702   re = CompileRun("/quux/").As<v8::RegExp>();
19703   CHECK(re->IsRegExp());
19704   CHECK(re->GetSource()->Equals(v8_str("quux")));
19705   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19706
19707   re = CompileRun("/quux/gm").As<v8::RegExp>();
19708   CHECK(re->IsRegExp());
19709   CHECK(re->GetSource()->Equals(v8_str("quux")));
19710   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19711            static_cast<int>(re->GetFlags()));
19712
19713   // Override the RegExp constructor and check the API constructor
19714   // still works.
19715   CompileRun("RegExp = function() {}");
19716
19717   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19718   CHECK(re->IsRegExp());
19719   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19720   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19721
19722   re = v8::RegExp::New(v8_str("foobarbaz"),
19723                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19724                                                       v8::RegExp::kMultiline));
19725   CHECK(re->IsRegExp());
19726   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19727   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19728            static_cast<int>(re->GetFlags()));
19729
19730   context->Global()->Set(v8_str("re"), re);
19731   ExpectTrue("re.test('FoobarbaZ')");
19732
19733   // RegExps are objects on which you can set properties.
19734   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19735   v8::Handle<v8::Value> value(CompileRun("re.property"));
19736   CHECK_EQ(32, value->Int32Value());
19737
19738   v8::TryCatch try_catch;
19739   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19740   CHECK(re.IsEmpty());
19741   CHECK(try_catch.HasCaught());
19742   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19743   ExpectTrue("ex instanceof SyntaxError");
19744 }
19745
19746
19747 THREADED_TEST(Equals) {
19748   LocalContext localContext;
19749   v8::HandleScope handleScope(localContext->GetIsolate());
19750
19751   v8::Handle<v8::Object> globalProxy = localContext->Global();
19752   v8::Handle<Value> global = globalProxy->GetPrototype();
19753
19754   CHECK(global->StrictEquals(global));
19755   CHECK(!global->StrictEquals(globalProxy));
19756   CHECK(!globalProxy->StrictEquals(global));
19757   CHECK(globalProxy->StrictEquals(globalProxy));
19758
19759   CHECK(global->Equals(global));
19760   CHECK(!global->Equals(globalProxy));
19761   CHECK(!globalProxy->Equals(global));
19762   CHECK(globalProxy->Equals(globalProxy));
19763 }
19764
19765
19766 static void Getter(v8::Local<v8::String> property,
19767                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19768   info.GetReturnValue().Set(v8_str("42!"));
19769 }
19770
19771
19772 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19773   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19774   result->Set(0, v8_str("universalAnswer"));
19775   info.GetReturnValue().Set(result);
19776 }
19777
19778
19779 TEST(NamedEnumeratorAndForIn) {
19780   LocalContext context;
19781   v8::Isolate* isolate = context->GetIsolate();
19782   v8::HandleScope handle_scope(isolate);
19783   v8::Context::Scope context_scope(context.local());
19784
19785   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19786   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19787   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19788   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19789         "var result = []; for (var k in o) result.push(k); result"));
19790   CHECK_EQ(1, result->Length());
19791   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19792 }
19793
19794
19795 TEST(DefinePropertyPostDetach) {
19796   LocalContext context;
19797   v8::HandleScope scope(context->GetIsolate());
19798   v8::Handle<v8::Object> proxy = context->Global();
19799   v8::Handle<v8::Function> define_property =
19800       CompileRun("(function() {"
19801                  "  Object.defineProperty("
19802                  "    this,"
19803                  "    1,"
19804                  "    { configurable: true, enumerable: true, value: 3 });"
19805                  "})").As<Function>();
19806   context->DetachGlobal();
19807   define_property->Call(proxy, 0, NULL);
19808 }
19809
19810
19811 static void InstallContextId(v8::Handle<Context> context, int id) {
19812   Context::Scope scope(context);
19813   CompileRun("Object.prototype").As<Object>()->
19814       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19815 }
19816
19817
19818 static void CheckContextId(v8::Handle<Object> object, int expected) {
19819   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19820 }
19821
19822
19823 THREADED_TEST(CreationContext) {
19824   v8::Isolate* isolate = CcTest::isolate();
19825   HandleScope handle_scope(isolate);
19826   Handle<Context> context1 = Context::New(isolate);
19827   InstallContextId(context1, 1);
19828   Handle<Context> context2 = Context::New(isolate);
19829   InstallContextId(context2, 2);
19830   Handle<Context> context3 = Context::New(isolate);
19831   InstallContextId(context3, 3);
19832
19833   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19834
19835   Local<Object> object1;
19836   Local<Function> func1;
19837   {
19838     Context::Scope scope(context1);
19839     object1 = Object::New(isolate);
19840     func1 = tmpl->GetFunction();
19841   }
19842
19843   Local<Object> object2;
19844   Local<Function> func2;
19845   {
19846     Context::Scope scope(context2);
19847     object2 = Object::New(isolate);
19848     func2 = tmpl->GetFunction();
19849   }
19850
19851   Local<Object> instance1;
19852   Local<Object> instance2;
19853
19854   {
19855     Context::Scope scope(context3);
19856     instance1 = func1->NewInstance();
19857     instance2 = func2->NewInstance();
19858   }
19859
19860   CHECK(object1->CreationContext() == context1);
19861   CheckContextId(object1, 1);
19862   CHECK(func1->CreationContext() == context1);
19863   CheckContextId(func1, 1);
19864   CHECK(instance1->CreationContext() == context1);
19865   CheckContextId(instance1, 1);
19866   CHECK(object2->CreationContext() == context2);
19867   CheckContextId(object2, 2);
19868   CHECK(func2->CreationContext() == context2);
19869   CheckContextId(func2, 2);
19870   CHECK(instance2->CreationContext() == context2);
19871   CheckContextId(instance2, 2);
19872
19873   {
19874     Context::Scope scope(context1);
19875     CHECK(object1->CreationContext() == context1);
19876     CheckContextId(object1, 1);
19877     CHECK(func1->CreationContext() == context1);
19878     CheckContextId(func1, 1);
19879     CHECK(instance1->CreationContext() == context1);
19880     CheckContextId(instance1, 1);
19881     CHECK(object2->CreationContext() == context2);
19882     CheckContextId(object2, 2);
19883     CHECK(func2->CreationContext() == context2);
19884     CheckContextId(func2, 2);
19885     CHECK(instance2->CreationContext() == context2);
19886     CheckContextId(instance2, 2);
19887   }
19888
19889   {
19890     Context::Scope scope(context2);
19891     CHECK(object1->CreationContext() == context1);
19892     CheckContextId(object1, 1);
19893     CHECK(func1->CreationContext() == context1);
19894     CheckContextId(func1, 1);
19895     CHECK(instance1->CreationContext() == context1);
19896     CheckContextId(instance1, 1);
19897     CHECK(object2->CreationContext() == context2);
19898     CheckContextId(object2, 2);
19899     CHECK(func2->CreationContext() == context2);
19900     CheckContextId(func2, 2);
19901     CHECK(instance2->CreationContext() == context2);
19902     CheckContextId(instance2, 2);
19903   }
19904 }
19905
19906
19907 THREADED_TEST(CreationContextOfJsFunction) {
19908   HandleScope handle_scope(CcTest::isolate());
19909   Handle<Context> context = Context::New(CcTest::isolate());
19910   InstallContextId(context, 1);
19911
19912   Local<Object> function;
19913   {
19914     Context::Scope scope(context);
19915     function = CompileRun("function foo() {}; foo").As<Object>();
19916   }
19917
19918   CHECK(function->CreationContext() == context);
19919   CheckContextId(function, 1);
19920 }
19921
19922
19923 void HasOwnPropertyIndexedPropertyGetter(
19924     uint32_t index,
19925     const v8::PropertyCallbackInfo<v8::Value>& info) {
19926   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19927 }
19928
19929
19930 void HasOwnPropertyNamedPropertyGetter(
19931     Local<String> property,
19932     const v8::PropertyCallbackInfo<v8::Value>& info) {
19933   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19934 }
19935
19936
19937 void HasOwnPropertyIndexedPropertyQuery(
19938     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19939   if (index == 42) info.GetReturnValue().Set(1);
19940 }
19941
19942
19943 void HasOwnPropertyNamedPropertyQuery(
19944     Local<String> property,
19945     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19946   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19947 }
19948
19949
19950 void HasOwnPropertyNamedPropertyQuery2(
19951     Local<String> property,
19952     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19953   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19954 }
19955
19956
19957 void HasOwnPropertyAccessorGetter(
19958     Local<String> property,
19959     const v8::PropertyCallbackInfo<v8::Value>& info) {
19960   info.GetReturnValue().Set(v8_str("yes"));
19961 }
19962
19963
19964 TEST(HasOwnProperty) {
19965   LocalContext env;
19966   v8::Isolate* isolate = env->GetIsolate();
19967   v8::HandleScope scope(isolate);
19968   { // Check normal properties and defined getters.
19969     Handle<Value> value = CompileRun(
19970         "function Foo() {"
19971         "    this.foo = 11;"
19972         "    this.__defineGetter__('baz', function() { return 1; });"
19973         "};"
19974         "function Bar() { "
19975         "    this.bar = 13;"
19976         "    this.__defineGetter__('bla', function() { return 2; });"
19977         "};"
19978         "Bar.prototype = new Foo();"
19979         "new Bar();");
19980     CHECK(value->IsObject());
19981     Handle<Object> object = value->ToObject();
19982     CHECK(object->Has(v8_str("foo")));
19983     CHECK(!object->HasOwnProperty(v8_str("foo")));
19984     CHECK(object->HasOwnProperty(v8_str("bar")));
19985     CHECK(object->Has(v8_str("baz")));
19986     CHECK(!object->HasOwnProperty(v8_str("baz")));
19987     CHECK(object->HasOwnProperty(v8_str("bla")));
19988   }
19989   { // Check named getter interceptors.
19990     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19991     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19992     Handle<Object> instance = templ->NewInstance();
19993     CHECK(!instance->HasOwnProperty(v8_str("42")));
19994     CHECK(instance->HasOwnProperty(v8_str("foo")));
19995     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19996   }
19997   { // Check indexed getter interceptors.
19998     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19999     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20000     Handle<Object> instance = templ->NewInstance();
20001     CHECK(instance->HasOwnProperty(v8_str("42")));
20002     CHECK(!instance->HasOwnProperty(v8_str("43")));
20003     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20004   }
20005   { // Check named query interceptors.
20006     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20007     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20008     Handle<Object> instance = templ->NewInstance();
20009     CHECK(instance->HasOwnProperty(v8_str("foo")));
20010     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20011   }
20012   { // Check indexed query interceptors.
20013     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20014     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20015     Handle<Object> instance = templ->NewInstance();
20016     CHECK(instance->HasOwnProperty(v8_str("42")));
20017     CHECK(!instance->HasOwnProperty(v8_str("41")));
20018   }
20019   { // Check callbacks.
20020     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20021     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20022     Handle<Object> instance = templ->NewInstance();
20023     CHECK(instance->HasOwnProperty(v8_str("foo")));
20024     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20025   }
20026   { // Check that query wins on disagreement.
20027     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20028     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20029                                    0,
20030                                    HasOwnPropertyNamedPropertyQuery2);
20031     Handle<Object> instance = templ->NewInstance();
20032     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20033     CHECK(instance->HasOwnProperty(v8_str("bar")));
20034   }
20035 }
20036
20037
20038 TEST(IndexedInterceptorWithStringProto) {
20039   v8::Isolate* isolate = CcTest::isolate();
20040   v8::HandleScope scope(isolate);
20041   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20042   templ->SetIndexedPropertyHandler(NULL,
20043                                    NULL,
20044                                    HasOwnPropertyIndexedPropertyQuery);
20045   LocalContext context;
20046   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20047   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20048   // These should be intercepted.
20049   CHECK(CompileRun("42 in obj")->BooleanValue());
20050   CHECK(CompileRun("'42' in obj")->BooleanValue());
20051   // These should fall through to the String prototype.
20052   CHECK(CompileRun("0 in obj")->BooleanValue());
20053   CHECK(CompileRun("'0' in obj")->BooleanValue());
20054   // And these should both fail.
20055   CHECK(!CompileRun("32 in obj")->BooleanValue());
20056   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20057 }
20058
20059
20060 void CheckCodeGenerationAllowed() {
20061   Handle<Value> result = CompileRun("eval('42')");
20062   CHECK_EQ(42, result->Int32Value());
20063   result = CompileRun("(function(e) { return e('42'); })(eval)");
20064   CHECK_EQ(42, result->Int32Value());
20065   result = CompileRun("var f = new Function('return 42'); f()");
20066   CHECK_EQ(42, result->Int32Value());
20067 }
20068
20069
20070 void CheckCodeGenerationDisallowed() {
20071   TryCatch try_catch;
20072
20073   Handle<Value> result = CompileRun("eval('42')");
20074   CHECK(result.IsEmpty());
20075   CHECK(try_catch.HasCaught());
20076   try_catch.Reset();
20077
20078   result = CompileRun("(function(e) { return e('42'); })(eval)");
20079   CHECK(result.IsEmpty());
20080   CHECK(try_catch.HasCaught());
20081   try_catch.Reset();
20082
20083   result = CompileRun("var f = new Function('return 42'); f()");
20084   CHECK(result.IsEmpty());
20085   CHECK(try_catch.HasCaught());
20086 }
20087
20088
20089 bool CodeGenerationAllowed(Local<Context> context) {
20090   ApiTestFuzzer::Fuzz();
20091   return true;
20092 }
20093
20094
20095 bool CodeGenerationDisallowed(Local<Context> context) {
20096   ApiTestFuzzer::Fuzz();
20097   return false;
20098 }
20099
20100
20101 THREADED_TEST(AllowCodeGenFromStrings) {
20102   LocalContext context;
20103   v8::HandleScope scope(context->GetIsolate());
20104
20105   // eval and the Function constructor allowed by default.
20106   CHECK(context->IsCodeGenerationFromStringsAllowed());
20107   CheckCodeGenerationAllowed();
20108
20109   // Disallow eval and the Function constructor.
20110   context->AllowCodeGenerationFromStrings(false);
20111   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20112   CheckCodeGenerationDisallowed();
20113
20114   // Allow again.
20115   context->AllowCodeGenerationFromStrings(true);
20116   CheckCodeGenerationAllowed();
20117
20118   // Disallow but setting a global callback that will allow the calls.
20119   context->AllowCodeGenerationFromStrings(false);
20120   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20121   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20122   CheckCodeGenerationAllowed();
20123
20124   // Set a callback that disallows the code generation.
20125   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20126   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20127   CheckCodeGenerationDisallowed();
20128 }
20129
20130
20131 TEST(SetErrorMessageForCodeGenFromStrings) {
20132   LocalContext context;
20133   v8::HandleScope scope(context->GetIsolate());
20134   TryCatch try_catch;
20135
20136   Handle<String> message = v8_str("Message") ;
20137   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20138   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20139   context->AllowCodeGenerationFromStrings(false);
20140   context->SetErrorMessageForCodeGenerationFromStrings(message);
20141   Handle<Value> result = CompileRun("eval('42')");
20142   CHECK(result.IsEmpty());
20143   CHECK(try_catch.HasCaught());
20144   Handle<String> actual_message = try_catch.Message()->Get();
20145   CHECK(expected_message->Equals(actual_message));
20146 }
20147
20148
20149 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20150 }
20151
20152
20153 THREADED_TEST(CallAPIFunctionOnNonObject) {
20154   LocalContext context;
20155   v8::Isolate* isolate = context->GetIsolate();
20156   v8::HandleScope scope(isolate);
20157   Handle<FunctionTemplate> templ =
20158       v8::FunctionTemplate::New(isolate, NonObjectThis);
20159   Handle<Function> function = templ->GetFunction();
20160   context->Global()->Set(v8_str("f"), function);
20161   TryCatch try_catch;
20162   CompileRun("f.call(2)");
20163 }
20164
20165
20166 // Regression test for issue 1470.
20167 THREADED_TEST(ReadOnlyIndexedProperties) {
20168   v8::Isolate* isolate = CcTest::isolate();
20169   v8::HandleScope scope(isolate);
20170   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20171
20172   LocalContext context;
20173   Local<v8::Object> obj = templ->NewInstance();
20174   context->Global()->Set(v8_str("obj"), obj);
20175   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20176   obj->Set(v8_str("1"), v8_str("foobar"));
20177   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20178   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20179   obj->Set(v8_num(2), v8_str("foobar"));
20180   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20181
20182   // Test non-smi case.
20183   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20184   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20185   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20186 }
20187
20188
20189 THREADED_TEST(Regress1516) {
20190   LocalContext context;
20191   v8::HandleScope scope(context->GetIsolate());
20192
20193   { v8::HandleScope temp_scope(context->GetIsolate());
20194     CompileRun("({'a': 0})");
20195   }
20196
20197   int elements;
20198   { i::MapCache* map_cache =
20199         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20200     elements = map_cache->NumberOfElements();
20201     CHECK_LE(1, elements);
20202   }
20203
20204   CcTest::heap()->CollectAllGarbage(
20205       i::Heap::kAbortIncrementalMarkingMask);
20206   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20207     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20208       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20209       CHECK_GT(elements, map_cache->NumberOfElements());
20210     }
20211   }
20212 }
20213
20214
20215 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20216                                                 Local<Value> name,
20217                                                 v8::AccessType type,
20218                                                 Local<Value> data) {
20219   // Only block read access to __proto__.
20220   if (type == v8::ACCESS_GET &&
20221       name->IsString() &&
20222       name->ToString()->Length() == 9 &&
20223       name->ToString()->Utf8Length() == 9) {
20224     char buffer[10];
20225     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20226     return strncmp(buffer, "__proto__", 9) != 0;
20227   }
20228
20229   return true;
20230 }
20231
20232
20233 THREADED_TEST(Regress93759) {
20234   v8::Isolate* isolate = CcTest::isolate();
20235   HandleScope scope(isolate);
20236
20237   // Template for object with security check.
20238   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20239   // We don't do indexing, so any callback can be used for that.
20240   no_proto_template->SetAccessCheckCallbacks(
20241       BlockProtoNamedSecurityTestCallback,
20242       IndexedSecurityTestCallback);
20243
20244   // Templates for objects with hidden prototypes and possibly security check.
20245   Local<FunctionTemplate> hidden_proto_template =
20246       v8::FunctionTemplate::New(isolate);
20247   hidden_proto_template->SetHiddenPrototype(true);
20248
20249   Local<FunctionTemplate> protected_hidden_proto_template =
20250       v8::FunctionTemplate::New(isolate);
20251   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20252       BlockProtoNamedSecurityTestCallback,
20253       IndexedSecurityTestCallback);
20254   protected_hidden_proto_template->SetHiddenPrototype(true);
20255
20256   // Context for "foreign" objects used in test.
20257   Local<Context> context = v8::Context::New(isolate);
20258   context->Enter();
20259
20260   // Plain object, no security check.
20261   Local<Object> simple_object = Object::New(isolate);
20262
20263   // Object with explicit security check.
20264   Local<Object> protected_object =
20265       no_proto_template->NewInstance();
20266
20267   // JSGlobalProxy object, always have security check.
20268   Local<Object> proxy_object =
20269       context->Global();
20270
20271   // Global object, the  prototype of proxy_object. No security checks.
20272   Local<Object> global_object =
20273       proxy_object->GetPrototype()->ToObject();
20274
20275   // Hidden prototype without security check.
20276   Local<Object> hidden_prototype =
20277       hidden_proto_template->GetFunction()->NewInstance();
20278   Local<Object> object_with_hidden =
20279     Object::New(isolate);
20280   object_with_hidden->SetPrototype(hidden_prototype);
20281
20282   // Hidden prototype with security check on the hidden prototype.
20283   Local<Object> protected_hidden_prototype =
20284       protected_hidden_proto_template->GetFunction()->NewInstance();
20285   Local<Object> object_with_protected_hidden =
20286     Object::New(isolate);
20287   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20288
20289   context->Exit();
20290
20291   // Template for object for second context. Values to test are put on it as
20292   // properties.
20293   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20294   global_template->Set(v8_str("simple"), simple_object);
20295   global_template->Set(v8_str("protected"), protected_object);
20296   global_template->Set(v8_str("global"), global_object);
20297   global_template->Set(v8_str("proxy"), proxy_object);
20298   global_template->Set(v8_str("hidden"), object_with_hidden);
20299   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20300
20301   LocalContext context2(NULL, global_template);
20302
20303   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20304   CHECK(result1->Equals(simple_object->GetPrototype()));
20305
20306   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20307   CHECK(result2->Equals(Undefined(isolate)));
20308
20309   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20310   CHECK(result3->Equals(global_object->GetPrototype()));
20311
20312   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20313   CHECK(result4->Equals(Undefined(isolate)));
20314
20315   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20316   CHECK(result5->Equals(
20317       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20318
20319   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20320   CHECK(result6->Equals(Undefined(isolate)));
20321 }
20322
20323
20324 THREADED_TEST(Regress125988) {
20325   v8::HandleScope scope(CcTest::isolate());
20326   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20327   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20328   LocalContext env;
20329   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20330   CompileRun("var a = new Object();"
20331              "var b = new Intercept();"
20332              "var c = new Object();"
20333              "c.__proto__ = b;"
20334              "b.__proto__ = a;"
20335              "a.x = 23;"
20336              "for (var i = 0; i < 3; i++) c.x;");
20337   ExpectBoolean("c.hasOwnProperty('x')", false);
20338   ExpectInt32("c.x", 23);
20339   CompileRun("a.y = 42;"
20340              "for (var i = 0; i < 3; i++) c.x;");
20341   ExpectBoolean("c.hasOwnProperty('x')", false);
20342   ExpectInt32("c.x", 23);
20343   ExpectBoolean("c.hasOwnProperty('y')", false);
20344   ExpectInt32("c.y", 42);
20345 }
20346
20347
20348 static void TestReceiver(Local<Value> expected_result,
20349                          Local<Value> expected_receiver,
20350                          const char* code) {
20351   Local<Value> result = CompileRun(code);
20352   CHECK(result->IsObject());
20353   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20354   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20355 }
20356
20357
20358 THREADED_TEST(ForeignFunctionReceiver) {
20359   v8::Isolate* isolate = CcTest::isolate();
20360   HandleScope scope(isolate);
20361
20362   // Create two contexts with different "id" properties ('i' and 'o').
20363   // Call a function both from its own context and from a the foreign
20364   // context, and see what "this" is bound to (returning both "this"
20365   // and "this.id" for comparison).
20366
20367   Local<Context> foreign_context = v8::Context::New(isolate);
20368   foreign_context->Enter();
20369   Local<Value> foreign_function =
20370     CompileRun("function func() { return { 0: this.id, "
20371                "                           1: this, "
20372                "                           toString: function() { "
20373                "                               return this[0];"
20374                "                           }"
20375                "                         };"
20376                "}"
20377                "var id = 'i';"
20378                "func;");
20379   CHECK(foreign_function->IsFunction());
20380   foreign_context->Exit();
20381
20382   LocalContext context;
20383
20384   Local<String> password = v8_str("Password");
20385   // Don't get hit by security checks when accessing foreign_context's
20386   // global receiver (aka. global proxy).
20387   context->SetSecurityToken(password);
20388   foreign_context->SetSecurityToken(password);
20389
20390   Local<String> i = v8_str("i");
20391   Local<String> o = v8_str("o");
20392   Local<String> id = v8_str("id");
20393
20394   CompileRun("function ownfunc() { return { 0: this.id, "
20395              "                              1: this, "
20396              "                              toString: function() { "
20397              "                                  return this[0];"
20398              "                              }"
20399              "                             };"
20400              "}"
20401              "var id = 'o';"
20402              "ownfunc");
20403   context->Global()->Set(v8_str("func"), foreign_function);
20404
20405   // Sanity check the contexts.
20406   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20407   CHECK(o->Equals(context->Global()->Get(id)));
20408
20409   // Checking local function's receiver.
20410   // Calling function using its call/apply methods.
20411   TestReceiver(o, context->Global(), "ownfunc.call()");
20412   TestReceiver(o, context->Global(), "ownfunc.apply()");
20413   // Making calls through built-in functions.
20414   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20415   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20416   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20417   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20418   // Calling with environment record as base.
20419   TestReceiver(o, context->Global(), "ownfunc()");
20420   // Calling with no base.
20421   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20422
20423   // Checking foreign function return value.
20424   // Calling function using its call/apply methods.
20425   TestReceiver(i, foreign_context->Global(), "func.call()");
20426   TestReceiver(i, foreign_context->Global(), "func.apply()");
20427   // Calling function using another context's call/apply methods.
20428   TestReceiver(i, foreign_context->Global(),
20429                "Function.prototype.call.call(func)");
20430   TestReceiver(i, foreign_context->Global(),
20431                "Function.prototype.call.apply(func)");
20432   TestReceiver(i, foreign_context->Global(),
20433                "Function.prototype.apply.call(func)");
20434   TestReceiver(i, foreign_context->Global(),
20435                "Function.prototype.apply.apply(func)");
20436   // Making calls through built-in functions.
20437   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20438   // ToString(func()) is func()[0], i.e., the returned this.id.
20439   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20440   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20441   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20442
20443   // Calling with environment record as base.
20444   TestReceiver(i, foreign_context->Global(), "func()");
20445   // Calling with no base.
20446   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20447 }
20448
20449
20450 uint8_t callback_fired = 0;
20451
20452
20453 void CallCompletedCallback1() {
20454   i::OS::Print("Firing callback 1.\n");
20455   callback_fired ^= 1;  // Toggle first bit.
20456 }
20457
20458
20459 void CallCompletedCallback2() {
20460   i::OS::Print("Firing callback 2.\n");
20461   callback_fired ^= 2;  // Toggle second bit.
20462 }
20463
20464
20465 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20466   int32_t level = args[0]->Int32Value();
20467   if (level < 3) {
20468     level++;
20469     i::OS::Print("Entering recursion level %d.\n", level);
20470     char script[64];
20471     i::Vector<char> script_vector(script, sizeof(script));
20472     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
20473     CompileRun(script_vector.start());
20474     i::OS::Print("Leaving recursion level %d.\n", level);
20475     CHECK_EQ(0, callback_fired);
20476   } else {
20477     i::OS::Print("Recursion ends.\n");
20478     CHECK_EQ(0, callback_fired);
20479   }
20480 }
20481
20482
20483 TEST(CallCompletedCallback) {
20484   LocalContext env;
20485   v8::HandleScope scope(env->GetIsolate());
20486   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20487       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20488   env->Global()->Set(v8_str("recursion"),
20489                      recursive_runtime->GetFunction());
20490   // Adding the same callback a second time has no effect.
20491   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20492   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
20493   v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
20494   i::OS::Print("--- Script (1) ---\n");
20495   Local<Script> script = v8::Script::Compile(
20496       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20497   script->Run();
20498   CHECK_EQ(3, callback_fired);
20499
20500   i::OS::Print("\n--- Script (2) ---\n");
20501   callback_fired = 0;
20502   v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
20503   script->Run();
20504   CHECK_EQ(2, callback_fired);
20505
20506   i::OS::Print("\n--- Function ---\n");
20507   callback_fired = 0;
20508   Local<Function> recursive_function =
20509       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20510   v8::Handle<Value> args[] = { v8_num(0) };
20511   recursive_function->Call(env->Global(), 1, args);
20512   CHECK_EQ(2, callback_fired);
20513 }
20514
20515
20516 void CallCompletedCallbackNoException() {
20517   v8::HandleScope scope(CcTest::isolate());
20518   CompileRun("1+1;");
20519 }
20520
20521
20522 void CallCompletedCallbackException() {
20523   v8::HandleScope scope(CcTest::isolate());
20524   CompileRun("throw 'second exception';");
20525 }
20526
20527
20528 TEST(CallCompletedCallbackOneException) {
20529   LocalContext env;
20530   v8::HandleScope scope(env->GetIsolate());
20531   v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
20532   CompileRun("throw 'exception';");
20533 }
20534
20535
20536 TEST(CallCompletedCallbackTwoExceptions) {
20537   LocalContext env;
20538   v8::HandleScope scope(env->GetIsolate());
20539   v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
20540   CompileRun("throw 'first exception';");
20541 }
20542
20543
20544 static int probes_counter = 0;
20545 static int misses_counter = 0;
20546 static int updates_counter = 0;
20547
20548
20549 static int* LookupCounter(const char* name) {
20550   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20551     return &probes_counter;
20552   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20553     return &misses_counter;
20554   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20555     return &updates_counter;
20556   }
20557   return NULL;
20558 }
20559
20560
20561 static const char* kMegamorphicTestProgram =
20562     "function ClassA() { };"
20563     "function ClassB() { };"
20564     "ClassA.prototype.foo = function() { };"
20565     "ClassB.prototype.foo = function() { };"
20566     "function fooify(obj) { obj.foo(); };"
20567     "var a = new ClassA();"
20568     "var b = new ClassB();"
20569     "for (var i = 0; i < 10000; i++) {"
20570     "  fooify(a);"
20571     "  fooify(b);"
20572     "}";
20573
20574
20575 static void StubCacheHelper(bool primary) {
20576   V8::SetCounterFunction(LookupCounter);
20577   USE(kMegamorphicTestProgram);
20578 #ifdef DEBUG
20579   i::FLAG_native_code_counters = true;
20580   if (primary) {
20581     i::FLAG_test_primary_stub_cache = true;
20582   } else {
20583     i::FLAG_test_secondary_stub_cache = true;
20584   }
20585   i::FLAG_crankshaft = false;
20586   LocalContext env;
20587   v8::HandleScope scope(env->GetIsolate());
20588   int initial_probes = probes_counter;
20589   int initial_misses = misses_counter;
20590   int initial_updates = updates_counter;
20591   CompileRun(kMegamorphicTestProgram);
20592   int probes = probes_counter - initial_probes;
20593   int misses = misses_counter - initial_misses;
20594   int updates = updates_counter - initial_updates;
20595   CHECK_LT(updates, 10);
20596   CHECK_LT(misses, 10);
20597   CHECK_GE(probes, 10000);
20598 #endif
20599 }
20600
20601
20602 TEST(SecondaryStubCache) {
20603   StubCacheHelper(true);
20604 }
20605
20606
20607 TEST(PrimaryStubCache) {
20608   StubCacheHelper(false);
20609 }
20610
20611
20612 static int cow_arrays_created_runtime = 0;
20613
20614
20615 static int* LookupCounterCOWArrays(const char* name) {
20616   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20617     return &cow_arrays_created_runtime;
20618   }
20619   return NULL;
20620 }
20621
20622
20623 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20624   V8::SetCounterFunction(LookupCounterCOWArrays);
20625 #ifdef DEBUG
20626   i::FLAG_native_code_counters = true;
20627   LocalContext env;
20628   v8::HandleScope scope(env->GetIsolate());
20629   int initial_cow_arrays = cow_arrays_created_runtime;
20630   CompileRun("var o = [1, 2, 3];");
20631   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20632   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20633   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20634   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20635   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20636 #endif
20637 }
20638
20639
20640 TEST(StaticGetters) {
20641   LocalContext context;
20642   i::Factory* factory = CcTest::i_isolate()->factory();
20643   v8::Isolate* isolate = CcTest::isolate();
20644   v8::HandleScope scope(isolate);
20645   i::Handle<i::Object> undefined_value = factory->undefined_value();
20646   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20647   i::Handle<i::Object> null_value = factory->null_value();
20648   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20649   i::Handle<i::Object> true_value = factory->true_value();
20650   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20651   i::Handle<i::Object> false_value = factory->false_value();
20652   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20653 }
20654
20655
20656 UNINITIALIZED_TEST(IsolateEmbedderData) {
20657   CcTest::DisableAutomaticDispose();
20658   v8::Isolate* isolate = v8::Isolate::New();
20659   isolate->Enter();
20660   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20661   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20662     CHECK_EQ(NULL, isolate->GetData(slot));
20663     CHECK_EQ(NULL, i_isolate->GetData(slot));
20664   }
20665   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20666     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20667     isolate->SetData(slot, data);
20668   }
20669   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20670     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20671     CHECK_EQ(data, isolate->GetData(slot));
20672     CHECK_EQ(data, i_isolate->GetData(slot));
20673   }
20674   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20675     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20676     isolate->SetData(slot, data);
20677   }
20678   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20679     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
20680     CHECK_EQ(data, isolate->GetData(slot));
20681     CHECK_EQ(data, i_isolate->GetData(slot));
20682   }
20683   isolate->Exit();
20684   isolate->Dispose();
20685 }
20686
20687
20688 TEST(StringEmpty) {
20689   LocalContext context;
20690   i::Factory* factory = CcTest::i_isolate()->factory();
20691   v8::Isolate* isolate = CcTest::isolate();
20692   v8::HandleScope scope(isolate);
20693   i::Handle<i::Object> empty_string = factory->empty_string();
20694   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
20695 }
20696
20697
20698 static int instance_checked_getter_count = 0;
20699 static void InstanceCheckedGetter(
20700     Local<String> name,
20701     const v8::PropertyCallbackInfo<v8::Value>& info) {
20702   CHECK_EQ(name, v8_str("foo"));
20703   instance_checked_getter_count++;
20704   info.GetReturnValue().Set(v8_num(11));
20705 }
20706
20707
20708 static int instance_checked_setter_count = 0;
20709 static void InstanceCheckedSetter(Local<String> name,
20710                       Local<Value> value,
20711                       const v8::PropertyCallbackInfo<void>& info) {
20712   CHECK_EQ(name, v8_str("foo"));
20713   CHECK_EQ(value, v8_num(23));
20714   instance_checked_setter_count++;
20715 }
20716
20717
20718 static void CheckInstanceCheckedResult(int getters,
20719                                        int setters,
20720                                        bool expects_callbacks,
20721                                        TryCatch* try_catch) {
20722   if (expects_callbacks) {
20723     CHECK(!try_catch->HasCaught());
20724     CHECK_EQ(getters, instance_checked_getter_count);
20725     CHECK_EQ(setters, instance_checked_setter_count);
20726   } else {
20727     CHECK(try_catch->HasCaught());
20728     CHECK_EQ(0, instance_checked_getter_count);
20729     CHECK_EQ(0, instance_checked_setter_count);
20730   }
20731   try_catch->Reset();
20732 }
20733
20734
20735 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
20736   instance_checked_getter_count = 0;
20737   instance_checked_setter_count = 0;
20738   TryCatch try_catch;
20739
20740   // Test path through generic runtime code.
20741   CompileRun("obj.foo");
20742   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
20743   CompileRun("obj.foo = 23");
20744   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
20745
20746   // Test path through generated LoadIC and StoredIC.
20747   CompileRun("function test_get(o) { o.foo; }"
20748              "test_get(obj);");
20749   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
20750   CompileRun("test_get(obj);");
20751   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
20752   CompileRun("test_get(obj);");
20753   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
20754   CompileRun("function test_set(o) { o.foo = 23; }"
20755              "test_set(obj);");
20756   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
20757   CompileRun("test_set(obj);");
20758   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
20759   CompileRun("test_set(obj);");
20760   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
20761
20762   // Test path through optimized code.
20763   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
20764              "test_get(obj);");
20765   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
20766   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
20767              "test_set(obj);");
20768   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
20769
20770   // Cleanup so that closures start out fresh in next check.
20771   CompileRun("%DeoptimizeFunction(test_get);"
20772              "%ClearFunctionTypeFeedback(test_get);"
20773              "%DeoptimizeFunction(test_set);"
20774              "%ClearFunctionTypeFeedback(test_set);");
20775 }
20776
20777
20778 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
20779   v8::internal::FLAG_allow_natives_syntax = true;
20780   LocalContext context;
20781   v8::HandleScope scope(context->GetIsolate());
20782
20783   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20784   Local<ObjectTemplate> inst = templ->InstanceTemplate();
20785   inst->SetAccessor(v8_str("foo"),
20786                     InstanceCheckedGetter, InstanceCheckedSetter,
20787                     Handle<Value>(),
20788                     v8::DEFAULT,
20789                     v8::None,
20790                     v8::AccessorSignature::New(context->GetIsolate(), templ));
20791   context->Global()->Set(v8_str("f"), templ->GetFunction());
20792
20793   printf("Testing positive ...\n");
20794   CompileRun("var obj = new f();");
20795   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20796   CheckInstanceCheckedAccessors(true);
20797
20798   printf("Testing negative ...\n");
20799   CompileRun("var obj = {};"
20800              "obj.__proto__ = new f();");
20801   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20802   CheckInstanceCheckedAccessors(false);
20803 }
20804
20805
20806 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
20807   v8::internal::FLAG_allow_natives_syntax = true;
20808   LocalContext context;
20809   v8::HandleScope scope(context->GetIsolate());
20810
20811   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20812   Local<ObjectTemplate> inst = templ->InstanceTemplate();
20813   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20814   inst->SetAccessor(v8_str("foo"),
20815                     InstanceCheckedGetter, InstanceCheckedSetter,
20816                     Handle<Value>(),
20817                     v8::DEFAULT,
20818                     v8::None,
20819                     v8::AccessorSignature::New(context->GetIsolate(), templ));
20820   context->Global()->Set(v8_str("f"), templ->GetFunction());
20821
20822   printf("Testing positive ...\n");
20823   CompileRun("var obj = new f();");
20824   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20825   CheckInstanceCheckedAccessors(true);
20826
20827   printf("Testing negative ...\n");
20828   CompileRun("var obj = {};"
20829              "obj.__proto__ = new f();");
20830   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20831   CheckInstanceCheckedAccessors(false);
20832 }
20833
20834
20835 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20836   v8::internal::FLAG_allow_natives_syntax = true;
20837   LocalContext context;
20838   v8::HandleScope scope(context->GetIsolate());
20839
20840   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
20841   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20842   proto->SetAccessor(v8_str("foo"),
20843                      InstanceCheckedGetter, InstanceCheckedSetter,
20844                      Handle<Value>(),
20845                      v8::DEFAULT,
20846                      v8::None,
20847                      v8::AccessorSignature::New(context->GetIsolate(), templ));
20848   context->Global()->Set(v8_str("f"), templ->GetFunction());
20849
20850   printf("Testing positive ...\n");
20851   CompileRun("var obj = new f();");
20852   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20853   CheckInstanceCheckedAccessors(true);
20854
20855   printf("Testing negative ...\n");
20856   CompileRun("var obj = {};"
20857              "obj.__proto__ = new f();");
20858   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20859   CheckInstanceCheckedAccessors(false);
20860
20861   printf("Testing positive with modified prototype chain ...\n");
20862   CompileRun("var obj = new f();"
20863              "var pro = {};"
20864              "pro.__proto__ = obj.__proto__;"
20865              "obj.__proto__ = pro;");
20866   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20867   CheckInstanceCheckedAccessors(true);
20868 }
20869
20870
20871 TEST(TryFinallyMessage) {
20872   LocalContext context;
20873   v8::HandleScope scope(context->GetIsolate());
20874   {
20875     // Test that the original error message is not lost if there is a
20876     // recursive call into Javascript is done in the finally block, e.g. to
20877     // initialize an IC. (crbug.com/129171)
20878     TryCatch try_catch;
20879     const char* trigger_ic =
20880         "try {                      \n"
20881         "  throw new Error('test'); \n"
20882         "} finally {                \n"
20883         "  var x = 0;               \n"
20884         "  x++;                     \n"  // Trigger an IC initialization here.
20885         "}                          \n";
20886     CompileRun(trigger_ic);
20887     CHECK(try_catch.HasCaught());
20888     Local<Message> message = try_catch.Message();
20889     CHECK(!message.IsEmpty());
20890     CHECK_EQ(2, message->GetLineNumber());
20891   }
20892
20893   {
20894     // Test that the original exception message is indeed overwritten if
20895     // a new error is thrown in the finally block.
20896     TryCatch try_catch;
20897     const char* throw_again =
20898         "try {                       \n"
20899         "  throw new Error('test');  \n"
20900         "} finally {                 \n"
20901         "  var x = 0;                \n"
20902         "  x++;                      \n"
20903         "  throw new Error('again'); \n"  // This is the new uncaught error.
20904         "}                           \n";
20905     CompileRun(throw_again);
20906     CHECK(try_catch.HasCaught());
20907     Local<Message> message = try_catch.Message();
20908     CHECK(!message.IsEmpty());
20909     CHECK_EQ(6, message->GetLineNumber());
20910   }
20911 }
20912
20913
20914 static void Helper137002(bool do_store,
20915                          bool polymorphic,
20916                          bool remove_accessor,
20917                          bool interceptor) {
20918   LocalContext context;
20919   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
20920   if (interceptor) {
20921     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
20922   } else {
20923     templ->SetAccessor(v8_str("foo"),
20924                        GetterWhichReturns42,
20925                        SetterWhichSetsYOnThisTo23);
20926   }
20927   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20928
20929   // Turn monomorphic on slow object with native accessor, then turn
20930   // polymorphic, finally optimize to create negative lookup and fail.
20931   CompileRun(do_store ?
20932              "function f(x) { x.foo = void 0; }" :
20933              "function f(x) { return x.foo; }");
20934   CompileRun("obj.y = void 0;");
20935   if (!interceptor) {
20936     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20937   }
20938   CompileRun("obj.__proto__ = null;"
20939              "f(obj); f(obj); f(obj);");
20940   if (polymorphic) {
20941     CompileRun("f({});");
20942   }
20943   CompileRun("obj.y = void 0;"
20944              "%OptimizeFunctionOnNextCall(f);");
20945   if (remove_accessor) {
20946     CompileRun("delete obj.foo;");
20947   }
20948   CompileRun("var result = f(obj);");
20949   if (do_store) {
20950     CompileRun("result = obj.y;");
20951   }
20952   if (remove_accessor && !interceptor) {
20953     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20954   } else {
20955     CHECK_EQ(do_store ? 23 : 42,
20956              context->Global()->Get(v8_str("result"))->Int32Value());
20957   }
20958 }
20959
20960
20961 THREADED_TEST(Regress137002a) {
20962   i::FLAG_allow_natives_syntax = true;
20963   i::FLAG_compilation_cache = false;
20964   v8::HandleScope scope(CcTest::isolate());
20965   for (int i = 0; i < 16; i++) {
20966     Helper137002(i & 8, i & 4, i & 2, i & 1);
20967   }
20968 }
20969
20970
20971 THREADED_TEST(Regress137002b) {
20972   i::FLAG_allow_natives_syntax = true;
20973   LocalContext context;
20974   v8::Isolate* isolate = context->GetIsolate();
20975   v8::HandleScope scope(isolate);
20976   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20977   templ->SetAccessor(v8_str("foo"),
20978                      GetterWhichReturns42,
20979                      SetterWhichSetsYOnThisTo23);
20980   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20981
20982   // Turn monomorphic on slow object with native accessor, then just
20983   // delete the property and fail.
20984   CompileRun("function load(x) { return x.foo; }"
20985              "function store(x) { x.foo = void 0; }"
20986              "function keyed_load(x, key) { return x[key]; }"
20987              // Second version of function has a different source (add void 0)
20988              // so that it does not share code with the first version.  This
20989              // ensures that the ICs are monomorphic.
20990              "function load2(x) { void 0; return x.foo; }"
20991              "function store2(x) { void 0; x.foo = void 0; }"
20992              "function keyed_load2(x, key) { void 0; return x[key]; }"
20993
20994              "obj.y = void 0;"
20995              "obj.__proto__ = null;"
20996              "var subobj = {};"
20997              "subobj.y = void 0;"
20998              "subobj.__proto__ = obj;"
20999              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21000
21001              // Make the ICs monomorphic.
21002              "load(obj); load(obj);"
21003              "load2(subobj); load2(subobj);"
21004              "store(obj); store(obj);"
21005              "store2(subobj); store2(subobj);"
21006              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21007              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21008
21009              // Actually test the shiny new ICs and better not crash. This
21010              // serves as a regression test for issue 142088 as well.
21011              "load(obj);"
21012              "load2(subobj);"
21013              "store(obj);"
21014              "store2(subobj);"
21015              "keyed_load(obj, 'foo');"
21016              "keyed_load2(subobj, 'foo');"
21017
21018              // Delete the accessor.  It better not be called any more now.
21019              "delete obj.foo;"
21020              "obj.y = void 0;"
21021              "subobj.y = void 0;"
21022
21023              "var load_result = load(obj);"
21024              "var load_result2 = load2(subobj);"
21025              "var keyed_load_result = keyed_load(obj, 'foo');"
21026              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21027              "store(obj);"
21028              "store2(subobj);"
21029              "var y_from_obj = obj.y;"
21030              "var y_from_subobj = subobj.y;");
21031   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21032   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21033   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21034   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21035   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21036   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21037 }
21038
21039
21040 THREADED_TEST(Regress142088) {
21041   i::FLAG_allow_natives_syntax = true;
21042   LocalContext context;
21043   v8::Isolate* isolate = context->GetIsolate();
21044   v8::HandleScope scope(isolate);
21045   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21046   templ->SetAccessor(v8_str("foo"),
21047                      GetterWhichReturns42,
21048                      SetterWhichSetsYOnThisTo23);
21049   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21050
21051   CompileRun("function load(x) { return x.foo; }"
21052              "var o = Object.create(obj);"
21053              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21054              "load(o); load(o); load(o); load(o);");
21055 }
21056
21057
21058 THREADED_TEST(Regress137496) {
21059   i::FLAG_expose_gc = true;
21060   LocalContext context;
21061   v8::HandleScope scope(context->GetIsolate());
21062
21063   // Compile a try-finally clause where the finally block causes a GC
21064   // while there still is a message pending for external reporting.
21065   TryCatch try_catch;
21066   try_catch.SetVerbose(true);
21067   CompileRun("try { throw new Error(); } finally { gc(); }");
21068   CHECK(try_catch.HasCaught());
21069 }
21070
21071
21072 THREADED_TEST(Regress149912) {
21073   LocalContext context;
21074   v8::HandleScope scope(context->GetIsolate());
21075   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21076   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21077   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21078   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21079 }
21080
21081
21082 THREADED_TEST(Regress157124) {
21083   LocalContext context;
21084   v8::Isolate* isolate = context->GetIsolate();
21085   v8::HandleScope scope(isolate);
21086   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21087   Local<Object> obj = templ->NewInstance();
21088   obj->GetIdentityHash();
21089   obj->DeleteHiddenValue(v8_str("Bug"));
21090 }
21091
21092
21093 THREADED_TEST(Regress2535) {
21094   i::FLAG_harmony_collections = true;
21095   LocalContext context;
21096   v8::HandleScope scope(context->GetIsolate());
21097   Local<Value> set_value = CompileRun("new Set();");
21098   Local<Object> set_object(Local<Object>::Cast(set_value));
21099   CHECK_EQ(0, set_object->InternalFieldCount());
21100   Local<Value> map_value = CompileRun("new Map();");
21101   Local<Object> map_object(Local<Object>::Cast(map_value));
21102   CHECK_EQ(0, map_object->InternalFieldCount());
21103 }
21104
21105
21106 THREADED_TEST(Regress2746) {
21107   LocalContext context;
21108   v8::Isolate* isolate = context->GetIsolate();
21109   v8::HandleScope scope(isolate);
21110   Local<Object> obj = Object::New(isolate);
21111   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21112   obj->SetHiddenValue(key, v8::Undefined(isolate));
21113   Local<Value> value = obj->GetHiddenValue(key);
21114   CHECK(!value.IsEmpty());
21115   CHECK(value->IsUndefined());
21116 }
21117
21118
21119 THREADED_TEST(Regress260106) {
21120   LocalContext context;
21121   v8::Isolate* isolate = context->GetIsolate();
21122   v8::HandleScope scope(isolate);
21123   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21124                                                         DummyCallHandler);
21125   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21126   Local<Function> function = templ->GetFunction();
21127   CHECK(!function.IsEmpty());
21128   CHECK(function->IsFunction());
21129 }
21130
21131
21132 THREADED_TEST(JSONParseObject) {
21133   LocalContext context;
21134   HandleScope scope(context->GetIsolate());
21135   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21136   Handle<Object> global = context->Global();
21137   global->Set(v8_str("obj"), obj);
21138   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21139 }
21140
21141
21142 THREADED_TEST(JSONParseNumber) {
21143   LocalContext context;
21144   HandleScope scope(context->GetIsolate());
21145   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21146   Handle<Object> global = context->Global();
21147   global->Set(v8_str("obj"), obj);
21148   ExpectString("JSON.stringify(obj)", "42");
21149 }
21150
21151
21152 #if V8_OS_POSIX
21153 class ThreadInterruptTest {
21154  public:
21155   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21156   ~ThreadInterruptTest() {}
21157
21158   void RunTest() {
21159     InterruptThread i_thread(this);
21160     i_thread.Start();
21161
21162     sem_.Wait();
21163     CHECK_EQ(kExpectedValue, sem_value_);
21164   }
21165
21166  private:
21167   static const int kExpectedValue = 1;
21168
21169   class InterruptThread : public i::Thread {
21170    public:
21171     explicit InterruptThread(ThreadInterruptTest* test)
21172         : Thread("InterruptThread"), test_(test) {}
21173
21174     virtual void Run() {
21175       struct sigaction action;
21176
21177       // Ensure that we'll enter waiting condition
21178       i::OS::Sleep(100);
21179
21180       // Setup signal handler
21181       memset(&action, 0, sizeof(action));
21182       action.sa_handler = SignalHandler;
21183       sigaction(SIGCHLD, &action, NULL);
21184
21185       // Send signal
21186       kill(getpid(), SIGCHLD);
21187
21188       // Ensure that if wait has returned because of error
21189       i::OS::Sleep(100);
21190
21191       // Set value and signal semaphore
21192       test_->sem_value_ = 1;
21193       test_->sem_.Signal();
21194     }
21195
21196     static void SignalHandler(int signal) {
21197     }
21198
21199    private:
21200      ThreadInterruptTest* test_;
21201   };
21202
21203   i::Semaphore sem_;
21204   volatile int sem_value_;
21205 };
21206
21207
21208 THREADED_TEST(SemaphoreInterruption) {
21209   ThreadInterruptTest().RunTest();
21210 }
21211
21212
21213 #endif  // V8_OS_POSIX
21214
21215
21216 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21217                                      Local<Value> name,
21218                                      v8::AccessType type,
21219                                      Local<Value> data) {
21220   i::PrintF("Named access blocked.\n");
21221   return false;
21222 }
21223
21224
21225 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21226                                      uint32_t key,
21227                                      v8::AccessType type,
21228                                      Local<Value> data) {
21229   i::PrintF("Indexed access blocked.\n");
21230   return false;
21231 }
21232
21233
21234 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21235   CHECK(false);
21236 }
21237
21238
21239 TEST(JSONStringifyAccessCheck) {
21240   v8::V8::Initialize();
21241   v8::Isolate* isolate = CcTest::isolate();
21242   v8::HandleScope scope(isolate);
21243
21244   // Create an ObjectTemplate for global objects and install access
21245   // check callbacks that will block access.
21246   v8::Handle<v8::ObjectTemplate> global_template =
21247       v8::ObjectTemplate::New(isolate);
21248   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21249                                            IndexAccessAlwaysBlocked);
21250
21251   // Create a context and set an x property on it's global object.
21252   LocalContext context0(NULL, global_template);
21253   v8::Handle<v8::Object> global0 = context0->Global();
21254   global0->Set(v8_str("x"), v8_num(42));
21255   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21256
21257   for (int i = 0; i < 2; i++) {
21258     if (i == 1) {
21259       // Install a toJSON function on the second run.
21260       v8::Handle<v8::FunctionTemplate> toJSON =
21261           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21262
21263       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21264     }
21265     // Create a context with a different security token so that the
21266     // failed access check callback will be called on each access.
21267     LocalContext context1(NULL, global_template);
21268     context1->Global()->Set(v8_str("other"), global0);
21269
21270     ExpectString("JSON.stringify(other)", "{}");
21271     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
21272                  "{\"a\":{},\"b\":[\"c\"]}");
21273     ExpectString("JSON.stringify([other, 'b', 'c'])",
21274                  "[{},\"b\",\"c\"]");
21275
21276     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21277     array->Set(0, v8_str("a"));
21278     array->Set(1, v8_str("b"));
21279     context1->Global()->Set(v8_str("array"), array);
21280     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21281     array->TurnOnAccessCheck();
21282     ExpectString("JSON.stringify(array)", "[]");
21283     ExpectString("JSON.stringify([array])", "[[]]");
21284     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
21285   }
21286 }
21287
21288
21289 bool access_check_fail_thrown = false;
21290 bool catch_callback_called = false;
21291
21292
21293 // Failed access check callback that performs a GC on each invocation.
21294 void FailedAccessCheckThrows(Local<v8::Object> target,
21295                              v8::AccessType type,
21296                              Local<v8::Value> data) {
21297   access_check_fail_thrown = true;
21298   i::PrintF("Access check failed. Error thrown.\n");
21299   CcTest::isolate()->ThrowException(
21300       v8::Exception::Error(v8_str("cross context")));
21301 }
21302
21303
21304 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21305   for (int i = 0; i < args.Length(); i++) {
21306     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21307   }
21308   catch_callback_called = true;
21309 }
21310
21311
21312 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21313   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21314 }
21315
21316
21317 void CheckCorrectThrow(const char* script) {
21318   // Test that the script, when wrapped into a try-catch, triggers the catch
21319   // clause due to failed access check throwing an exception.
21320   // The subsequent try-catch should run without any exception.
21321   access_check_fail_thrown = false;
21322   catch_callback_called = false;
21323   i::ScopedVector<char> source(1024);
21324   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21325   CompileRun(source.start());
21326   CHECK(access_check_fail_thrown);
21327   CHECK(catch_callback_called);
21328
21329   access_check_fail_thrown = false;
21330   catch_callback_called = false;
21331   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21332   CHECK(!access_check_fail_thrown);
21333   CHECK(!catch_callback_called);
21334 }
21335
21336
21337 TEST(AccessCheckThrows) {
21338   i::FLAG_allow_natives_syntax = true;
21339   v8::V8::Initialize();
21340   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21341   v8::Isolate* isolate = CcTest::isolate();
21342   v8::HandleScope scope(isolate);
21343
21344   // Create an ObjectTemplate for global objects and install access
21345   // check callbacks that will block access.
21346   v8::Handle<v8::ObjectTemplate> global_template =
21347       v8::ObjectTemplate::New(isolate);
21348   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21349                                            IndexAccessAlwaysBlocked);
21350
21351   // Create a context and set an x property on it's global object.
21352   LocalContext context0(NULL, global_template);
21353   context0->Global()->Set(v8_str("x"), v8_num(42));
21354   v8::Handle<v8::Object> global0 = context0->Global();
21355
21356   // Create a context with a different security token so that the
21357   // failed access check callback will be called on each access.
21358   LocalContext context1(NULL, global_template);
21359   context1->Global()->Set(v8_str("other"), global0);
21360
21361   v8::Handle<v8::FunctionTemplate> catcher_fun =
21362       v8::FunctionTemplate::New(isolate, CatcherCallback);
21363   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21364
21365   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21366       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21367   context1->Global()->Set(v8_str("has_own_property"),
21368                           has_own_property_fun->GetFunction());
21369
21370   { v8::TryCatch try_catch;
21371     access_check_fail_thrown = false;
21372     CompileRun("other.x;");
21373     CHECK(access_check_fail_thrown);
21374     CHECK(try_catch.HasCaught());
21375   }
21376
21377   CheckCorrectThrow("other.x");
21378   CheckCorrectThrow("other[1]");
21379   CheckCorrectThrow("JSON.stringify(other)");
21380   CheckCorrectThrow("has_own_property(other, 'x')");
21381   CheckCorrectThrow("%GetProperty(other, 'x')");
21382   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
21383   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
21384   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21385   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21386   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
21387   CheckCorrectThrow("%HasProperty(other, 'x')");
21388   CheckCorrectThrow("%HasElement(other, 1)");
21389   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21390   CheckCorrectThrow("%GetPropertyNames(other)");
21391   // PROPERTY_ATTRIBUTES_NONE = 0
21392   CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
21393   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
21394                         "other, 'x', null, null, 1)");
21395
21396   // Reset the failed access check callback so it does not influence
21397   // the other tests.
21398   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21399 }
21400
21401
21402 THREADED_TEST(Regress256330) {
21403   i::FLAG_allow_natives_syntax = true;
21404   LocalContext context;
21405   v8::HandleScope scope(context->GetIsolate());
21406   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21407   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21408   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21409   CompileRun("\"use strict\"; var o = new Bug;"
21410              "function f(o) { o.x = 10; };"
21411              "f(o); f(o); f(o);"
21412              "%OptimizeFunctionOnNextCall(f);"
21413              "f(o);");
21414   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21415 }
21416
21417
21418 THREADED_TEST(CrankshaftInterceptorSetter) {
21419   i::FLAG_allow_natives_syntax = true;
21420   v8::HandleScope scope(CcTest::isolate());
21421   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21422   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21423   LocalContext env;
21424   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21425   CompileRun("var obj = new Obj;"
21426              // Initialize fields to avoid transitions later.
21427              "obj.age = 0;"
21428              "obj.accessor_age = 42;"
21429              "function setter(i) { this.accessor_age = i; };"
21430              "function getter() { return this.accessor_age; };"
21431              "function setAge(i) { obj.age = i; };"
21432              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21433              "setAge(1);"
21434              "setAge(2);"
21435              "setAge(3);"
21436              "%OptimizeFunctionOnNextCall(setAge);"
21437              "setAge(4);");
21438   // All stores went through the interceptor.
21439   ExpectInt32("obj.interceptor_age", 4);
21440   ExpectInt32("obj.accessor_age", 42);
21441 }
21442
21443
21444 THREADED_TEST(CrankshaftInterceptorGetter) {
21445   i::FLAG_allow_natives_syntax = true;
21446   v8::HandleScope scope(CcTest::isolate());
21447   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21448   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21449   LocalContext env;
21450   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21451   CompileRun("var obj = new Obj;"
21452              // Initialize fields to avoid transitions later.
21453              "obj.age = 1;"
21454              "obj.accessor_age = 42;"
21455              "function getter() { return this.accessor_age; };"
21456              "function getAge() { return obj.interceptor_age; };"
21457              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21458              "getAge();"
21459              "getAge();"
21460              "getAge();"
21461              "%OptimizeFunctionOnNextCall(getAge);");
21462   // Access through interceptor.
21463   ExpectInt32("getAge()", 1);
21464 }
21465
21466
21467 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21468   i::FLAG_allow_natives_syntax = true;
21469   v8::HandleScope scope(CcTest::isolate());
21470   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21471   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21472   LocalContext env;
21473   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21474   CompileRun("var obj = new Obj;"
21475              "obj.__proto__.interceptor_age = 42;"
21476              "obj.age = 100;"
21477              "function getAge() { return obj.interceptor_age; };");
21478   ExpectInt32("getAge();", 100);
21479   ExpectInt32("getAge();", 100);
21480   ExpectInt32("getAge();", 100);
21481   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21482   // Access through interceptor.
21483   ExpectInt32("getAge();", 100);
21484 }
21485
21486
21487 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21488   i::FLAG_allow_natives_syntax = true;
21489   v8::HandleScope scope(CcTest::isolate());
21490   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21491   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21492   LocalContext env;
21493   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21494   CompileRun("var obj = new Obj;"
21495              "obj.age = 100000;"
21496              "function setAge(i) { obj.age = i };"
21497              "setAge(100);"
21498              "setAge(101);"
21499              "setAge(102);"
21500              "%OptimizeFunctionOnNextCall(setAge);"
21501              "setAge(103);");
21502   ExpectInt32("obj.age", 100000);
21503   ExpectInt32("obj.interceptor_age", 103);
21504 }
21505
21506
21507 class RequestInterruptTestBase {
21508  public:
21509   RequestInterruptTestBase()
21510       : env_(),
21511         isolate_(env_->GetIsolate()),
21512         sem_(0),
21513         warmup_(20000),
21514         should_continue_(true) {
21515   }
21516
21517   virtual ~RequestInterruptTestBase() { }
21518
21519   virtual void TestBody() = 0;
21520
21521   void RunTest() {
21522     InterruptThread i_thread(this);
21523     i_thread.Start();
21524
21525     v8::HandleScope handle_scope(isolate_);
21526
21527     TestBody();
21528
21529     isolate_->ClearInterrupt();
21530
21531     // Verify we arrived here because interruptor was called
21532     // not due to a bug causing us to exit the loop too early.
21533     CHECK(!should_continue());
21534   }
21535
21536   void WakeUpInterruptor() {
21537     sem_.Signal();
21538   }
21539
21540   bool should_continue() const { return should_continue_; }
21541
21542   bool ShouldContinue() {
21543     if (warmup_ > 0) {
21544       if (--warmup_ == 0) {
21545         WakeUpInterruptor();
21546       }
21547     }
21548
21549     return should_continue_;
21550   }
21551
21552  protected:
21553   static void ShouldContinueCallback(
21554       const v8::FunctionCallbackInfo<Value>& info) {
21555     RequestInterruptTestBase* test =
21556         reinterpret_cast<RequestInterruptTestBase*>(
21557             info.Data().As<v8::External>()->Value());
21558     info.GetReturnValue().Set(test->ShouldContinue());
21559   }
21560
21561   class InterruptThread : public i::Thread {
21562    public:
21563     explicit InterruptThread(RequestInterruptTestBase* test)
21564         : Thread("RequestInterruptTest"), test_(test) {}
21565
21566     virtual void Run() {
21567       test_->sem_.Wait();
21568       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21569     }
21570
21571     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21572       reinterpret_cast<RequestInterruptTestBase*>(data)->
21573           should_continue_ = false;
21574     }
21575
21576    private:
21577      RequestInterruptTestBase* test_;
21578   };
21579
21580   LocalContext env_;
21581   v8::Isolate* isolate_;
21582   i::Semaphore sem_;
21583   int warmup_;
21584   bool should_continue_;
21585 };
21586
21587
21588 class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
21589  public:
21590   virtual void TestBody() {
21591     Local<Function> func = Function::New(
21592         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21593     env_->Global()->Set(v8_str("ShouldContinue"), func);
21594
21595     CompileRun("while (ShouldContinue()) { }");
21596   }
21597 };
21598
21599
21600 class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
21601  public:
21602   virtual void TestBody() {
21603     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21604     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21605     proto->Set(v8_str("shouldContinue"), Function::New(
21606         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21607     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21608
21609     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21610   }
21611 };
21612
21613
21614 class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
21615  public:
21616   virtual void TestBody() {
21617     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21618     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21619     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21620         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21621     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21622
21623     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21624   }
21625 };
21626
21627
21628 class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
21629  public:
21630   virtual void TestBody() {
21631     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21632     t->InstanceTemplate()->SetNativeDataProperty(
21633         v8_str("shouldContinue"),
21634         &ShouldContinueNativeGetter,
21635         NULL,
21636         v8::External::New(isolate_, this));
21637     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21638
21639     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21640   }
21641
21642  private:
21643   static void ShouldContinueNativeGetter(
21644       Local<String> property,
21645       const v8::PropertyCallbackInfo<v8::Value>& info) {
21646     RequestInterruptTestBase* test =
21647         reinterpret_cast<RequestInterruptTestBase*>(
21648             info.Data().As<v8::External>()->Value());
21649     info.GetReturnValue().Set(test->ShouldContinue());
21650   }
21651 };
21652
21653
21654 class RequestInterruptTestWithMethodCallAndInterceptor
21655     : public RequestInterruptTestBase {
21656  public:
21657   virtual void TestBody() {
21658     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21659     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21660     proto->Set(v8_str("shouldContinue"), Function::New(
21661         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21662     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
21663     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
21664
21665     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21666
21667     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21668   }
21669
21670  private:
21671   static void EmptyInterceptor(
21672       Local<String> property,
21673       const v8::PropertyCallbackInfo<v8::Value>& info) {
21674   }
21675 };
21676
21677
21678 class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
21679  public:
21680   virtual void TestBody() {
21681     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
21682         isolate_,
21683         WakeUpInterruptorCallback,
21684         v8::External::New(isolate_, this)));
21685
21686     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
21687         isolate_,
21688         ShouldContinueCallback,
21689         v8::External::New(isolate_, this)));
21690
21691     i::FLAG_allow_natives_syntax = true;
21692     CompileRun("function loopish(o) {"
21693                "  var pre = 10;"
21694                "  while (o.abs(1) > 0) {"
21695                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
21696                "    if (pre > 0) {"
21697                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
21698                "    }"
21699                "  }"
21700                "}"
21701                "var i = 50;"
21702                "var obj = {abs: function () { return i-- }, x: null};"
21703                "delete obj.x;"
21704                "loopish(obj);"
21705                "%OptimizeFunctionOnNextCall(loopish);"
21706                "loopish(Math);");
21707
21708     i::FLAG_allow_natives_syntax = false;
21709   }
21710
21711  private:
21712   static void WakeUpInterruptorCallback(
21713       const v8::FunctionCallbackInfo<Value>& info) {
21714     if (!info[0]->BooleanValue()) return;
21715
21716     RequestInterruptTestBase* test =
21717         reinterpret_cast<RequestInterruptTestBase*>(
21718             info.Data().As<v8::External>()->Value());
21719     test->WakeUpInterruptor();
21720   }
21721
21722   static void ShouldContinueCallback(
21723       const v8::FunctionCallbackInfo<Value>& info) {
21724     RequestInterruptTestBase* test =
21725         reinterpret_cast<RequestInterruptTestBase*>(
21726             info.Data().As<v8::External>()->Value());
21727     info.GetReturnValue().Set(test->should_continue());
21728   }
21729 };
21730
21731
21732 TEST(RequestInterruptTestWithFunctionCall) {
21733   RequestInterruptTestWithFunctionCall().RunTest();
21734 }
21735
21736
21737 TEST(RequestInterruptTestWithMethodCall) {
21738   RequestInterruptTestWithMethodCall().RunTest();
21739 }
21740
21741
21742 TEST(RequestInterruptTestWithAccessor) {
21743   RequestInterruptTestWithAccessor().RunTest();
21744 }
21745
21746
21747 TEST(RequestInterruptTestWithNativeAccessor) {
21748   RequestInterruptTestWithNativeAccessor().RunTest();
21749 }
21750
21751
21752 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
21753   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
21754 }
21755
21756
21757 TEST(RequestInterruptTestWithMathAbs) {
21758   RequestInterruptTestWithMathAbs().RunTest();
21759 }
21760
21761
21762 static Local<Value> function_new_expected_env;
21763 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
21764   CHECK_EQ(function_new_expected_env, info.Data());
21765   info.GetReturnValue().Set(17);
21766 }
21767
21768
21769 THREADED_TEST(FunctionNew) {
21770   LocalContext env;
21771   v8::Isolate* isolate = env->GetIsolate();
21772   v8::HandleScope scope(isolate);
21773   Local<Object> data = v8::Object::New(isolate);
21774   function_new_expected_env = data;
21775   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
21776   env->Global()->Set(v8_str("func"), func);
21777   Local<Value> result = CompileRun("func();");
21778   CHECK_EQ(v8::Integer::New(isolate, 17), result);
21779   // Verify function not cached
21780   int serial_number =
21781       i::Smi::cast(v8::Utils::OpenHandle(*func)
21782           ->shared()->get_api_func_data()->serial_number())->value();
21783   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21784   i::Object* elm = i_isolate->native_context()->function_cache()
21785       ->GetElementNoExceptionThrown(i_isolate, serial_number);
21786   CHECK(elm->IsUndefined());
21787   // Verify that each Function::New creates a new function instance
21788   Local<Object> data2 = v8::Object::New(isolate);
21789   function_new_expected_env = data2;
21790   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
21791   CHECK(!func2->IsNull());
21792   CHECK_NE(func, func2);
21793   env->Global()->Set(v8_str("func2"), func2);
21794   Local<Value> result2 = CompileRun("func2();");
21795   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
21796 }
21797
21798
21799 TEST(EscapeableHandleScope) {
21800   HandleScope outer_scope(CcTest::isolate());
21801   LocalContext context;
21802   const int runs = 10;
21803   Local<String> values[runs];
21804   for (int i = 0; i < runs; i++) {
21805     v8::EscapableHandleScope inner_scope(CcTest::isolate());
21806     Local<String> value;
21807     if (i != 0) value = v8_str("escape value");
21808     values[i] = inner_scope.Escape(value);
21809   }
21810   for (int i = 0; i < runs; i++) {
21811     Local<String> expected;
21812     if (i != 0) {
21813       CHECK_EQ(v8_str("escape value"), values[i]);
21814     } else {
21815       CHECK(values[i].IsEmpty());
21816     }
21817   }
21818 }
21819
21820
21821 static void SetterWhichExpectsThisAndHolderToDiffer(
21822     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
21823   CHECK(info.Holder() != info.This());
21824 }
21825
21826
21827 TEST(Regress239669) {
21828   LocalContext context;
21829   v8::Isolate* isolate = context->GetIsolate();
21830   v8::HandleScope scope(isolate);
21831   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21832   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
21833   context->Global()->Set(v8_str("P"), templ->NewInstance());
21834   CompileRun(
21835       "function C1() {"
21836       "  this.x = 23;"
21837       "};"
21838       "C1.prototype = P;"
21839       "for (var i = 0; i < 4; i++ ) {"
21840       "  new C1();"
21841       "}");
21842 }