Merge remote-tracking branch 'upstream/v0.10'
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <string>
31 #include <map>
32
33 #include "v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "api.h"
40 #include "arguments.h"
41 #include "cctest.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
45 #include "isolate.h"
46 #include "objects.h"
47 #include "parser.h"
48 #include "platform.h"
49 #include "snapshot.h"
50 #include "unicode-inl.h"
51 #include "utils.h"
52 #include "vm-state.h"
53
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 = v8::String::New("my_profile1");
92   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
93
94   cpu_profiler->StartCpuProfiling(profile_name);
95   (*test)();
96   cpu_profiler->DeleteAllCpuProfiles();
97 }
98
99
100 static void ExpectString(const char* code, const char* expected) {
101   Local<Value> result = CompileRun(code);
102   CHECK(result->IsString());
103   String::Utf8Value utf8(result);
104   CHECK_EQ(expected, *utf8);
105 }
106
107
108 static void ExpectInt32(const char* code, int expected) {
109   Local<Value> result = CompileRun(code);
110   CHECK(result->IsInt32());
111   CHECK_EQ(expected, result->Int32Value());
112 }
113
114
115 static void ExpectBoolean(const char* code, bool expected) {
116   Local<Value> result = CompileRun(code);
117   CHECK(result->IsBoolean());
118   CHECK_EQ(expected, result->BooleanValue());
119 }
120
121
122 static void ExpectTrue(const char* code) {
123   ExpectBoolean(code, true);
124 }
125
126
127 static void ExpectFalse(const char* code) {
128   ExpectBoolean(code, false);
129 }
130
131
132 static void ExpectObject(const char* code, Local<Value> expected) {
133   Local<Value> result = CompileRun(code);
134   CHECK(result->Equals(expected));
135 }
136
137
138 static void ExpectUndefined(const char* code) {
139   Local<Value> result = CompileRun(code);
140   CHECK(result->IsUndefined());
141 }
142
143
144 static int signature_callback_count;
145 static Local<Value> signature_expected_receiver;
146 static void IncrementingSignatureCallback(
147     const v8::FunctionCallbackInfo<v8::Value>& args) {
148   ApiTestFuzzer::Fuzz();
149   signature_callback_count++;
150   CHECK_EQ(signature_expected_receiver, args.Holder());
151   CHECK_EQ(signature_expected_receiver, args.This());
152   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
153   for (int i = 0; i < args.Length(); i++)
154     result->Set(v8::Integer::New(i), args[i]);
155   args.GetReturnValue().Set(result);
156 }
157
158
159 static void SignatureCallback(
160     const v8::FunctionCallbackInfo<v8::Value>& args) {
161   ApiTestFuzzer::Fuzz();
162   v8::Handle<v8::Array> result = v8::Array::New(args.Length());
163   for (int i = 0; i < args.Length(); i++) {
164     result->Set(v8::Integer::New(i), args[i]);
165   }
166   args.GetReturnValue().Set(result);
167 }
168
169
170 // Tests that call v8::V8::Dispose() cannot be threaded.
171 TEST(InitializeAndDisposeOnce) {
172   CHECK(v8::V8::Initialize());
173   CHECK(v8::V8::Dispose());
174 }
175
176
177 // Tests that call v8::V8::Dispose() cannot be threaded.
178 TEST(InitializeAndDisposeMultiple) {
179   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
180   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
181   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
182   // TODO(mstarzinger): This should fail gracefully instead of asserting.
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 }
186
187
188 THREADED_TEST(Handles) {
189   v8::HandleScope scope(CcTest::isolate());
190   Local<Context> local_env;
191   {
192     LocalContext env;
193     local_env = env.local();
194   }
195
196   // Local context should still be live.
197   CHECK(!local_env.IsEmpty());
198   local_env->Enter();
199
200   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
201   CHECK(!undef.IsEmpty());
202   CHECK(undef->IsUndefined());
203
204   const char* c_source = "1 + 2 + 3";
205   Local<String> source = String::New(c_source);
206   Local<Script> script = Script::Compile(source);
207   CHECK_EQ(6, script->Run()->Int32Value());
208
209   local_env->Exit();
210 }
211
212
213 THREADED_TEST(IsolateOfContext) {
214   v8::HandleScope scope(CcTest::isolate());
215   v8::Handle<Context> env = Context::New(CcTest::isolate());
216
217   CHECK(!env->InContext());
218   CHECK(env->GetIsolate() == CcTest::isolate());
219   env->Enter();
220   CHECK(env->InContext());
221   CHECK(env->GetIsolate() == CcTest::isolate());
222   env->Exit();
223   CHECK(!env->InContext());
224   CHECK(env->GetIsolate() == CcTest::isolate());
225 }
226
227
228 static void TestSignature(const char* loop_js, Local<Value> receiver) {
229   i::ScopedVector<char> source(200);
230   i::OS::SNPrintF(source,
231                   "for (var i = 0; i < 10; i++) {"
232                   "  %s"
233                   "}",
234                   loop_js);
235   signature_callback_count = 0;
236   signature_expected_receiver = receiver;
237   bool expected_to_throw = receiver.IsEmpty();
238   v8::TryCatch try_catch;
239   CompileRun(source.start());
240   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
241   if (!expected_to_throw) {
242     CHECK_EQ(10, signature_callback_count);
243   } else {
244     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
245              try_catch.Exception()->ToString());
246   }
247 }
248
249
250 THREADED_TEST(ReceiverSignature) {
251   LocalContext env;
252   v8::HandleScope scope(env->GetIsolate());
253   // Setup templates.
254   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
255   v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
256   v8::Handle<v8::FunctionTemplate> callback_sig =
257       v8::FunctionTemplate::New(
258           IncrementingSignatureCallback, Local<Value>(), sig);
259   v8::Handle<v8::FunctionTemplate> callback =
260       v8::FunctionTemplate::New(IncrementingSignatureCallback);
261   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
262   sub_fun->Inherit(fun);
263   v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
264   // Install properties.
265   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
266   fun_proto->Set(v8_str("prop_sig"), callback_sig);
267   fun_proto->Set(v8_str("prop"), callback);
268   fun_proto->SetAccessorProperty(
269       v8_str("accessor_sig"), callback_sig, callback_sig);
270   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
271   // Instantiate templates.
272   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
273   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
274   // Setup global variables.
275   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
276   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
277   env->Global()->Set(v8_str("fun_instance"), fun_instance);
278   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
279   CompileRun(
280       "var accessor_sig_key = 'accessor_sig';"
281       "var accessor_key = 'accessor';"
282       "var prop_sig_key = 'prop_sig';"
283       "var prop_key = 'prop';"
284       ""
285       "function copy_props(obj) {"
286       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
287       "  var source = Fun.prototype;"
288       "  for (var i in keys) {"
289       "    var key = keys[i];"
290       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
291       "    Object.defineProperty(obj, key, desc);"
292       "  }"
293       "}"
294       ""
295       "var obj = {};"
296       "copy_props(obj);"
297       "var unrel = new UnrelFun();"
298       "copy_props(unrel);");
299   // Test with and without ICs
300   const char* test_objects[] = {
301       "fun_instance", "sub_fun_instance", "obj", "unrel" };
302   unsigned bad_signature_start_offset = 2;
303   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
304     i::ScopedVector<char> source(200);
305     i::OS::SNPrintF(
306         source, "var test_object = %s; test_object", test_objects[i]);
307     Local<Value> test_object = CompileRun(source.start());
308     TestSignature("test_object.prop();", test_object);
309     TestSignature("test_object.accessor;", test_object);
310     TestSignature("test_object[accessor_key];", test_object);
311     TestSignature("test_object.accessor = 1;", test_object);
312     TestSignature("test_object[accessor_key] = 1;", test_object);
313     if (i >= bad_signature_start_offset) test_object = Local<Value>();
314     TestSignature("test_object.prop_sig();", test_object);
315     TestSignature("test_object.accessor_sig;", test_object);
316     TestSignature("test_object[accessor_sig_key];", test_object);
317     TestSignature("test_object.accessor_sig = 1;", test_object);
318     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
319   }
320 }
321
322
323 THREADED_TEST(ArgumentSignature) {
324   LocalContext env;
325   v8::HandleScope scope(env->GetIsolate());
326   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
327   cons->SetClassName(v8_str("Cons"));
328   v8::Handle<v8::Signature> sig =
329       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
330   v8::Handle<v8::FunctionTemplate> fun =
331       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
332   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
333   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
334
335   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
336   CHECK(value1->IsTrue());
337
338   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
339   CHECK(value2->IsTrue());
340
341   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
342   CHECK(value3->IsTrue());
343
344   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
345   cons1->SetClassName(v8_str("Cons1"));
346   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
347   cons2->SetClassName(v8_str("Cons2"));
348   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
349   cons3->SetClassName(v8_str("Cons3"));
350
351   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
352   v8::Handle<v8::Signature> wsig =
353       v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
354   v8::Handle<v8::FunctionTemplate> fun2 =
355       v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
356
357   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
358   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
359   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
360   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
361   v8::Handle<Value> value4 = CompileRun(
362       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
363       "'[object Cons1],[object Cons2],[object Cons3]'");
364   CHECK(value4->IsTrue());
365
366   v8::Handle<Value> value5 = CompileRun(
367       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
368   CHECK(value5->IsTrue());
369
370   v8::Handle<Value> value6 = CompileRun(
371       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
372   CHECK(value6->IsTrue());
373
374   v8::Handle<Value> value7 = CompileRun(
375       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
376       "'[object Cons1],[object Cons2],[object Cons3],d';");
377   CHECK(value7->IsTrue());
378
379   v8::Handle<Value> value8 = CompileRun(
380       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
381   CHECK(value8->IsTrue());
382 }
383
384
385 THREADED_TEST(HulIgennem) {
386   LocalContext env;
387   v8::Isolate* isolate = env->GetIsolate();
388   v8::HandleScope scope(isolate);
389   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
390   Local<String> undef_str = undef->ToString();
391   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
392   undef_str->WriteUtf8(value);
393   CHECK_EQ(0, strcmp(value, "undefined"));
394   i::DeleteArray(value);
395 }
396
397
398 THREADED_TEST(Access) {
399   LocalContext env;
400   v8::Isolate* isolate = env->GetIsolate();
401   v8::HandleScope scope(isolate);
402   Local<v8::Object> obj = v8::Object::New();
403   Local<Value> foo_before = obj->Get(v8_str("foo"));
404   CHECK(foo_before->IsUndefined());
405   Local<String> bar_str = v8_str("bar");
406   obj->Set(v8_str("foo"), bar_str);
407   Local<Value> foo_after = obj->Get(v8_str("foo"));
408   CHECK(!foo_after->IsUndefined());
409   CHECK(foo_after->IsString());
410   CHECK_EQ(bar_str, foo_after);
411 }
412
413
414 THREADED_TEST(AccessElement) {
415   LocalContext env;
416   v8::HandleScope scope(env->GetIsolate());
417   Local<v8::Object> obj = v8::Object::New();
418   Local<Value> before = obj->Get(1);
419   CHECK(before->IsUndefined());
420   Local<String> bar_str = v8_str("bar");
421   obj->Set(1, bar_str);
422   Local<Value> after = obj->Get(1);
423   CHECK(!after->IsUndefined());
424   CHECK(after->IsString());
425   CHECK_EQ(bar_str, after);
426
427   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
428   CHECK_EQ(v8_str("a"), value->Get(0));
429   CHECK_EQ(v8_str("b"), value->Get(1));
430 }
431
432
433 THREADED_TEST(Script) {
434   LocalContext env;
435   v8::HandleScope scope(env->GetIsolate());
436   const char* c_source = "1 + 2 + 3";
437   Local<String> source = String::New(c_source);
438   Local<Script> script = Script::Compile(source);
439   CHECK_EQ(6, script->Run()->Int32Value());
440 }
441
442
443 static uint16_t* AsciiToTwoByteString(const char* source) {
444   int array_length = i::StrLength(source) + 1;
445   uint16_t* converted = i::NewArray<uint16_t>(array_length);
446   for (int i = 0; i < array_length; i++) converted[i] = source[i];
447   return converted;
448 }
449
450
451 class TestResource: public String::ExternalStringResource {
452  public:
453   explicit TestResource(uint16_t* data, int* counter = NULL)
454     : data_(data), length_(0), counter_(counter) {
455     while (data[length_]) ++length_;
456   }
457
458   ~TestResource() {
459     i::DeleteArray(data_);
460     if (counter_ != NULL) ++*counter_;
461   }
462
463   const uint16_t* data() const {
464     return data_;
465   }
466
467   size_t length() const {
468     return length_;
469   }
470  private:
471   uint16_t* data_;
472   size_t length_;
473   int* counter_;
474 };
475
476
477 class TestAsciiResource: public String::ExternalAsciiStringResource {
478  public:
479   explicit TestAsciiResource(const char* data, int* counter = NULL)
480     : data_(data), length_(strlen(data)), counter_(counter) { }
481
482   ~TestAsciiResource() {
483     i::DeleteArray(data_);
484     if (counter_ != NULL) ++*counter_;
485   }
486
487   const char* data() const {
488     return data_;
489   }
490
491   size_t length() const {
492     return length_;
493   }
494  private:
495   const char* data_;
496   size_t length_;
497   int* counter_;
498 };
499
500
501 THREADED_TEST(ScriptUsingStringResource) {
502   int dispose_count = 0;
503   const char* c_source = "1 + 2 * 3";
504   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
505   {
506     LocalContext env;
507     v8::HandleScope scope(env->GetIsolate());
508     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
509     Local<String> source = String::NewExternal(resource);
510     Local<Script> script = Script::Compile(source);
511     Local<Value> value = script->Run();
512     CHECK(value->IsNumber());
513     CHECK_EQ(7, value->Int32Value());
514     CHECK(source->IsExternal());
515     CHECK_EQ(resource,
516              static_cast<TestResource*>(source->GetExternalStringResource()));
517     String::Encoding encoding = String::UNKNOWN_ENCODING;
518     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
519              source->GetExternalStringResourceBase(&encoding));
520     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
521     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
522     CHECK_EQ(0, dispose_count);
523   }
524   CcTest::i_isolate()->compilation_cache()->Clear();
525   CcTest::heap()->CollectAllAvailableGarbage();
526   CHECK_EQ(1, dispose_count);
527 }
528
529
530 THREADED_TEST(ScriptUsingAsciiStringResource) {
531   int dispose_count = 0;
532   const char* c_source = "1 + 2 * 3";
533   {
534     LocalContext env;
535     v8::HandleScope scope(env->GetIsolate());
536     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
537                                                         &dispose_count);
538     Local<String> source = String::NewExternal(resource);
539     CHECK(source->IsExternalAscii());
540     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
541              source->GetExternalAsciiStringResource());
542     String::Encoding encoding = String::UNKNOWN_ENCODING;
543     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
544              source->GetExternalStringResourceBase(&encoding));
545     CHECK_EQ(String::ASCII_ENCODING, encoding);
546     Local<Script> script = Script::Compile(source);
547     Local<Value> value = script->Run();
548     CHECK(value->IsNumber());
549     CHECK_EQ(7, value->Int32Value());
550     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
551     CHECK_EQ(0, dispose_count);
552   }
553   CcTest::i_isolate()->compilation_cache()->Clear();
554   CcTest::heap()->CollectAllAvailableGarbage();
555   CHECK_EQ(1, dispose_count);
556 }
557
558
559 THREADED_TEST(ScriptMakingExternalString) {
560   int dispose_count = 0;
561   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
562   {
563     LocalContext env;
564     v8::HandleScope scope(env->GetIsolate());
565     Local<String> source = String::New(two_byte_source);
566     // Trigger GCs so that the newly allocated string moves to old gen.
567     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
568     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
569     CHECK_EQ(source->IsExternal(), false);
570     CHECK_EQ(source->IsExternalAscii(), false);
571     String::Encoding encoding = String::UNKNOWN_ENCODING;
572     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
573     CHECK_EQ(String::ASCII_ENCODING, encoding);
574     bool success = source->MakeExternal(new TestResource(two_byte_source,
575                                                          &dispose_count));
576     CHECK(success);
577     Local<Script> script = Script::Compile(source);
578     Local<Value> value = script->Run();
579     CHECK(value->IsNumber());
580     CHECK_EQ(7, value->Int32Value());
581     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
582     CHECK_EQ(0, dispose_count);
583   }
584   CcTest::i_isolate()->compilation_cache()->Clear();
585   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
586   CHECK_EQ(1, dispose_count);
587 }
588
589
590 THREADED_TEST(ScriptMakingExternalAsciiString) {
591   int dispose_count = 0;
592   const char* c_source = "1 + 2 * 3";
593   {
594     LocalContext env;
595     v8::HandleScope scope(env->GetIsolate());
596     Local<String> source = v8_str(c_source);
597     // Trigger GCs so that the newly allocated string moves to old gen.
598     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
599     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
600     bool success = source->MakeExternal(
601         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
602     CHECK(success);
603     Local<Script> script = Script::Compile(source);
604     Local<Value> value = script->Run();
605     CHECK(value->IsNumber());
606     CHECK_EQ(7, value->Int32Value());
607     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
608     CHECK_EQ(0, dispose_count);
609   }
610   CcTest::i_isolate()->compilation_cache()->Clear();
611   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
612   CHECK_EQ(1, dispose_count);
613 }
614
615
616 TEST(MakingExternalStringConditions) {
617   LocalContext env;
618   v8::HandleScope scope(env->GetIsolate());
619
620   // Free some space in the new space so that we can check freshness.
621   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
622   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
623
624   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
625   Local<String> small_string = String::New(two_byte_string);
626   i::DeleteArray(two_byte_string);
627
628   // We should refuse to externalize newly created small string.
629   CHECK(!small_string->CanMakeExternal());
630   // Trigger GCs so that the newly allocated string moves to old gen.
631   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
632   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
633   // Old space strings should be accepted.
634   CHECK(small_string->CanMakeExternal());
635
636   two_byte_string = AsciiToTwoByteString("small string 2");
637   small_string = String::New(two_byte_string);
638   i::DeleteArray(two_byte_string);
639
640   // We should refuse externalizing newly created small string.
641   CHECK(!small_string->CanMakeExternal());
642   for (int i = 0; i < 100; i++) {
643     String::Value value(small_string);
644   }
645   // Frequently used strings should be accepted.
646   CHECK(small_string->CanMakeExternal());
647
648   const int buf_size = 10 * 1024;
649   char* buf = i::NewArray<char>(buf_size);
650   memset(buf, 'a', buf_size);
651   buf[buf_size - 1] = '\0';
652
653   two_byte_string = AsciiToTwoByteString(buf);
654   Local<String> large_string = String::New(two_byte_string);
655   i::DeleteArray(buf);
656   i::DeleteArray(two_byte_string);
657   // Large strings should be immediately accepted.
658   CHECK(large_string->CanMakeExternal());
659 }
660
661
662 TEST(MakingExternalAsciiStringConditions) {
663   LocalContext env;
664   v8::HandleScope scope(env->GetIsolate());
665
666   // Free some space in the new space so that we can check freshness.
667   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
668   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
669
670   Local<String> small_string = String::New("s1");
671   // We should refuse to externalize newly created small string.
672   CHECK(!small_string->CanMakeExternal());
673   // Trigger GCs so that the newly allocated string moves to old gen.
674   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
675   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
676   // Old space strings should be accepted.
677   CHECK(small_string->CanMakeExternal());
678
679   small_string = String::New("small string 2");
680   // We should refuse externalizing newly created small string.
681   CHECK(!small_string->CanMakeExternal());
682   for (int i = 0; i < 100; i++) {
683     String::Value value(small_string);
684   }
685   // Frequently used strings should be accepted.
686   CHECK(small_string->CanMakeExternal());
687
688   const int buf_size = 10 * 1024;
689   char* buf = i::NewArray<char>(buf_size);
690   memset(buf, 'a', buf_size);
691   buf[buf_size - 1] = '\0';
692   Local<String> large_string = String::New(buf);
693   i::DeleteArray(buf);
694   // Large strings should be immediately accepted.
695   CHECK(large_string->CanMakeExternal());
696 }
697
698
699 TEST(MakingExternalUnalignedAsciiString) {
700   LocalContext env;
701   v8::HandleScope scope(env->GetIsolate());
702
703   CompileRun("function cons(a, b) { return a + b; }"
704              "function slice(a) { return a.substring(1); }");
705   // Create a cons string that will land in old pointer space.
706   Local<String> cons = Local<String>::Cast(CompileRun(
707       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
708   // Create a sliced string that will land in old pointer space.
709   Local<String> slice = Local<String>::Cast(CompileRun(
710       "slice('abcdefghijklmnopqrstuvwxyz');"));
711
712   // Trigger GCs so that the newly allocated string moves to old gen.
713   SimulateFullSpace(CcTest::heap()->old_pointer_space());
714   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
715   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
716
717   // Turn into external string with unaligned resource data.
718   int dispose_count = 0;
719   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
720   bool success = cons->MakeExternal(
721       new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
722   CHECK(success);
723   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
724   success = slice->MakeExternal(
725       new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
726   CHECK(success);
727
728   // Trigger GCs and force evacuation.
729   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
730   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
731 }
732
733
734 THREADED_TEST(UsingExternalString) {
735   i::Factory* factory = CcTest::i_isolate()->factory();
736   {
737     v8::HandleScope scope(CcTest::isolate());
738     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
739     Local<String> string =
740         String::NewExternal(new TestResource(two_byte_string));
741     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
742     // Trigger GCs so that the newly allocated string moves to old gen.
743     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
744     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
745     i::Handle<i::String> isymbol =
746         factory->InternalizedStringFromString(istring);
747     CHECK(isymbol->IsInternalizedString());
748   }
749   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
750   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
751 }
752
753
754 THREADED_TEST(UsingExternalAsciiString) {
755   i::Factory* factory = CcTest::i_isolate()->factory();
756   {
757     v8::HandleScope scope(CcTest::isolate());
758     const char* one_byte_string = "test string";
759     Local<String> string = String::NewExternal(
760         new TestAsciiResource(i::StrDup(one_byte_string)));
761     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
762     // Trigger GCs so that the newly allocated string moves to old gen.
763     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
764     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
765     i::Handle<i::String> isymbol =
766         factory->InternalizedStringFromString(istring);
767     CHECK(isymbol->IsInternalizedString());
768   }
769   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
770   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
771 }
772
773
774 THREADED_TEST(ScavengeExternalString) {
775   i::FLAG_stress_compaction = false;
776   i::FLAG_gc_global = false;
777   int dispose_count = 0;
778   bool in_new_space = false;
779   {
780     v8::HandleScope scope(CcTest::isolate());
781     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
782     Local<String> string =
783       String::NewExternal(new TestResource(two_byte_string,
784                                            &dispose_count));
785     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
786     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
787     in_new_space = CcTest::heap()->InNewSpace(*istring);
788     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
789     CHECK_EQ(0, dispose_count);
790   }
791   CcTest::heap()->CollectGarbage(
792       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
793   CHECK_EQ(1, dispose_count);
794 }
795
796
797 THREADED_TEST(ScavengeExternalAsciiString) {
798   i::FLAG_stress_compaction = false;
799   i::FLAG_gc_global = false;
800   int dispose_count = 0;
801   bool in_new_space = false;
802   {
803     v8::HandleScope scope(CcTest::isolate());
804     const char* one_byte_string = "test string";
805     Local<String> string = String::NewExternal(
806         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
807     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
808     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
809     in_new_space = CcTest::heap()->InNewSpace(*istring);
810     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
811     CHECK_EQ(0, dispose_count);
812   }
813   CcTest::heap()->CollectGarbage(
814       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
815   CHECK_EQ(1, dispose_count);
816 }
817
818
819 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
820  public:
821   // Only used by non-threaded tests, so it can use static fields.
822   static int dispose_calls;
823   static int dispose_count;
824
825   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
826       : TestAsciiResource(data, &dispose_count),
827         dispose_(dispose) { }
828
829   void Dispose() {
830     ++dispose_calls;
831     if (dispose_) delete this;
832   }
833  private:
834   bool dispose_;
835 };
836
837
838 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
839 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
840
841
842 TEST(ExternalStringWithDisposeHandling) {
843   const char* c_source = "1 + 2 * 3";
844
845   // Use a stack allocated external string resource allocated object.
846   TestAsciiResourceWithDisposeControl::dispose_count = 0;
847   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
848   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
849   {
850     LocalContext env;
851     v8::HandleScope scope(env->GetIsolate());
852     Local<String> source =  String::NewExternal(&res_stack);
853     Local<Script> script = Script::Compile(source);
854     Local<Value> value = script->Run();
855     CHECK(value->IsNumber());
856     CHECK_EQ(7, value->Int32Value());
857     CcTest::heap()->CollectAllAvailableGarbage();
858     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
859   }
860   CcTest::i_isolate()->compilation_cache()->Clear();
861   CcTest::heap()->CollectAllAvailableGarbage();
862   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
863   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
864
865   // Use a heap allocated external string resource allocated object.
866   TestAsciiResourceWithDisposeControl::dispose_count = 0;
867   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
868   TestAsciiResource* res_heap =
869       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
870   {
871     LocalContext env;
872     v8::HandleScope scope(env->GetIsolate());
873     Local<String> source =  String::NewExternal(res_heap);
874     Local<Script> script = Script::Compile(source);
875     Local<Value> value = script->Run();
876     CHECK(value->IsNumber());
877     CHECK_EQ(7, value->Int32Value());
878     CcTest::heap()->CollectAllAvailableGarbage();
879     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
880   }
881   CcTest::i_isolate()->compilation_cache()->Clear();
882   CcTest::heap()->CollectAllAvailableGarbage();
883   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
884   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
885 }
886
887
888 THREADED_TEST(StringConcat) {
889   {
890     LocalContext env;
891     v8::HandleScope scope(env->GetIsolate());
892     const char* one_byte_string_1 = "function a_times_t";
893     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
894     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
895     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
896     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
897     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
898     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
899     Local<String> left = v8_str(one_byte_string_1);
900
901     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
902     Local<String> right = String::New(two_byte_source);
903     i::DeleteArray(two_byte_source);
904
905     Local<String> source = String::Concat(left, right);
906     right = String::NewExternal(
907         new TestAsciiResource(i::StrDup(one_byte_extern_1)));
908     source = String::Concat(source, right);
909     right = String::NewExternal(
910         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
911     source = String::Concat(source, right);
912     right = v8_str(one_byte_string_2);
913     source = String::Concat(source, right);
914
915     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
916     right = String::New(two_byte_source);
917     i::DeleteArray(two_byte_source);
918
919     source = String::Concat(source, right);
920     right = String::NewExternal(
921         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
922     source = String::Concat(source, right);
923     Local<Script> script = Script::Compile(source);
924     Local<Value> value = script->Run();
925     CHECK(value->IsNumber());
926     CHECK_EQ(68, value->Int32Value());
927   }
928   CcTest::i_isolate()->compilation_cache()->Clear();
929   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
930   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
931 }
932
933
934 THREADED_TEST(GlobalProperties) {
935   LocalContext env;
936   v8::HandleScope scope(env->GetIsolate());
937   v8::Handle<v8::Object> global = env->Global();
938   global->Set(v8_str("pi"), v8_num(3.1415926));
939   Local<Value> pi = global->Get(v8_str("pi"));
940   CHECK_EQ(3.1415926, pi->NumberValue());
941 }
942
943
944 template<typename T>
945 static void CheckReturnValue(const T& t, i::Address callback) {
946   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
947   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
948   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
949   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
950   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
951   // Verify reset
952   bool is_runtime = (*o)->IsTheHole();
953   rv.Set(true);
954   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
955   rv.Set(v8::Handle<v8::Object>());
956   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
957   CHECK_EQ(is_runtime, (*o)->IsTheHole());
958
959   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
960   // If CPU profiler is active check that when API callback is invoked
961   // VMState is set to EXTERNAL.
962   if (isolate->cpu_profiler()->is_profiling()) {
963     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
964     CHECK(isolate->external_callback_scope());
965     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
966   }
967 }
968
969
970 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
971                                  i::Address callback) {
972   ApiTestFuzzer::Fuzz();
973   CheckReturnValue(info, callback);
974   info.GetReturnValue().Set(v8_str("bad value"));
975   info.GetReturnValue().Set(v8_num(102));
976 }
977
978
979 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
980   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
981 }
982
983
984 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
985   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
986 }
987
988 static void construct_callback(
989     const v8::FunctionCallbackInfo<Value>& info) {
990   ApiTestFuzzer::Fuzz();
991   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
992   info.This()->Set(v8_str("x"), v8_num(1));
993   info.This()->Set(v8_str("y"), v8_num(2));
994   info.GetReturnValue().Set(v8_str("bad value"));
995   info.GetReturnValue().Set(info.This());
996 }
997
998
999 static void Return239Callback(
1000     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1001   ApiTestFuzzer::Fuzz();
1002   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1003   info.GetReturnValue().Set(v8_str("bad value"));
1004   info.GetReturnValue().Set(v8_num(239));
1005 }
1006
1007
1008 template<typename Handler>
1009 static void TestFunctionTemplateInitializer(Handler handler,
1010                                             Handler handler_2) {
1011   // Test constructor calls.
1012   {
1013     LocalContext env;
1014     v8::HandleScope scope(env->GetIsolate());
1015
1016     Local<v8::FunctionTemplate> fun_templ =
1017         v8::FunctionTemplate::New(handler);
1018     Local<Function> fun = fun_templ->GetFunction();
1019     env->Global()->Set(v8_str("obj"), fun);
1020     Local<Script> script = v8_compile("obj()");
1021     for (int i = 0; i < 30; i++) {
1022       CHECK_EQ(102, script->Run()->Int32Value());
1023     }
1024   }
1025   // Use SetCallHandler to initialize a function template, should work like
1026   // the previous one.
1027   {
1028     LocalContext env;
1029     v8::HandleScope scope(env->GetIsolate());
1030
1031     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
1032     fun_templ->SetCallHandler(handler_2);
1033     Local<Function> fun = fun_templ->GetFunction();
1034     env->Global()->Set(v8_str("obj"), fun);
1035     Local<Script> script = v8_compile("obj()");
1036     for (int i = 0; i < 30; i++) {
1037       CHECK_EQ(102, script->Run()->Int32Value());
1038     }
1039   }
1040 }
1041
1042
1043 template<typename Constructor, typename Accessor>
1044 static void TestFunctionTemplateAccessor(Constructor constructor,
1045                                          Accessor accessor) {
1046   LocalContext env;
1047   v8::HandleScope scope(env->GetIsolate());
1048
1049   Local<v8::FunctionTemplate> fun_templ =
1050       v8::FunctionTemplate::New(constructor);
1051   fun_templ->SetClassName(v8_str("funky"));
1052   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1053   Local<Function> fun = fun_templ->GetFunction();
1054   env->Global()->Set(v8_str("obj"), fun);
1055   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1056   CHECK_EQ(v8_str("[object funky]"), result);
1057   CompileRun("var obj_instance = new obj();");
1058   Local<Script> script;
1059   script = v8_compile("obj_instance.x");
1060   for (int i = 0; i < 30; i++) {
1061     CHECK_EQ(1, script->Run()->Int32Value());
1062   }
1063   script = v8_compile("obj_instance.m");
1064   for (int i = 0; i < 30; i++) {
1065     CHECK_EQ(239, script->Run()->Int32Value());
1066   }
1067 }
1068
1069
1070 THREADED_PROFILED_TEST(FunctionTemplate) {
1071   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1072   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1073 }
1074
1075
1076 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1077   ApiTestFuzzer::Fuzz();
1078   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1079   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1080 }
1081
1082
1083 template<typename Callback>
1084 static void TestSimpleCallback(Callback callback) {
1085   LocalContext env;
1086   v8::HandleScope scope(env->GetIsolate());
1087
1088   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1089   object_template->Set("callback", v8::FunctionTemplate::New(callback));
1090   v8::Local<v8::Object> object = object_template->NewInstance();
1091   (*env)->Global()->Set(v8_str("callback_object"), object);
1092   v8::Handle<v8::Script> script;
1093   script = v8_compile("callback_object.callback(17)");
1094   for (int i = 0; i < 30; i++) {
1095     CHECK_EQ(51424, script->Run()->Int32Value());
1096   }
1097   script = v8_compile("callback_object.callback(17, 24)");
1098   for (int i = 0; i < 30; i++) {
1099     CHECK_EQ(51425, script->Run()->Int32Value());
1100   }
1101 }
1102
1103
1104 THREADED_PROFILED_TEST(SimpleCallback) {
1105   TestSimpleCallback(SimpleCallback);
1106 }
1107
1108
1109 template<typename T>
1110 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1111
1112 // constant return values
1113 static int32_t fast_return_value_int32 = 471;
1114 static uint32_t fast_return_value_uint32 = 571;
1115 static const double kFastReturnValueDouble = 2.7;
1116 // variable return values
1117 static bool fast_return_value_bool = false;
1118 enum ReturnValueOddball {
1119   kNullReturnValue,
1120   kUndefinedReturnValue,
1121   kEmptyStringReturnValue
1122 };
1123 static ReturnValueOddball fast_return_value_void;
1124 static bool fast_return_value_object_is_empty = false;
1125
1126 // Helper function to avoid compiler error: insufficient contextual information
1127 // to determine type when applying FUNCTION_ADDR to a template function.
1128 static i::Address address_of(v8::FunctionCallback callback) {
1129   return FUNCTION_ADDR(callback);
1130 }
1131
1132 template<>
1133 void FastReturnValueCallback<int32_t>(
1134     const v8::FunctionCallbackInfo<v8::Value>& info) {
1135   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1136   info.GetReturnValue().Set(fast_return_value_int32);
1137 }
1138
1139 template<>
1140 void FastReturnValueCallback<uint32_t>(
1141     const v8::FunctionCallbackInfo<v8::Value>& info) {
1142   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1143   info.GetReturnValue().Set(fast_return_value_uint32);
1144 }
1145
1146 template<>
1147 void FastReturnValueCallback<double>(
1148     const v8::FunctionCallbackInfo<v8::Value>& info) {
1149   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1150   info.GetReturnValue().Set(kFastReturnValueDouble);
1151 }
1152
1153 template<>
1154 void FastReturnValueCallback<bool>(
1155     const v8::FunctionCallbackInfo<v8::Value>& info) {
1156   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1157   info.GetReturnValue().Set(fast_return_value_bool);
1158 }
1159
1160 template<>
1161 void FastReturnValueCallback<void>(
1162     const v8::FunctionCallbackInfo<v8::Value>& info) {
1163   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1164   switch (fast_return_value_void) {
1165     case kNullReturnValue:
1166       info.GetReturnValue().SetNull();
1167       break;
1168     case kUndefinedReturnValue:
1169       info.GetReturnValue().SetUndefined();
1170       break;
1171     case kEmptyStringReturnValue:
1172       info.GetReturnValue().SetEmptyString();
1173       break;
1174   }
1175 }
1176
1177 template<>
1178 void FastReturnValueCallback<Object>(
1179     const v8::FunctionCallbackInfo<v8::Value>& info) {
1180   v8::Handle<v8::Object> object;
1181   if (!fast_return_value_object_is_empty) object = Object::New();
1182   info.GetReturnValue().Set(object);
1183 }
1184
1185 template<typename T>
1186 Handle<Value> TestFastReturnValues() {
1187   LocalContext env;
1188   v8::HandleScope scope(env->GetIsolate());
1189   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1190   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1191   object_template->Set("callback", v8::FunctionTemplate::New(callback));
1192   v8::Local<v8::Object> object = object_template->NewInstance();
1193   (*env)->Global()->Set(v8_str("callback_object"), object);
1194   return scope.Close(CompileRun("callback_object.callback()"));
1195 }
1196
1197
1198 THREADED_PROFILED_TEST(FastReturnValues) {
1199   LocalContext env;
1200   v8::HandleScope scope(CcTest::isolate());
1201   v8::Handle<v8::Value> value;
1202   // check int32_t and uint32_t
1203   int32_t int_values[] = {
1204       0, 234, -723,
1205       i::Smi::kMinValue, i::Smi::kMaxValue
1206   };
1207   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1208     for (int modifier = -1; modifier <= 1; modifier++) {
1209       int int_value = int_values[i] + modifier;
1210       // check int32_t
1211       fast_return_value_int32 = int_value;
1212       value = TestFastReturnValues<int32_t>();
1213       CHECK(value->IsInt32());
1214       CHECK(fast_return_value_int32 == value->Int32Value());
1215       // check uint32_t
1216       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1217       value = TestFastReturnValues<uint32_t>();
1218       CHECK(value->IsUint32());
1219       CHECK(fast_return_value_uint32 == value->Uint32Value());
1220     }
1221   }
1222   // check double
1223   value = TestFastReturnValues<double>();
1224   CHECK(value->IsNumber());
1225   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1226   // check bool values
1227   for (int i = 0; i < 2; i++) {
1228     fast_return_value_bool = i == 0;
1229     value = TestFastReturnValues<bool>();
1230     CHECK(value->IsBoolean());
1231     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1232   }
1233   // check oddballs
1234   ReturnValueOddball oddballs[] = {
1235       kNullReturnValue,
1236       kUndefinedReturnValue,
1237       kEmptyStringReturnValue
1238   };
1239   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1240     fast_return_value_void = oddballs[i];
1241     value = TestFastReturnValues<void>();
1242     switch (fast_return_value_void) {
1243       case kNullReturnValue:
1244         CHECK(value->IsNull());
1245         break;
1246       case kUndefinedReturnValue:
1247         CHECK(value->IsUndefined());
1248         break;
1249       case kEmptyStringReturnValue:
1250         CHECK(value->IsString());
1251         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1252         break;
1253     }
1254   }
1255   // check handles
1256   fast_return_value_object_is_empty = false;
1257   value = TestFastReturnValues<Object>();
1258   CHECK(value->IsObject());
1259   fast_return_value_object_is_empty = true;
1260   value = TestFastReturnValues<Object>();
1261   CHECK(value->IsUndefined());
1262 }
1263
1264
1265 THREADED_TEST(FunctionTemplateSetLength) {
1266   LocalContext env;
1267   v8::HandleScope scope(env->GetIsolate());
1268   {
1269     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
1270         handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
1271     Local<Function> fun = fun_templ->GetFunction();
1272     env->Global()->Set(v8_str("obj"), fun);
1273     Local<Script> script = v8_compile("obj.length");
1274     CHECK_EQ(23, script->Run()->Int32Value());
1275   }
1276   {
1277     Local<v8::FunctionTemplate> fun_templ =
1278         v8::FunctionTemplate::New(handle_callback);
1279     fun_templ->SetLength(22);
1280     Local<Function> fun = fun_templ->GetFunction();
1281     env->Global()->Set(v8_str("obj"), fun);
1282     Local<Script> script = v8_compile("obj.length");
1283     CHECK_EQ(22, script->Run()->Int32Value());
1284   }
1285   {
1286     // Without setting length it defaults to 0.
1287     Local<v8::FunctionTemplate> fun_templ =
1288         v8::FunctionTemplate::New(handle_callback);
1289     Local<Function> fun = fun_templ->GetFunction();
1290     env->Global()->Set(v8_str("obj"), fun);
1291     Local<Script> script = v8_compile("obj.length");
1292     CHECK_EQ(0, script->Run()->Int32Value());
1293   }
1294 }
1295
1296
1297 static void* expected_ptr;
1298 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1299   void* ptr = v8::External::Cast(*args.Data())->Value();
1300   CHECK_EQ(expected_ptr, ptr);
1301   args.GetReturnValue().Set(true);
1302 }
1303
1304
1305 static void TestExternalPointerWrapping() {
1306   LocalContext env;
1307   v8::HandleScope scope(env->GetIsolate());
1308
1309   v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
1310
1311   v8::Handle<v8::Object> obj = v8::Object::New();
1312   obj->Set(v8_str("func"),
1313            v8::FunctionTemplate::New(callback, data)->GetFunction());
1314   env->Global()->Set(v8_str("obj"), obj);
1315
1316   CHECK(CompileRun(
1317         "function foo() {\n"
1318         "  for (var i = 0; i < 13; i++) obj.func();\n"
1319         "}\n"
1320         "foo(), true")->BooleanValue());
1321 }
1322
1323
1324 THREADED_TEST(ExternalWrap) {
1325   // Check heap allocated object.
1326   int* ptr = new int;
1327   expected_ptr = ptr;
1328   TestExternalPointerWrapping();
1329   delete ptr;
1330
1331   // Check stack allocated object.
1332   int foo;
1333   expected_ptr = &foo;
1334   TestExternalPointerWrapping();
1335
1336   // Check not aligned addresses.
1337   const int n = 100;
1338   char* s = new char[n];
1339   for (int i = 0; i < n; i++) {
1340     expected_ptr = s + i;
1341     TestExternalPointerWrapping();
1342   }
1343
1344   delete[] s;
1345
1346   // Check several invalid addresses.
1347   expected_ptr = reinterpret_cast<void*>(1);
1348   TestExternalPointerWrapping();
1349
1350   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1351   TestExternalPointerWrapping();
1352
1353   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1354   TestExternalPointerWrapping();
1355
1356 #if defined(V8_HOST_ARCH_X64)
1357   // Check a value with a leading 1 bit in x64 Smi encoding.
1358   expected_ptr = reinterpret_cast<void*>(0x400000000);
1359   TestExternalPointerWrapping();
1360
1361   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1362   TestExternalPointerWrapping();
1363
1364   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1365   TestExternalPointerWrapping();
1366 #endif
1367 }
1368
1369
1370 THREADED_TEST(FindInstanceInPrototypeChain) {
1371   LocalContext env;
1372   v8::HandleScope scope(env->GetIsolate());
1373
1374   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
1375   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
1376   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
1377   derived->Inherit(base);
1378
1379   Local<v8::Function> base_function = base->GetFunction();
1380   Local<v8::Function> derived_function = derived->GetFunction();
1381   Local<v8::Function> other_function = other->GetFunction();
1382
1383   Local<v8::Object> base_instance = base_function->NewInstance();
1384   Local<v8::Object> derived_instance = derived_function->NewInstance();
1385   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1386   Local<v8::Object> other_instance = other_function->NewInstance();
1387   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1388   other_instance->Set(v8_str("__proto__"), derived_instance2);
1389
1390   // base_instance is only an instance of base.
1391   CHECK_EQ(base_instance,
1392            base_instance->FindInstanceInPrototypeChain(base));
1393   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1394   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1395
1396   // derived_instance is an instance of base and derived.
1397   CHECK_EQ(derived_instance,
1398            derived_instance->FindInstanceInPrototypeChain(base));
1399   CHECK_EQ(derived_instance,
1400            derived_instance->FindInstanceInPrototypeChain(derived));
1401   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1402
1403   // other_instance is an instance of other and its immediate
1404   // prototype derived_instance2 is an instance of base and derived.
1405   // Note, derived_instance is an instance of base and derived too,
1406   // but it comes after derived_instance2 in the prototype chain of
1407   // other_instance.
1408   CHECK_EQ(derived_instance2,
1409            other_instance->FindInstanceInPrototypeChain(base));
1410   CHECK_EQ(derived_instance2,
1411            other_instance->FindInstanceInPrototypeChain(derived));
1412   CHECK_EQ(other_instance,
1413            other_instance->FindInstanceInPrototypeChain(other));
1414 }
1415
1416
1417 THREADED_TEST(TinyInteger) {
1418   LocalContext env;
1419   v8::HandleScope scope(env->GetIsolate());
1420   v8::Isolate* isolate = CcTest::isolate();
1421
1422   int32_t value = 239;
1423   Local<v8::Integer> value_obj = v8::Integer::New(value);
1424   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1425
1426   value_obj = v8::Integer::New(value, isolate);
1427   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1428 }
1429
1430
1431 THREADED_TEST(BigSmiInteger) {
1432   LocalContext env;
1433   v8::HandleScope scope(env->GetIsolate());
1434   v8::Isolate* isolate = CcTest::isolate();
1435
1436   int32_t value = i::Smi::kMaxValue;
1437   // We cannot add one to a Smi::kMaxValue without wrapping.
1438   if (i::SmiValuesAre31Bits()) {
1439     CHECK(i::Smi::IsValid(value));
1440     CHECK(!i::Smi::IsValid(value + 1));
1441
1442     Local<v8::Integer> value_obj = v8::Integer::New(value);
1443     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1444
1445     value_obj = v8::Integer::New(value, isolate);
1446     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1447   }
1448 }
1449
1450
1451 THREADED_TEST(BigInteger) {
1452   LocalContext env;
1453   v8::HandleScope scope(env->GetIsolate());
1454   v8::Isolate* isolate = CcTest::isolate();
1455
1456   // We cannot add one to a Smi::kMaxValue without wrapping.
1457   if (i::SmiValuesAre31Bits()) {
1458     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1459     // The code will not be run in that case, due to the "if" guard.
1460     int32_t value =
1461         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1462     CHECK(value > i::Smi::kMaxValue);
1463     CHECK(!i::Smi::IsValid(value));
1464
1465     Local<v8::Integer> value_obj = v8::Integer::New(value);
1466     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1467
1468     value_obj = v8::Integer::New(value, isolate);
1469     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1470   }
1471 }
1472
1473
1474 THREADED_TEST(TinyUnsignedInteger) {
1475   LocalContext env;
1476   v8::HandleScope scope(env->GetIsolate());
1477   v8::Isolate* isolate = CcTest::isolate();
1478
1479   uint32_t value = 239;
1480
1481   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1482   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1483
1484   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1485   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1486 }
1487
1488
1489 THREADED_TEST(BigUnsignedSmiInteger) {
1490   LocalContext env;
1491   v8::HandleScope scope(env->GetIsolate());
1492   v8::Isolate* isolate = CcTest::isolate();
1493
1494   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1495   CHECK(i::Smi::IsValid(value));
1496   CHECK(!i::Smi::IsValid(value + 1));
1497
1498   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1499   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1500
1501   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1502   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1503 }
1504
1505
1506 THREADED_TEST(BigUnsignedInteger) {
1507   LocalContext env;
1508   v8::HandleScope scope(env->GetIsolate());
1509   v8::Isolate* isolate = CcTest::isolate();
1510
1511   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1512   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1513   CHECK(!i::Smi::IsValid(value));
1514
1515   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1516   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1517
1518   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1519   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1520 }
1521
1522
1523 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1524   LocalContext env;
1525   v8::HandleScope scope(env->GetIsolate());
1526   v8::Isolate* isolate = CcTest::isolate();
1527
1528   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1529   uint32_t value = INT32_MAX_AS_UINT + 1;
1530   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1531
1532   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1533   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1534
1535   value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1536   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1537 }
1538
1539
1540 THREADED_TEST(IsNativeError) {
1541   LocalContext env;
1542   v8::HandleScope scope(env->GetIsolate());
1543   v8::Handle<Value> syntax_error = CompileRun(
1544       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1545   CHECK(syntax_error->IsNativeError());
1546   v8::Handle<Value> not_error = CompileRun("{a:42}");
1547   CHECK(!not_error->IsNativeError());
1548   v8::Handle<Value> not_object = CompileRun("42");
1549   CHECK(!not_object->IsNativeError());
1550 }
1551
1552
1553 THREADED_TEST(StringObject) {
1554   LocalContext env;
1555   v8::HandleScope scope(env->GetIsolate());
1556   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1557   CHECK(boxed_string->IsStringObject());
1558   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1559   CHECK(!unboxed_string->IsStringObject());
1560   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1561   CHECK(!boxed_not_string->IsStringObject());
1562   v8::Handle<Value> not_object = CompileRun("0");
1563   CHECK(!not_object->IsStringObject());
1564   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1565   CHECK(!as_boxed.IsEmpty());
1566   Local<v8::String> the_string = as_boxed->ValueOf();
1567   CHECK(!the_string.IsEmpty());
1568   ExpectObject("\"test\"", the_string);
1569   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1570   CHECK(new_boxed_string->IsStringObject());
1571   as_boxed = new_boxed_string.As<v8::StringObject>();
1572   the_string = as_boxed->ValueOf();
1573   CHECK(!the_string.IsEmpty());
1574   ExpectObject("\"test\"", the_string);
1575 }
1576
1577
1578 THREADED_TEST(NumberObject) {
1579   LocalContext env;
1580   v8::HandleScope scope(env->GetIsolate());
1581   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1582   CHECK(boxed_number->IsNumberObject());
1583   v8::Handle<Value> unboxed_number = CompileRun("42");
1584   CHECK(!unboxed_number->IsNumberObject());
1585   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1586   CHECK(!boxed_not_number->IsNumberObject());
1587   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1588   CHECK(!as_boxed.IsEmpty());
1589   double the_number = as_boxed->ValueOf();
1590   CHECK_EQ(42.0, the_number);
1591   v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1592   CHECK(new_boxed_number->IsNumberObject());
1593   as_boxed = new_boxed_number.As<v8::NumberObject>();
1594   the_number = as_boxed->ValueOf();
1595   CHECK_EQ(43.0, the_number);
1596 }
1597
1598
1599 THREADED_TEST(BooleanObject) {
1600   LocalContext env;
1601   v8::HandleScope scope(env->GetIsolate());
1602   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1603   CHECK(boxed_boolean->IsBooleanObject());
1604   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1605   CHECK(!unboxed_boolean->IsBooleanObject());
1606   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1607   CHECK(!boxed_not_boolean->IsBooleanObject());
1608   v8::Handle<v8::BooleanObject> as_boxed =
1609       boxed_boolean.As<v8::BooleanObject>();
1610   CHECK(!as_boxed.IsEmpty());
1611   bool the_boolean = as_boxed->ValueOf();
1612   CHECK_EQ(true, the_boolean);
1613   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1614   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1615   CHECK(boxed_true->IsBooleanObject());
1616   CHECK(boxed_false->IsBooleanObject());
1617   as_boxed = boxed_true.As<v8::BooleanObject>();
1618   CHECK_EQ(true, as_boxed->ValueOf());
1619   as_boxed = boxed_false.As<v8::BooleanObject>();
1620   CHECK_EQ(false, as_boxed->ValueOf());
1621 }
1622
1623
1624 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1625   LocalContext env;
1626   v8::HandleScope scope(env->GetIsolate());
1627
1628   Local<Value> primitive_false = Boolean::New(false);
1629   CHECK(primitive_false->IsBoolean());
1630   CHECK(!primitive_false->IsBooleanObject());
1631   CHECK(!primitive_false->BooleanValue());
1632   CHECK(!primitive_false->IsTrue());
1633   CHECK(primitive_false->IsFalse());
1634
1635   Local<Value> false_value = BooleanObject::New(false);
1636   CHECK(!false_value->IsBoolean());
1637   CHECK(false_value->IsBooleanObject());
1638   CHECK(false_value->BooleanValue());
1639   CHECK(!false_value->IsTrue());
1640   CHECK(!false_value->IsFalse());
1641
1642   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1643   CHECK(!false_boolean_object->IsBoolean());
1644   CHECK(false_boolean_object->IsBooleanObject());
1645   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1646   // CHECK(false_boolean_object->BooleanValue());
1647   CHECK(!false_boolean_object->ValueOf());
1648   CHECK(!false_boolean_object->IsTrue());
1649   CHECK(!false_boolean_object->IsFalse());
1650
1651   Local<Value> primitive_true = Boolean::New(true);
1652   CHECK(primitive_true->IsBoolean());
1653   CHECK(!primitive_true->IsBooleanObject());
1654   CHECK(primitive_true->BooleanValue());
1655   CHECK(primitive_true->IsTrue());
1656   CHECK(!primitive_true->IsFalse());
1657
1658   Local<Value> true_value = BooleanObject::New(true);
1659   CHECK(!true_value->IsBoolean());
1660   CHECK(true_value->IsBooleanObject());
1661   CHECK(true_value->BooleanValue());
1662   CHECK(!true_value->IsTrue());
1663   CHECK(!true_value->IsFalse());
1664
1665   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1666   CHECK(!true_boolean_object->IsBoolean());
1667   CHECK(true_boolean_object->IsBooleanObject());
1668   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1669   // CHECK(true_boolean_object->BooleanValue());
1670   CHECK(true_boolean_object->ValueOf());
1671   CHECK(!true_boolean_object->IsTrue());
1672   CHECK(!true_boolean_object->IsFalse());
1673 }
1674
1675
1676 THREADED_TEST(Number) {
1677   LocalContext env;
1678   v8::HandleScope scope(env->GetIsolate());
1679   double PI = 3.1415926;
1680   Local<v8::Number> pi_obj = v8::Number::New(PI);
1681   CHECK_EQ(PI, pi_obj->NumberValue());
1682 }
1683
1684
1685 THREADED_TEST(ToNumber) {
1686   LocalContext env;
1687   v8::Isolate* isolate = CcTest::isolate();
1688   v8::HandleScope scope(isolate);
1689   Local<String> str = v8_str("3.1415926");
1690   CHECK_EQ(3.1415926, str->NumberValue());
1691   v8::Handle<v8::Boolean> t = v8::True(isolate);
1692   CHECK_EQ(1.0, t->NumberValue());
1693   v8::Handle<v8::Boolean> f = v8::False(isolate);
1694   CHECK_EQ(0.0, f->NumberValue());
1695 }
1696
1697
1698 THREADED_TEST(Date) {
1699   LocalContext env;
1700   v8::HandleScope scope(env->GetIsolate());
1701   double PI = 3.1415926;
1702   Local<Value> date = v8::Date::New(PI);
1703   CHECK_EQ(3.0, date->NumberValue());
1704   date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1705   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1706 }
1707
1708
1709 THREADED_TEST(Boolean) {
1710   LocalContext env;
1711   v8::HandleScope scope(env->GetIsolate());
1712   v8::Handle<v8::Boolean> t = v8::True(CcTest::isolate());
1713   CHECK(t->Value());
1714   v8::Handle<v8::Boolean> f = v8::False(CcTest::isolate());
1715   CHECK(!f->Value());
1716   v8::Handle<v8::Primitive> u = v8::Undefined(CcTest::isolate());
1717   CHECK(!u->BooleanValue());
1718   v8::Handle<v8::Primitive> n = v8::Null(CcTest::isolate());
1719   CHECK(!n->BooleanValue());
1720   v8::Handle<String> str1 = v8_str("");
1721   CHECK(!str1->BooleanValue());
1722   v8::Handle<String> str2 = v8_str("x");
1723   CHECK(str2->BooleanValue());
1724   CHECK(!v8::Number::New(0)->BooleanValue());
1725   CHECK(v8::Number::New(-1)->BooleanValue());
1726   CHECK(v8::Number::New(1)->BooleanValue());
1727   CHECK(v8::Number::New(42)->BooleanValue());
1728   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1729 }
1730
1731
1732 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1733   ApiTestFuzzer::Fuzz();
1734   args.GetReturnValue().Set(v8_num(13.4));
1735 }
1736
1737
1738 static void GetM(Local<String> name,
1739                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1740   ApiTestFuzzer::Fuzz();
1741   info.GetReturnValue().Set(v8_num(876));
1742 }
1743
1744
1745 THREADED_TEST(GlobalPrototype) {
1746   v8::HandleScope scope(CcTest::isolate());
1747   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1748   func_templ->PrototypeTemplate()->Set(
1749       "dummy",
1750       v8::FunctionTemplate::New(DummyCallHandler));
1751   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1752   templ->Set("x", v8_num(200));
1753   templ->SetAccessor(v8_str("m"), GetM);
1754   LocalContext env(0, templ);
1755   v8::Handle<Script> script(v8_compile("dummy()"));
1756   v8::Handle<Value> result(script->Run());
1757   CHECK_EQ(13.4, result->NumberValue());
1758   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1759   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1760 }
1761
1762
1763 THREADED_TEST(ObjectTemplate) {
1764   v8::HandleScope scope(CcTest::isolate());
1765   Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1766   templ1->Set("x", v8_num(10));
1767   templ1->Set("y", v8_num(13));
1768   LocalContext env;
1769   Local<v8::Object> instance1 = templ1->NewInstance();
1770   env->Global()->Set(v8_str("p"), instance1);
1771   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1772   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1773   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1774   fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1775   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1776   templ2->Set("a", v8_num(12));
1777   templ2->Set("b", templ1);
1778   Local<v8::Object> instance2 = templ2->NewInstance();
1779   env->Global()->Set(v8_str("q"), instance2);
1780   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1781   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1782   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1783   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1784 }
1785
1786
1787 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1788   ApiTestFuzzer::Fuzz();
1789   args.GetReturnValue().Set(v8_num(17.2));
1790 }
1791
1792
1793 static void GetKnurd(Local<String> property,
1794                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1795   ApiTestFuzzer::Fuzz();
1796   info.GetReturnValue().Set(v8_num(15.2));
1797 }
1798
1799
1800 THREADED_TEST(DescriptorInheritance) {
1801   v8::HandleScope scope(CcTest::isolate());
1802   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1803   super->PrototypeTemplate()->Set("flabby",
1804                                   v8::FunctionTemplate::New(GetFlabby));
1805   super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1806
1807   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1808
1809   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1810   base1->Inherit(super);
1811   base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1812
1813   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1814   base2->Inherit(super);
1815   base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1816
1817   LocalContext env;
1818
1819   env->Global()->Set(v8_str("s"), super->GetFunction());
1820   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1821   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1822
1823   // Checks right __proto__ chain.
1824   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1825   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1826
1827   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1828
1829   // Instance accessor should not be visible on function object or its prototype
1830   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1831   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1832   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1833
1834   env->Global()->Set(v8_str("obj"),
1835                      base1->GetFunction()->NewInstance());
1836   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1837   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1838   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1839   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1840   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1841
1842   env->Global()->Set(v8_str("obj2"),
1843                      base2->GetFunction()->NewInstance());
1844   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1845   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1846   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1847   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1848   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1849
1850   // base1 and base2 cannot cross reference to each's prototype
1851   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1852   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1853 }
1854
1855
1856 int echo_named_call_count;
1857
1858
1859 static void EchoNamedProperty(Local<String> name,
1860                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1861   ApiTestFuzzer::Fuzz();
1862   CHECK_EQ(v8_str("data"), info.Data());
1863   echo_named_call_count++;
1864   info.GetReturnValue().Set(name);
1865 }
1866
1867
1868 // Helper functions for Interceptor/Accessor interaction tests
1869
1870 void SimpleAccessorGetter(Local<String> name,
1871                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1872   Handle<Object> self = info.This();
1873   info.GetReturnValue().Set(
1874       self->Get(String::Concat(v8_str("accessor_"), name)));
1875 }
1876
1877 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1878                           const v8::PropertyCallbackInfo<void>& info) {
1879   Handle<Object> self = info.This();
1880   self->Set(String::Concat(v8_str("accessor_"), name), value);
1881 }
1882
1883 void EmptyInterceptorGetter(Local<String> name,
1884                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1885 }
1886
1887 void EmptyInterceptorSetter(Local<String> name,
1888                             Local<Value> value,
1889                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1890 }
1891
1892 void InterceptorGetter(Local<String> name,
1893                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1894   // Intercept names that start with 'interceptor_'.
1895   String::Utf8Value utf8(name);
1896   char* name_str = *utf8;
1897   char prefix[] = "interceptor_";
1898   int i;
1899   for (i = 0; name_str[i] && prefix[i]; ++i) {
1900     if (name_str[i] != prefix[i]) return;
1901   }
1902   Handle<Object> self = info.This();
1903   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1904 }
1905
1906 void InterceptorSetter(Local<String> name,
1907                        Local<Value> value,
1908                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1909   // Intercept accesses that set certain integer values, for which the name does
1910   // not start with 'accessor_'.
1911   String::Utf8Value utf8(name);
1912   char* name_str = *utf8;
1913   char prefix[] = "accessor_";
1914   int i;
1915   for (i = 0; name_str[i] && prefix[i]; ++i) {
1916     if (name_str[i] != prefix[i]) break;
1917   }
1918   if (!prefix[i]) return;
1919
1920   if (value->IsInt32() && value->Int32Value() < 10000) {
1921     Handle<Object> self = info.This();
1922     self->SetHiddenValue(name, value);
1923     info.GetReturnValue().Set(value);
1924   }
1925 }
1926
1927 void AddAccessor(Handle<FunctionTemplate> templ,
1928                  Handle<String> name,
1929                  v8::AccessorGetterCallback getter,
1930                  v8::AccessorSetterCallback setter) {
1931   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1932 }
1933
1934 void AddInterceptor(Handle<FunctionTemplate> templ,
1935                     v8::NamedPropertyGetterCallback getter,
1936                     v8::NamedPropertySetterCallback setter) {
1937   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1938 }
1939
1940
1941 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1942   v8::HandleScope scope(CcTest::isolate());
1943   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1944   Handle<FunctionTemplate> child = FunctionTemplate::New();
1945   child->Inherit(parent);
1946   AddAccessor(parent, v8_str("age"),
1947               SimpleAccessorGetter, SimpleAccessorSetter);
1948   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1949   LocalContext env;
1950   env->Global()->Set(v8_str("Child"), child->GetFunction());
1951   CompileRun("var child = new Child;"
1952              "child.age = 10;");
1953   ExpectBoolean("child.hasOwnProperty('age')", false);
1954   ExpectInt32("child.age", 10);
1955   ExpectInt32("child.accessor_age", 10);
1956 }
1957
1958
1959 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1960   v8::HandleScope scope(CcTest::isolate());
1961   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1962   Handle<FunctionTemplate> child = FunctionTemplate::New();
1963   child->Inherit(parent);
1964   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1965   LocalContext env;
1966   env->Global()->Set(v8_str("Child"), child->GetFunction());
1967   CompileRun("var child = new Child;"
1968              "var parent = child.__proto__;"
1969              "Object.defineProperty(parent, 'age', "
1970              "  {get: function(){ return this.accessor_age; }, "
1971              "   set: function(v){ this.accessor_age = v; }, "
1972              "   enumerable: true, configurable: true});"
1973              "child.age = 10;");
1974   ExpectBoolean("child.hasOwnProperty('age')", false);
1975   ExpectInt32("child.age", 10);
1976   ExpectInt32("child.accessor_age", 10);
1977 }
1978
1979
1980 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1981   v8::HandleScope scope(CcTest::isolate());
1982   Handle<FunctionTemplate> parent = FunctionTemplate::New();
1983   Handle<FunctionTemplate> child = FunctionTemplate::New();
1984   child->Inherit(parent);
1985   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1986   LocalContext env;
1987   env->Global()->Set(v8_str("Child"), child->GetFunction());
1988   CompileRun("var child = new Child;"
1989              "var parent = child.__proto__;"
1990              "parent.name = 'Alice';");
1991   ExpectBoolean("child.hasOwnProperty('name')", false);
1992   ExpectString("child.name", "Alice");
1993   CompileRun("child.name = 'Bob';");
1994   ExpectString("child.name", "Bob");
1995   ExpectBoolean("child.hasOwnProperty('name')", true);
1996   ExpectString("parent.name", "Alice");
1997 }
1998
1999
2000 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2001   v8::HandleScope scope(CcTest::isolate());
2002   Handle<FunctionTemplate> templ = FunctionTemplate::New();
2003   AddAccessor(templ, v8_str("age"),
2004               SimpleAccessorGetter, SimpleAccessorSetter);
2005   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2006   LocalContext env;
2007   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2008   CompileRun("var obj = new Obj;"
2009              "function setAge(i){ obj.age = i; };"
2010              "for(var i = 0; i <= 10000; i++) setAge(i);");
2011   // All i < 10000 go to the interceptor.
2012   ExpectInt32("obj.interceptor_age", 9999);
2013   // The last i goes to the accessor.
2014   ExpectInt32("obj.accessor_age", 10000);
2015 }
2016
2017
2018 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2019   v8::HandleScope scope(CcTest::isolate());
2020   Handle<FunctionTemplate> templ = FunctionTemplate::New();
2021   AddAccessor(templ, v8_str("age"),
2022               SimpleAccessorGetter, SimpleAccessorSetter);
2023   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2024   LocalContext env;
2025   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2026   CompileRun("var obj = new Obj;"
2027              "function setAge(i){ obj.age = i; };"
2028              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2029   // All i >= 10000 go to the accessor.
2030   ExpectInt32("obj.accessor_age", 10000);
2031   // The last i goes to the interceptor.
2032   ExpectInt32("obj.interceptor_age", 9999);
2033 }
2034
2035
2036 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2037   v8::HandleScope scope(CcTest::isolate());
2038   Handle<FunctionTemplate> parent = FunctionTemplate::New();
2039   Handle<FunctionTemplate> child = FunctionTemplate::New();
2040   child->Inherit(parent);
2041   AddAccessor(parent, v8_str("age"),
2042               SimpleAccessorGetter, SimpleAccessorSetter);
2043   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2044   LocalContext env;
2045   env->Global()->Set(v8_str("Child"), child->GetFunction());
2046   CompileRun("var child = new Child;"
2047              "function setAge(i){ child.age = i; };"
2048              "for(var i = 0; i <= 10000; i++) setAge(i);");
2049   // All i < 10000 go to the interceptor.
2050   ExpectInt32("child.interceptor_age", 9999);
2051   // The last i goes to the accessor.
2052   ExpectInt32("child.accessor_age", 10000);
2053 }
2054
2055
2056 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2057   v8::HandleScope scope(CcTest::isolate());
2058   Handle<FunctionTemplate> parent = FunctionTemplate::New();
2059   Handle<FunctionTemplate> child = FunctionTemplate::New();
2060   child->Inherit(parent);
2061   AddAccessor(parent, v8_str("age"),
2062               SimpleAccessorGetter, SimpleAccessorSetter);
2063   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2064   LocalContext env;
2065   env->Global()->Set(v8_str("Child"), child->GetFunction());
2066   CompileRun("var child = new Child;"
2067              "function setAge(i){ child.age = i; };"
2068              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2069   // All i >= 10000 go to the accessor.
2070   ExpectInt32("child.accessor_age", 10000);
2071   // The last i goes to the interceptor.
2072   ExpectInt32("child.interceptor_age", 9999);
2073 }
2074
2075
2076 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2077   v8::HandleScope scope(CcTest::isolate());
2078   Handle<FunctionTemplate> templ = FunctionTemplate::New();
2079   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2080   LocalContext env;
2081   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2082   CompileRun("var obj = new Obj;"
2083              "function setter(i) { this.accessor_age = i; };"
2084              "function getter() { return this.accessor_age; };"
2085              "function setAge(i) { obj.age = i; };"
2086              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2087              "for(var i = 0; i <= 10000; i++) setAge(i);");
2088   // All i < 10000 go to the interceptor.
2089   ExpectInt32("obj.interceptor_age", 9999);
2090   // The last i goes to the JavaScript accessor.
2091   ExpectInt32("obj.accessor_age", 10000);
2092   // The installed JavaScript getter is still intact.
2093   // This last part is a regression test for issue 1651 and relies on the fact
2094   // that both interceptor and accessor are being installed on the same object.
2095   ExpectInt32("obj.age", 10000);
2096   ExpectBoolean("obj.hasOwnProperty('age')", true);
2097   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2098 }
2099
2100
2101 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2102   v8::HandleScope scope(CcTest::isolate());
2103   Handle<FunctionTemplate> templ = FunctionTemplate::New();
2104   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2105   LocalContext env;
2106   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2107   CompileRun("var obj = new Obj;"
2108              "function setter(i) { this.accessor_age = i; };"
2109              "function getter() { return this.accessor_age; };"
2110              "function setAge(i) { obj.age = i; };"
2111              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2112              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2113   // All i >= 10000 go to the accessor.
2114   ExpectInt32("obj.accessor_age", 10000);
2115   // The last i goes to the interceptor.
2116   ExpectInt32("obj.interceptor_age", 9999);
2117   // The installed JavaScript getter is still intact.
2118   // This last part is a regression test for issue 1651 and relies on the fact
2119   // that both interceptor and accessor are being installed on the same object.
2120   ExpectInt32("obj.age", 10000);
2121   ExpectBoolean("obj.hasOwnProperty('age')", true);
2122   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2123 }
2124
2125
2126 THREADED_TEST(SwitchFromInterceptorToProperty) {
2127   v8::HandleScope scope(CcTest::isolate());
2128   Handle<FunctionTemplate> parent = FunctionTemplate::New();
2129   Handle<FunctionTemplate> child = FunctionTemplate::New();
2130   child->Inherit(parent);
2131   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2132   LocalContext env;
2133   env->Global()->Set(v8_str("Child"), child->GetFunction());
2134   CompileRun("var child = new Child;"
2135              "function setAge(i){ child.age = i; };"
2136              "for(var i = 0; i <= 10000; i++) setAge(i);");
2137   // All i < 10000 go to the interceptor.
2138   ExpectInt32("child.interceptor_age", 9999);
2139   // The last i goes to child's own property.
2140   ExpectInt32("child.age", 10000);
2141 }
2142
2143
2144 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2145   v8::HandleScope scope(CcTest::isolate());
2146   Handle<FunctionTemplate> parent = FunctionTemplate::New();
2147   Handle<FunctionTemplate> child = FunctionTemplate::New();
2148   child->Inherit(parent);
2149   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2150   LocalContext env;
2151   env->Global()->Set(v8_str("Child"), child->GetFunction());
2152   CompileRun("var child = new Child;"
2153              "function setAge(i){ child.age = i; };"
2154              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2155   // All i >= 10000 go to child's own property.
2156   ExpectInt32("child.age", 10000);
2157   // The last i goes to the interceptor.
2158   ExpectInt32("child.interceptor_age", 9999);
2159 }
2160
2161
2162 THREADED_TEST(NamedPropertyHandlerGetter) {
2163   echo_named_call_count = 0;
2164   v8::HandleScope scope(CcTest::isolate());
2165   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2166   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2167                                                      0, 0, 0, 0,
2168                                                      v8_str("data"));
2169   LocalContext env;
2170   env->Global()->Set(v8_str("obj"),
2171                      templ->GetFunction()->NewInstance());
2172   CHECK_EQ(echo_named_call_count, 0);
2173   v8_compile("obj.x")->Run();
2174   CHECK_EQ(echo_named_call_count, 1);
2175   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2176   v8::Handle<Value> str = CompileRun(code);
2177   String::Utf8Value value(str);
2178   CHECK_EQ(*value, "oddlepoddle");
2179   // Check default behavior
2180   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2181   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2182   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2183 }
2184
2185
2186 int echo_indexed_call_count = 0;
2187
2188
2189 static void EchoIndexedProperty(
2190     uint32_t index,
2191     const v8::PropertyCallbackInfo<v8::Value>& info) {
2192   ApiTestFuzzer::Fuzz();
2193   CHECK_EQ(v8_num(637), info.Data());
2194   echo_indexed_call_count++;
2195   info.GetReturnValue().Set(v8_num(index));
2196 }
2197
2198
2199 THREADED_TEST(IndexedPropertyHandlerGetter) {
2200   v8::HandleScope scope(CcTest::isolate());
2201   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2202   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2203                                                        0, 0, 0, 0,
2204                                                        v8_num(637));
2205   LocalContext env;
2206   env->Global()->Set(v8_str("obj"),
2207                      templ->GetFunction()->NewInstance());
2208   Local<Script> script = v8_compile("obj[900]");
2209   CHECK_EQ(script->Run()->Int32Value(), 900);
2210 }
2211
2212
2213 v8::Handle<v8::Object> bottom;
2214
2215 static void CheckThisIndexedPropertyHandler(
2216     uint32_t index,
2217     const v8::PropertyCallbackInfo<v8::Value>& info) {
2218   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2219   ApiTestFuzzer::Fuzz();
2220   CHECK(info.This()->Equals(bottom));
2221 }
2222
2223 static void CheckThisNamedPropertyHandler(
2224     Local<String> name,
2225     const v8::PropertyCallbackInfo<v8::Value>& info) {
2226   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2227   ApiTestFuzzer::Fuzz();
2228   CHECK(info.This()->Equals(bottom));
2229 }
2230
2231 void CheckThisIndexedPropertySetter(
2232     uint32_t index,
2233     Local<Value> value,
2234     const v8::PropertyCallbackInfo<v8::Value>& info) {
2235   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2236   ApiTestFuzzer::Fuzz();
2237   CHECK(info.This()->Equals(bottom));
2238 }
2239
2240
2241 void CheckThisNamedPropertySetter(
2242     Local<String> property,
2243     Local<Value> value,
2244     const v8::PropertyCallbackInfo<v8::Value>& info) {
2245   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2246   ApiTestFuzzer::Fuzz();
2247   CHECK(info.This()->Equals(bottom));
2248 }
2249
2250 void CheckThisIndexedPropertyQuery(
2251     uint32_t index,
2252     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2253   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2254   ApiTestFuzzer::Fuzz();
2255   CHECK(info.This()->Equals(bottom));
2256 }
2257
2258
2259 void CheckThisNamedPropertyQuery(
2260     Local<String> property,
2261     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2262   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2263   ApiTestFuzzer::Fuzz();
2264   CHECK(info.This()->Equals(bottom));
2265 }
2266
2267
2268 void CheckThisIndexedPropertyDeleter(
2269     uint32_t index,
2270     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2271   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2272   ApiTestFuzzer::Fuzz();
2273   CHECK(info.This()->Equals(bottom));
2274 }
2275
2276
2277 void CheckThisNamedPropertyDeleter(
2278     Local<String> property,
2279     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2280   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2281   ApiTestFuzzer::Fuzz();
2282   CHECK(info.This()->Equals(bottom));
2283 }
2284
2285
2286 void CheckThisIndexedPropertyEnumerator(
2287     const v8::PropertyCallbackInfo<v8::Array>& info) {
2288   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2289   ApiTestFuzzer::Fuzz();
2290   CHECK(info.This()->Equals(bottom));
2291 }
2292
2293
2294 void CheckThisNamedPropertyEnumerator(
2295     const v8::PropertyCallbackInfo<v8::Array>& info) {
2296   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2297   ApiTestFuzzer::Fuzz();
2298   CHECK(info.This()->Equals(bottom));
2299 }
2300
2301
2302 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2303   LocalContext env;
2304   v8::HandleScope scope(env->GetIsolate());
2305
2306   // Set up a prototype chain with three interceptors.
2307   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2308   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2309       CheckThisIndexedPropertyHandler,
2310       CheckThisIndexedPropertySetter,
2311       CheckThisIndexedPropertyQuery,
2312       CheckThisIndexedPropertyDeleter,
2313       CheckThisIndexedPropertyEnumerator);
2314
2315   templ->InstanceTemplate()->SetNamedPropertyHandler(
2316       CheckThisNamedPropertyHandler,
2317       CheckThisNamedPropertySetter,
2318       CheckThisNamedPropertyQuery,
2319       CheckThisNamedPropertyDeleter,
2320       CheckThisNamedPropertyEnumerator);
2321
2322   bottom = templ->GetFunction()->NewInstance();
2323   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2324   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2325
2326   bottom->SetPrototype(middle);
2327   middle->SetPrototype(top);
2328   env->Global()->Set(v8_str("obj"), bottom);
2329
2330   // Indexed and named get.
2331   Script::Compile(v8_str("obj[0]"))->Run();
2332   Script::Compile(v8_str("obj.x"))->Run();
2333
2334   // Indexed and named set.
2335   Script::Compile(v8_str("obj[1] = 42"))->Run();
2336   Script::Compile(v8_str("obj.y = 42"))->Run();
2337
2338   // Indexed and named query.
2339   Script::Compile(v8_str("0 in obj"))->Run();
2340   Script::Compile(v8_str("'x' in obj"))->Run();
2341
2342   // Indexed and named deleter.
2343   Script::Compile(v8_str("delete obj[0]"))->Run();
2344   Script::Compile(v8_str("delete obj.x"))->Run();
2345
2346   // Enumerators.
2347   Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2348 }
2349
2350
2351 static void PrePropertyHandlerGet(
2352     Local<String> key,
2353     const v8::PropertyCallbackInfo<v8::Value>& info) {
2354   ApiTestFuzzer::Fuzz();
2355   if (v8_str("pre")->Equals(key)) {
2356     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2357   }
2358 }
2359
2360
2361 static void PrePropertyHandlerQuery(
2362     Local<String> key,
2363     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2364   if (v8_str("pre")->Equals(key)) {
2365     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2366   }
2367 }
2368
2369
2370 THREADED_TEST(PrePropertyHandler) {
2371   v8::HandleScope scope(CcTest::isolate());
2372   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
2373   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2374                                                     0,
2375                                                     PrePropertyHandlerQuery);
2376   LocalContext env(NULL, desc->InstanceTemplate());
2377   Script::Compile(v8_str(
2378       "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2379   v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2380   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2381   v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2382   CHECK_EQ(v8_str("Object: on"), result_on);
2383   v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2384   CHECK(result_post.IsEmpty());
2385 }
2386
2387
2388 THREADED_TEST(UndefinedIsNotEnumerable) {
2389   LocalContext env;
2390   v8::HandleScope scope(env->GetIsolate());
2391   v8::Handle<Value> result = Script::Compile(v8_str(
2392       "this.propertyIsEnumerable(undefined)"))->Run();
2393   CHECK(result->IsFalse());
2394 }
2395
2396
2397 v8::Handle<Script> call_recursively_script;
2398 static const int kTargetRecursionDepth = 200;  // near maximum
2399
2400
2401 static void CallScriptRecursivelyCall(
2402     const v8::FunctionCallbackInfo<v8::Value>& args) {
2403   ApiTestFuzzer::Fuzz();
2404   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2405   if (depth == kTargetRecursionDepth) return;
2406   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2407   args.GetReturnValue().Set(call_recursively_script->Run());
2408 }
2409
2410
2411 static void CallFunctionRecursivelyCall(
2412     const v8::FunctionCallbackInfo<v8::Value>& args) {
2413   ApiTestFuzzer::Fuzz();
2414   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2415   if (depth == kTargetRecursionDepth) {
2416     printf("[depth = %d]\n", depth);
2417     return;
2418   }
2419   args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2420   v8::Handle<Value> function =
2421       args.This()->Get(v8_str("callFunctionRecursively"));
2422   args.GetReturnValue().Set(
2423       function.As<Function>()->Call(args.This(), 0, NULL));
2424 }
2425
2426
2427 THREADED_TEST(DeepCrossLanguageRecursion) {
2428   v8::HandleScope scope(CcTest::isolate());
2429   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2430   global->Set(v8_str("callScriptRecursively"),
2431               v8::FunctionTemplate::New(CallScriptRecursivelyCall));
2432   global->Set(v8_str("callFunctionRecursively"),
2433               v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
2434   LocalContext env(NULL, global);
2435
2436   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2437   call_recursively_script = v8_compile("callScriptRecursively()");
2438   call_recursively_script->Run();
2439   call_recursively_script = v8::Handle<Script>();
2440
2441   env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2442   Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2443 }
2444
2445
2446 static void ThrowingPropertyHandlerGet(
2447     Local<String> key,
2448     const v8::PropertyCallbackInfo<v8::Value>& info) {
2449   ApiTestFuzzer::Fuzz();
2450   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2451 }
2452
2453
2454 static void ThrowingPropertyHandlerSet(
2455     Local<String> key,
2456     Local<Value>,
2457     const v8::PropertyCallbackInfo<v8::Value>& info) {
2458   info.GetIsolate()->ThrowException(key);
2459   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2460 }
2461
2462
2463 THREADED_TEST(CallbackExceptionRegression) {
2464   v8::HandleScope scope(CcTest::isolate());
2465   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2466   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2467                                ThrowingPropertyHandlerSet);
2468   LocalContext env;
2469   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2470   v8::Handle<Value> otto = Script::Compile(v8_str(
2471       "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2472   CHECK_EQ(v8_str("otto"), otto);
2473   v8::Handle<Value> netto = Script::Compile(v8_str(
2474       "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2475   CHECK_EQ(v8_str("netto"), netto);
2476 }
2477
2478
2479 THREADED_TEST(FunctionPrototype) {
2480   v8::HandleScope scope(CcTest::isolate());
2481   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2482   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2483   LocalContext env;
2484   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2485   Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2486   CHECK_EQ(script->Run()->Int32Value(), 321);
2487 }
2488
2489
2490 THREADED_TEST(InternalFields) {
2491   LocalContext env;
2492   v8::HandleScope scope(env->GetIsolate());
2493
2494   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2495   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2496   instance_templ->SetInternalFieldCount(1);
2497   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2498   CHECK_EQ(1, obj->InternalFieldCount());
2499   CHECK(obj->GetInternalField(0)->IsUndefined());
2500   obj->SetInternalField(0, v8_num(17));
2501   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2502 }
2503
2504
2505 THREADED_TEST(GlobalObjectInternalFields) {
2506   v8::HandleScope scope(CcTest::isolate());
2507   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2508   global_template->SetInternalFieldCount(1);
2509   LocalContext env(NULL, global_template);
2510   v8::Handle<v8::Object> global_proxy = env->Global();
2511   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2512   CHECK_EQ(1, global->InternalFieldCount());
2513   CHECK(global->GetInternalField(0)->IsUndefined());
2514   global->SetInternalField(0, v8_num(17));
2515   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2516 }
2517
2518
2519 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2520   LocalContext env;
2521   v8::HandleScope scope(CcTest::isolate());
2522
2523   v8::Local<v8::Object> global = env->Global();
2524   global->Set(0, v8::String::New("value"));
2525   CHECK(global->HasRealIndexedProperty(0));
2526 }
2527
2528
2529 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2530                                                void* value) {
2531   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2532   obj->SetAlignedPointerInInternalField(0, value);
2533   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2534   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2535 }
2536
2537
2538 THREADED_TEST(InternalFieldsAlignedPointers) {
2539   LocalContext env;
2540   v8::HandleScope scope(env->GetIsolate());
2541
2542   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2543   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2544   instance_templ->SetInternalFieldCount(1);
2545   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2546   CHECK_EQ(1, obj->InternalFieldCount());
2547
2548   CheckAlignedPointerInInternalField(obj, NULL);
2549
2550   int* heap_allocated = new int[100];
2551   CheckAlignedPointerInInternalField(obj, heap_allocated);
2552   delete[] heap_allocated;
2553
2554   int stack_allocated[100];
2555   CheckAlignedPointerInInternalField(obj, stack_allocated);
2556
2557   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2558   CheckAlignedPointerInInternalField(obj, huge);
2559 }
2560
2561
2562 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2563                                               int index,
2564                                               void* value) {
2565   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2566   (*env)->SetAlignedPointerInEmbedderData(index, value);
2567   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2568   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2569 }
2570
2571
2572 static void* AlignedTestPointer(int i) {
2573   return reinterpret_cast<void*>(i * 1234);
2574 }
2575
2576
2577 THREADED_TEST(EmbedderDataAlignedPointers) {
2578   LocalContext env;
2579   v8::HandleScope scope(env->GetIsolate());
2580
2581   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2582
2583   int* heap_allocated = new int[100];
2584   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2585   delete[] heap_allocated;
2586
2587   int stack_allocated[100];
2588   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2589
2590   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2591   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2592
2593   // Test growing of the embedder data's backing store.
2594   for (int i = 0; i < 100; i++) {
2595     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2596   }
2597   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2598   for (int i = 0; i < 100; i++) {
2599     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2600   }
2601 }
2602
2603
2604 static void CheckEmbedderData(LocalContext* env,
2605                               int index,
2606                               v8::Handle<Value> data) {
2607   (*env)->SetEmbedderData(index, data);
2608   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2609 }
2610
2611
2612 THREADED_TEST(EmbedderData) {
2613   LocalContext env;
2614   v8::HandleScope scope(env->GetIsolate());
2615
2616   CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2617   CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2618   CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2619   CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2620 }
2621
2622
2623 THREADED_TEST(IdentityHash) {
2624   LocalContext env;
2625   v8::HandleScope scope(env->GetIsolate());
2626
2627   // Ensure that the test starts with an fresh heap to test whether the hash
2628   // code is based on the address.
2629   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2630   Local<v8::Object> obj = v8::Object::New();
2631   int hash = obj->GetIdentityHash();
2632   int hash1 = obj->GetIdentityHash();
2633   CHECK_EQ(hash, hash1);
2634   int hash2 = v8::Object::New()->GetIdentityHash();
2635   // Since the identity hash is essentially a random number two consecutive
2636   // objects should not be assigned the same hash code. If the test below fails
2637   // the random number generator should be evaluated.
2638   CHECK_NE(hash, hash2);
2639   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2640   int hash3 = v8::Object::New()->GetIdentityHash();
2641   // Make sure that the identity hash is not based on the initial address of
2642   // the object alone. If the test below fails the random number generator
2643   // should be evaluated.
2644   CHECK_NE(hash, hash3);
2645   int hash4 = obj->GetIdentityHash();
2646   CHECK_EQ(hash, hash4);
2647
2648   // Check identity hashes behaviour in the presence of JS accessors.
2649   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2650   {
2651     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2652     Local<v8::Object> o1 = v8::Object::New();
2653     Local<v8::Object> o2 = v8::Object::New();
2654     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2655   }
2656   {
2657     CompileRun(
2658         "function cnst() { return 42; };\n"
2659         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2660     Local<v8::Object> o1 = v8::Object::New();
2661     Local<v8::Object> o2 = v8::Object::New();
2662     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2663   }
2664 }
2665
2666
2667 THREADED_TEST(SymbolProperties) {
2668   i::FLAG_harmony_symbols = true;
2669
2670   LocalContext env;
2671   v8::Isolate* isolate = env->GetIsolate();
2672   v8::HandleScope scope(isolate);
2673
2674   v8::Local<v8::Object> obj = v8::Object::New();
2675   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2676   v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2677
2678   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2679
2680   // Check basic symbol functionality.
2681   CHECK(sym1->IsSymbol());
2682   CHECK(sym2->IsSymbol());
2683   CHECK(!obj->IsSymbol());
2684
2685   CHECK(sym1->Equals(sym1));
2686   CHECK(sym2->Equals(sym2));
2687   CHECK(!sym1->Equals(sym2));
2688   CHECK(!sym2->Equals(sym1));
2689   CHECK(sym1->StrictEquals(sym1));
2690   CHECK(sym2->StrictEquals(sym2));
2691   CHECK(!sym1->StrictEquals(sym2));
2692   CHECK(!sym2->StrictEquals(sym1));
2693
2694   CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
2695
2696   v8::Local<v8::Value> sym_val = sym2;
2697   CHECK(sym_val->IsSymbol());
2698   CHECK(sym_val->Equals(sym2));
2699   CHECK(sym_val->StrictEquals(sym2));
2700   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2701
2702   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2703   CHECK(sym_obj->IsSymbolObject());
2704   CHECK(!sym2->IsSymbolObject());
2705   CHECK(!obj->IsSymbolObject());
2706   CHECK(sym_obj->Equals(sym2));
2707   CHECK(!sym_obj->StrictEquals(sym2));
2708   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2709   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2710
2711   // Make sure delete of a non-existent symbol property works.
2712   CHECK(obj->Delete(sym1));
2713   CHECK(!obj->Has(sym1));
2714
2715   CHECK(obj->Set(sym1, v8::Integer::New(1503)));
2716   CHECK(obj->Has(sym1));
2717   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2718   CHECK(obj->Set(sym1, v8::Integer::New(2002)));
2719   CHECK(obj->Has(sym1));
2720   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2721   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2722
2723   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2724   int num_props = obj->GetPropertyNames()->Length();
2725   CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
2726   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2727   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2728
2729   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2730
2731   // Add another property and delete it afterwards to force the object in
2732   // slow case.
2733   CHECK(obj->Set(sym2, v8::Integer::New(2008)));
2734   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2735   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2736   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2737   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2738
2739   CHECK(obj->Has(sym1));
2740   CHECK(obj->Has(sym2));
2741   CHECK(obj->Delete(sym2));
2742   CHECK(obj->Has(sym1));
2743   CHECK(!obj->Has(sym2));
2744   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2745   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2746 }
2747
2748
2749 class ScopedArrayBufferContents {
2750  public:
2751   explicit ScopedArrayBufferContents(
2752       const v8::ArrayBuffer::Contents& contents)
2753     : contents_(contents) {}
2754   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2755   void* Data() const { return contents_.Data(); }
2756   size_t ByteLength() const { return contents_.ByteLength(); }
2757  private:
2758   const v8::ArrayBuffer::Contents contents_;
2759 };
2760
2761 template <typename T>
2762 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2763   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2764   for (int i = 0; i < value->InternalFieldCount(); i++) {
2765     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2766   }
2767 }
2768
2769
2770 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2771   LocalContext env;
2772   v8::Isolate* isolate = env->GetIsolate();
2773   v8::HandleScope handle_scope(isolate);
2774
2775   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
2776   CheckInternalFieldsAreZero(ab);
2777   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2778   CHECK(!ab->IsExternal());
2779   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2780
2781   ScopedArrayBufferContents ab_contents(ab->Externalize());
2782   CHECK(ab->IsExternal());
2783
2784   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2785   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2786   ASSERT(data != NULL);
2787   env->Global()->Set(v8_str("ab"), ab);
2788
2789   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2790   CHECK_EQ(1024, result->Int32Value());
2791
2792   result = CompileRun("var u8 = new Uint8Array(ab);"
2793                       "u8[0] = 0xFF;"
2794                       "u8[1] = 0xAA;"
2795                       "u8.length");
2796   CHECK_EQ(1024, result->Int32Value());
2797   CHECK_EQ(0xFF, data[0]);
2798   CHECK_EQ(0xAA, data[1]);
2799   data[0] = 0xCC;
2800   data[1] = 0x11;
2801   result = CompileRun("u8[0] + u8[1]");
2802   CHECK_EQ(0xDD, result->Int32Value());
2803 }
2804
2805
2806 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2807   LocalContext env;
2808   v8::Isolate* isolate = env->GetIsolate();
2809   v8::HandleScope handle_scope(isolate);
2810
2811
2812   v8::Local<v8::Value> result =
2813       CompileRun("var ab1 = new ArrayBuffer(2);"
2814                  "var u8_a = new Uint8Array(ab1);"
2815                  "u8_a[0] = 0xAA;"
2816                  "u8_a[1] = 0xFF; u8_a.buffer");
2817   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2818   CheckInternalFieldsAreZero(ab1);
2819   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2820   CHECK(!ab1->IsExternal());
2821   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2822   CHECK(ab1->IsExternal());
2823
2824   result = CompileRun("ab1.byteLength");
2825   CHECK_EQ(2, result->Int32Value());
2826   result = CompileRun("u8_a[0]");
2827   CHECK_EQ(0xAA, result->Int32Value());
2828   result = CompileRun("u8_a[1]");
2829   CHECK_EQ(0xFF, result->Int32Value());
2830   result = CompileRun("var u8_b = new Uint8Array(ab1);"
2831                       "u8_b[0] = 0xBB;"
2832                       "u8_a[0]");
2833   CHECK_EQ(0xBB, result->Int32Value());
2834   result = CompileRun("u8_b[1]");
2835   CHECK_EQ(0xFF, result->Int32Value());
2836
2837   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2838   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2839   CHECK_EQ(0xBB, ab1_data[0]);
2840   CHECK_EQ(0xFF, ab1_data[1]);
2841   ab1_data[0] = 0xCC;
2842   ab1_data[1] = 0x11;
2843   result = CompileRun("u8_a[0] + u8_a[1]");
2844   CHECK_EQ(0xDD, result->Int32Value());
2845 }
2846
2847
2848 THREADED_TEST(ArrayBuffer_External) {
2849   LocalContext env;
2850   v8::Isolate* isolate = env->GetIsolate();
2851   v8::HandleScope handle_scope(isolate);
2852
2853   i::ScopedVector<uint8_t> my_data(100);
2854   memset(my_data.start(), 0, 100);
2855   Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100);
2856   CheckInternalFieldsAreZero(ab3);
2857   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2858   CHECK(ab3->IsExternal());
2859
2860   env->Global()->Set(v8_str("ab3"), ab3);
2861
2862   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2863   CHECK_EQ(100, result->Int32Value());
2864
2865   result = CompileRun("var u8_b = new Uint8Array(ab3);"
2866                       "u8_b[0] = 0xBB;"
2867                       "u8_b[1] = 0xCC;"
2868                       "u8_b.length");
2869   CHECK_EQ(100, result->Int32Value());
2870   CHECK_EQ(0xBB, my_data[0]);
2871   CHECK_EQ(0xCC, my_data[1]);
2872   my_data[0] = 0xCC;
2873   my_data[1] = 0x11;
2874   result = CompileRun("u8_b[0] + u8_b[1]");
2875   CHECK_EQ(0xDD, result->Int32Value());
2876 }
2877
2878
2879 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2880   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2881   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2882 }
2883
2884
2885 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2886   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2887   CHECK_EQ(0, static_cast<int>(ta->Length()));
2888   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2889 }
2890
2891
2892 static void CheckIsTypedArrayVarNeutered(const char* name) {
2893   i::ScopedVector<char> source(1024);
2894   i::OS::SNPrintF(source,
2895       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2896       name, name, name);
2897   CHECK(CompileRun(source.start())->IsTrue());
2898   v8::Handle<v8::TypedArray> ta =
2899     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2900   CheckIsNeutered(ta);
2901 }
2902
2903
2904 template <typename TypedArray, int kElementSize>
2905 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2906                                          int byteOffset,
2907                                          int length) {
2908   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2909   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2910   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2911   CHECK_EQ(length, static_cast<int>(ta->Length()));
2912   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2913   return ta;
2914 }
2915
2916
2917 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2918   LocalContext env;
2919   v8::Isolate* isolate = env->GetIsolate();
2920   v8::HandleScope handle_scope(isolate);
2921
2922   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(1024);
2923
2924   v8::Handle<v8::Uint8Array> u8a =
2925     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2926   v8::Handle<v8::Uint8ClampedArray> u8c =
2927     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2928   v8::Handle<v8::Int8Array> i8a =
2929     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2930
2931   v8::Handle<v8::Uint16Array> u16a =
2932     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2933   v8::Handle<v8::Int16Array> i16a =
2934     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2935
2936   v8::Handle<v8::Uint32Array> u32a =
2937     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2938   v8::Handle<v8::Int32Array> i32a =
2939     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2940
2941   v8::Handle<v8::Float32Array> f32a =
2942     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2943   v8::Handle<v8::Float64Array> f64a =
2944     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2945
2946   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2947   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2948   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2949   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2950
2951   ScopedArrayBufferContents contents(buffer->Externalize());
2952   buffer->Neuter();
2953   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2954   CheckIsNeutered(u8a);
2955   CheckIsNeutered(u8c);
2956   CheckIsNeutered(i8a);
2957   CheckIsNeutered(u16a);
2958   CheckIsNeutered(i16a);
2959   CheckIsNeutered(u32a);
2960   CheckIsNeutered(i32a);
2961   CheckIsNeutered(f32a);
2962   CheckIsNeutered(f64a);
2963   CheckDataViewIsNeutered(dv);
2964 }
2965
2966
2967 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2968   LocalContext env;
2969   v8::Isolate* isolate = env->GetIsolate();
2970   v8::HandleScope handle_scope(isolate);
2971
2972   CompileRun(
2973       "var ab = new ArrayBuffer(1024);"
2974       "var u8a = new Uint8Array(ab, 1, 1023);"
2975       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2976       "var i8a = new Int8Array(ab, 1, 1023);"
2977       "var u16a = new Uint16Array(ab, 2, 511);"
2978       "var i16a = new Int16Array(ab, 2, 511);"
2979       "var u32a = new Uint32Array(ab, 4, 255);"
2980       "var i32a = new Int32Array(ab, 4, 255);"
2981       "var f32a = new Float32Array(ab, 4, 255);"
2982       "var f64a = new Float64Array(ab, 8, 127);"
2983       "var dv = new DataView(ab, 1, 1023);");
2984
2985   v8::Handle<v8::ArrayBuffer> ab =
2986       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2987
2988   v8::Handle<v8::DataView> dv =
2989     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2990
2991   ScopedArrayBufferContents contents(ab->Externalize());
2992   ab->Neuter();
2993   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2994   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2995
2996   CheckIsTypedArrayVarNeutered("u8a");
2997   CheckIsTypedArrayVarNeutered("u8c");
2998   CheckIsTypedArrayVarNeutered("i8a");
2999   CheckIsTypedArrayVarNeutered("u16a");
3000   CheckIsTypedArrayVarNeutered("i16a");
3001   CheckIsTypedArrayVarNeutered("u32a");
3002   CheckIsTypedArrayVarNeutered("i32a");
3003   CheckIsTypedArrayVarNeutered("f32a");
3004   CheckIsTypedArrayVarNeutered("f64a");
3005
3006   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3007   CheckDataViewIsNeutered(dv);
3008 }
3009
3010
3011
3012 THREADED_TEST(HiddenProperties) {
3013   LocalContext env;
3014   v8::HandleScope scope(env->GetIsolate());
3015
3016   v8::Local<v8::Object> obj = v8::Object::New();
3017   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3018   v8::Local<v8::String> empty = v8_str("");
3019   v8::Local<v8::String> prop_name = v8_str("prop_name");
3020
3021   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3022
3023   // Make sure delete of a non-existent hidden value works
3024   CHECK(obj->DeleteHiddenValue(key));
3025
3026   CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
3027   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3028   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
3029   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3030
3031   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3032
3033   // Make sure we do not find the hidden property.
3034   CHECK(!obj->Has(empty));
3035   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3036   CHECK(obj->Get(empty)->IsUndefined());
3037   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3038   CHECK(obj->Set(empty, v8::Integer::New(2003)));
3039   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3040   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3041
3042   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3043
3044   // Add another property and delete it afterwards to force the object in
3045   // slow case.
3046   CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
3047   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3048   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3049   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3050   CHECK(obj->Delete(prop_name));
3051   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3052
3053   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3054
3055   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3056   CHECK(obj->GetHiddenValue(key).IsEmpty());
3057
3058   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
3059   CHECK(obj->DeleteHiddenValue(key));
3060   CHECK(obj->GetHiddenValue(key).IsEmpty());
3061 }
3062
3063
3064 THREADED_TEST(Regress97784) {
3065   // Regression test for crbug.com/97784
3066   // Messing with the Object.prototype should not have effect on
3067   // hidden properties.
3068   LocalContext env;
3069   v8::HandleScope scope(env->GetIsolate());
3070
3071   v8::Local<v8::Object> obj = v8::Object::New();
3072   v8::Local<v8::String> key = v8_str("hidden");
3073
3074   CompileRun(
3075       "set_called = false;"
3076       "Object.defineProperty("
3077       "    Object.prototype,"
3078       "    'hidden',"
3079       "    {get: function() { return 45; },"
3080       "     set: function() { set_called = true; }})");
3081
3082   CHECK(obj->GetHiddenValue(key).IsEmpty());
3083   // Make sure that the getter and setter from Object.prototype is not invoked.
3084   // If it did we would have full access to the hidden properties in
3085   // the accessor.
3086   CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
3087   ExpectFalse("set_called");
3088   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3089 }
3090
3091
3092 static bool interceptor_for_hidden_properties_called;
3093 static void InterceptorForHiddenProperties(
3094     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3095   interceptor_for_hidden_properties_called = true;
3096 }
3097
3098
3099 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3100   LocalContext context;
3101   v8::HandleScope scope(context->GetIsolate());
3102
3103   interceptor_for_hidden_properties_called = false;
3104
3105   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3106
3107   // Associate an interceptor with an object and start setting hidden values.
3108   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
3109   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3110   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3111   Local<v8::Function> function = fun_templ->GetFunction();
3112   Local<v8::Object> obj = function->NewInstance();
3113   CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
3114   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3115   CHECK(!interceptor_for_hidden_properties_called);
3116 }
3117
3118
3119 THREADED_TEST(External) {
3120   v8::HandleScope scope(CcTest::isolate());
3121   int x = 3;
3122   Local<v8::External> ext = v8::External::New(&x);
3123   LocalContext env;
3124   env->Global()->Set(v8_str("ext"), ext);
3125   Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3126   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3127   int* ptr = static_cast<int*>(reext->Value());
3128   CHECK_EQ(x, 3);
3129   *ptr = 10;
3130   CHECK_EQ(x, 10);
3131
3132   // Make sure unaligned pointers are wrapped properly.
3133   char* data = i::StrDup("0123456789");
3134   Local<v8::Value> zero = v8::External::New(&data[0]);
3135   Local<v8::Value> one = v8::External::New(&data[1]);
3136   Local<v8::Value> two = v8::External::New(&data[2]);
3137   Local<v8::Value> three = v8::External::New(&data[3]);
3138
3139   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3140   CHECK_EQ('0', *char_ptr);
3141   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3142   CHECK_EQ('1', *char_ptr);
3143   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3144   CHECK_EQ('2', *char_ptr);
3145   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3146   CHECK_EQ('3', *char_ptr);
3147   i::DeleteArray(data);
3148 }
3149
3150
3151 THREADED_TEST(GlobalHandle) {
3152   v8::Isolate* isolate = CcTest::isolate();
3153   v8::Persistent<String> global;
3154   {
3155     v8::HandleScope scope(isolate);
3156     global.Reset(isolate, v8_str("str"));
3157   }
3158   {
3159     v8::HandleScope scope(isolate);
3160     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3161   }
3162   global.Dispose();
3163   global.Clear();
3164   {
3165     v8::HandleScope scope(isolate);
3166     global.Reset(isolate, v8_str("str"));
3167   }
3168   {
3169     v8::HandleScope scope(isolate);
3170     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3171   }
3172   global.Dispose();
3173 }
3174
3175
3176 THREADED_TEST(ResettingGlobalHandle) {
3177   v8::Isolate* isolate = CcTest::isolate();
3178   v8::Persistent<String> global;
3179   {
3180     v8::HandleScope scope(isolate);
3181     global.Reset(isolate, v8_str("str"));
3182   }
3183   v8::internal::GlobalHandles* global_handles =
3184       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3185   int initial_handle_count = global_handles->global_handles_count();
3186   {
3187     v8::HandleScope scope(isolate);
3188     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3189   }
3190   {
3191     v8::HandleScope scope(isolate);
3192     global.Reset(isolate, v8_str("longer"));
3193   }
3194   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3195   {
3196     v8::HandleScope scope(isolate);
3197     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3198   }
3199   global.Dispose();
3200   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3201 }
3202
3203
3204 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3205   v8::Isolate* isolate = CcTest::isolate();
3206   v8::Persistent<String> global;
3207   {
3208     v8::HandleScope scope(isolate);
3209     global.Reset(isolate, v8_str("str"));
3210   }
3211   v8::internal::GlobalHandles* global_handles =
3212       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3213   int initial_handle_count = global_handles->global_handles_count();
3214   {
3215     v8::HandleScope scope(isolate);
3216     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3217   }
3218   {
3219     v8::HandleScope scope(isolate);
3220     Local<String> empty;
3221     global.Reset(isolate, empty);
3222   }
3223   CHECK(global.IsEmpty());
3224   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3225 }
3226
3227
3228 THREADED_TEST(ClearAndLeakGlobal) {
3229   v8::Isolate* isolate = CcTest::isolate();
3230   v8::internal::GlobalHandles* global_handles = NULL;
3231   int initial_handle_count = 0;
3232   v8::Persistent<String> global;
3233   {
3234     v8::HandleScope scope(isolate);
3235     Local<String> str = v8_str("str");
3236     global_handles =
3237         reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3238     initial_handle_count = global_handles->global_handles_count();
3239     global.Reset(isolate, str);
3240   }
3241   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3242   String* str = global.ClearAndLeak();
3243   CHECK(global.IsEmpty());
3244   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3245   global_handles->Destroy(reinterpret_cast<i::Object**>(str));
3246   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3247 }
3248
3249
3250 THREADED_TEST(GlobalHandleUpcast) {
3251   v8::Isolate* isolate = CcTest::isolate();
3252   v8::HandleScope scope(isolate);
3253   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3254   v8::Persistent<String> global_string(isolate, local);
3255   v8::Persistent<Value>& global_value =
3256       v8::Persistent<Value>::Cast(global_string);
3257   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3258   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3259   global_string.Dispose();
3260 }
3261
3262
3263 THREADED_TEST(HandleEquality) {
3264   v8::Isolate* isolate = CcTest::isolate();
3265   v8::Persistent<String> global1;
3266   v8::Persistent<String> global2;
3267   {
3268     v8::HandleScope scope(isolate);
3269     global1.Reset(isolate, v8_str("str"));
3270     global2.Reset(isolate, v8_str("str2"));
3271   }
3272   CHECK_EQ(global1 == global1, true);
3273   CHECK_EQ(global1 != global1, false);
3274   {
3275     v8::HandleScope scope(isolate);
3276     Local<String> local1 = Local<String>::New(isolate, global1);
3277     Local<String> local2 = Local<String>::New(isolate, global2);
3278
3279     CHECK_EQ(global1 == local1, true);
3280     CHECK_EQ(global1 != local1, false);
3281     CHECK_EQ(local1 == global1, true);
3282     CHECK_EQ(local1 != global1, false);
3283
3284     CHECK_EQ(global1 == local2, false);
3285     CHECK_EQ(global1 != local2, true);
3286     CHECK_EQ(local2 == global1, false);
3287     CHECK_EQ(local2 != global1, true);
3288
3289     CHECK_EQ(local1 == local2, false);
3290     CHECK_EQ(local1 != local2, true);
3291
3292     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3293     CHECK_EQ(local1 == anotherLocal1, true);
3294     CHECK_EQ(local1 != anotherLocal1, false);
3295   }
3296   global1.Dispose();
3297   global2.Dispose();
3298 }
3299
3300
3301 THREADED_TEST(LocalHandle) {
3302   v8::HandleScope scope(CcTest::isolate());
3303   v8::Local<String> local =
3304       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3305   CHECK_EQ(local->Length(), 3);
3306 }
3307
3308
3309 class WeakCallCounter {
3310  public:
3311   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3312   int id() { return id_; }
3313   void increment() { number_of_weak_calls_++; }
3314   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3315  private:
3316   int id_;
3317   int number_of_weak_calls_;
3318 };
3319
3320
3321 template<typename T>
3322 static void WeakPointerCallback(v8::Isolate* isolate,
3323                                 Persistent<T>* handle,
3324                                 WeakCallCounter* counter) {
3325   CHECK_EQ(1234, counter->id());
3326   counter->increment();
3327   handle->Dispose();
3328 }
3329
3330
3331 template<typename T>
3332 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3333   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3334 }
3335
3336
3337 THREADED_TEST(ApiObjectGroups) {
3338   LocalContext env;
3339   v8::Isolate* iso = env->GetIsolate();
3340   HandleScope scope(iso);
3341
3342   Persistent<Value> g1s1;
3343   Persistent<Value> g1s2;
3344   Persistent<Value> g1c1;
3345   Persistent<Value> g2s1;
3346   Persistent<Value> g2s2;
3347   Persistent<Value> g2c1;
3348
3349   WeakCallCounter counter(1234);
3350
3351   {
3352     HandleScope scope(iso);
3353     g1s1.Reset(iso, Object::New());
3354     g1s2.Reset(iso, Object::New());
3355     g1c1.Reset(iso, Object::New());
3356     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3357     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3358     g1c1.MakeWeak(&counter, &WeakPointerCallback);
3359
3360     g2s1.Reset(iso, Object::New());
3361     g2s2.Reset(iso, Object::New());
3362     g2c1.Reset(iso, Object::New());
3363     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3364     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3365     g2c1.MakeWeak(&counter, &WeakPointerCallback);
3366   }
3367
3368   Persistent<Value> root(iso, g1s1);  // make a root.
3369
3370   // Connect group 1 and 2, make a cycle.
3371   {
3372     HandleScope scope(iso);
3373     CHECK(Local<Object>::New(iso, g1s2.As<Object>())->
3374             Set(0, Local<Value>::New(iso, g2s2)));
3375     CHECK(Local<Object>::New(iso, g2s1.As<Object>())->
3376             Set(0, Local<Value>::New(iso, g1s1)));
3377   }
3378
3379   {
3380     UniqueId id1 = MakeUniqueId(g1s1);
3381     UniqueId id2 = MakeUniqueId(g2s2);
3382     iso->SetObjectGroupId(g1s1, id1);
3383     iso->SetObjectGroupId(g1s2, id1);
3384     iso->SetReferenceFromGroup(id1, g1c1);
3385     iso->SetObjectGroupId(g2s1, id2);
3386     iso->SetObjectGroupId(g2s2, id2);
3387     iso->SetReferenceFromGroup(id2, g2c1);
3388   }
3389   // Do a single full GC, ensure incremental marking is stopped.
3390   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3391       iso)->heap();
3392   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3393
3394   // All object should be alive.
3395   CHECK_EQ(0, counter.NumberOfWeakCalls());
3396
3397   // Weaken the root.
3398   root.MakeWeak(&counter, &WeakPointerCallback);
3399   // But make children strong roots---all the objects (except for children)
3400   // should be collectable now.
3401   g1c1.ClearWeak();
3402   g2c1.ClearWeak();
3403
3404   // Groups are deleted, rebuild groups.
3405   {
3406     UniqueId id1 = MakeUniqueId(g1s1);
3407     UniqueId id2 = MakeUniqueId(g2s2);
3408     iso->SetObjectGroupId(g1s1, id1);
3409     iso->SetObjectGroupId(g1s2, id1);
3410     iso->SetReferenceFromGroup(id1, g1c1);
3411     iso->SetObjectGroupId(g2s1, id2);
3412     iso->SetObjectGroupId(g2s2, id2);
3413     iso->SetReferenceFromGroup(id2, g2c1);
3414   }
3415
3416   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3417
3418   // All objects should be gone. 5 global handles in total.
3419   CHECK_EQ(5, counter.NumberOfWeakCalls());
3420
3421   // And now make children weak again and collect them.
3422   g1c1.MakeWeak(&counter, &WeakPointerCallback);
3423   g2c1.MakeWeak(&counter, &WeakPointerCallback);
3424
3425   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3426   CHECK_EQ(7, counter.NumberOfWeakCalls());
3427 }
3428
3429
3430 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3431   LocalContext env;
3432   v8::Isolate* iso = env->GetIsolate();
3433   HandleScope scope(iso);
3434
3435   Persistent<Object> g1s1;
3436   Persistent<String> g1s2;
3437   Persistent<String> g1c1;
3438   Persistent<Object> g2s1;
3439   Persistent<String> g2s2;
3440   Persistent<String> g2c1;
3441
3442   WeakCallCounter counter(1234);
3443
3444   {
3445     HandleScope scope(iso);
3446     g1s1.Reset(iso, Object::New());
3447     g1s2.Reset(iso, String::New("foo1"));
3448     g1c1.Reset(iso, String::New("foo2"));
3449     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3450     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3451     g1c1.MakeWeak(&counter, &WeakPointerCallback);
3452
3453     g2s1.Reset(iso, Object::New());
3454     g2s2.Reset(iso, String::New("foo3"));
3455     g2c1.Reset(iso, String::New("foo4"));
3456     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3457     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3458     g2c1.MakeWeak(&counter, &WeakPointerCallback);
3459   }
3460
3461   Persistent<Value> root(iso, g1s1);  // make a root.
3462
3463   // Connect group 1 and 2, make a cycle.
3464   {
3465     HandleScope scope(iso);
3466     CHECK(Local<Object>::New(iso, g1s1)->Set(0, Local<Object>::New(iso, g2s1)));
3467     CHECK(Local<Object>::New(iso, g2s1)->Set(0, Local<Object>::New(iso, g1s1)));
3468   }
3469
3470   {
3471     UniqueId id1 = MakeUniqueId(g1s1);
3472     UniqueId id2 = MakeUniqueId(g2s2);
3473     iso->SetObjectGroupId(g1s1, id1);
3474     iso->SetObjectGroupId(g1s2, id1);
3475     iso->SetReference(g1s1, g1c1);
3476     iso->SetObjectGroupId(g2s1, id2);
3477     iso->SetObjectGroupId(g2s2, id2);
3478     iso->SetReferenceFromGroup(id2, g2c1);
3479   }
3480   // Do a single full GC, ensure incremental marking is stopped.
3481   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3482       iso)->heap();
3483   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3484
3485   // All object should be alive.
3486   CHECK_EQ(0, counter.NumberOfWeakCalls());
3487
3488   // Weaken the root.
3489   root.MakeWeak(&counter, &WeakPointerCallback);
3490   // But make children strong roots---all the objects (except for children)
3491   // should be collectable now.
3492   g1c1.ClearWeak();
3493   g2c1.ClearWeak();
3494
3495   // Groups are deleted, rebuild groups.
3496   {
3497     UniqueId id1 = MakeUniqueId(g1s1);
3498     UniqueId id2 = MakeUniqueId(g2s2);
3499     iso->SetObjectGroupId(g1s1, id1);
3500     iso->SetObjectGroupId(g1s2, id1);
3501     iso->SetReference(g1s1, g1c1);
3502     iso->SetObjectGroupId(g2s1, id2);
3503     iso->SetObjectGroupId(g2s2, id2);
3504     iso->SetReferenceFromGroup(id2, g2c1);
3505   }
3506
3507   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3508
3509   // All objects should be gone. 5 global handles in total.
3510   CHECK_EQ(5, counter.NumberOfWeakCalls());
3511
3512   // And now make children weak again and collect them.
3513   g1c1.MakeWeak(&counter, &WeakPointerCallback);
3514   g2c1.MakeWeak(&counter, &WeakPointerCallback);
3515
3516   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3517   CHECK_EQ(7, counter.NumberOfWeakCalls());
3518 }
3519
3520
3521 THREADED_TEST(ApiObjectGroupsCycle) {
3522   LocalContext env;
3523   v8::Isolate* iso = env->GetIsolate();
3524   HandleScope scope(iso);
3525
3526   WeakCallCounter counter(1234);
3527
3528   Persistent<Value> g1s1;
3529   Persistent<Value> g1s2;
3530   Persistent<Value> g2s1;
3531   Persistent<Value> g2s2;
3532   Persistent<Value> g3s1;
3533   Persistent<Value> g3s2;
3534   Persistent<Value> g4s1;
3535   Persistent<Value> g4s2;
3536
3537   {
3538     HandleScope scope(iso);
3539     g1s1.Reset(iso, Object::New());
3540     g1s2.Reset(iso, Object::New());
3541     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3542     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3543     CHECK(g1s1.IsWeak());
3544     CHECK(g1s2.IsWeak());
3545
3546     g2s1.Reset(iso, Object::New());
3547     g2s2.Reset(iso, Object::New());
3548     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3549     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3550     CHECK(g2s1.IsWeak());
3551     CHECK(g2s2.IsWeak());
3552
3553     g3s1.Reset(iso, Object::New());
3554     g3s2.Reset(iso, Object::New());
3555     g3s1.MakeWeak(&counter, &WeakPointerCallback);
3556     g3s2.MakeWeak(&counter, &WeakPointerCallback);
3557     CHECK(g3s1.IsWeak());
3558     CHECK(g3s2.IsWeak());
3559
3560     g4s1.Reset(iso, Object::New());
3561     g4s2.Reset(iso, Object::New());
3562     g4s1.MakeWeak(&counter, &WeakPointerCallback);
3563     g4s2.MakeWeak(&counter, &WeakPointerCallback);
3564     CHECK(g4s1.IsWeak());
3565     CHECK(g4s2.IsWeak());
3566   }
3567
3568   Persistent<Value> root(iso, g1s1);  // make a root.
3569
3570   // Connect groups.  We're building the following cycle:
3571   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3572   // groups.
3573   {
3574     UniqueId id1 = MakeUniqueId(g1s1);
3575     UniqueId id2 = MakeUniqueId(g2s1);
3576     UniqueId id3 = MakeUniqueId(g3s1);
3577     UniqueId id4 = MakeUniqueId(g4s1);
3578     iso->SetObjectGroupId(g1s1, id1);
3579     iso->SetObjectGroupId(g1s2, id1);
3580     iso->SetReferenceFromGroup(id1, g2s1);
3581     iso->SetObjectGroupId(g2s1, id2);
3582     iso->SetObjectGroupId(g2s2, id2);
3583     iso->SetReferenceFromGroup(id2, g3s1);
3584     iso->SetObjectGroupId(g3s1, id3);
3585     iso->SetObjectGroupId(g3s2, id3);
3586     iso->SetReferenceFromGroup(id3, g4s1);
3587     iso->SetObjectGroupId(g4s1, id4);
3588     iso->SetObjectGroupId(g4s2, id4);
3589     iso->SetReferenceFromGroup(id4, g1s1);
3590   }
3591   // Do a single full GC
3592   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3593       iso)->heap();
3594   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3595
3596   // All object should be alive.
3597   CHECK_EQ(0, counter.NumberOfWeakCalls());
3598
3599   // Weaken the root.
3600   root.MakeWeak(&counter, &WeakPointerCallback);
3601
3602   // Groups are deleted, rebuild groups.
3603   {
3604     UniqueId id1 = MakeUniqueId(g1s1);
3605     UniqueId id2 = MakeUniqueId(g2s1);
3606     UniqueId id3 = MakeUniqueId(g3s1);
3607     UniqueId id4 = MakeUniqueId(g4s1);
3608     iso->SetObjectGroupId(g1s1, id1);
3609     iso->SetObjectGroupId(g1s2, id1);
3610     iso->SetReferenceFromGroup(id1, g2s1);
3611     iso->SetObjectGroupId(g2s1, id2);
3612     iso->SetObjectGroupId(g2s2, id2);
3613     iso->SetReferenceFromGroup(id2, g3s1);
3614     iso->SetObjectGroupId(g3s1, id3);
3615     iso->SetObjectGroupId(g3s2, id3);
3616     iso->SetReferenceFromGroup(id3, g4s1);
3617     iso->SetObjectGroupId(g4s1, id4);
3618     iso->SetObjectGroupId(g4s2, id4);
3619     iso->SetReferenceFromGroup(id4, g1s1);
3620   }
3621
3622   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3623
3624   // All objects should be gone. 9 global handles in total.
3625   CHECK_EQ(9, counter.NumberOfWeakCalls());
3626 }
3627
3628
3629 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3630 // on the buildbots, so was made non-threaded for the time being.
3631 TEST(ApiObjectGroupsCycleForScavenger) {
3632   i::FLAG_stress_compaction = false;
3633   i::FLAG_gc_global = false;
3634   LocalContext env;
3635   v8::Isolate* iso = env->GetIsolate();
3636   HandleScope scope(iso);
3637
3638   WeakCallCounter counter(1234);
3639
3640   Persistent<Value> g1s1;
3641   Persistent<Value> g1s2;
3642   Persistent<Value> g2s1;
3643   Persistent<Value> g2s2;
3644   Persistent<Value> g3s1;
3645   Persistent<Value> g3s2;
3646
3647   {
3648     HandleScope scope(iso);
3649     g1s1.Reset(iso, Object::New());
3650     g1s2.Reset(iso, Object::New());
3651     g1s1.MakeWeak(&counter, &WeakPointerCallback);
3652     g1s2.MakeWeak(&counter, &WeakPointerCallback);
3653
3654     g2s1.Reset(iso, Object::New());
3655     g2s2.Reset(iso, Object::New());
3656     g2s1.MakeWeak(&counter, &WeakPointerCallback);
3657     g2s2.MakeWeak(&counter, &WeakPointerCallback);
3658
3659     g3s1.Reset(iso, Object::New());
3660     g3s2.Reset(iso, Object::New());
3661     g3s1.MakeWeak(&counter, &WeakPointerCallback);
3662     g3s2.MakeWeak(&counter, &WeakPointerCallback);
3663   }
3664
3665   // Make a root.
3666   Persistent<Value> root(iso, g1s1);
3667   root.MarkPartiallyDependent();
3668
3669   // Connect groups.  We're building the following cycle:
3670   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3671   // groups.
3672   {
3673     HandleScope handle_scope(iso);
3674     g1s1.MarkPartiallyDependent();
3675     g1s2.MarkPartiallyDependent();
3676     g2s1.MarkPartiallyDependent();
3677     g2s2.MarkPartiallyDependent();
3678     g3s1.MarkPartiallyDependent();
3679     g3s2.MarkPartiallyDependent();
3680     iso->SetObjectGroupId(g1s1, UniqueId(1));
3681     iso->SetObjectGroupId(g1s2, UniqueId(1));
3682     Local<Object>::New(iso, g1s1.As<Object>())->Set(
3683         v8_str("x"), Local<Value>::New(iso, g2s1));
3684     iso->SetObjectGroupId(g2s1, UniqueId(2));
3685     iso->SetObjectGroupId(g2s2, UniqueId(2));
3686     Local<Object>::New(iso, g2s1.As<Object>())->Set(
3687         v8_str("x"), Local<Value>::New(iso, g3s1));
3688     iso->SetObjectGroupId(g3s1, UniqueId(3));
3689     iso->SetObjectGroupId(g3s2, UniqueId(3));
3690     Local<Object>::New(iso, g3s1.As<Object>())->Set(
3691         v8_str("x"), Local<Value>::New(iso, g1s1));
3692   }
3693
3694   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3695       iso)->heap();
3696   heap->CollectGarbage(i::NEW_SPACE);
3697
3698   // All objects should be alive.
3699   CHECK_EQ(0, counter.NumberOfWeakCalls());
3700
3701   // Weaken the root.
3702   root.MakeWeak(&counter, &WeakPointerCallback);
3703   root.MarkPartiallyDependent();
3704
3705   // Groups are deleted, rebuild groups.
3706   {
3707     HandleScope handle_scope(iso);
3708     g1s1.MarkPartiallyDependent();
3709     g1s2.MarkPartiallyDependent();
3710     g2s1.MarkPartiallyDependent();
3711     g2s2.MarkPartiallyDependent();
3712     g3s1.MarkPartiallyDependent();
3713     g3s2.MarkPartiallyDependent();
3714     iso->SetObjectGroupId(g1s1, UniqueId(1));
3715     iso->SetObjectGroupId(g1s2, UniqueId(1));
3716     Local<Object>::New(iso, g1s1.As<Object>())->Set(
3717         v8_str("x"), Local<Value>::New(iso, g2s1));
3718     iso->SetObjectGroupId(g2s1, UniqueId(2));
3719     iso->SetObjectGroupId(g2s2, UniqueId(2));
3720     Local<Object>::New(iso, g2s1.As<Object>())->Set(
3721         v8_str("x"), Local<Value>::New(iso, g3s1));
3722     iso->SetObjectGroupId(g3s1, UniqueId(3));
3723     iso->SetObjectGroupId(g3s2, UniqueId(3));
3724     Local<Object>::New(iso, g3s1.As<Object>())->Set(
3725         v8_str("x"), Local<Value>::New(iso, g1s1));
3726   }
3727
3728   heap->CollectGarbage(i::NEW_SPACE);
3729
3730   // All objects should be gone. 7 global handles in total.
3731   CHECK_EQ(7, counter.NumberOfWeakCalls());
3732 }
3733
3734
3735 THREADED_TEST(ScriptException) {
3736   LocalContext env;
3737   v8::HandleScope scope(env->GetIsolate());
3738   Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3739   v8::TryCatch try_catch;
3740   Local<Value> result = script->Run();
3741   CHECK(result.IsEmpty());
3742   CHECK(try_catch.HasCaught());
3743   String::Utf8Value exception_value(try_catch.Exception());
3744   CHECK_EQ(*exception_value, "panama!");
3745 }
3746
3747
3748 TEST(TryCatchCustomException) {
3749   LocalContext env;
3750   v8::HandleScope scope(env->GetIsolate());
3751   v8::TryCatch try_catch;
3752   CompileRun("function CustomError() { this.a = 'b'; }"
3753              "(function f() { throw new CustomError(); })();");
3754   CHECK(try_catch.HasCaught());
3755   CHECK(try_catch.Exception()->ToObject()->
3756             Get(v8_str("a"))->Equals(v8_str("b")));
3757 }
3758
3759
3760 bool message_received;
3761
3762
3763 static void check_message_0(v8::Handle<v8::Message> message,
3764                             v8::Handle<Value> data) {
3765   CHECK_EQ(5.76, data->NumberValue());
3766   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3767   CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3768   CHECK(!message->IsSharedCrossOrigin());
3769   message_received = true;
3770 }
3771
3772
3773 THREADED_TEST(MessageHandler0) {
3774   message_received = false;
3775   v8::HandleScope scope(CcTest::isolate());
3776   CHECK(!message_received);
3777   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3778   LocalContext context;
3779   v8::ScriptOrigin origin =
3780       v8::ScriptOrigin(v8_str("6.75"));
3781   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3782                                                   &origin);
3783   script->SetData(v8_str("7.56"));
3784   script->Run();
3785   CHECK(message_received);
3786   // clear out the message listener
3787   v8::V8::RemoveMessageListeners(check_message_0);
3788 }
3789
3790
3791 static void check_message_1(v8::Handle<v8::Message> message,
3792                             v8::Handle<Value> data) {
3793   CHECK(data->IsNumber());
3794   CHECK_EQ(1337, data->Int32Value());
3795   CHECK(!message->IsSharedCrossOrigin());
3796   message_received = true;
3797 }
3798
3799
3800 TEST(MessageHandler1) {
3801   message_received = false;
3802   v8::HandleScope scope(CcTest::isolate());
3803   CHECK(!message_received);
3804   v8::V8::AddMessageListener(check_message_1);
3805   LocalContext context;
3806   CompileRun("throw 1337;");
3807   CHECK(message_received);
3808   // clear out the message listener
3809   v8::V8::RemoveMessageListeners(check_message_1);
3810 }
3811
3812
3813 static void check_message_2(v8::Handle<v8::Message> message,
3814                             v8::Handle<Value> data) {
3815   LocalContext context;
3816   CHECK(data->IsObject());
3817   v8::Local<v8::Value> hidden_property =
3818       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
3819   CHECK(v8_str("hidden value")->Equals(hidden_property));
3820   CHECK(!message->IsSharedCrossOrigin());
3821   message_received = true;
3822 }
3823
3824
3825 TEST(MessageHandler2) {
3826   message_received = false;
3827   v8::HandleScope scope(CcTest::isolate());
3828   CHECK(!message_received);
3829   v8::V8::AddMessageListener(check_message_2);
3830   LocalContext context;
3831   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
3832   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
3833                                            v8_str("hidden value"));
3834   context->Global()->Set(v8_str("error"), error);
3835   CompileRun("throw error;");
3836   CHECK(message_received);
3837   // clear out the message listener
3838   v8::V8::RemoveMessageListeners(check_message_2);
3839 }
3840
3841
3842 static void check_message_3(v8::Handle<v8::Message> message,
3843                             v8::Handle<Value> data) {
3844   CHECK(message->IsSharedCrossOrigin());
3845   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3846   message_received = true;
3847 }
3848
3849
3850 TEST(MessageHandler3) {
3851   message_received = false;
3852   v8::Isolate* isolate = CcTest::isolate();
3853   v8::HandleScope scope(isolate);
3854   CHECK(!message_received);
3855   v8::V8::AddMessageListener(check_message_3);
3856   LocalContext context;
3857   v8::ScriptOrigin origin =
3858       v8::ScriptOrigin(v8_str("6.75"),
3859                        v8::Integer::New(1, isolate),
3860                        v8::Integer::New(2, isolate),
3861                        v8::True(isolate));
3862   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3863                                                   &origin);
3864   script->Run();
3865   CHECK(message_received);
3866   // clear out the message listener
3867   v8::V8::RemoveMessageListeners(check_message_3);
3868 }
3869
3870
3871 static void check_message_4(v8::Handle<v8::Message> message,
3872                             v8::Handle<Value> data) {
3873   CHECK(!message->IsSharedCrossOrigin());
3874   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3875   message_received = true;
3876 }
3877
3878
3879 TEST(MessageHandler4) {
3880   message_received = false;
3881   v8::Isolate* isolate = CcTest::isolate();
3882   v8::HandleScope scope(isolate);
3883   CHECK(!message_received);
3884   v8::V8::AddMessageListener(check_message_4);
3885   LocalContext context;
3886   v8::ScriptOrigin origin =
3887       v8::ScriptOrigin(v8_str("6.75"),
3888                        v8::Integer::New(1, isolate),
3889                        v8::Integer::New(2, isolate),
3890                        v8::False(isolate));
3891   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3892                                                   &origin);
3893   script->Run();
3894   CHECK(message_received);
3895   // clear out the message listener
3896   v8::V8::RemoveMessageListeners(check_message_4);
3897 }
3898
3899
3900 static void check_message_5a(v8::Handle<v8::Message> message,
3901                             v8::Handle<Value> data) {
3902   CHECK(message->IsSharedCrossOrigin());
3903   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3904   message_received = true;
3905 }
3906
3907
3908 static void check_message_5b(v8::Handle<v8::Message> message,
3909                             v8::Handle<Value> data) {
3910   CHECK(!message->IsSharedCrossOrigin());
3911   CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3912   message_received = true;
3913 }
3914
3915
3916 TEST(MessageHandler5) {
3917   message_received = false;
3918   v8::Isolate* isolate = CcTest::isolate();
3919   v8::HandleScope scope(isolate);
3920   CHECK(!message_received);
3921   v8::V8::AddMessageListener(check_message_5a);
3922   LocalContext context;
3923   v8::ScriptOrigin origin =
3924       v8::ScriptOrigin(v8_str("6.75"),
3925                        v8::Integer::New(1, isolate),
3926                        v8::Integer::New(2, isolate),
3927                        v8::True(isolate));
3928   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3929                                                   &origin);
3930   script->Run();
3931   CHECK(message_received);
3932   // clear out the message listener
3933   v8::V8::RemoveMessageListeners(check_message_5a);
3934
3935   message_received = false;
3936   v8::V8::AddMessageListener(check_message_5b);
3937   origin =
3938       v8::ScriptOrigin(v8_str("6.75"),
3939                        v8::Integer::New(1, isolate),
3940                        v8::Integer::New(2, isolate),
3941                        v8::False(isolate));
3942   script = Script::Compile(v8_str("throw 'error'"),
3943                            &origin);
3944   script->Run();
3945   CHECK(message_received);
3946   // clear out the message listener
3947   v8::V8::RemoveMessageListeners(check_message_5b);
3948 }
3949
3950
3951 THREADED_TEST(GetSetProperty) {
3952   LocalContext context;
3953   v8::HandleScope scope(context->GetIsolate());
3954   context->Global()->Set(v8_str("foo"), v8_num(14));
3955   context->Global()->Set(v8_str("12"), v8_num(92));
3956   context->Global()->Set(v8::Integer::New(16), v8_num(32));
3957   context->Global()->Set(v8_num(13), v8_num(56));
3958   Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
3959   CHECK_EQ(14, foo->Int32Value());
3960   Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
3961   CHECK_EQ(92, twelve->Int32Value());
3962   Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
3963   CHECK_EQ(32, sixteen->Int32Value());
3964   Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
3965   CHECK_EQ(56, thirteen->Int32Value());
3966   CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
3967   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
3968   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
3969   CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
3970   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
3971   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
3972   CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
3973   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
3974   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
3975 }
3976
3977
3978 THREADED_TEST(PropertyAttributes) {
3979   LocalContext context;
3980   v8::HandleScope scope(context->GetIsolate());
3981   // none
3982   Local<String> prop = v8_str("none");
3983   context->Global()->Set(prop, v8_num(7));
3984   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3985   // read-only
3986   prop = v8_str("read_only");
3987   context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
3988   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3989   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
3990   Script::Compile(v8_str("read_only = 9"))->Run();
3991   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3992   context->Global()->Set(prop, v8_num(10));
3993   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3994   // dont-delete
3995   prop = v8_str("dont_delete");
3996   context->Global()->Set(prop, v8_num(13), v8::DontDelete);
3997   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3998   Script::Compile(v8_str("delete dont_delete"))->Run();
3999   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4000   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4001   // dont-enum
4002   prop = v8_str("dont_enum");
4003   context->Global()->Set(prop, v8_num(28), v8::DontEnum);
4004   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4005   // absent
4006   prop = v8_str("absent");
4007   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4008   Local<Value> fake_prop = v8_num(1);
4009   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4010   // exception
4011   TryCatch try_catch;
4012   Local<Value> exception =
4013       CompileRun("({ toString: function() { throw 'exception';} })");
4014   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4015   CHECK(try_catch.HasCaught());
4016   String::Utf8Value exception_value(try_catch.Exception());
4017   CHECK_EQ("exception", *exception_value);
4018   try_catch.Reset();
4019 }
4020
4021
4022 THREADED_TEST(Array) {
4023   LocalContext context;
4024   v8::HandleScope scope(context->GetIsolate());
4025   Local<v8::Array> array = v8::Array::New();
4026   CHECK_EQ(0, array->Length());
4027   CHECK(array->Get(0)->IsUndefined());
4028   CHECK(!array->Has(0));
4029   CHECK(array->Get(100)->IsUndefined());
4030   CHECK(!array->Has(100));
4031   array->Set(2, v8_num(7));
4032   CHECK_EQ(3, array->Length());
4033   CHECK(!array->Has(0));
4034   CHECK(!array->Has(1));
4035   CHECK(array->Has(2));
4036   CHECK_EQ(7, array->Get(2)->Int32Value());
4037   Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
4038   Local<v8::Array> arr = obj.As<v8::Array>();
4039   CHECK_EQ(3, arr->Length());
4040   CHECK_EQ(1, arr->Get(0)->Int32Value());
4041   CHECK_EQ(2, arr->Get(1)->Int32Value());
4042   CHECK_EQ(3, arr->Get(2)->Int32Value());
4043   array = v8::Array::New(27);
4044   CHECK_EQ(27, array->Length());
4045   array = v8::Array::New(-27);
4046   CHECK_EQ(0, array->Length());
4047 }
4048
4049
4050 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4051   v8::HandleScope scope(args.GetIsolate());
4052   ApiTestFuzzer::Fuzz();
4053   Local<v8::Array> result = v8::Array::New(args.Length());
4054   for (int i = 0; i < args.Length(); i++)
4055     result->Set(i, args[i]);
4056   args.GetReturnValue().Set(scope.Close(result));
4057 }
4058
4059
4060 THREADED_TEST(Vector) {
4061   v8::HandleScope scope(CcTest::isolate());
4062   Local<ObjectTemplate> global = ObjectTemplate::New();
4063   global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
4064   LocalContext context(0, global);
4065
4066   const char* fun = "f()";
4067   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4068   CHECK_EQ(0, a0->Length());
4069
4070   const char* fun2 = "f(11)";
4071   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4072   CHECK_EQ(1, a1->Length());
4073   CHECK_EQ(11, a1->Get(0)->Int32Value());
4074
4075   const char* fun3 = "f(12, 13)";
4076   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4077   CHECK_EQ(2, a2->Length());
4078   CHECK_EQ(12, a2->Get(0)->Int32Value());
4079   CHECK_EQ(13, a2->Get(1)->Int32Value());
4080
4081   const char* fun4 = "f(14, 15, 16)";
4082   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4083   CHECK_EQ(3, a3->Length());
4084   CHECK_EQ(14, a3->Get(0)->Int32Value());
4085   CHECK_EQ(15, a3->Get(1)->Int32Value());
4086   CHECK_EQ(16, a3->Get(2)->Int32Value());
4087
4088   const char* fun5 = "f(17, 18, 19, 20)";
4089   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4090   CHECK_EQ(4, a4->Length());
4091   CHECK_EQ(17, a4->Get(0)->Int32Value());
4092   CHECK_EQ(18, a4->Get(1)->Int32Value());
4093   CHECK_EQ(19, a4->Get(2)->Int32Value());
4094   CHECK_EQ(20, a4->Get(3)->Int32Value());
4095 }
4096
4097
4098 THREADED_TEST(FunctionCall) {
4099   LocalContext context;
4100   v8::Isolate* isolate = context->GetIsolate();
4101   v8::HandleScope scope(isolate);
4102   CompileRun(
4103     "function Foo() {"
4104     "  var result = [];"
4105     "  for (var i = 0; i < arguments.length; i++) {"
4106     "    result.push(arguments[i]);"
4107     "  }"
4108     "  return result;"
4109     "}"
4110     "function ReturnThisSloppy() {"
4111     "  return this;"
4112     "}"
4113     "function ReturnThisStrict() {"
4114     "  'use strict';"
4115     "  return this;"
4116     "}");
4117   Local<Function> Foo =
4118       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4119   Local<Function> ReturnThisSloppy =
4120       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4121   Local<Function> ReturnThisStrict =
4122       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4123
4124   v8::Handle<Value>* args0 = NULL;
4125   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4126   CHECK_EQ(0, a0->Length());
4127
4128   v8::Handle<Value> args1[] = { v8_num(1.1) };
4129   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4130   CHECK_EQ(1, a1->Length());
4131   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
4132
4133   v8::Handle<Value> args2[] = { v8_num(2.2),
4134                                 v8_num(3.3) };
4135   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4136   CHECK_EQ(2, a2->Length());
4137   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
4138   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
4139
4140   v8::Handle<Value> args3[] = { v8_num(4.4),
4141                                 v8_num(5.5),
4142                                 v8_num(6.6) };
4143   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4144   CHECK_EQ(3, a3->Length());
4145   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
4146   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
4147   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
4148
4149   v8::Handle<Value> args4[] = { v8_num(7.7),
4150                                 v8_num(8.8),
4151                                 v8_num(9.9),
4152                                 v8_num(10.11) };
4153   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4154   CHECK_EQ(4, a4->Length());
4155   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
4156   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
4157   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
4158   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
4159
4160   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4161   CHECK(r1->StrictEquals(context->Global()));
4162   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4163   CHECK(r2->StrictEquals(context->Global()));
4164   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4165   CHECK(r3->IsNumberObject());
4166   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4167   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4168   CHECK(r4->IsStringObject());
4169   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4170   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4171   CHECK(r5->IsBooleanObject());
4172   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4173
4174   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4175   CHECK(r6->IsUndefined());
4176   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4177   CHECK(r7->IsNull());
4178   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4179   CHECK(r8->StrictEquals(v8_num(42)));
4180   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4181   CHECK(r9->StrictEquals(v8_str("hello")));
4182   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4183   CHECK(r10->StrictEquals(v8::True(isolate)));
4184 }
4185
4186
4187 static const char* js_code_causing_out_of_memory =
4188     "var a = new Array(); while(true) a.push(a);";
4189
4190
4191 // These tests run for a long time and prevent us from running tests
4192 // that come after them so they cannot run in parallel.
4193 TEST(OutOfMemory) {
4194   // It's not possible to read a snapshot into a heap with different dimensions.
4195   if (i::Snapshot::IsEnabled()) return;
4196   // Set heap limits.
4197   static const int K = 1024;
4198   v8::ResourceConstraints constraints;
4199   constraints.set_max_young_space_size(256 * K);
4200   constraints.set_max_old_space_size(5 * K * K);
4201   v8::SetResourceConstraints(&constraints);
4202
4203   // Execute a script that causes out of memory.
4204   LocalContext context;
4205   v8::HandleScope scope(context->GetIsolate());
4206   v8::V8::IgnoreOutOfMemoryException();
4207   Local<Script> script =
4208       Script::Compile(String::New(js_code_causing_out_of_memory));
4209   Local<Value> result = script->Run();
4210
4211   // Check for out of memory state.
4212   CHECK(result.IsEmpty());
4213   CHECK(context->HasOutOfMemoryException());
4214 }
4215
4216
4217 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
4218   ApiTestFuzzer::Fuzz();
4219
4220   LocalContext context;
4221   v8::HandleScope scope(context->GetIsolate());
4222   Local<Script> script =
4223       Script::Compile(String::New(js_code_causing_out_of_memory));
4224   Local<Value> result = script->Run();
4225
4226   // Check for out of memory state.
4227   CHECK(result.IsEmpty());
4228   CHECK(context->HasOutOfMemoryException());
4229
4230   args.GetReturnValue().Set(result);
4231 }
4232
4233
4234 TEST(OutOfMemoryNested) {
4235   // It's not possible to read a snapshot into a heap with different dimensions.
4236   if (i::Snapshot::IsEnabled()) return;
4237   // Set heap limits.
4238   static const int K = 1024;
4239   v8::ResourceConstraints constraints;
4240   constraints.set_max_young_space_size(256 * K);
4241   constraints.set_max_old_space_size(5 * K * K);
4242   v8::SetResourceConstraints(&constraints);
4243
4244   v8::HandleScope scope(CcTest::isolate());
4245   Local<ObjectTemplate> templ = ObjectTemplate::New();
4246   templ->Set(v8_str("ProvokeOutOfMemory"),
4247              v8::FunctionTemplate::New(ProvokeOutOfMemory));
4248   LocalContext context(0, templ);
4249   v8::V8::IgnoreOutOfMemoryException();
4250   Local<Value> result = CompileRun(
4251     "var thrown = false;"
4252     "try {"
4253     "  ProvokeOutOfMemory();"
4254     "} catch (e) {"
4255     "  thrown = true;"
4256     "}");
4257   // Check for out of memory state.
4258   CHECK(result.IsEmpty());
4259   CHECK(context->HasOutOfMemoryException());
4260 }
4261
4262
4263 TEST(HugeConsStringOutOfMemory) {
4264   // It's not possible to read a snapshot into a heap with different dimensions.
4265   if (i::Snapshot::IsEnabled()) return;
4266   // Set heap limits.
4267   static const int K = 1024;
4268   v8::ResourceConstraints constraints;
4269   constraints.set_max_young_space_size(256 * K);
4270   constraints.set_max_old_space_size(4 * K * K);
4271   v8::SetResourceConstraints(&constraints);
4272
4273   // Execute a script that causes out of memory.
4274   v8::V8::IgnoreOutOfMemoryException();
4275
4276   LocalContext context;
4277   v8::HandleScope scope(context->GetIsolate());
4278
4279   // Build huge string. This should fail with out of memory exception.
4280   Local<Value> result = CompileRun(
4281     "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
4282     "for (var i = 0; i < 22; i++) { str = str + str; }");
4283
4284   // Check for out of memory state.
4285   CHECK(result.IsEmpty());
4286   CHECK(context->HasOutOfMemoryException());
4287 }
4288
4289
4290 THREADED_TEST(ConstructCall) {
4291   LocalContext context;
4292   v8::HandleScope scope(context->GetIsolate());
4293   CompileRun(
4294     "function Foo() {"
4295     "  var result = [];"
4296     "  for (var i = 0; i < arguments.length; i++) {"
4297     "    result.push(arguments[i]);"
4298     "  }"
4299     "  return result;"
4300     "}");
4301   Local<Function> Foo =
4302       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4303
4304   v8::Handle<Value>* args0 = NULL;
4305   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4306   CHECK_EQ(0, a0->Length());
4307
4308   v8::Handle<Value> args1[] = { v8_num(1.1) };
4309   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4310   CHECK_EQ(1, a1->Length());
4311   CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
4312
4313   v8::Handle<Value> args2[] = { v8_num(2.2),
4314                                 v8_num(3.3) };
4315   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4316   CHECK_EQ(2, a2->Length());
4317   CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
4318   CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
4319
4320   v8::Handle<Value> args3[] = { v8_num(4.4),
4321                                 v8_num(5.5),
4322                                 v8_num(6.6) };
4323   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4324   CHECK_EQ(3, a3->Length());
4325   CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
4326   CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
4327   CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
4328
4329   v8::Handle<Value> args4[] = { v8_num(7.7),
4330                                 v8_num(8.8),
4331                                 v8_num(9.9),
4332                                 v8_num(10.11) };
4333   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4334   CHECK_EQ(4, a4->Length());
4335   CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
4336   CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
4337   CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
4338   CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
4339 }
4340
4341
4342 static void CheckUncle(v8::TryCatch* try_catch) {
4343   CHECK(try_catch->HasCaught());
4344   String::Utf8Value str_value(try_catch->Exception());
4345   CHECK_EQ(*str_value, "uncle?");
4346   try_catch->Reset();
4347 }
4348
4349
4350 THREADED_TEST(ConversionNumber) {
4351   LocalContext env;
4352   v8::HandleScope scope(env->GetIsolate());
4353   // Very large number.
4354   CompileRun("var obj = Math.pow(2,32) * 1237;");
4355   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4356   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4357   CHECK_EQ(0, obj->ToInt32()->Value());
4358   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4359   // Large number.
4360   CompileRun("var obj = -1234567890123;");
4361   obj = env->Global()->Get(v8_str("obj"));
4362   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4363   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4364   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4365   // Small positive integer.
4366   CompileRun("var obj = 42;");
4367   obj = env->Global()->Get(v8_str("obj"));
4368   CHECK_EQ(42.0, obj->ToNumber()->Value());
4369   CHECK_EQ(42, obj->ToInt32()->Value());
4370   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4371   // Negative integer.
4372   CompileRun("var obj = -37;");
4373   obj = env->Global()->Get(v8_str("obj"));
4374   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4375   CHECK_EQ(-37, obj->ToInt32()->Value());
4376   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4377   // Positive non-int32 integer.
4378   CompileRun("var obj = 0x81234567;");
4379   obj = env->Global()->Get(v8_str("obj"));
4380   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4381   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4382   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4383   // Fraction.
4384   CompileRun("var obj = 42.3;");
4385   obj = env->Global()->Get(v8_str("obj"));
4386   CHECK_EQ(42.3, obj->ToNumber()->Value());
4387   CHECK_EQ(42, obj->ToInt32()->Value());
4388   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4389   // Large negative fraction.
4390   CompileRun("var obj = -5726623061.75;");
4391   obj = env->Global()->Get(v8_str("obj"));
4392   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4393   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4394   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4395 }
4396
4397
4398 THREADED_TEST(isNumberType) {
4399   LocalContext env;
4400   v8::HandleScope scope(env->GetIsolate());
4401   // Very large number.
4402   CompileRun("var obj = Math.pow(2,32) * 1237;");
4403   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4404   CHECK(!obj->IsInt32());
4405   CHECK(!obj->IsUint32());
4406   // Large negative number.
4407   CompileRun("var obj = -1234567890123;");
4408   obj = env->Global()->Get(v8_str("obj"));
4409   CHECK(!obj->IsInt32());
4410   CHECK(!obj->IsUint32());
4411   // Small positive integer.
4412   CompileRun("var obj = 42;");
4413   obj = env->Global()->Get(v8_str("obj"));
4414   CHECK(obj->IsInt32());
4415   CHECK(obj->IsUint32());
4416   // Negative integer.
4417   CompileRun("var obj = -37;");
4418   obj = env->Global()->Get(v8_str("obj"));
4419   CHECK(obj->IsInt32());
4420   CHECK(!obj->IsUint32());
4421   // Positive non-int32 integer.
4422   CompileRun("var obj = 0x81234567;");
4423   obj = env->Global()->Get(v8_str("obj"));
4424   CHECK(!obj->IsInt32());
4425   CHECK(obj->IsUint32());
4426   // Fraction.
4427   CompileRun("var obj = 42.3;");
4428   obj = env->Global()->Get(v8_str("obj"));
4429   CHECK(!obj->IsInt32());
4430   CHECK(!obj->IsUint32());
4431   // Large negative fraction.
4432   CompileRun("var obj = -5726623061.75;");
4433   obj = env->Global()->Get(v8_str("obj"));
4434   CHECK(!obj->IsInt32());
4435   CHECK(!obj->IsUint32());
4436   // Positive zero
4437   CompileRun("var obj = 0.0;");
4438   obj = env->Global()->Get(v8_str("obj"));
4439   CHECK(obj->IsInt32());
4440   CHECK(obj->IsUint32());
4441   // Positive zero
4442   CompileRun("var obj = -0.0;");
4443   obj = env->Global()->Get(v8_str("obj"));
4444   CHECK(!obj->IsInt32());
4445   CHECK(!obj->IsUint32());
4446 }
4447
4448
4449 THREADED_TEST(ConversionException) {
4450   LocalContext env;
4451   v8::Isolate* isolate = env->GetIsolate();
4452   v8::HandleScope scope(isolate);
4453   CompileRun(
4454     "function TestClass() { };"
4455     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4456     "var obj = new TestClass();");
4457   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4458
4459   v8::TryCatch try_catch;
4460
4461   Local<Value> to_string_result = obj->ToString();
4462   CHECK(to_string_result.IsEmpty());
4463   CheckUncle(&try_catch);
4464
4465   Local<Value> to_number_result = obj->ToNumber();
4466   CHECK(to_number_result.IsEmpty());
4467   CheckUncle(&try_catch);
4468
4469   Local<Value> to_integer_result = obj->ToInteger();
4470   CHECK(to_integer_result.IsEmpty());
4471   CheckUncle(&try_catch);
4472
4473   Local<Value> to_uint32_result = obj->ToUint32();
4474   CHECK(to_uint32_result.IsEmpty());
4475   CheckUncle(&try_catch);
4476
4477   Local<Value> to_int32_result = obj->ToInt32();
4478   CHECK(to_int32_result.IsEmpty());
4479   CheckUncle(&try_catch);
4480
4481   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4482   CHECK(to_object_result.IsEmpty());
4483   CHECK(try_catch.HasCaught());
4484   try_catch.Reset();
4485
4486   int32_t int32_value = obj->Int32Value();
4487   CHECK_EQ(0, int32_value);
4488   CheckUncle(&try_catch);
4489
4490   uint32_t uint32_value = obj->Uint32Value();
4491   CHECK_EQ(0, uint32_value);
4492   CheckUncle(&try_catch);
4493
4494   double number_value = obj->NumberValue();
4495   CHECK_NE(0, std::isnan(number_value));
4496   CheckUncle(&try_catch);
4497
4498   int64_t integer_value = obj->IntegerValue();
4499   CHECK_EQ(0.0, static_cast<double>(integer_value));
4500   CheckUncle(&try_catch);
4501 }
4502
4503
4504 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4505   ApiTestFuzzer::Fuzz();
4506   args.GetIsolate()->ThrowException(v8_str("konto"));
4507 }
4508
4509
4510 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4511   if (args.Length() < 1) {
4512     args.GetReturnValue().Set(false);
4513     return;
4514   }
4515   v8::HandleScope scope(args.GetIsolate());
4516   v8::TryCatch try_catch;
4517   Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4518   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4519   args.GetReturnValue().Set(try_catch.HasCaught());
4520 }
4521
4522
4523 THREADED_TEST(APICatch) {
4524   v8::HandleScope scope(CcTest::isolate());
4525   Local<ObjectTemplate> templ = ObjectTemplate::New();
4526   templ->Set(v8_str("ThrowFromC"),
4527              v8::FunctionTemplate::New(ThrowFromC));
4528   LocalContext context(0, templ);
4529   CompileRun(
4530     "var thrown = false;"
4531     "try {"
4532     "  ThrowFromC();"
4533     "} catch (e) {"
4534     "  thrown = true;"
4535     "}");
4536   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4537   CHECK(thrown->BooleanValue());
4538 }
4539
4540
4541 THREADED_TEST(APIThrowTryCatch) {
4542   v8::HandleScope scope(CcTest::isolate());
4543   Local<ObjectTemplate> templ = ObjectTemplate::New();
4544   templ->Set(v8_str("ThrowFromC"),
4545              v8::FunctionTemplate::New(ThrowFromC));
4546   LocalContext context(0, templ);
4547   v8::TryCatch try_catch;
4548   CompileRun("ThrowFromC();");
4549   CHECK(try_catch.HasCaught());
4550 }
4551
4552
4553 // Test that a try-finally block doesn't shadow a try-catch block
4554 // when setting up an external handler.
4555 //
4556 // BUG(271): Some of the exception propagation does not work on the
4557 // ARM simulator because the simulator separates the C++ stack and the
4558 // JS stack.  This test therefore fails on the simulator.  The test is
4559 // not threaded to allow the threading tests to run on the simulator.
4560 TEST(TryCatchInTryFinally) {
4561   v8::HandleScope scope(CcTest::isolate());
4562   Local<ObjectTemplate> templ = ObjectTemplate::New();
4563   templ->Set(v8_str("CCatcher"),
4564              v8::FunctionTemplate::New(CCatcher));
4565   LocalContext context(0, templ);
4566   Local<Value> result = CompileRun("try {"
4567                                    "  try {"
4568                                    "    CCatcher('throw 7;');"
4569                                    "  } finally {"
4570                                    "  }"
4571                                    "} catch (e) {"
4572                                    "}");
4573   CHECK(result->IsTrue());
4574 }
4575
4576
4577 static void check_reference_error_message(
4578     v8::Handle<v8::Message> message,
4579     v8::Handle<v8::Value> data) {
4580   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4581   CHECK(message->Get()->Equals(v8_str(reference_error)));
4582 }
4583
4584
4585 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4586   ApiTestFuzzer::Fuzz();
4587   CHECK(false);
4588 }
4589
4590
4591 // Test that overwritten methods are not invoked on uncaught exception
4592 // formatting. However, they are invoked when performing normal error
4593 // string conversions.
4594 TEST(APIThrowMessageOverwrittenToString) {
4595   v8::HandleScope scope(CcTest::isolate());
4596   v8::V8::AddMessageListener(check_reference_error_message);
4597   Local<ObjectTemplate> templ = ObjectTemplate::New();
4598   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
4599   LocalContext context(NULL, templ);
4600   CompileRun("asdf;");
4601   CompileRun("var limit = {};"
4602              "limit.valueOf = fail;"
4603              "Error.stackTraceLimit = limit;");
4604   CompileRun("asdf");
4605   CompileRun("Array.prototype.pop = fail;");
4606   CompileRun("Object.prototype.hasOwnProperty = fail;");
4607   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4608   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4609   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4610   CompileRun("ReferenceError.prototype.toString ="
4611              "  function() { return 'Whoops' }");
4612   CompileRun("asdf;");
4613   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4614   CompileRun("asdf;");
4615   CompileRun("ReferenceError.prototype.constructor = void 0;");
4616   CompileRun("asdf;");
4617   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4618   CompileRun("asdf;");
4619   CompileRun("ReferenceError.prototype = new Object();");
4620   CompileRun("asdf;");
4621   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4622   CHECK(string->Equals(v8_str("Whoops")));
4623   CompileRun("ReferenceError.prototype.constructor = new Object();"
4624              "ReferenceError.prototype.constructor.name = 1;"
4625              "Number.prototype.toString = function() { return 'Whoops'; };"
4626              "ReferenceError.prototype.toString = Object.prototype.toString;");
4627   CompileRun("asdf;");
4628   v8::V8::RemoveMessageListeners(check_reference_error_message);
4629 }
4630
4631
4632 static void check_custom_error_tostring(
4633     v8::Handle<v8::Message> message,
4634     v8::Handle<v8::Value> data) {
4635   const char* uncaught_error = "Uncaught MyError toString";
4636   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4637 }
4638
4639
4640 TEST(CustomErrorToString) {
4641   LocalContext context;
4642   v8::HandleScope scope(context->GetIsolate());
4643   v8::V8::AddMessageListener(check_custom_error_tostring);
4644   CompileRun(
4645     "function MyError(name, message) {                   "
4646     "  this.name = name;                                 "
4647     "  this.message = message;                           "
4648     "}                                                   "
4649     "MyError.prototype = Object.create(Error.prototype); "
4650     "MyError.prototype.toString = function() {           "
4651     "  return 'MyError toString';                        "
4652     "};                                                  "
4653     "throw new MyError('my name', 'my message');         ");
4654   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4655 }
4656
4657
4658 static void check_custom_error_message(
4659     v8::Handle<v8::Message> message,
4660     v8::Handle<v8::Value> data) {
4661   const char* uncaught_error = "Uncaught MyError: my message";
4662   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4663   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4664 }
4665
4666
4667 TEST(CustomErrorMessage) {
4668   LocalContext context;
4669   v8::HandleScope scope(context->GetIsolate());
4670   v8::V8::AddMessageListener(check_custom_error_message);
4671
4672   // Handlebars.
4673   CompileRun(
4674     "function MyError(msg) {                             "
4675     "  this.name = 'MyError';                            "
4676     "  this.message = msg;                               "
4677     "}                                                   "
4678     "MyError.prototype = new Error();                    "
4679     "throw new MyError('my message');                    ");
4680
4681   // Closure.
4682   CompileRun(
4683     "function MyError(msg) {                             "
4684     "  this.name = 'MyError';                            "
4685     "  this.message = msg;                               "
4686     "}                                                   "
4687     "inherits = function(childCtor, parentCtor) {        "
4688     "    function tempCtor() {};                         "
4689     "    tempCtor.prototype = parentCtor.prototype;      "
4690     "    childCtor.superClass_ = parentCtor.prototype;   "
4691     "    childCtor.prototype = new tempCtor();           "
4692     "    childCtor.prototype.constructor = childCtor;    "
4693     "};                                                  "
4694     "inherits(MyError, Error);                           "
4695     "throw new MyError('my message');                    ");
4696
4697   // Object.create.
4698   CompileRun(
4699     "function MyError(msg) {                             "
4700     "  this.name = 'MyError';                            "
4701     "  this.message = msg;                               "
4702     "}                                                   "
4703     "MyError.prototype = Object.create(Error.prototype); "
4704     "throw new MyError('my message');                    ");
4705
4706   v8::V8::RemoveMessageListeners(check_custom_error_message);
4707 }
4708
4709
4710 static void receive_message(v8::Handle<v8::Message> message,
4711                             v8::Handle<v8::Value> data) {
4712   message->Get();
4713   message_received = true;
4714 }
4715
4716
4717 TEST(APIThrowMessage) {
4718   message_received = false;
4719   v8::HandleScope scope(CcTest::isolate());
4720   v8::V8::AddMessageListener(receive_message);
4721   Local<ObjectTemplate> templ = ObjectTemplate::New();
4722   templ->Set(v8_str("ThrowFromC"),
4723              v8::FunctionTemplate::New(ThrowFromC));
4724   LocalContext context(0, templ);
4725   CompileRun("ThrowFromC();");
4726   CHECK(message_received);
4727   v8::V8::RemoveMessageListeners(receive_message);
4728 }
4729
4730
4731 TEST(APIThrowMessageAndVerboseTryCatch) {
4732   message_received = false;
4733   v8::HandleScope scope(CcTest::isolate());
4734   v8::V8::AddMessageListener(receive_message);
4735   Local<ObjectTemplate> templ = ObjectTemplate::New();
4736   templ->Set(v8_str("ThrowFromC"),
4737              v8::FunctionTemplate::New(ThrowFromC));
4738   LocalContext context(0, templ);
4739   v8::TryCatch try_catch;
4740   try_catch.SetVerbose(true);
4741   Local<Value> result = CompileRun("ThrowFromC();");
4742   CHECK(try_catch.HasCaught());
4743   CHECK(result.IsEmpty());
4744   CHECK(message_received);
4745   v8::V8::RemoveMessageListeners(receive_message);
4746 }
4747
4748
4749 TEST(APIStackOverflowAndVerboseTryCatch) {
4750   message_received = false;
4751   LocalContext context;
4752   v8::HandleScope scope(context->GetIsolate());
4753   v8::V8::AddMessageListener(receive_message);
4754   v8::TryCatch try_catch;
4755   try_catch.SetVerbose(true);
4756   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4757   CHECK(try_catch.HasCaught());
4758   CHECK(result.IsEmpty());
4759   CHECK(message_received);
4760   v8::V8::RemoveMessageListeners(receive_message);
4761 }
4762
4763
4764 THREADED_TEST(ExternalScriptException) {
4765   v8::HandleScope scope(CcTest::isolate());
4766   Local<ObjectTemplate> templ = ObjectTemplate::New();
4767   templ->Set(v8_str("ThrowFromC"),
4768              v8::FunctionTemplate::New(ThrowFromC));
4769   LocalContext context(0, templ);
4770
4771   v8::TryCatch try_catch;
4772   Local<Script> script
4773       = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4774   Local<Value> result = script->Run();
4775   CHECK(result.IsEmpty());
4776   CHECK(try_catch.HasCaught());
4777   String::Utf8Value exception_value(try_catch.Exception());
4778   CHECK_EQ("konto", *exception_value);
4779 }
4780
4781
4782
4783 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
4784   ApiTestFuzzer::Fuzz();
4785   CHECK_EQ(4, args.Length());
4786   int count = args[0]->Int32Value();
4787   int cInterval = args[2]->Int32Value();
4788   if (count == 0) {
4789     args.GetIsolate()->ThrowException(v8_str("FromC"));
4790     return;
4791   } else {
4792     Local<v8::Object> global =
4793         args.GetIsolate()->GetCurrentContext()->Global();
4794     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
4795     v8::Handle<Value> argv[] = { v8_num(count - 1),
4796                                  args[1],
4797                                  args[2],
4798                                  args[3] };
4799     if (count % cInterval == 0) {
4800       v8::TryCatch try_catch;
4801       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
4802       int expected = args[3]->Int32Value();
4803       if (try_catch.HasCaught()) {
4804         CHECK_EQ(expected, count);
4805         CHECK(result.IsEmpty());
4806         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
4807       } else {
4808         CHECK_NE(expected, count);
4809       }
4810       args.GetReturnValue().Set(result);
4811       return;
4812     } else {
4813       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
4814       return;
4815     }
4816   }
4817 }
4818
4819
4820 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
4821   ApiTestFuzzer::Fuzz();
4822   CHECK_EQ(3, args.Length());
4823   bool equality = args[0]->BooleanValue();
4824   int count = args[1]->Int32Value();
4825   int expected = args[2]->Int32Value();
4826   if (equality) {
4827     CHECK_EQ(count, expected);
4828   } else {
4829     CHECK_NE(count, expected);
4830   }
4831 }
4832
4833
4834 THREADED_TEST(EvalInTryFinally) {
4835   LocalContext context;
4836   v8::HandleScope scope(context->GetIsolate());
4837   v8::TryCatch try_catch;
4838   CompileRun("(function() {"
4839              "  try {"
4840              "    eval('asldkf (*&^&*^');"
4841              "  } finally {"
4842              "    return;"
4843              "  }"
4844              "})()");
4845   CHECK(!try_catch.HasCaught());
4846 }
4847
4848
4849 // This test works by making a stack of alternating JavaScript and C
4850 // activations.  These activations set up exception handlers with regular
4851 // intervals, one interval for C activations and another for JavaScript
4852 // activations.  When enough activations have been created an exception is
4853 // thrown and we check that the right activation catches the exception and that
4854 // no other activations do.  The right activation is always the topmost one with
4855 // a handler, regardless of whether it is in JavaScript or C.
4856 //
4857 // The notation used to describe a test case looks like this:
4858 //
4859 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
4860 //
4861 // Each entry is an activation, either JS or C.  The index is the count at that
4862 // level.  Stars identify activations with exception handlers, the @ identifies
4863 // the exception handler that should catch the exception.
4864 //
4865 // BUG(271): Some of the exception propagation does not work on the
4866 // ARM simulator because the simulator separates the C++ stack and the
4867 // JS stack.  This test therefore fails on the simulator.  The test is
4868 // not threaded to allow the threading tests to run on the simulator.
4869 TEST(ExceptionOrder) {
4870   v8::HandleScope scope(CcTest::isolate());
4871   Local<ObjectTemplate> templ = ObjectTemplate::New();
4872   templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
4873   templ->Set(v8_str("CThrowCountDown"),
4874              v8::FunctionTemplate::New(CThrowCountDown));
4875   LocalContext context(0, templ);
4876   CompileRun(
4877     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
4878     "  if (count == 0) throw 'FromJS';"
4879     "  if (count % jsInterval == 0) {"
4880     "    try {"
4881     "      var value = CThrowCountDown(count - 1,"
4882     "                                  jsInterval,"
4883     "                                  cInterval,"
4884     "                                  expected);"
4885     "      check(false, count, expected);"
4886     "      return value;"
4887     "    } catch (e) {"
4888     "      check(true, count, expected);"
4889     "    }"
4890     "  } else {"
4891     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
4892     "  }"
4893     "}");
4894   Local<Function> fun =
4895       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
4896
4897   const int argc = 4;
4898   //                             count      jsInterval cInterval  expected
4899
4900   // *JS[4] *C[3] @JS[2] C[1] JS[0]
4901   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
4902   fun->Call(fun, argc, a0);
4903
4904   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
4905   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
4906   fun->Call(fun, argc, a1);
4907
4908   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
4909   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
4910   fun->Call(fun, argc, a2);
4911
4912   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
4913   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
4914   fun->Call(fun, argc, a3);
4915
4916   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
4917   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
4918   fun->Call(fun, argc, a4);
4919
4920   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
4921   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
4922   fun->Call(fun, argc, a5);
4923 }
4924
4925
4926 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
4927   ApiTestFuzzer::Fuzz();
4928   CHECK_EQ(1, args.Length());
4929   args.GetIsolate()->ThrowException(args[0]);
4930 }
4931
4932
4933 THREADED_TEST(ThrowValues) {
4934   v8::HandleScope scope(CcTest::isolate());
4935   Local<ObjectTemplate> templ = ObjectTemplate::New();
4936   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
4937   LocalContext context(0, templ);
4938   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4939     "function Run(obj) {"
4940     "  try {"
4941     "    Throw(obj);"
4942     "  } catch (e) {"
4943     "    return e;"
4944     "  }"
4945     "  return 'no exception';"
4946     "}"
4947     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
4948   CHECK_EQ(5, result->Length());
4949   CHECK(result->Get(v8::Integer::New(0))->IsString());
4950   CHECK(result->Get(v8::Integer::New(1))->IsNumber());
4951   CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
4952   CHECK(result->Get(v8::Integer::New(2))->IsNumber());
4953   CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
4954   CHECK(result->Get(v8::Integer::New(3))->IsNull());
4955   CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
4956 }
4957
4958
4959 THREADED_TEST(CatchZero) {
4960   LocalContext context;
4961   v8::HandleScope scope(context->GetIsolate());
4962   v8::TryCatch try_catch;
4963   CHECK(!try_catch.HasCaught());
4964   Script::Compile(v8_str("throw 10"))->Run();
4965   CHECK(try_catch.HasCaught());
4966   CHECK_EQ(10, try_catch.Exception()->Int32Value());
4967   try_catch.Reset();
4968   CHECK(!try_catch.HasCaught());
4969   Script::Compile(v8_str("throw 0"))->Run();
4970   CHECK(try_catch.HasCaught());
4971   CHECK_EQ(0, try_catch.Exception()->Int32Value());
4972 }
4973
4974
4975 THREADED_TEST(CatchExceptionFromWith) {
4976   LocalContext context;
4977   v8::HandleScope scope(context->GetIsolate());
4978   v8::TryCatch try_catch;
4979   CHECK(!try_catch.HasCaught());
4980   Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
4981   CHECK(try_catch.HasCaught());
4982 }
4983
4984
4985 THREADED_TEST(TryCatchAndFinallyHidingException) {
4986   LocalContext context;
4987   v8::HandleScope scope(context->GetIsolate());
4988   v8::TryCatch try_catch;
4989   CHECK(!try_catch.HasCaught());
4990   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
4991   CompileRun("f({toString: function() { throw 42; }});");
4992   CHECK(!try_catch.HasCaught());
4993 }
4994
4995
4996 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
4997   v8::TryCatch try_catch;
4998 }
4999
5000
5001 THREADED_TEST(TryCatchAndFinally) {
5002   LocalContext context;
5003   v8::HandleScope scope(context->GetIsolate());
5004   context->Global()->Set(
5005       v8_str("native_with_try_catch"),
5006       v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
5007   v8::TryCatch try_catch;
5008   CHECK(!try_catch.HasCaught());
5009   CompileRun(
5010       "try {\n"
5011       "  throw new Error('a');\n"
5012       "} finally {\n"
5013       "  native_with_try_catch();\n"
5014       "}\n");
5015   CHECK(try_catch.HasCaught());
5016 }
5017
5018
5019 static void TryCatchNestedHelper(int depth) {
5020   if (depth > 0) {
5021     v8::TryCatch try_catch;
5022     try_catch.SetVerbose(true);
5023     TryCatchNestedHelper(depth - 1);
5024     CHECK(try_catch.HasCaught());
5025     try_catch.ReThrow();
5026   } else {
5027     CcTest::isolate()->ThrowException(v8_str("back"));
5028   }
5029 }
5030
5031
5032 TEST(TryCatchNested) {
5033   v8::V8::Initialize();
5034   LocalContext context;
5035   v8::HandleScope scope(context->GetIsolate());
5036   v8::TryCatch try_catch;
5037   TryCatchNestedHelper(5);
5038   CHECK(try_catch.HasCaught());
5039   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
5040 }
5041
5042
5043 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5044   CHECK(try_catch->HasCaught());
5045   Handle<Message> message = try_catch->Message();
5046   Handle<Value> resource = message->GetScriptResourceName();
5047   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5048   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5049                      "Uncaught Error: a"));
5050   CHECK_EQ(1, message->GetLineNumber());
5051   CHECK_EQ(6, message->GetStartColumn());
5052 }
5053
5054
5055 void TryCatchMixedNestingHelper(
5056     const v8::FunctionCallbackInfo<v8::Value>& args) {
5057   ApiTestFuzzer::Fuzz();
5058   v8::TryCatch try_catch;
5059   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5060   CHECK(try_catch.HasCaught());
5061   TryCatchMixedNestingCheck(&try_catch);
5062   try_catch.ReThrow();
5063 }
5064
5065
5066 // This test ensures that an outer TryCatch in the following situation:
5067 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5068 // does not clobber the Message object generated for the inner TryCatch.
5069 // This exercises the ability of TryCatch.ReThrow() to restore the
5070 // inner pending Message before throwing the exception again.
5071 TEST(TryCatchMixedNesting) {
5072   v8::HandleScope scope(CcTest::isolate());
5073   v8::V8::Initialize();
5074   v8::TryCatch try_catch;
5075   Local<ObjectTemplate> templ = ObjectTemplate::New();
5076   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5077              v8::FunctionTemplate::New(TryCatchMixedNestingHelper));
5078   LocalContext context(0, templ);
5079   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5080   TryCatchMixedNestingCheck(&try_catch);
5081 }
5082
5083
5084 THREADED_TEST(Equality) {
5085   LocalContext context;
5086   v8::Isolate* isolate = context->GetIsolate();
5087   v8::HandleScope scope(context->GetIsolate());
5088   // Check that equality works at all before relying on CHECK_EQ
5089   CHECK(v8_str("a")->Equals(v8_str("a")));
5090   CHECK(!v8_str("a")->Equals(v8_str("b")));
5091
5092   CHECK_EQ(v8_str("a"), v8_str("a"));
5093   CHECK_NE(v8_str("a"), v8_str("b"));
5094   CHECK_EQ(v8_num(1), v8_num(1));
5095   CHECK_EQ(v8_num(1.00), v8_num(1));
5096   CHECK_NE(v8_num(1), v8_num(2));
5097
5098   // Assume String is not internalized.
5099   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5100   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5101   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5102   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5103   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5104   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5105   Local<Value> not_a_number = v8_num(i::OS::nan_value());
5106   CHECK(!not_a_number->StrictEquals(not_a_number));
5107   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5108   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5109
5110   v8::Handle<v8::Object> obj = v8::Object::New();
5111   v8::Persistent<v8::Object> alias(isolate, obj);
5112   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5113   alias.Dispose();
5114
5115   CHECK(v8_str("a")->SameValue(v8_str("a")));
5116   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5117   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5118   CHECK(v8_num(1)->SameValue(v8_num(1)));
5119   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5120   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5121   CHECK(not_a_number->SameValue(not_a_number));
5122   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5123   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5124 }
5125
5126
5127 THREADED_TEST(MultiRun) {
5128   LocalContext context;
5129   v8::HandleScope scope(context->GetIsolate());
5130   Local<Script> script = Script::Compile(v8_str("x"));
5131   for (int i = 0; i < 10; i++)
5132     script->Run();
5133 }
5134
5135
5136 static void GetXValue(Local<String> name,
5137                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5138   ApiTestFuzzer::Fuzz();
5139   CHECK_EQ(info.Data(), v8_str("donut"));
5140   CHECK_EQ(name, v8_str("x"));
5141   info.GetReturnValue().Set(name);
5142 }
5143
5144
5145 THREADED_TEST(SimplePropertyRead) {
5146   LocalContext context;
5147   v8::HandleScope scope(context->GetIsolate());
5148   Local<ObjectTemplate> templ = ObjectTemplate::New();
5149   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5150   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5151   Local<Script> script = Script::Compile(v8_str("obj.x"));
5152   for (int i = 0; i < 10; i++) {
5153     Local<Value> result = script->Run();
5154     CHECK_EQ(result, v8_str("x"));
5155   }
5156 }
5157
5158
5159 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5160   LocalContext context;
5161   v8::HandleScope scope(context->GetIsolate());
5162   Local<ObjectTemplate> templ = ObjectTemplate::New();
5163   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5164   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5165
5166   // Uses getOwnPropertyDescriptor to check the configurable status
5167   Local<Script> script_desc
5168     = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
5169                              "obj, 'x');"
5170                              "prop.configurable;"));
5171   Local<Value> result = script_desc->Run();
5172   CHECK_EQ(result->BooleanValue(), true);
5173
5174   // Redefine get - but still configurable
5175   Local<Script> script_define
5176     = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
5177                              "            configurable: true };"
5178                              "Object.defineProperty(obj, 'x', desc);"
5179                              "obj.x"));
5180   result = script_define->Run();
5181   CHECK_EQ(result, v8_num(42));
5182
5183   // Check that the accessor is still configurable
5184   result = script_desc->Run();
5185   CHECK_EQ(result->BooleanValue(), true);
5186
5187   // Redefine to a non-configurable
5188   script_define
5189     = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
5190                              "             configurable: false };"
5191                              "Object.defineProperty(obj, 'x', desc);"
5192                              "obj.x"));
5193   result = script_define->Run();
5194   CHECK_EQ(result, v8_num(43));
5195   result = script_desc->Run();
5196   CHECK_EQ(result->BooleanValue(), false);
5197
5198   // Make sure that it is not possible to redefine again
5199   v8::TryCatch try_catch;
5200   result = script_define->Run();
5201   CHECK(try_catch.HasCaught());
5202   String::Utf8Value exception_value(try_catch.Exception());
5203   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5204 }
5205
5206
5207 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5208   v8::HandleScope scope(CcTest::isolate());
5209   Local<ObjectTemplate> templ = ObjectTemplate::New();
5210   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5211   LocalContext context;
5212   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5213
5214   Local<Script> script_desc = Script::Compile(v8_str("var prop ="
5215                                     "Object.getOwnPropertyDescriptor( "
5216                                     "obj, 'x');"
5217                                     "prop.configurable;"));
5218   Local<Value> result = script_desc->Run();
5219   CHECK_EQ(result->BooleanValue(), true);
5220
5221   Local<Script> script_define =
5222     Script::Compile(v8_str("var desc = {get: function(){return 42; },"
5223                            "            configurable: true };"
5224                            "Object.defineProperty(obj, 'x', desc);"
5225                            "obj.x"));
5226   result = script_define->Run();
5227   CHECK_EQ(result, v8_num(42));
5228
5229
5230   result = script_desc->Run();
5231   CHECK_EQ(result->BooleanValue(), true);
5232
5233
5234   script_define =
5235     Script::Compile(v8_str("var desc = {get: function(){return 43; },"
5236                            "            configurable: false };"
5237                            "Object.defineProperty(obj, 'x', desc);"
5238                            "obj.x"));
5239   result = script_define->Run();
5240   CHECK_EQ(result, v8_num(43));
5241   result = script_desc->Run();
5242
5243   CHECK_EQ(result->BooleanValue(), false);
5244
5245   v8::TryCatch try_catch;
5246   result = script_define->Run();
5247   CHECK(try_catch.HasCaught());
5248   String::Utf8Value exception_value(try_catch.Exception());
5249   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5250 }
5251
5252
5253 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5254                                                 char const* name) {
5255   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5256 }
5257
5258
5259 THREADED_TEST(DefineAPIAccessorOnObject) {
5260   v8::HandleScope scope(CcTest::isolate());
5261   Local<ObjectTemplate> templ = ObjectTemplate::New();
5262   LocalContext context;
5263
5264   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5265   CompileRun("var obj2 = {};");
5266
5267   CHECK(CompileRun("obj1.x")->IsUndefined());
5268   CHECK(CompileRun("obj2.x")->IsUndefined());
5269
5270   CHECK(GetGlobalProperty(&context, "obj1")->
5271       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5272
5273   ExpectString("obj1.x", "x");
5274   CHECK(CompileRun("obj2.x")->IsUndefined());
5275
5276   CHECK(GetGlobalProperty(&context, "obj2")->
5277       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5278
5279   ExpectString("obj1.x", "x");
5280   ExpectString("obj2.x", "x");
5281
5282   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5283   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5284
5285   CompileRun("Object.defineProperty(obj1, 'x',"
5286              "{ get: function() { return 'y'; }, configurable: true })");
5287
5288   ExpectString("obj1.x", "y");
5289   ExpectString("obj2.x", "x");
5290
5291   CompileRun("Object.defineProperty(obj2, 'x',"
5292              "{ get: function() { return 'y'; }, configurable: true })");
5293
5294   ExpectString("obj1.x", "y");
5295   ExpectString("obj2.x", "y");
5296
5297   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5298   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5299
5300   CHECK(GetGlobalProperty(&context, "obj1")->
5301       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5302   CHECK(GetGlobalProperty(&context, "obj2")->
5303       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5304
5305   ExpectString("obj1.x", "x");
5306   ExpectString("obj2.x", "x");
5307
5308   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5309   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5310
5311   // Define getters/setters, but now make them not configurable.
5312   CompileRun("Object.defineProperty(obj1, 'x',"
5313              "{ get: function() { return 'z'; }, configurable: false })");
5314   CompileRun("Object.defineProperty(obj2, 'x',"
5315              "{ get: function() { return 'z'; }, configurable: false })");
5316
5317   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5318   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5319
5320   ExpectString("obj1.x", "z");
5321   ExpectString("obj2.x", "z");
5322
5323   CHECK(!GetGlobalProperty(&context, "obj1")->
5324       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5325   CHECK(!GetGlobalProperty(&context, "obj2")->
5326       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5327
5328   ExpectString("obj1.x", "z");
5329   ExpectString("obj2.x", "z");
5330 }
5331
5332
5333 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5334   v8::HandleScope scope(CcTest::isolate());
5335   Local<ObjectTemplate> templ = ObjectTemplate::New();
5336   LocalContext context;
5337
5338   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5339   CompileRun("var obj2 = {};");
5340
5341   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5342         v8_str("x"),
5343         GetXValue, NULL,
5344         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5345   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5346         v8_str("x"),
5347         GetXValue, NULL,
5348         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5349
5350   ExpectString("obj1.x", "x");
5351   ExpectString("obj2.x", "x");
5352
5353   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5354   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5355
5356   CHECK(!GetGlobalProperty(&context, "obj1")->
5357       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5358   CHECK(!GetGlobalProperty(&context, "obj2")->
5359       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5360
5361   {
5362     v8::TryCatch try_catch;
5363     CompileRun("Object.defineProperty(obj1, 'x',"
5364         "{get: function() { return 'func'; }})");
5365     CHECK(try_catch.HasCaught());
5366     String::Utf8Value exception_value(try_catch.Exception());
5367     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5368   }
5369   {
5370     v8::TryCatch try_catch;
5371     CompileRun("Object.defineProperty(obj2, 'x',"
5372         "{get: function() { return 'func'; }})");
5373     CHECK(try_catch.HasCaught());
5374     String::Utf8Value exception_value(try_catch.Exception());
5375     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5376   }
5377 }
5378
5379
5380 static void Get239Value(Local<String> name,
5381                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5382   ApiTestFuzzer::Fuzz();
5383   CHECK_EQ(info.Data(), v8_str("donut"));
5384   CHECK_EQ(name, v8_str("239"));
5385   info.GetReturnValue().Set(name);
5386 }
5387
5388
5389 THREADED_TEST(ElementAPIAccessor) {
5390   v8::HandleScope scope(CcTest::isolate());
5391   Local<ObjectTemplate> templ = ObjectTemplate::New();
5392   LocalContext context;
5393
5394   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5395   CompileRun("var obj2 = {};");
5396
5397   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5398         v8_str("239"),
5399         Get239Value, NULL,
5400         v8_str("donut")));
5401   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5402         v8_str("239"),
5403         Get239Value, NULL,
5404         v8_str("donut")));
5405
5406   ExpectString("obj1[239]", "239");
5407   ExpectString("obj2[239]", "239");
5408   ExpectString("obj1['239']", "239");
5409   ExpectString("obj2['239']", "239");
5410 }
5411
5412
5413 v8::Persistent<Value> xValue;
5414
5415
5416 static void SetXValue(Local<String> name,
5417                       Local<Value> value,
5418                       const v8::PropertyCallbackInfo<void>& info) {
5419   CHECK_EQ(value, v8_num(4));
5420   CHECK_EQ(info.Data(), v8_str("donut"));
5421   CHECK_EQ(name, v8_str("x"));
5422   CHECK(xValue.IsEmpty());
5423   xValue.Reset(info.GetIsolate(), value);
5424 }
5425
5426
5427 THREADED_TEST(SimplePropertyWrite) {
5428   v8::HandleScope scope(CcTest::isolate());
5429   Local<ObjectTemplate> templ = ObjectTemplate::New();
5430   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5431   LocalContext context;
5432   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5433   Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5434   for (int i = 0; i < 10; i++) {
5435     CHECK(xValue.IsEmpty());
5436     script->Run();
5437     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5438     xValue.Dispose();
5439     xValue.Clear();
5440   }
5441 }
5442
5443
5444 THREADED_TEST(SetterOnly) {
5445   v8::HandleScope scope(CcTest::isolate());
5446   Local<ObjectTemplate> templ = ObjectTemplate::New();
5447   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5448   LocalContext context;
5449   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5450   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5451   for (int i = 0; i < 10; i++) {
5452     CHECK(xValue.IsEmpty());
5453     script->Run();
5454     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5455     xValue.Dispose();
5456     xValue.Clear();
5457   }
5458 }
5459
5460
5461 THREADED_TEST(NoAccessors) {
5462   v8::HandleScope scope(CcTest::isolate());
5463   Local<ObjectTemplate> templ = ObjectTemplate::New();
5464   templ->SetAccessor(v8_str("x"),
5465                      static_cast<v8::AccessorGetterCallback>(NULL),
5466                      NULL,
5467                      v8_str("donut"));
5468   LocalContext context;
5469   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5470   Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5471   for (int i = 0; i < 10; i++) {
5472     script->Run();
5473   }
5474 }
5475
5476
5477 static void XPropertyGetter(Local<String> property,
5478                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5479   ApiTestFuzzer::Fuzz();
5480   CHECK(info.Data()->IsUndefined());
5481   info.GetReturnValue().Set(property);
5482 }
5483
5484
5485 THREADED_TEST(NamedInterceptorPropertyRead) {
5486   v8::HandleScope scope(CcTest::isolate());
5487   Local<ObjectTemplate> templ = ObjectTemplate::New();
5488   templ->SetNamedPropertyHandler(XPropertyGetter);
5489   LocalContext context;
5490   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5491   Local<Script> script = Script::Compile(v8_str("obj.x"));
5492   for (int i = 0; i < 10; i++) {
5493     Local<Value> result = script->Run();
5494     CHECK_EQ(result, v8_str("x"));
5495   }
5496 }
5497
5498
5499 THREADED_TEST(NamedInterceptorDictionaryIC) {
5500   v8::HandleScope scope(CcTest::isolate());
5501   Local<ObjectTemplate> templ = ObjectTemplate::New();
5502   templ->SetNamedPropertyHandler(XPropertyGetter);
5503   LocalContext context;
5504   // Create an object with a named interceptor.
5505   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5506   Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5507   for (int i = 0; i < 10; i++) {
5508     Local<Value> result = script->Run();
5509     CHECK_EQ(result, v8_str("x"));
5510   }
5511   // Create a slow case object and a function accessing a property in
5512   // that slow case object (with dictionary probing in generated
5513   // code). Then force object with a named interceptor into slow-case,
5514   // pass it to the function, and check that the interceptor is called
5515   // instead of accessing the local property.
5516   Local<Value> result =
5517       CompileRun("function get_x(o) { return o.x; };"
5518                  "var obj = { x : 42, y : 0 };"
5519                  "delete obj.y;"
5520                  "for (var i = 0; i < 10; i++) get_x(obj);"
5521                  "interceptor_obj.x = 42;"
5522                  "interceptor_obj.y = 10;"
5523                  "delete interceptor_obj.y;"
5524                  "get_x(interceptor_obj)");
5525   CHECK_EQ(result, v8_str("x"));
5526 }
5527
5528
5529 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5530   v8::Isolate* isolate = CcTest::isolate();
5531   v8::HandleScope scope(isolate);
5532   v8::Local<Context> context1 = Context::New(isolate);
5533
5534   context1->Enter();
5535   Local<ObjectTemplate> templ = ObjectTemplate::New();
5536   templ->SetNamedPropertyHandler(XPropertyGetter);
5537   // Create an object with a named interceptor.
5538   v8::Local<v8::Object> object = templ->NewInstance();
5539   context1->Global()->Set(v8_str("interceptor_obj"), object);
5540
5541   // Force the object into the slow case.
5542   CompileRun("interceptor_obj.y = 0;"
5543              "delete interceptor_obj.y;");
5544   context1->Exit();
5545
5546   {
5547     // Introduce the object into a different context.
5548     // Repeat named loads to exercise ICs.
5549     LocalContext context2;
5550     context2->Global()->Set(v8_str("interceptor_obj"), object);
5551     Local<Value> result =
5552       CompileRun("function get_x(o) { return o.x; }"
5553                  "interceptor_obj.x = 42;"
5554                  "for (var i=0; i != 10; i++) {"
5555                  "  get_x(interceptor_obj);"
5556                  "}"
5557                  "get_x(interceptor_obj)");
5558     // Check that the interceptor was actually invoked.
5559     CHECK_EQ(result, v8_str("x"));
5560   }
5561
5562   // Return to the original context and force some object to the slow case
5563   // to cause the NormalizedMapCache to verify.
5564   context1->Enter();
5565   CompileRun("var obj = { x : 0 }; delete obj.x;");
5566   context1->Exit();
5567 }
5568
5569
5570 static void SetXOnPrototypeGetter(
5571     Local<String> property,
5572     const v8::PropertyCallbackInfo<v8::Value>& info) {
5573   // Set x on the prototype object and do not handle the get request.
5574   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5575   proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
5576 }
5577
5578
5579 // This is a regression test for http://crbug.com/20104. Map
5580 // transitions should not interfere with post interceptor lookup.
5581 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5582   v8::HandleScope scope(CcTest::isolate());
5583   Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
5584   Local<v8::ObjectTemplate> instance_template
5585       = function_template->InstanceTemplate();
5586   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5587   LocalContext context;
5588   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5589   // Create an instance of F and introduce a map transition for x.
5590   CompileRun("var o = new F(); o.x = 23;");
5591   // Create an instance of F and invoke the getter. The result should be 23.
5592   Local<Value> result = CompileRun("o = new F(); o.x");
5593   CHECK_EQ(result->Int32Value(), 23);
5594 }
5595
5596
5597 static void IndexedPropertyGetter(
5598     uint32_t index,
5599     const v8::PropertyCallbackInfo<v8::Value>& info) {
5600   ApiTestFuzzer::Fuzz();
5601   if (index == 37) {
5602     info.GetReturnValue().Set(v8_num(625));
5603   }
5604 }
5605
5606
5607 static void IndexedPropertySetter(
5608     uint32_t index,
5609     Local<Value> value,
5610     const v8::PropertyCallbackInfo<v8::Value>& info) {
5611   ApiTestFuzzer::Fuzz();
5612   if (index == 39) {
5613     info.GetReturnValue().Set(value);
5614   }
5615 }
5616
5617
5618 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5619   v8::HandleScope scope(CcTest::isolate());
5620   Local<ObjectTemplate> templ = ObjectTemplate::New();
5621   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5622                                    IndexedPropertySetter);
5623   LocalContext context;
5624   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5625   Local<Script> getter_script = Script::Compile(v8_str(
5626       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5627   Local<Script> setter_script = Script::Compile(v8_str(
5628       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5629       "obj[17] = 23;"
5630       "obj.foo;"));
5631   Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5632       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5633       "obj[39] = 47;"
5634       "obj.foo;"));  // This setter should not run, due to the interceptor.
5635   Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5636       "obj[37];"));
5637   Local<Value> result = getter_script->Run();
5638   CHECK_EQ(v8_num(5), result);
5639   result = setter_script->Run();
5640   CHECK_EQ(v8_num(23), result);
5641   result = interceptor_setter_script->Run();
5642   CHECK_EQ(v8_num(23), result);
5643   result = interceptor_getter_script->Run();
5644   CHECK_EQ(v8_num(625), result);
5645 }
5646
5647
5648 static void UnboxedDoubleIndexedPropertyGetter(
5649     uint32_t index,
5650     const v8::PropertyCallbackInfo<v8::Value>& info) {
5651   ApiTestFuzzer::Fuzz();
5652   if (index < 25) {
5653     info.GetReturnValue().Set(v8_num(index));
5654   }
5655 }
5656
5657
5658 static void UnboxedDoubleIndexedPropertySetter(
5659     uint32_t index,
5660     Local<Value> value,
5661     const v8::PropertyCallbackInfo<v8::Value>& info) {
5662   ApiTestFuzzer::Fuzz();
5663   if (index < 25) {
5664     info.GetReturnValue().Set(v8_num(index));
5665   }
5666 }
5667
5668
5669 void UnboxedDoubleIndexedPropertyEnumerator(
5670     const v8::PropertyCallbackInfo<v8::Array>& info) {
5671   // Force the list of returned keys to be stored in a FastDoubleArray.
5672   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5673       "keys = new Array(); keys[125000] = 1;"
5674       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5675       "keys.length = 25; keys;"));
5676   Local<Value> result = indexed_property_names_script->Run();
5677   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5678 }
5679
5680
5681 // Make sure that the the interceptor code in the runtime properly handles
5682 // merging property name lists for double-array-backed arrays.
5683 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5684   v8::HandleScope scope(CcTest::isolate());
5685   Local<ObjectTemplate> templ = ObjectTemplate::New();
5686   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5687                                    UnboxedDoubleIndexedPropertySetter,
5688                                    0,
5689                                    0,
5690                                    UnboxedDoubleIndexedPropertyEnumerator);
5691   LocalContext context;
5692   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5693   // When obj is created, force it to be Stored in a FastDoubleArray.
5694   Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5695       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5696       "key_count = 0; "
5697       "for (x in obj) {key_count++;};"
5698       "obj;"));
5699   Local<Value> result = create_unboxed_double_script->Run();
5700   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5701   Local<Script> key_count_check = Script::Compile(v8_str(
5702       "key_count;"));
5703   result = key_count_check->Run();
5704   CHECK_EQ(v8_num(40013), result);
5705 }
5706
5707
5708 void NonStrictArgsIndexedPropertyEnumerator(
5709     const v8::PropertyCallbackInfo<v8::Array>& info) {
5710   // Force the list of returned keys to be stored in a Arguments object.
5711   Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5712       "function f(w,x) {"
5713       " return arguments;"
5714       "}"
5715       "keys = f(0, 1, 2, 3);"
5716       "keys;"));
5717   Local<Object> result =
5718       Local<Object>::Cast(indexed_property_names_script->Run());
5719   // Have to populate the handle manually, as it's not Cast-able.
5720   i::Handle<i::JSObject> o =
5721       v8::Utils::OpenHandle<Object, i::JSObject>(result);
5722   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5723   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5724 }
5725
5726
5727 static void NonStrictIndexedPropertyGetter(
5728     uint32_t index,
5729     const v8::PropertyCallbackInfo<v8::Value>& info) {
5730   ApiTestFuzzer::Fuzz();
5731   if (index < 4) {
5732     info.GetReturnValue().Set(v8_num(index));
5733   }
5734 }
5735
5736
5737 // Make sure that the the interceptor code in the runtime properly handles
5738 // merging property name lists for non-string arguments arrays.
5739 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5740   v8::HandleScope scope(CcTest::isolate());
5741   Local<ObjectTemplate> templ = ObjectTemplate::New();
5742   templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5743                                    0,
5744                                    0,
5745                                    0,
5746                                    NonStrictArgsIndexedPropertyEnumerator);
5747   LocalContext context;
5748   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5749   Local<Script> create_args_script =
5750       Script::Compile(v8_str(
5751           "var key_count = 0;"
5752           "for (x in obj) {key_count++;} key_count;"));
5753   Local<Value> result = create_args_script->Run();
5754   CHECK_EQ(v8_num(4), result);
5755 }
5756
5757
5758 static void IdentityIndexedPropertyGetter(
5759     uint32_t index,
5760     const v8::PropertyCallbackInfo<v8::Value>& info) {
5761   info.GetReturnValue().Set(index);
5762 }
5763
5764
5765 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
5766   v8::HandleScope scope(CcTest::isolate());
5767   Local<ObjectTemplate> templ = ObjectTemplate::New();
5768   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5769
5770   LocalContext context;
5771   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5772
5773   // Check fast object case.
5774   const char* fast_case_code =
5775       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
5776   ExpectString(fast_case_code, "0");
5777
5778   // Check slow case.
5779   const char* slow_case_code =
5780       "obj.x = 1; delete obj.x;"
5781       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
5782   ExpectString(slow_case_code, "1");
5783 }
5784
5785
5786 THREADED_TEST(IndexedInterceptorWithNoSetter) {
5787   v8::HandleScope scope(CcTest::isolate());
5788   Local<ObjectTemplate> templ = ObjectTemplate::New();
5789   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5790
5791   LocalContext context;
5792   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5793
5794   const char* code =
5795       "try {"
5796       "  obj[0] = 239;"
5797       "  for (var i = 0; i < 100; i++) {"
5798       "    var v = obj[0];"
5799       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
5800       "  }"
5801       "  'PASSED'"
5802       "} catch(e) {"
5803       "  e"
5804       "}";
5805   ExpectString(code, "PASSED");
5806 }
5807
5808
5809 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
5810   v8::HandleScope scope(CcTest::isolate());
5811   Local<ObjectTemplate> templ = ObjectTemplate::New();
5812   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5813
5814   LocalContext context;
5815   Local<v8::Object> obj = templ->NewInstance();
5816   obj->TurnOnAccessCheck();
5817   context->Global()->Set(v8_str("obj"), obj);
5818
5819   const char* code =
5820       "try {"
5821       "  for (var i = 0; i < 100; i++) {"
5822       "    var v = obj[0];"
5823       "    if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
5824       "  }"
5825       "  'PASSED'"
5826       "} catch(e) {"
5827       "  e"
5828       "}";
5829   ExpectString(code, "PASSED");
5830 }
5831
5832
5833 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
5834   i::FLAG_allow_natives_syntax = true;
5835   v8::HandleScope scope(CcTest::isolate());
5836   Local<ObjectTemplate> templ = ObjectTemplate::New();
5837   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5838
5839   LocalContext context;
5840   Local<v8::Object> obj = templ->NewInstance();
5841   context->Global()->Set(v8_str("obj"), obj);
5842
5843   const char* code =
5844       "try {"
5845       "  for (var i = 0; i < 100; i++) {"
5846       "    var expected = i;"
5847       "    if (i == 5) {"
5848       "      %EnableAccessChecks(obj);"
5849       "      expected = undefined;"
5850       "    }"
5851       "    var v = obj[i];"
5852       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5853       "    if (i == 5) %DisableAccessChecks(obj);"
5854       "  }"
5855       "  'PASSED'"
5856       "} catch(e) {"
5857       "  e"
5858       "}";
5859   ExpectString(code, "PASSED");
5860 }
5861
5862
5863 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
5864   v8::HandleScope scope(CcTest::isolate());
5865   Local<ObjectTemplate> templ = ObjectTemplate::New();
5866   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5867
5868   LocalContext context;
5869   Local<v8::Object> obj = templ->NewInstance();
5870   context->Global()->Set(v8_str("obj"), obj);
5871
5872   const char* code =
5873       "try {"
5874       "  for (var i = 0; i < 100; i++) {"
5875       "    var v = obj[i];"
5876       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5877       "  }"
5878       "  'PASSED'"
5879       "} catch(e) {"
5880       "  e"
5881       "}";
5882   ExpectString(code, "PASSED");
5883 }
5884
5885
5886 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
5887   v8::HandleScope scope(CcTest::isolate());
5888   Local<ObjectTemplate> templ = ObjectTemplate::New();
5889   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5890
5891   LocalContext context;
5892   Local<v8::Object> obj = templ->NewInstance();
5893   context->Global()->Set(v8_str("obj"), obj);
5894
5895   const char* code =
5896       "try {"
5897       "  for (var i = 0; i < 100; i++) {"
5898       "    var expected = i;"
5899       "    var key = i;"
5900       "    if (i == 25) {"
5901       "       key = -1;"
5902       "       expected = undefined;"
5903       "    }"
5904       "    if (i == 50) {"
5905       "       /* probe minimal Smi number on 32-bit platforms */"
5906       "       key = -(1 << 30);"
5907       "       expected = undefined;"
5908       "    }"
5909       "    if (i == 75) {"
5910       "       /* probe minimal Smi number on 64-bit platforms */"
5911       "       key = 1 << 31;"
5912       "       expected = undefined;"
5913       "    }"
5914       "    var v = obj[key];"
5915       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5916       "  }"
5917       "  'PASSED'"
5918       "} catch(e) {"
5919       "  e"
5920       "}";
5921   ExpectString(code, "PASSED");
5922 }
5923
5924
5925 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
5926   v8::HandleScope scope(CcTest::isolate());
5927   Local<ObjectTemplate> templ = ObjectTemplate::New();
5928   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5929
5930   LocalContext context;
5931   Local<v8::Object> obj = templ->NewInstance();
5932   context->Global()->Set(v8_str("obj"), obj);
5933
5934   const char* code =
5935       "try {"
5936       "  for (var i = 0; i < 100; i++) {"
5937       "    var expected = i;"
5938       "    var key = i;"
5939       "    if (i == 50) {"
5940       "       key = 'foobar';"
5941       "       expected = undefined;"
5942       "    }"
5943       "    var v = obj[key];"
5944       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5945       "  }"
5946       "  'PASSED'"
5947       "} catch(e) {"
5948       "  e"
5949       "}";
5950   ExpectString(code, "PASSED");
5951 }
5952
5953
5954 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
5955   v8::HandleScope scope(CcTest::isolate());
5956   Local<ObjectTemplate> templ = ObjectTemplate::New();
5957   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5958
5959   LocalContext context;
5960   Local<v8::Object> obj = templ->NewInstance();
5961   context->Global()->Set(v8_str("obj"), obj);
5962
5963   const char* code =
5964       "var original = obj;"
5965       "try {"
5966       "  for (var i = 0; i < 100; i++) {"
5967       "    var expected = i;"
5968       "    if (i == 50) {"
5969       "       obj = {50: 'foobar'};"
5970       "       expected = 'foobar';"
5971       "    }"
5972       "    var v = obj[i];"
5973       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5974       "    if (i == 50) obj = original;"
5975       "  }"
5976       "  'PASSED'"
5977       "} catch(e) {"
5978       "  e"
5979       "}";
5980   ExpectString(code, "PASSED");
5981 }
5982
5983
5984 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
5985   v8::HandleScope scope(CcTest::isolate());
5986   Local<ObjectTemplate> templ = ObjectTemplate::New();
5987   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5988
5989   LocalContext context;
5990   Local<v8::Object> obj = templ->NewInstance();
5991   context->Global()->Set(v8_str("obj"), obj);
5992
5993   const char* code =
5994       "var original = obj;"
5995       "try {"
5996       "  for (var i = 0; i < 100; i++) {"
5997       "    var expected = i;"
5998       "    if (i == 5) {"
5999       "       obj = 239;"
6000       "       expected = undefined;"
6001       "    }"
6002       "    var v = obj[i];"
6003       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6004       "    if (i == 5) obj = original;"
6005       "  }"
6006       "  'PASSED'"
6007       "} catch(e) {"
6008       "  e"
6009       "}";
6010   ExpectString(code, "PASSED");
6011 }
6012
6013
6014 THREADED_TEST(IndexedInterceptorOnProto) {
6015   v8::HandleScope scope(CcTest::isolate());
6016   Local<ObjectTemplate> templ = ObjectTemplate::New();
6017   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6018
6019   LocalContext context;
6020   Local<v8::Object> obj = templ->NewInstance();
6021   context->Global()->Set(v8_str("obj"), obj);
6022
6023   const char* code =
6024       "var o = {__proto__: obj};"
6025       "try {"
6026       "  for (var i = 0; i < 100; i++) {"
6027       "    var v = o[i];"
6028       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6029       "  }"
6030       "  'PASSED'"
6031       "} catch(e) {"
6032       "  e"
6033       "}";
6034   ExpectString(code, "PASSED");
6035 }
6036
6037
6038 THREADED_TEST(MultiContexts) {
6039   v8::HandleScope scope(CcTest::isolate());
6040   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
6041   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
6042
6043   Local<String> password = v8_str("Password");
6044
6045   // Create an environment
6046   LocalContext context0(0, templ);
6047   context0->SetSecurityToken(password);
6048   v8::Handle<v8::Object> global0 = context0->Global();
6049   global0->Set(v8_str("custom"), v8_num(1234));
6050   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6051
6052   // Create an independent environment
6053   LocalContext context1(0, templ);
6054   context1->SetSecurityToken(password);
6055   v8::Handle<v8::Object> global1 = context1->Global();
6056   global1->Set(v8_str("custom"), v8_num(1234));
6057   CHECK_NE(global0, global1);
6058   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6059   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6060
6061   // Now create a new context with the old global
6062   LocalContext context2(0, templ, global1);
6063   context2->SetSecurityToken(password);
6064   v8::Handle<v8::Object> global2 = context2->Global();
6065   CHECK_EQ(global1, global2);
6066   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6067   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6068 }
6069
6070
6071 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6072   // Make sure that functions created by cloning boilerplates cannot
6073   // communicate through their __proto__ field.
6074
6075   v8::HandleScope scope(CcTest::isolate());
6076
6077   LocalContext env0;
6078   v8::Handle<v8::Object> global0 =
6079       env0->Global();
6080   v8::Handle<v8::Object> object0 =
6081       global0->Get(v8_str("Object")).As<v8::Object>();
6082   v8::Handle<v8::Object> tostring0 =
6083       object0->Get(v8_str("toString")).As<v8::Object>();
6084   v8::Handle<v8::Object> proto0 =
6085       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6086   proto0->Set(v8_str("custom"), v8_num(1234));
6087
6088   LocalContext env1;
6089   v8::Handle<v8::Object> global1 =
6090       env1->Global();
6091   v8::Handle<v8::Object> object1 =
6092       global1->Get(v8_str("Object")).As<v8::Object>();
6093   v8::Handle<v8::Object> tostring1 =
6094       object1->Get(v8_str("toString")).As<v8::Object>();
6095   v8::Handle<v8::Object> proto1 =
6096       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6097   CHECK(!proto1->Has(v8_str("custom")));
6098 }
6099
6100
6101 THREADED_TEST(Regress892105) {
6102   // Make sure that object and array literals created by cloning
6103   // boilerplates cannot communicate through their __proto__
6104   // field. This is rather difficult to check, but we try to add stuff
6105   // to Object.prototype and Array.prototype and create a new
6106   // environment. This should succeed.
6107
6108   v8::HandleScope scope(CcTest::isolate());
6109
6110   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6111                                 "Array.prototype.arr = 4567;"
6112                                 "8901");
6113
6114   LocalContext env0;
6115   Local<Script> script0 = Script::Compile(source);
6116   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6117
6118   LocalContext env1;
6119   Local<Script> script1 = Script::Compile(source);
6120   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6121 }
6122
6123
6124 THREADED_TEST(UndetectableObject) {
6125   LocalContext env;
6126   v8::HandleScope scope(env->GetIsolate());
6127
6128   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6129   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6130
6131   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6132   env->Global()->Set(v8_str("undetectable"), obj);
6133
6134   ExpectString("undetectable.toString()", "[object Object]");
6135   ExpectString("typeof undetectable", "undefined");
6136   ExpectString("typeof(undetectable)", "undefined");
6137   ExpectBoolean("typeof undetectable == 'undefined'", true);
6138   ExpectBoolean("typeof undetectable == 'object'", false);
6139   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6140   ExpectBoolean("!undetectable", true);
6141
6142   ExpectObject("true&&undetectable", obj);
6143   ExpectBoolean("false&&undetectable", false);
6144   ExpectBoolean("true||undetectable", true);
6145   ExpectObject("false||undetectable", obj);
6146
6147   ExpectObject("undetectable&&true", obj);
6148   ExpectObject("undetectable&&false", obj);
6149   ExpectBoolean("undetectable||true", true);
6150   ExpectBoolean("undetectable||false", false);
6151
6152   ExpectBoolean("undetectable==null", true);
6153   ExpectBoolean("null==undetectable", true);
6154   ExpectBoolean("undetectable==undefined", true);
6155   ExpectBoolean("undefined==undetectable", true);
6156   ExpectBoolean("undetectable==undetectable", true);
6157
6158
6159   ExpectBoolean("undetectable===null", false);
6160   ExpectBoolean("null===undetectable", false);
6161   ExpectBoolean("undetectable===undefined", false);
6162   ExpectBoolean("undefined===undetectable", false);
6163   ExpectBoolean("undetectable===undetectable", true);
6164 }
6165
6166
6167 THREADED_TEST(VoidLiteral) {
6168   LocalContext env;
6169   v8::HandleScope scope(env->GetIsolate());
6170
6171   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6172   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6173
6174   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6175   env->Global()->Set(v8_str("undetectable"), obj);
6176
6177   ExpectBoolean("undefined == void 0", true);
6178   ExpectBoolean("undetectable == void 0", true);
6179   ExpectBoolean("null == void 0", true);
6180   ExpectBoolean("undefined === void 0", true);
6181   ExpectBoolean("undetectable === void 0", false);
6182   ExpectBoolean("null === void 0", false);
6183
6184   ExpectBoolean("void 0 == undefined", true);
6185   ExpectBoolean("void 0 == undetectable", true);
6186   ExpectBoolean("void 0 == null", true);
6187   ExpectBoolean("void 0 === undefined", true);
6188   ExpectBoolean("void 0 === undetectable", false);
6189   ExpectBoolean("void 0 === null", false);
6190
6191   ExpectString("(function() {"
6192                "  try {"
6193                "    return x === void 0;"
6194                "  } catch(e) {"
6195                "    return e.toString();"
6196                "  }"
6197                "})()",
6198                "ReferenceError: x is not defined");
6199   ExpectString("(function() {"
6200                "  try {"
6201                "    return void 0 === x;"
6202                "  } catch(e) {"
6203                "    return e.toString();"
6204                "  }"
6205                "})()",
6206                "ReferenceError: x is not defined");
6207 }
6208
6209
6210 THREADED_TEST(ExtensibleOnUndetectable) {
6211   LocalContext env;
6212   v8::HandleScope scope(env->GetIsolate());
6213
6214   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
6215   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6216
6217   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6218   env->Global()->Set(v8_str("undetectable"), obj);
6219
6220   Local<String> source = v8_str("undetectable.x = 42;"
6221                                 "undetectable.x");
6222
6223   Local<Script> script = Script::Compile(source);
6224
6225   CHECK_EQ(v8::Integer::New(42), script->Run());
6226
6227   ExpectBoolean("Object.isExtensible(undetectable)", true);
6228
6229   source = v8_str("Object.preventExtensions(undetectable);");
6230   script = Script::Compile(source);
6231   script->Run();
6232   ExpectBoolean("Object.isExtensible(undetectable)", false);
6233
6234   source = v8_str("undetectable.y = 2000;");
6235   script = Script::Compile(source);
6236   script->Run();
6237   ExpectBoolean("undetectable.y == undefined", true);
6238 }
6239
6240
6241
6242 THREADED_TEST(UndetectableString) {
6243   LocalContext env;
6244   v8::HandleScope scope(env->GetIsolate());
6245
6246   Local<String> obj = String::NewUndetectable("foo");
6247   env->Global()->Set(v8_str("undetectable"), obj);
6248
6249   ExpectString("undetectable", "foo");
6250   ExpectString("typeof undetectable", "undefined");
6251   ExpectString("typeof(undetectable)", "undefined");
6252   ExpectBoolean("typeof undetectable == 'undefined'", true);
6253   ExpectBoolean("typeof undetectable == 'string'", false);
6254   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6255   ExpectBoolean("!undetectable", true);
6256
6257   ExpectObject("true&&undetectable", obj);
6258   ExpectBoolean("false&&undetectable", false);
6259   ExpectBoolean("true||undetectable", true);
6260   ExpectObject("false||undetectable", obj);
6261
6262   ExpectObject("undetectable&&true", obj);
6263   ExpectObject("undetectable&&false", obj);
6264   ExpectBoolean("undetectable||true", true);
6265   ExpectBoolean("undetectable||false", false);
6266
6267   ExpectBoolean("undetectable==null", true);
6268   ExpectBoolean("null==undetectable", true);
6269   ExpectBoolean("undetectable==undefined", true);
6270   ExpectBoolean("undefined==undetectable", true);
6271   ExpectBoolean("undetectable==undetectable", true);
6272
6273
6274   ExpectBoolean("undetectable===null", false);
6275   ExpectBoolean("null===undetectable", false);
6276   ExpectBoolean("undetectable===undefined", false);
6277   ExpectBoolean("undefined===undetectable", false);
6278   ExpectBoolean("undetectable===undetectable", true);
6279 }
6280
6281
6282 TEST(UndetectableOptimized) {
6283   i::FLAG_allow_natives_syntax = true;
6284   LocalContext env;
6285   v8::HandleScope scope(env->GetIsolate());
6286
6287   Local<String> obj = String::NewUndetectable("foo");
6288   env->Global()->Set(v8_str("undetectable"), obj);
6289   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6290
6291   ExpectString(
6292       "function testBranch() {"
6293       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6294       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6295       "}\n"
6296       "function testBool() {"
6297       "  var b1 = !%_IsUndetectableObject(undetectable);"
6298       "  var b2 = %_IsUndetectableObject(detectable);"
6299       "  if (b1) throw 3;"
6300       "  if (b2) throw 4;"
6301       "  return b1 == b2;"
6302       "}\n"
6303       "%OptimizeFunctionOnNextCall(testBranch);"
6304       "%OptimizeFunctionOnNextCall(testBool);"
6305       "for (var i = 0; i < 10; i++) {"
6306       "  testBranch();"
6307       "  testBool();"
6308       "}\n"
6309       "\"PASS\"",
6310       "PASS");
6311 }
6312
6313
6314 template <typename T> static void USE(T) { }
6315
6316
6317 // This test is not intended to be run, just type checked.
6318 static inline void PersistentHandles(v8::Isolate* isolate) {
6319   USE(PersistentHandles);
6320   Local<String> str = v8_str("foo");
6321   v8::Persistent<String> p_str(isolate, str);
6322   p_str.Dispose();
6323   Local<Script> scr = Script::Compile(v8_str(""));
6324   v8::Persistent<Script> p_scr(isolate, scr);
6325   p_scr.Dispose();
6326   Local<ObjectTemplate> templ = ObjectTemplate::New();
6327   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6328   p_templ.Dispose();
6329 }
6330
6331
6332 static void HandleLogDelegator(
6333     const v8::FunctionCallbackInfo<v8::Value>& args) {
6334   ApiTestFuzzer::Fuzz();
6335 }
6336
6337
6338 THREADED_TEST(GlobalObjectTemplate) {
6339   v8::Isolate* isolate = CcTest::isolate();
6340   v8::HandleScope handle_scope(isolate);
6341   Local<ObjectTemplate> global_template = ObjectTemplate::New();
6342   global_template->Set(v8_str("JSNI_Log"),
6343                        v8::FunctionTemplate::New(HandleLogDelegator));
6344   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6345   Context::Scope context_scope(context);
6346   Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
6347 }
6348
6349
6350 static const char* kSimpleExtensionSource =
6351   "function Foo() {"
6352   "  return 4;"
6353   "}";
6354
6355
6356 THREADED_TEST(SimpleExtensions) {
6357   v8::HandleScope handle_scope(CcTest::isolate());
6358   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6359   const char* extension_names[] = { "simpletest" };
6360   v8::ExtensionConfiguration extensions(1, extension_names);
6361   v8::Handle<Context> context =
6362       Context::New(CcTest::isolate(), &extensions);
6363   Context::Scope lock(context);
6364   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6365   CHECK_EQ(result, v8::Integer::New(4));
6366 }
6367
6368
6369 THREADED_TEST(NullExtensions) {
6370   v8::HandleScope handle_scope(CcTest::isolate());
6371   v8::RegisterExtension(new Extension("nulltest", NULL));
6372   const char* extension_names[] = { "nulltest" };
6373   v8::ExtensionConfiguration extensions(1, extension_names);
6374   v8::Handle<Context> context =
6375       Context::New(CcTest::isolate(), &extensions);
6376   Context::Scope lock(context);
6377   v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
6378   CHECK_EQ(result, v8::Integer::New(4));
6379 }
6380
6381
6382 static const char* kEmbeddedExtensionSource =
6383     "function Ret54321(){return 54321;}~~@@$"
6384     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6385 static const int kEmbeddedExtensionSourceValidLen = 34;
6386
6387
6388 THREADED_TEST(ExtensionMissingSourceLength) {
6389   v8::HandleScope handle_scope(CcTest::isolate());
6390   v8::RegisterExtension(new Extension("srclentest_fail",
6391                                       kEmbeddedExtensionSource));
6392   const char* extension_names[] = { "srclentest_fail" };
6393   v8::ExtensionConfiguration extensions(1, extension_names);
6394   v8::Handle<Context> context =
6395       Context::New(CcTest::isolate(), &extensions);
6396   CHECK_EQ(0, *context);
6397 }
6398
6399
6400 THREADED_TEST(ExtensionWithSourceLength) {
6401   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6402        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6403     v8::HandleScope handle_scope(CcTest::isolate());
6404     i::ScopedVector<char> extension_name(32);
6405     i::OS::SNPrintF(extension_name, "ext #%d", source_len);
6406     v8::RegisterExtension(new Extension(extension_name.start(),
6407                                         kEmbeddedExtensionSource, 0, 0,
6408                                         source_len));
6409     const char* extension_names[1] = { extension_name.start() };
6410     v8::ExtensionConfiguration extensions(1, extension_names);
6411     v8::Handle<Context> context =
6412       Context::New(CcTest::isolate(), &extensions);
6413     if (source_len == kEmbeddedExtensionSourceValidLen) {
6414       Context::Scope lock(context);
6415       v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6416       CHECK_EQ(v8::Integer::New(54321), result);
6417     } else {
6418       // Anything but exactly the right length should fail to compile.
6419       CHECK_EQ(0, *context);
6420     }
6421   }
6422 }
6423
6424
6425 static const char* kEvalExtensionSource1 =
6426   "function UseEval1() {"
6427   "  var x = 42;"
6428   "  return eval('x');"
6429   "}";
6430
6431
6432 static const char* kEvalExtensionSource2 =
6433   "(function() {"
6434   "  var x = 42;"
6435   "  function e() {"
6436   "    return eval('x');"
6437   "  }"
6438   "  this.UseEval2 = e;"
6439   "})()";
6440
6441
6442 THREADED_TEST(UseEvalFromExtension) {
6443   v8::HandleScope handle_scope(CcTest::isolate());
6444   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6445   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6446   const char* extension_names[] = { "evaltest1", "evaltest2" };
6447   v8::ExtensionConfiguration extensions(2, extension_names);
6448   v8::Handle<Context> context =
6449       Context::New(CcTest::isolate(), &extensions);
6450   Context::Scope lock(context);
6451   v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6452   CHECK_EQ(result, v8::Integer::New(42));
6453   result = Script::Compile(v8_str("UseEval2()"))->Run();
6454   CHECK_EQ(result, v8::Integer::New(42));
6455 }
6456
6457
6458 static const char* kWithExtensionSource1 =
6459   "function UseWith1() {"
6460   "  var x = 42;"
6461   "  with({x:87}) { return x; }"
6462   "}";
6463
6464
6465
6466 static const char* kWithExtensionSource2 =
6467   "(function() {"
6468   "  var x = 42;"
6469   "  function e() {"
6470   "    with ({x:87}) { return x; }"
6471   "  }"
6472   "  this.UseWith2 = e;"
6473   "})()";
6474
6475
6476 THREADED_TEST(UseWithFromExtension) {
6477   v8::HandleScope handle_scope(CcTest::isolate());
6478   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6479   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6480   const char* extension_names[] = { "withtest1", "withtest2" };
6481   v8::ExtensionConfiguration extensions(2, extension_names);
6482   v8::Handle<Context> context =
6483       Context::New(CcTest::isolate(), &extensions);
6484   Context::Scope lock(context);
6485   v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6486   CHECK_EQ(result, v8::Integer::New(87));
6487   result = Script::Compile(v8_str("UseWith2()"))->Run();
6488   CHECK_EQ(result, v8::Integer::New(87));
6489 }
6490
6491
6492 THREADED_TEST(AutoExtensions) {
6493   v8::HandleScope handle_scope(CcTest::isolate());
6494   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6495   extension->set_auto_enable(true);
6496   v8::RegisterExtension(extension);
6497   v8::Handle<Context> context =
6498       Context::New(CcTest::isolate());
6499   Context::Scope lock(context);
6500   v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6501   CHECK_EQ(result, v8::Integer::New(4));
6502 }
6503
6504
6505 static const char* kSyntaxErrorInExtensionSource =
6506     "[";
6507
6508
6509 // Test that a syntax error in an extension does not cause a fatal
6510 // error but results in an empty context.
6511 THREADED_TEST(SyntaxErrorExtensions) {
6512   v8::HandleScope handle_scope(CcTest::isolate());
6513   v8::RegisterExtension(new Extension("syntaxerror",
6514                                       kSyntaxErrorInExtensionSource));
6515   const char* extension_names[] = { "syntaxerror" };
6516   v8::ExtensionConfiguration extensions(1, extension_names);
6517   v8::Handle<Context> context =
6518       Context::New(CcTest::isolate(), &extensions);
6519   CHECK(context.IsEmpty());
6520 }
6521
6522
6523 static const char* kExceptionInExtensionSource =
6524     "throw 42";
6525
6526
6527 // Test that an exception when installing an extension does not cause
6528 // a fatal error but results in an empty context.
6529 THREADED_TEST(ExceptionExtensions) {
6530   v8::HandleScope handle_scope(CcTest::isolate());
6531   v8::RegisterExtension(new Extension("exception",
6532                                       kExceptionInExtensionSource));
6533   const char* extension_names[] = { "exception" };
6534   v8::ExtensionConfiguration extensions(1, extension_names);
6535   v8::Handle<Context> context =
6536       Context::New(CcTest::isolate(), &extensions);
6537   CHECK(context.IsEmpty());
6538 }
6539
6540
6541 static const char* kNativeCallInExtensionSource =
6542     "function call_runtime_last_index_of(x) {"
6543     "  return %StringLastIndexOf(x, 'bob', 10);"
6544     "}";
6545
6546
6547 static const char* kNativeCallTest =
6548     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6549
6550 // Test that a native runtime calls are supported in extensions.
6551 THREADED_TEST(NativeCallInExtensions) {
6552   v8::HandleScope handle_scope(CcTest::isolate());
6553   v8::RegisterExtension(new Extension("nativecall",
6554                                       kNativeCallInExtensionSource));
6555   const char* extension_names[] = { "nativecall" };
6556   v8::ExtensionConfiguration extensions(1, extension_names);
6557   v8::Handle<Context> context =
6558       Context::New(CcTest::isolate(), &extensions);
6559   Context::Scope lock(context);
6560   v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6561   CHECK_EQ(result, v8::Integer::New(3));
6562 }
6563
6564
6565 class NativeFunctionExtension : public Extension {
6566  public:
6567   NativeFunctionExtension(const char* name,
6568                           const char* source,
6569                           v8::FunctionCallback fun = &Echo)
6570       : Extension(name, source),
6571         function_(fun) { }
6572
6573   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6574       v8::Handle<v8::String> name) {
6575     return v8::FunctionTemplate::New(function_);
6576   }
6577
6578   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6579     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6580   }
6581  private:
6582   v8::FunctionCallback function_;
6583 };
6584
6585
6586 THREADED_TEST(NativeFunctionDeclaration) {
6587   v8::HandleScope handle_scope(CcTest::isolate());
6588   const char* name = "nativedecl";
6589   v8::RegisterExtension(new NativeFunctionExtension(name,
6590                                                     "native function foo();"));
6591   const char* extension_names[] = { name };
6592   v8::ExtensionConfiguration extensions(1, extension_names);
6593   v8::Handle<Context> context =
6594       Context::New(CcTest::isolate(), &extensions);
6595   Context::Scope lock(context);
6596   v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6597   CHECK_EQ(result, v8::Integer::New(42));
6598 }
6599
6600
6601 THREADED_TEST(NativeFunctionDeclarationError) {
6602   v8::HandleScope handle_scope(CcTest::isolate());
6603   const char* name = "nativedeclerr";
6604   // Syntax error in extension code.
6605   v8::RegisterExtension(new NativeFunctionExtension(name,
6606                                                     "native\nfunction foo();"));
6607   const char* extension_names[] = { name };
6608   v8::ExtensionConfiguration extensions(1, extension_names);
6609   v8::Handle<Context> context =
6610       Context::New(CcTest::isolate(), &extensions);
6611   CHECK(context.IsEmpty());
6612 }
6613
6614
6615 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6616   v8::HandleScope handle_scope(CcTest::isolate());
6617   const char* name = "nativedeclerresc";
6618   // Syntax error in extension code - escape code in "native" means that
6619   // it's not treated as a keyword.
6620   v8::RegisterExtension(new NativeFunctionExtension(
6621       name,
6622       "nativ\\u0065 function foo();"));
6623   const char* extension_names[] = { name };
6624   v8::ExtensionConfiguration extensions(1, extension_names);
6625   v8::Handle<Context> context =
6626       Context::New(CcTest::isolate(), &extensions);
6627   CHECK(context.IsEmpty());
6628 }
6629
6630
6631 static void CheckDependencies(const char* name, const char* expected) {
6632   v8::HandleScope handle_scope(CcTest::isolate());
6633   v8::ExtensionConfiguration config(1, &name);
6634   LocalContext context(&config);
6635   CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
6636 }
6637
6638
6639 /*
6640  * Configuration:
6641  *
6642  *     /-- B <--\
6643  * A <-          -- D <-- E
6644  *     \-- C <--/
6645  */
6646 THREADED_TEST(ExtensionDependency) {
6647   static const char* kEDeps[] = { "D" };
6648   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6649   static const char* kDDeps[] = { "B", "C" };
6650   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6651   static const char* kBCDeps[] = { "A" };
6652   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6653   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6654   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6655   CheckDependencies("A", "undefinedA");
6656   CheckDependencies("B", "undefinedAB");
6657   CheckDependencies("C", "undefinedAC");
6658   CheckDependencies("D", "undefinedABCD");
6659   CheckDependencies("E", "undefinedABCDE");
6660   v8::HandleScope handle_scope(CcTest::isolate());
6661   static const char* exts[2] = { "C", "E" };
6662   v8::ExtensionConfiguration config(2, exts);
6663   LocalContext context(&config);
6664   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6665 }
6666
6667
6668 static const char* kExtensionTestScript =
6669   "native function A();"
6670   "native function B();"
6671   "native function C();"
6672   "function Foo(i) {"
6673   "  if (i == 0) return A();"
6674   "  if (i == 1) return B();"
6675   "  if (i == 2) return C();"
6676   "}";
6677
6678
6679 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6680   ApiTestFuzzer::Fuzz();
6681   if (args.IsConstructCall()) {
6682     args.This()->Set(v8_str("data"), args.Data());
6683     args.GetReturnValue().SetNull();
6684     return;
6685   }
6686   args.GetReturnValue().Set(args.Data());
6687 }
6688
6689
6690 class FunctionExtension : public Extension {
6691  public:
6692   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6693   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6694       v8::Handle<String> name);
6695 };
6696
6697
6698 static int lookup_count = 0;
6699 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
6700       v8::Handle<String> name) {
6701   lookup_count++;
6702   if (name->Equals(v8_str("A"))) {
6703     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
6704   } else if (name->Equals(v8_str("B"))) {
6705     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
6706   } else if (name->Equals(v8_str("C"))) {
6707     return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
6708   } else {
6709     return v8::Handle<v8::FunctionTemplate>();
6710   }
6711 }
6712
6713
6714 THREADED_TEST(FunctionLookup) {
6715   v8::RegisterExtension(new FunctionExtension());
6716   v8::HandleScope handle_scope(CcTest::isolate());
6717   static const char* exts[1] = { "functiontest" };
6718   v8::ExtensionConfiguration config(1, exts);
6719   LocalContext context(&config);
6720   CHECK_EQ(3, lookup_count);
6721   CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
6722   CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
6723   CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
6724 }
6725
6726
6727 THREADED_TEST(NativeFunctionConstructCall) {
6728   v8::RegisterExtension(new FunctionExtension());
6729   v8::HandleScope handle_scope(CcTest::isolate());
6730   static const char* exts[1] = { "functiontest" };
6731   v8::ExtensionConfiguration config(1, exts);
6732   LocalContext context(&config);
6733   for (int i = 0; i < 10; i++) {
6734     // Run a few times to ensure that allocation of objects doesn't
6735     // change behavior of a constructor function.
6736     CHECK_EQ(v8::Integer::New(8),
6737              Script::Compile(v8_str("(new A()).data"))->Run());
6738     CHECK_EQ(v8::Integer::New(7),
6739              Script::Compile(v8_str("(new B()).data"))->Run());
6740     CHECK_EQ(v8::Integer::New(6),
6741              Script::Compile(v8_str("(new C()).data"))->Run());
6742   }
6743 }
6744
6745
6746 static const char* last_location;
6747 static const char* last_message;
6748 void StoringErrorCallback(const char* location, const char* message) {
6749   if (last_location == NULL) {
6750     last_location = location;
6751     last_message = message;
6752   }
6753 }
6754
6755
6756 // ErrorReporting creates a circular extensions configuration and
6757 // tests that the fatal error handler gets called.  This renders V8
6758 // unusable and therefore this test cannot be run in parallel.
6759 TEST(ErrorReporting) {
6760   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6761   static const char* aDeps[] = { "B" };
6762   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6763   static const char* bDeps[] = { "A" };
6764   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6765   last_location = NULL;
6766   v8::ExtensionConfiguration config(1, bDeps);
6767   v8::Handle<Context> context =
6768       Context::New(CcTest::isolate(), &config);
6769   CHECK(context.IsEmpty());
6770   CHECK_NE(last_location, NULL);
6771 }
6772
6773
6774 static const char* js_code_causing_huge_string_flattening =
6775     "var str = 'X';"
6776     "for (var i = 0; i < 30; i++) {"
6777     "  str = str + str;"
6778     "}"
6779     "str.match(/X/);";
6780
6781
6782 void OOMCallback(const char* location, const char* message) {
6783   exit(0);
6784 }
6785
6786
6787 TEST(RegexpOutOfMemory) {
6788   // Execute a script that causes out of memory when flattening a string.
6789   v8::HandleScope scope(CcTest::isolate());
6790   v8::V8::SetFatalErrorHandler(OOMCallback);
6791   LocalContext context;
6792   Local<Script> script =
6793       Script::Compile(String::New(js_code_causing_huge_string_flattening));
6794   last_location = NULL;
6795   script->Run();
6796
6797   CHECK(false);  // Should not return.
6798 }
6799
6800
6801 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6802                                              v8::Handle<Value> data) {
6803   CHECK(message->GetScriptResourceName()->IsUndefined());
6804   CHECK_EQ(v8::Undefined(CcTest::isolate()), message->GetScriptResourceName());
6805   message->GetLineNumber();
6806   message->GetSourceLine();
6807 }
6808
6809
6810 THREADED_TEST(ErrorWithMissingScriptInfo) {
6811   LocalContext context;
6812   v8::HandleScope scope(context->GetIsolate());
6813   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6814   Script::Compile(v8_str("throw Error()"))->Run();
6815   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6816 }
6817
6818
6819 int global_index = 0;
6820
6821 class Snorkel {
6822  public:
6823   Snorkel() { index_ = global_index++; }
6824   int index_;
6825 };
6826
6827 class Whammy {
6828  public:
6829   explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
6830   ~Whammy() { script_.Dispose(); }
6831   v8::Handle<Script> getScript() {
6832     if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
6833     return Local<Script>::New(isolate_, script_);
6834   }
6835
6836  public:
6837   static const int kObjectCount = 256;
6838   int cursor_;
6839   v8::Isolate* isolate_;
6840   v8::Persistent<v8::Object> objects_[kObjectCount];
6841   v8::Persistent<Script> script_;
6842 };
6843
6844 static void HandleWeakReference(v8::Isolate* isolate,
6845                                 v8::Persistent<v8::Value>* obj,
6846                                 Snorkel* snorkel) {
6847   delete snorkel;
6848   obj->ClearWeak();
6849 }
6850
6851 void WhammyPropertyGetter(Local<String> name,
6852                           const v8::PropertyCallbackInfo<v8::Value>& info) {
6853   Whammy* whammy =
6854     static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
6855
6856   v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
6857
6858   v8::Handle<v8::Object> obj = v8::Object::New();
6859   if (!prev.IsEmpty()) {
6860     v8::Local<v8::Object>::New(info.GetIsolate(), prev)
6861         ->Set(v8_str("next"), obj);
6862     prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference);
6863     whammy->objects_[whammy->cursor_].Clear();
6864   }
6865   whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
6866   whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
6867   info.GetReturnValue().Set(whammy->getScript()->Run());
6868 }
6869
6870
6871 THREADED_TEST(WeakReference) {
6872   v8::HandleScope handle_scope(CcTest::isolate());
6873   v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
6874   Whammy* whammy = new Whammy(CcTest::isolate());
6875   templ->SetNamedPropertyHandler(WhammyPropertyGetter,
6876                                  0, 0, 0, 0,
6877                                  v8::External::New(whammy));
6878   const char* extension_list[] = { "v8/gc" };
6879   v8::ExtensionConfiguration extensions(1, extension_list);
6880   v8::Handle<Context> context =
6881       Context::New(CcTest::isolate(), &extensions);
6882   Context::Scope context_scope(context);
6883
6884   v8::Handle<v8::Object> interceptor = templ->NewInstance();
6885   context->Global()->Set(v8_str("whammy"), interceptor);
6886   const char* code =
6887       "var last;"
6888       "for (var i = 0; i < 10000; i++) {"
6889       "  var obj = whammy.length;"
6890       "  if (last) last.next = obj;"
6891       "  last = obj;"
6892       "}"
6893       "gc();"
6894       "4";
6895   v8::Handle<Value> result = CompileRun(code);
6896   CHECK_EQ(4.0, result->NumberValue());
6897   delete whammy;
6898 }
6899
6900
6901 static void DisposeAndSetFlag(v8::Isolate* isolate,
6902                               v8::Persistent<v8::Object>* obj,
6903                               bool* data) {
6904   obj->Dispose();
6905   *(data) = true;
6906 }
6907
6908
6909 THREADED_TEST(IndependentWeakHandle) {
6910   v8::Isolate* iso = CcTest::isolate();
6911   v8::HandleScope scope(iso);
6912   v8::Handle<Context> context = Context::New(iso);
6913   Context::Scope context_scope(context);
6914
6915   v8::Persistent<v8::Object> object_a, object_b;
6916
6917   {
6918     v8::HandleScope handle_scope(iso);
6919     object_a.Reset(iso, v8::Object::New());
6920     object_b.Reset(iso, v8::Object::New());
6921   }
6922
6923   bool object_a_disposed = false;
6924   bool object_b_disposed = false;
6925   object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
6926   object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
6927   CHECK(!object_b.IsIndependent());
6928   object_a.MarkIndependent();
6929   object_b.MarkIndependent();
6930   CHECK(object_b.IsIndependent());
6931   CcTest::heap()->PerformScavenge();
6932   CHECK(object_a_disposed);
6933   CHECK(object_b_disposed);
6934 }
6935
6936
6937 static void InvokeScavenge() {
6938   CcTest::heap()->PerformScavenge();
6939 }
6940
6941
6942 static void InvokeMarkSweep() {
6943   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6944 }
6945
6946
6947 static void ForceScavenge(v8::Isolate* isolate,
6948                           v8::Persistent<v8::Object>* obj,
6949                           bool* data) {
6950   obj->Dispose();
6951   *(data) = true;
6952   InvokeScavenge();
6953 }
6954
6955
6956 static void ForceMarkSweep(v8::Isolate* isolate,
6957                            v8::Persistent<v8::Object>* obj,
6958                            bool* data) {
6959   obj->Dispose();
6960   *(data) = true;
6961   InvokeMarkSweep();
6962 }
6963
6964
6965 THREADED_TEST(GCFromWeakCallbacks) {
6966   v8::Isolate* isolate = CcTest::isolate();
6967   v8::HandleScope scope(isolate);
6968   v8::Handle<Context> context = Context::New(isolate);
6969   Context::Scope context_scope(context);
6970
6971   static const int kNumberOfGCTypes = 2;
6972   typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback;
6973   Callback gc_forcing_callback[kNumberOfGCTypes] =
6974       {&ForceScavenge, &ForceMarkSweep};
6975
6976   typedef void (*GCInvoker)();
6977   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6978
6979   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6980     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6981       v8::Persistent<v8::Object> object;
6982       {
6983         v8::HandleScope handle_scope(isolate);
6984         object.Reset(isolate, v8::Object::New());
6985       }
6986       bool disposed = false;
6987       object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
6988       object.MarkIndependent();
6989       invoke_gc[outer_gc]();
6990       CHECK(disposed);
6991     }
6992   }
6993 }
6994
6995
6996 static void RevivingCallback(v8::Isolate* isolate,
6997                              v8::Persistent<v8::Object>* obj,
6998                              bool* data) {
6999   obj->ClearWeak();
7000   *(data) = true;
7001 }
7002
7003
7004 THREADED_TEST(IndependentHandleRevival) {
7005   v8::Isolate* isolate = CcTest::isolate();
7006   v8::HandleScope scope(isolate);
7007   v8::Handle<Context> context = Context::New(isolate);
7008   Context::Scope context_scope(context);
7009
7010   v8::Persistent<v8::Object> object;
7011   {
7012     v8::HandleScope handle_scope(isolate);
7013     v8::Local<v8::Object> o = v8::Object::New();
7014     object.Reset(isolate, o);
7015     o->Set(v8_str("x"), v8::Integer::New(1));
7016     v8::Local<String> y_str = v8_str("y");
7017     o->Set(y_str, y_str);
7018   }
7019   bool revived = false;
7020   object.MakeWeak(&revived, &RevivingCallback);
7021   object.MarkIndependent();
7022   CcTest::heap()->PerformScavenge();
7023   CHECK(revived);
7024   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7025   {
7026     v8::HandleScope handle_scope(isolate);
7027     v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object);
7028     v8::Local<String> y_str = v8_str("y");
7029     CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x")));
7030     CHECK(o->Get(y_str)->Equals(y_str));
7031   }
7032 }
7033
7034
7035 v8::Handle<Function> args_fun;
7036
7037
7038 static void ArgumentsTestCallback(
7039     const v8::FunctionCallbackInfo<v8::Value>& args) {
7040   ApiTestFuzzer::Fuzz();
7041   v8::Isolate* isolate = args.GetIsolate();
7042   CHECK_EQ(args_fun, args.Callee());
7043   CHECK_EQ(3, args.Length());
7044   CHECK_EQ(v8::Integer::New(1, isolate), args[0]);
7045   CHECK_EQ(v8::Integer::New(2, isolate), args[1]);
7046   CHECK_EQ(v8::Integer::New(3, isolate), args[2]);
7047   CHECK_EQ(v8::Undefined(isolate), args[3]);
7048   v8::HandleScope scope(args.GetIsolate());
7049   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7050 }
7051
7052
7053 THREADED_TEST(Arguments) {
7054   v8::HandleScope scope(CcTest::isolate());
7055   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
7056   global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
7057   LocalContext context(NULL, global);
7058   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7059   v8_compile("f(1, 2, 3)")->Run();
7060 }
7061
7062
7063 static void NoBlockGetterX(Local<String> name,
7064                            const v8::PropertyCallbackInfo<v8::Value>&) {
7065 }
7066
7067
7068 static void NoBlockGetterI(uint32_t index,
7069                            const v8::PropertyCallbackInfo<v8::Value>&) {
7070 }
7071
7072
7073 static void PDeleter(Local<String> name,
7074                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7075   if (!name->Equals(v8_str("foo"))) {
7076     return;  // not intercepted
7077   }
7078
7079   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7080 }
7081
7082
7083 static void IDeleter(uint32_t index,
7084                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7085   if (index != 2) {
7086     return;  // not intercepted
7087   }
7088
7089   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7090 }
7091
7092
7093 THREADED_TEST(Deleter) {
7094   v8::HandleScope scope(CcTest::isolate());
7095   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7096   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7097   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7098   LocalContext context;
7099   context->Global()->Set(v8_str("k"), obj->NewInstance());
7100   CompileRun(
7101     "k.foo = 'foo';"
7102     "k.bar = 'bar';"
7103     "k[2] = 2;"
7104     "k[4] = 4;");
7105   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7106   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7107
7108   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7109   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7110
7111   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7112   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7113
7114   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7115   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7116 }
7117
7118
7119 static void GetK(Local<String> name,
7120                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7121   ApiTestFuzzer::Fuzz();
7122   if (name->Equals(v8_str("foo")) ||
7123       name->Equals(v8_str("bar")) ||
7124       name->Equals(v8_str("baz"))) {
7125     info.GetReturnValue().SetUndefined();
7126   }
7127 }
7128
7129
7130 static void IndexedGetK(uint32_t index,
7131                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7132   ApiTestFuzzer::Fuzz();
7133   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7134 }
7135
7136
7137 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7138   ApiTestFuzzer::Fuzz();
7139   v8::Handle<v8::Array> result = v8::Array::New(3);
7140   result->Set(v8::Integer::New(0), v8_str("foo"));
7141   result->Set(v8::Integer::New(1), v8_str("bar"));
7142   result->Set(v8::Integer::New(2), v8_str("baz"));
7143   info.GetReturnValue().Set(result);
7144 }
7145
7146
7147 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7148   ApiTestFuzzer::Fuzz();
7149   v8::Handle<v8::Array> result = v8::Array::New(2);
7150   result->Set(v8::Integer::New(0), v8_str("0"));
7151   result->Set(v8::Integer::New(1), v8_str("1"));
7152   info.GetReturnValue().Set(result);
7153 }
7154
7155
7156 THREADED_TEST(Enumerators) {
7157   v8::HandleScope scope(CcTest::isolate());
7158   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7159   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7160   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7161   LocalContext context;
7162   context->Global()->Set(v8_str("k"), obj->NewInstance());
7163   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7164     "k[10] = 0;"
7165     "k.a = 0;"
7166     "k[5] = 0;"
7167     "k.b = 0;"
7168     "k[4294967295] = 0;"
7169     "k.c = 0;"
7170     "k[4294967296] = 0;"
7171     "k.d = 0;"
7172     "k[140000] = 0;"
7173     "k.e = 0;"
7174     "k[30000000000] = 0;"
7175     "k.f = 0;"
7176     "var result = [];"
7177     "for (var prop in k) {"
7178     "  result.push(prop);"
7179     "}"
7180     "result"));
7181   // Check that we get all the property names returned including the
7182   // ones from the enumerators in the right order: indexed properties
7183   // in numerical order, indexed interceptor properties, named
7184   // properties in insertion order, named interceptor properties.
7185   // This order is not mandated by the spec, so this test is just
7186   // documenting our behavior.
7187   CHECK_EQ(17, result->Length());
7188   // Indexed properties in numerical order.
7189   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
7190   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
7191   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
7192   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
7193   // Indexed interceptor properties in the order they are returned
7194   // from the enumerator interceptor.
7195   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
7196   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
7197   // Named properties in insertion order.
7198   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
7199   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
7200   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
7201   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
7202   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
7203   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
7204   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
7205   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
7206   // Named interceptor properties.
7207   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
7208   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
7209   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
7210 }
7211
7212
7213 int p_getter_count;
7214 int p_getter_count2;
7215
7216
7217 static void PGetter(Local<String> name,
7218                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7219   ApiTestFuzzer::Fuzz();
7220   p_getter_count++;
7221   v8::Handle<v8::Object> global =
7222       info.GetIsolate()->GetCurrentContext()->Global();
7223   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7224   if (name->Equals(v8_str("p1"))) {
7225     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7226   } else if (name->Equals(v8_str("p2"))) {
7227     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7228   } else if (name->Equals(v8_str("p3"))) {
7229     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7230   } else if (name->Equals(v8_str("p4"))) {
7231     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7232   }
7233 }
7234
7235
7236 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7237   ApiTestFuzzer::Fuzz();
7238   LocalContext context;
7239   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7240   CompileRun(
7241     "o1.__proto__ = { };"
7242     "var o2 = { __proto__: o1 };"
7243     "var o3 = { __proto__: o2 };"
7244     "var o4 = { __proto__: o3 };"
7245     "for (var i = 0; i < 10; i++) o4.p4;"
7246     "for (var i = 0; i < 10; i++) o3.p3;"
7247     "for (var i = 0; i < 10; i++) o2.p2;"
7248     "for (var i = 0; i < 10; i++) o1.p1;");
7249 }
7250
7251
7252 static void PGetter2(Local<String> name,
7253                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7254   ApiTestFuzzer::Fuzz();
7255   p_getter_count2++;
7256   v8::Handle<v8::Object> global =
7257       info.GetIsolate()->GetCurrentContext()->Global();
7258   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7259   if (name->Equals(v8_str("p1"))) {
7260     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7261   } else if (name->Equals(v8_str("p2"))) {
7262     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7263   } else if (name->Equals(v8_str("p3"))) {
7264     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7265   } else if (name->Equals(v8_str("p4"))) {
7266     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7267   }
7268 }
7269
7270
7271 THREADED_TEST(GetterHolders) {
7272   v8::HandleScope scope(CcTest::isolate());
7273   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7274   obj->SetAccessor(v8_str("p1"), PGetter);
7275   obj->SetAccessor(v8_str("p2"), PGetter);
7276   obj->SetAccessor(v8_str("p3"), PGetter);
7277   obj->SetAccessor(v8_str("p4"), PGetter);
7278   p_getter_count = 0;
7279   RunHolderTest(obj);
7280   CHECK_EQ(40, p_getter_count);
7281 }
7282
7283
7284 THREADED_TEST(PreInterceptorHolders) {
7285   v8::HandleScope scope(CcTest::isolate());
7286   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7287   obj->SetNamedPropertyHandler(PGetter2);
7288   p_getter_count2 = 0;
7289   RunHolderTest(obj);
7290   CHECK_EQ(40, p_getter_count2);
7291 }
7292
7293
7294 THREADED_TEST(ObjectInstantiation) {
7295   v8::Isolate* isolate = CcTest::isolate();
7296   v8::HandleScope scope(isolate);
7297   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
7298   templ->SetAccessor(v8_str("t"), PGetter2);
7299   LocalContext context;
7300   context->Global()->Set(v8_str("o"), templ->NewInstance());
7301   for (int i = 0; i < 100; i++) {
7302     v8::HandleScope inner_scope(CcTest::isolate());
7303     v8::Handle<v8::Object> obj = templ->NewInstance();
7304     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7305     context->Global()->Set(v8_str("o2"), obj);
7306     v8::Handle<Value> value =
7307         Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
7308     CHECK_EQ(v8::True(isolate), value);
7309     context->Global()->Set(v8_str("o"), obj);
7310   }
7311 }
7312
7313
7314 static int StrCmp16(uint16_t* a, uint16_t* b) {
7315   while (true) {
7316     if (*a == 0 && *b == 0) return 0;
7317     if (*a != *b) return 0 + *a - *b;
7318     a++;
7319     b++;
7320   }
7321 }
7322
7323
7324 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7325   while (true) {
7326     if (n-- == 0) return 0;
7327     if (*a == 0 && *b == 0) return 0;
7328     if (*a != *b) return 0 + *a - *b;
7329     a++;
7330     b++;
7331   }
7332 }
7333
7334
7335 int GetUtf8Length(Handle<String> str) {
7336   int len = str->Utf8Length();
7337   if (len < 0) {
7338     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7339     i::FlattenString(istr);
7340     len = str->Utf8Length();
7341   }
7342   return len;
7343 }
7344
7345
7346 THREADED_TEST(StringWrite) {
7347   LocalContext context;
7348   v8::HandleScope scope(context->GetIsolate());
7349   v8::Handle<String> str = v8_str("abcde");
7350   // abc<Icelandic eth><Unicode snowman>.
7351   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7352   v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
7353   const int kStride = 4;  // Must match stride in for loops in JS below.
7354   CompileRun(
7355       "var left = '';"
7356       "for (var i = 0; i < 0xd800; i += 4) {"
7357       "  left = left + String.fromCharCode(i);"
7358       "}");
7359   CompileRun(
7360       "var right = '';"
7361       "for (var i = 0; i < 0xd800; i += 4) {"
7362       "  right = String.fromCharCode(i) + right;"
7363       "}");
7364   v8::Handle<v8::Object> global = context->Global();
7365   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7366   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7367
7368   CHECK_EQ(5, str2->Length());
7369   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7370   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7371
7372   char buf[100];
7373   char utf8buf[0xd800 * 3];
7374   uint16_t wbuf[100];
7375   int len;
7376   int charlen;
7377
7378   memset(utf8buf, 0x1, 1000);
7379   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7380   CHECK_EQ(9, len);
7381   CHECK_EQ(5, charlen);
7382   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7383
7384   memset(utf8buf, 0x1, 1000);
7385   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7386   CHECK_EQ(8, len);
7387   CHECK_EQ(5, charlen);
7388   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7389
7390   memset(utf8buf, 0x1, 1000);
7391   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7392   CHECK_EQ(5, len);
7393   CHECK_EQ(4, charlen);
7394   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7395
7396   memset(utf8buf, 0x1, 1000);
7397   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7398   CHECK_EQ(5, len);
7399   CHECK_EQ(4, charlen);
7400   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7401
7402   memset(utf8buf, 0x1, 1000);
7403   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7404   CHECK_EQ(5, len);
7405   CHECK_EQ(4, charlen);
7406   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7407
7408   memset(utf8buf, 0x1, 1000);
7409   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7410   CHECK_EQ(3, len);
7411   CHECK_EQ(3, charlen);
7412   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7413
7414   memset(utf8buf, 0x1, 1000);
7415   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7416   CHECK_EQ(3, len);
7417   CHECK_EQ(3, charlen);
7418   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7419
7420   memset(utf8buf, 0x1, 1000);
7421   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7422   CHECK_EQ(2, len);
7423   CHECK_EQ(2, charlen);
7424   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7425
7426   memset(utf8buf, 0x1, sizeof(utf8buf));
7427   len = GetUtf8Length(left_tree);
7428   int utf8_expected =
7429       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7430   CHECK_EQ(utf8_expected, len);
7431   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7432   CHECK_EQ(utf8_expected, len);
7433   CHECK_EQ(0xd800 / kStride, charlen);
7434   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7435   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7436   CHECK_EQ(0xc0 - kStride,
7437            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7438   CHECK_EQ(1, utf8buf[utf8_expected]);
7439
7440   memset(utf8buf, 0x1, sizeof(utf8buf));
7441   len = GetUtf8Length(right_tree);
7442   CHECK_EQ(utf8_expected, len);
7443   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7444   CHECK_EQ(utf8_expected, len);
7445   CHECK_EQ(0xd800 / kStride, charlen);
7446   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7447   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7448   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7449   CHECK_EQ(1, utf8buf[utf8_expected]);
7450
7451   memset(buf, 0x1, sizeof(buf));
7452   memset(wbuf, 0x1, sizeof(wbuf));
7453   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7454   CHECK_EQ(5, len);
7455   len = str->Write(wbuf);
7456   CHECK_EQ(5, len);
7457   CHECK_EQ(0, strcmp("abcde", buf));
7458   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7459   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7460
7461   memset(buf, 0x1, sizeof(buf));
7462   memset(wbuf, 0x1, sizeof(wbuf));
7463   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7464   CHECK_EQ(4, len);
7465   len = str->Write(wbuf, 0, 4);
7466   CHECK_EQ(4, len);
7467   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7468   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7469   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7470
7471   memset(buf, 0x1, sizeof(buf));
7472   memset(wbuf, 0x1, sizeof(wbuf));
7473   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7474   CHECK_EQ(5, len);
7475   len = str->Write(wbuf, 0, 5);
7476   CHECK_EQ(5, len);
7477   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7478   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7479   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7480
7481   memset(buf, 0x1, sizeof(buf));
7482   memset(wbuf, 0x1, sizeof(wbuf));
7483   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7484   CHECK_EQ(5, len);
7485   len = str->Write(wbuf, 0, 6);
7486   CHECK_EQ(5, len);
7487   CHECK_EQ(0, strcmp("abcde", buf));
7488   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7489   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7490
7491   memset(buf, 0x1, sizeof(buf));
7492   memset(wbuf, 0x1, sizeof(wbuf));
7493   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7494   CHECK_EQ(1, len);
7495   len = str->Write(wbuf, 4, -1);
7496   CHECK_EQ(1, len);
7497   CHECK_EQ(0, strcmp("e", buf));
7498   uint16_t answer5[] = {'e', '\0'};
7499   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7500
7501   memset(buf, 0x1, sizeof(buf));
7502   memset(wbuf, 0x1, sizeof(wbuf));
7503   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7504   CHECK_EQ(1, len);
7505   len = str->Write(wbuf, 4, 6);
7506   CHECK_EQ(1, len);
7507   CHECK_EQ(0, strcmp("e", buf));
7508   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7509
7510   memset(buf, 0x1, sizeof(buf));
7511   memset(wbuf, 0x1, sizeof(wbuf));
7512   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7513   CHECK_EQ(1, len);
7514   len = str->Write(wbuf, 4, 1);
7515   CHECK_EQ(1, len);
7516   CHECK_EQ(0, strncmp("e\1", buf, 2));
7517   uint16_t answer6[] = {'e', 0x101};
7518   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7519
7520   memset(buf, 0x1, sizeof(buf));
7521   memset(wbuf, 0x1, sizeof(wbuf));
7522   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7523   CHECK_EQ(1, len);
7524   len = str->Write(wbuf, 3, 1);
7525   CHECK_EQ(1, len);
7526   CHECK_EQ(0, strncmp("d\1", buf, 2));
7527   uint16_t answer7[] = {'d', 0x101};
7528   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7529
7530   memset(wbuf, 0x1, sizeof(wbuf));
7531   wbuf[5] = 'X';
7532   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7533   CHECK_EQ(5, len);
7534   CHECK_EQ('X', wbuf[5]);
7535   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7536   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7537   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7538   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7539   wbuf[5] = '\0';
7540   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7541
7542   memset(buf, 0x1, sizeof(buf));
7543   buf[5] = 'X';
7544   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7545                           0,
7546                           6,
7547                           String::NO_NULL_TERMINATION);
7548   CHECK_EQ(5, len);
7549   CHECK_EQ('X', buf[5]);
7550   CHECK_EQ(0, strncmp("abcde", buf, 5));
7551   CHECK_NE(0, strcmp("abcde", buf));
7552   buf[5] = '\0';
7553   CHECK_EQ(0, strcmp("abcde", buf));
7554
7555   memset(utf8buf, 0x1, sizeof(utf8buf));
7556   utf8buf[8] = 'X';
7557   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7558                         String::NO_NULL_TERMINATION);
7559   CHECK_EQ(8, len);
7560   CHECK_EQ('X', utf8buf[8]);
7561   CHECK_EQ(5, charlen);
7562   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7563   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7564   utf8buf[8] = '\0';
7565   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7566
7567   memset(utf8buf, 0x1, sizeof(utf8buf));
7568   utf8buf[5] = 'X';
7569   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7570                         String::NO_NULL_TERMINATION);
7571   CHECK_EQ(5, len);
7572   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7573   CHECK_EQ(5, charlen);
7574   utf8buf[5] = '\0';
7575   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7576
7577   memset(buf, 0x1, sizeof(buf));
7578   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7579   CHECK_EQ(7, len);
7580   CHECK_EQ(0, strcmp("abc", buf));
7581   CHECK_EQ(0, buf[3]);
7582   CHECK_EQ(0, strcmp("def", buf + 4));
7583
7584   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7585   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7586   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7587 }
7588
7589
7590 static void Utf16Helper(
7591     LocalContext& context,
7592     const char* name,
7593     const char* lengths_name,
7594     int len) {
7595   Local<v8::Array> a =
7596       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7597   Local<v8::Array> alens =
7598       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7599   for (int i = 0; i < len; i++) {
7600     Local<v8::String> string =
7601       Local<v8::String>::Cast(a->Get(i));
7602     Local<v8::Number> expected_len =
7603       Local<v8::Number>::Cast(alens->Get(i));
7604     int length = GetUtf8Length(string);
7605     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7606   }
7607 }
7608
7609
7610 static uint16_t StringGet(Handle<String> str, int index) {
7611   i::Handle<i::String> istring =
7612       v8::Utils::OpenHandle(String::Cast(*str));
7613   return istring->Get(index);
7614 }
7615
7616
7617 static void WriteUtf8Helper(
7618     LocalContext& context,
7619     const char* name,
7620     const char* lengths_name,
7621     int len) {
7622   Local<v8::Array> b =
7623       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7624   Local<v8::Array> alens =
7625       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7626   char buffer[1000];
7627   char buffer2[1000];
7628   for (int i = 0; i < len; i++) {
7629     Local<v8::String> string =
7630       Local<v8::String>::Cast(b->Get(i));
7631     Local<v8::Number> expected_len =
7632       Local<v8::Number>::Cast(alens->Get(i));
7633     int utf8_length = static_cast<int>(expected_len->Value());
7634     for (int j = utf8_length + 1; j >= 0; j--) {
7635       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7636       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7637       int nchars;
7638       int utf8_written =
7639           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7640       int utf8_written2 =
7641           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7642       CHECK_GE(utf8_length + 1, utf8_written);
7643       CHECK_GE(utf8_length, utf8_written2);
7644       for (int k = 0; k < utf8_written2; k++) {
7645         CHECK_EQ(buffer[k], buffer2[k]);
7646       }
7647       CHECK(nchars * 3 >= utf8_written - 1);
7648       CHECK(nchars <= utf8_written);
7649       if (j == utf8_length + 1) {
7650         CHECK_EQ(utf8_written2, utf8_length);
7651         CHECK_EQ(utf8_written2 + 1, utf8_written);
7652       }
7653       CHECK_EQ(buffer[utf8_written], 42);
7654       if (j > utf8_length) {
7655         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7656         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7657         Handle<String> roundtrip = v8_str(buffer);
7658         CHECK(roundtrip->Equals(string));
7659       } else {
7660         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7661       }
7662       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7663       if (nchars >= 2) {
7664         uint16_t trail = StringGet(string, nchars - 1);
7665         uint16_t lead = StringGet(string, nchars - 2);
7666         if (((lead & 0xfc00) == 0xd800) &&
7667             ((trail & 0xfc00) == 0xdc00)) {
7668           unsigned char u1 = buffer2[utf8_written2 - 4];
7669           unsigned char u2 = buffer2[utf8_written2 - 3];
7670           unsigned char u3 = buffer2[utf8_written2 - 2];
7671           unsigned char u4 = buffer2[utf8_written2 - 1];
7672           CHECK_EQ((u1 & 0xf8), 0xf0);
7673           CHECK_EQ((u2 & 0xc0), 0x80);
7674           CHECK_EQ((u3 & 0xc0), 0x80);
7675           CHECK_EQ((u4 & 0xc0), 0x80);
7676           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7677           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7678           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7679           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7680           CHECK_EQ((u1 & 0x3), c >> 18);
7681         }
7682       }
7683     }
7684   }
7685 }
7686
7687
7688 THREADED_TEST(Utf16) {
7689   LocalContext context;
7690   v8::HandleScope scope(context->GetIsolate());
7691   CompileRun(
7692       "var pad = '01234567890123456789';"
7693       "var p = [];"
7694       "var plens = [20, 3, 3];"
7695       "p.push('01234567890123456789');"
7696       "var lead = 0xd800;"
7697       "var trail = 0xdc00;"
7698       "p.push(String.fromCharCode(0xd800));"
7699       "p.push(String.fromCharCode(0xdc00));"
7700       "var a = [];"
7701       "var b = [];"
7702       "var c = [];"
7703       "var alens = [];"
7704       "for (var i = 0; i < 3; i++) {"
7705       "  p[1] = String.fromCharCode(lead++);"
7706       "  for (var j = 0; j < 3; j++) {"
7707       "    p[2] = String.fromCharCode(trail++);"
7708       "    a.push(p[i] + p[j]);"
7709       "    b.push(p[i] + p[j]);"
7710       "    c.push(p[i] + p[j]);"
7711       "    alens.push(plens[i] + plens[j]);"
7712       "  }"
7713       "}"
7714       "alens[5] -= 2;"  // Here the surrogate pairs match up.
7715       "var a2 = [];"
7716       "var b2 = [];"
7717       "var c2 = [];"
7718       "var a2lens = [];"
7719       "for (var m = 0; m < 9; m++) {"
7720       "  for (var n = 0; n < 9; n++) {"
7721       "    a2.push(a[m] + a[n]);"
7722       "    b2.push(b[m] + b[n]);"
7723       "    var newc = 'x' + c[m] + c[n] + 'y';"
7724       "    c2.push(newc.substring(1, newc.length - 1));"
7725       "    var utf = alens[m] + alens[n];"  // And here.
7726            // The 'n's that start with 0xdc.. are 6-8
7727            // The 'm's that end with 0xd8.. are 1, 4 and 7
7728       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
7729       "    a2lens.push(utf);"
7730       "  }"
7731       "}");
7732   Utf16Helper(context, "a", "alens", 9);
7733   Utf16Helper(context, "a2", "a2lens", 81);
7734   WriteUtf8Helper(context, "b", "alens", 9);
7735   WriteUtf8Helper(context, "b2", "a2lens", 81);
7736   WriteUtf8Helper(context, "c2", "a2lens", 81);
7737 }
7738
7739
7740 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7741   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7742   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7743   return *is1 == *is2;
7744 }
7745
7746
7747 static void SameSymbolHelper(const char* a, const char* b) {
7748   Handle<String> symbol1 = v8::String::NewSymbol(a);
7749   Handle<String> symbol2 = v8::String::NewSymbol(b);
7750   CHECK(SameSymbol(symbol1, symbol2));
7751 }
7752
7753
7754 THREADED_TEST(Utf16Symbol) {
7755   LocalContext context;
7756   v8::HandleScope scope(context->GetIsolate());
7757
7758   Handle<String> symbol1 = v8::String::NewSymbol("abc");
7759   Handle<String> symbol2 = v8::String::NewSymbol("abc");
7760   CHECK(SameSymbol(symbol1, symbol2));
7761
7762   SameSymbolHelper("\360\220\220\205",  // 4 byte encoding.
7763                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
7764   SameSymbolHelper("\355\240\201\355\260\206",  // 2 3-byte surrogates.
7765                    "\360\220\220\206");  // 4 byte encoding.
7766   SameSymbolHelper("x\360\220\220\205",  // 4 byte encoding.
7767                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
7768   SameSymbolHelper("x\355\240\201\355\260\206",  // 2 3-byte surrogates.
7769                    "x\360\220\220\206");  // 4 byte encoding.
7770   CompileRun(
7771       "var sym0 = 'benedictus';"
7772       "var sym0b = 'S\303\270ren';"
7773       "var sym1 = '\355\240\201\355\260\207';"
7774       "var sym2 = '\360\220\220\210';"
7775       "var sym3 = 'x\355\240\201\355\260\207';"
7776       "var sym4 = 'x\360\220\220\210';"
7777       "if (sym1.length != 2) throw sym1;"
7778       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7779       "if (sym2.length != 2) throw sym2;"
7780       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7781       "if (sym3.length != 3) throw sym3;"
7782       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7783       "if (sym4.length != 3) throw sym4;"
7784       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7785   Handle<String> sym0 = v8::String::NewSymbol("benedictus");
7786   Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
7787   Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
7788   Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
7789   Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
7790   Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
7791   v8::Local<v8::Object> global = context->Global();
7792   Local<Value> s0 = global->Get(v8_str("sym0"));
7793   Local<Value> s0b = global->Get(v8_str("sym0b"));
7794   Local<Value> s1 = global->Get(v8_str("sym1"));
7795   Local<Value> s2 = global->Get(v8_str("sym2"));
7796   Local<Value> s3 = global->Get(v8_str("sym3"));
7797   Local<Value> s4 = global->Get(v8_str("sym4"));
7798   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7799   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7800   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7801   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7802   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7803   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7804 }
7805
7806
7807 THREADED_TEST(ToArrayIndex) {
7808   LocalContext context;
7809   v8::HandleScope scope(context->GetIsolate());
7810
7811   v8::Handle<String> str = v8_str("42");
7812   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7813   CHECK(!index.IsEmpty());
7814   CHECK_EQ(42.0, index->Uint32Value());
7815   str = v8_str("42asdf");
7816   index = str->ToArrayIndex();
7817   CHECK(index.IsEmpty());
7818   str = v8_str("-42");
7819   index = str->ToArrayIndex();
7820   CHECK(index.IsEmpty());
7821   str = v8_str("4294967295");
7822   index = str->ToArrayIndex();
7823   CHECK(!index.IsEmpty());
7824   CHECK_EQ(4294967295.0, index->Uint32Value());
7825   v8::Handle<v8::Number> num = v8::Number::New(1);
7826   index = num->ToArrayIndex();
7827   CHECK(!index.IsEmpty());
7828   CHECK_EQ(1.0, index->Uint32Value());
7829   num = v8::Number::New(-1);
7830   index = num->ToArrayIndex();
7831   CHECK(index.IsEmpty());
7832   v8::Handle<v8::Object> obj = v8::Object::New();
7833   index = obj->ToArrayIndex();
7834   CHECK(index.IsEmpty());
7835 }
7836
7837
7838 THREADED_TEST(ErrorConstruction) {
7839   LocalContext context;
7840   v8::HandleScope scope(context->GetIsolate());
7841
7842   v8::Handle<String> foo = v8_str("foo");
7843   v8::Handle<String> message = v8_str("message");
7844   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7845   CHECK(range_error->IsObject());
7846   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7847   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7848   CHECK(reference_error->IsObject());
7849   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7850   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7851   CHECK(syntax_error->IsObject());
7852   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7853   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7854   CHECK(type_error->IsObject());
7855   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7856   v8::Handle<Value> error = v8::Exception::Error(foo);
7857   CHECK(error->IsObject());
7858   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7859 }
7860
7861
7862 static void YGetter(Local<String> name,
7863                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7864   ApiTestFuzzer::Fuzz();
7865   info.GetReturnValue().Set(v8_num(10));
7866 }
7867
7868
7869 static void YSetter(Local<String> name,
7870                     Local<Value> value,
7871                     const v8::PropertyCallbackInfo<void>& info) {
7872   if (info.This()->Has(name)) {
7873     info.This()->Delete(name);
7874   }
7875   info.This()->Set(name, value);
7876 }
7877
7878
7879 THREADED_TEST(DeleteAccessor) {
7880   v8::HandleScope scope(CcTest::isolate());
7881   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7882   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7883   LocalContext context;
7884   v8::Handle<v8::Object> holder = obj->NewInstance();
7885   context->Global()->Set(v8_str("holder"), holder);
7886   v8::Handle<Value> result = CompileRun(
7887       "holder.y = 11; holder.y = 12; holder.y");
7888   CHECK_EQ(12, result->Uint32Value());
7889 }
7890
7891
7892 THREADED_TEST(TypeSwitch) {
7893   v8::HandleScope scope(CcTest::isolate());
7894   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
7895   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
7896   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
7897   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7898   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7899   LocalContext context;
7900   v8::Handle<v8::Object> obj0 = v8::Object::New();
7901   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7902   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7903   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7904   for (int i = 0; i < 10; i++) {
7905     CHECK_EQ(0, type_switch->match(obj0));
7906     CHECK_EQ(1, type_switch->match(obj1));
7907     CHECK_EQ(2, type_switch->match(obj2));
7908     CHECK_EQ(3, type_switch->match(obj3));
7909     CHECK_EQ(3, type_switch->match(obj3));
7910     CHECK_EQ(2, type_switch->match(obj2));
7911     CHECK_EQ(1, type_switch->match(obj1));
7912     CHECK_EQ(0, type_switch->match(obj0));
7913   }
7914 }
7915
7916
7917 // For use within the TestSecurityHandler() test.
7918 static bool g_security_callback_result = false;
7919 static bool NamedSecurityTestCallback(Local<v8::Object> global,
7920                                       Local<Value> name,
7921                                       v8::AccessType type,
7922                                       Local<Value> data) {
7923   // Always allow read access.
7924   if (type == v8::ACCESS_GET)
7925     return true;
7926
7927   // Sometimes allow other access.
7928   return g_security_callback_result;
7929 }
7930
7931
7932 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
7933                                         uint32_t key,
7934                                         v8::AccessType type,
7935                                         Local<Value> data) {
7936   // Always allow read access.
7937   if (type == v8::ACCESS_GET)
7938     return true;
7939
7940   // Sometimes allow other access.
7941   return g_security_callback_result;
7942 }
7943
7944
7945 static int trouble_nesting = 0;
7946 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7947   ApiTestFuzzer::Fuzz();
7948   trouble_nesting++;
7949
7950   // Call a JS function that throws an uncaught exception.
7951   Local<v8::Object> arg_this =
7952       args.GetIsolate()->GetCurrentContext()->Global();
7953   Local<Value> trouble_callee = (trouble_nesting == 3) ?
7954     arg_this->Get(v8_str("trouble_callee")) :
7955     arg_this->Get(v8_str("trouble_caller"));
7956   CHECK(trouble_callee->IsFunction());
7957   args.GetReturnValue().Set(
7958       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7959 }
7960
7961
7962 static int report_count = 0;
7963 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7964                                              v8::Handle<Value>) {
7965   report_count++;
7966 }
7967
7968
7969 // Counts uncaught exceptions, but other tests running in parallel
7970 // also have uncaught exceptions.
7971 TEST(ApiUncaughtException) {
7972   report_count = 0;
7973   LocalContext env;
7974   v8::HandleScope scope(env->GetIsolate());
7975   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7976
7977   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7978   v8::Local<v8::Object> global = env->Global();
7979   global->Set(v8_str("trouble"), fun->GetFunction());
7980
7981   Script::Compile(v8_str("function trouble_callee() {"
7982                          "  var x = null;"
7983                          "  return x.foo;"
7984                          "};"
7985                          "function trouble_caller() {"
7986                          "  trouble();"
7987                          "};"))->Run();
7988   Local<Value> trouble = global->Get(v8_str("trouble"));
7989   CHECK(trouble->IsFunction());
7990   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7991   CHECK(trouble_callee->IsFunction());
7992   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7993   CHECK(trouble_caller->IsFunction());
7994   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7995   CHECK_EQ(1, report_count);
7996   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7997 }
7998
7999 static const char* script_resource_name = "ExceptionInNativeScript.js";
8000 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8001                                                 v8::Handle<Value>) {
8002   v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
8003   CHECK(!name_val.IsEmpty() && name_val->IsString());
8004   v8::String::Utf8Value name(message->GetScriptResourceName());
8005   CHECK_EQ(script_resource_name, *name);
8006   CHECK_EQ(3, message->GetLineNumber());
8007   v8::String::Utf8Value source_line(message->GetSourceLine());
8008   CHECK_EQ("  new o.foo();", *source_line);
8009 }
8010
8011
8012 TEST(ExceptionInNativeScript) {
8013   LocalContext env;
8014   v8::HandleScope scope(env->GetIsolate());
8015   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8016
8017   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
8018   v8::Local<v8::Object> global = env->Global();
8019   global->Set(v8_str("trouble"), fun->GetFunction());
8020
8021   Script::Compile(v8_str("function trouble() {\n"
8022                          "  var o = {};\n"
8023                          "  new o.foo();\n"
8024                          "};"), v8::String::New(script_resource_name))->Run();
8025   Local<Value> trouble = global->Get(v8_str("trouble"));
8026   CHECK(trouble->IsFunction());
8027   Function::Cast(*trouble)->Call(global, 0, NULL);
8028   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8029 }
8030
8031
8032 TEST(CompilationErrorUsingTryCatchHandler) {
8033   LocalContext env;
8034   v8::HandleScope scope(env->GetIsolate());
8035   v8::TryCatch try_catch;
8036   Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
8037   CHECK_NE(NULL, *try_catch.Exception());
8038   CHECK(try_catch.HasCaught());
8039 }
8040
8041
8042 TEST(TryCatchFinallyUsingTryCatchHandler) {
8043   LocalContext env;
8044   v8::HandleScope scope(env->GetIsolate());
8045   v8::TryCatch try_catch;
8046   Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
8047   CHECK(!try_catch.HasCaught());
8048   Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
8049   CHECK(try_catch.HasCaught());
8050   try_catch.Reset();
8051   Script::Compile(v8_str("(function() {"
8052                          "try { throw ''; } finally { return; }"
8053                          "})()"))->Run();
8054   CHECK(!try_catch.HasCaught());
8055   Script::Compile(v8_str("(function()"
8056                          "  { try { throw ''; } finally { throw 0; }"
8057                          "})()"))->Run();
8058   CHECK(try_catch.HasCaught());
8059 }
8060
8061
8062 // SecurityHandler can't be run twice
8063 TEST(SecurityHandler) {
8064   v8::HandleScope scope0(CcTest::isolate());
8065   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8066   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8067                                            IndexedSecurityTestCallback);
8068   // Create an environment
8069   v8::Handle<Context> context0 =
8070     Context::New(CcTest::isolate(), NULL, global_template);
8071   context0->Enter();
8072
8073   v8::Handle<v8::Object> global0 = context0->Global();
8074   v8::Handle<Script> script0 = v8_compile("foo = 111");
8075   script0->Run();
8076   global0->Set(v8_str("0"), v8_num(999));
8077   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8078   CHECK_EQ(111, foo0->Int32Value());
8079   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8080   CHECK_EQ(999, z0->Int32Value());
8081
8082   // Create another environment, should fail security checks.
8083   v8::HandleScope scope1(CcTest::isolate());
8084
8085   v8::Handle<Context> context1 =
8086     Context::New(CcTest::isolate(), NULL, global_template);
8087   context1->Enter();
8088
8089   v8::Handle<v8::Object> global1 = context1->Global();
8090   global1->Set(v8_str("othercontext"), global0);
8091   // This set will fail the security check.
8092   v8::Handle<Script> script1 =
8093     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8094   script1->Run();
8095   // This read will pass the security check.
8096   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8097   CHECK_EQ(111, foo1->Int32Value());
8098   // This read will pass the security check.
8099   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8100   CHECK_EQ(999, z1->Int32Value());
8101
8102   // Create another environment, should pass security checks.
8103   { g_security_callback_result = true;  // allow security handler to pass.
8104     v8::HandleScope scope2(CcTest::isolate());
8105     LocalContext context2;
8106     v8::Handle<v8::Object> global2 = context2->Global();
8107     global2->Set(v8_str("othercontext"), global0);
8108     v8::Handle<Script> script2 =
8109         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8110     script2->Run();
8111     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8112     CHECK_EQ(333, foo2->Int32Value());
8113     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8114     CHECK_EQ(888, z2->Int32Value());
8115   }
8116
8117   context1->Exit();
8118   context0->Exit();
8119 }
8120
8121
8122 THREADED_TEST(SecurityChecks) {
8123   LocalContext env1;
8124   v8::HandleScope handle_scope(env1->GetIsolate());
8125   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8126
8127   Local<Value> foo = v8_str("foo");
8128   Local<Value> bar = v8_str("bar");
8129
8130   // Set to the same domain.
8131   env1->SetSecurityToken(foo);
8132
8133   // Create a function in env1.
8134   Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
8135   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8136   CHECK(spy->IsFunction());
8137
8138   // Create another function accessing global objects.
8139   Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
8140   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8141   CHECK(spy2->IsFunction());
8142
8143   // Switch to env2 in the same domain and invoke spy on env2.
8144   {
8145     env2->SetSecurityToken(foo);
8146     // Enter env2
8147     Context::Scope scope_env2(env2);
8148     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8149     CHECK(result->IsFunction());
8150   }
8151
8152   {
8153     env2->SetSecurityToken(bar);
8154     Context::Scope scope_env2(env2);
8155
8156     // Call cross_domain_call, it should throw an exception
8157     v8::TryCatch try_catch;
8158     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8159     CHECK(try_catch.HasCaught());
8160   }
8161 }
8162
8163
8164 // Regression test case for issue 1183439.
8165 THREADED_TEST(SecurityChecksForPrototypeChain) {
8166   LocalContext current;
8167   v8::HandleScope scope(current->GetIsolate());
8168   v8::Handle<Context> other = Context::New(current->GetIsolate());
8169
8170   // Change context to be able to get to the Object function in the
8171   // other context without hitting the security checks.
8172   v8::Local<Value> other_object;
8173   { Context::Scope scope(other);
8174     other_object = other->Global()->Get(v8_str("Object"));
8175     other->Global()->Set(v8_num(42), v8_num(87));
8176   }
8177
8178   current->Global()->Set(v8_str("other"), other->Global());
8179   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8180
8181   // Make sure the security check fails here and we get an undefined
8182   // result instead of getting the Object function. Repeat in a loop
8183   // to make sure to exercise the IC code.
8184   v8::Local<Script> access_other0 = v8_compile("other.Object");
8185   v8::Local<Script> access_other1 = v8_compile("other[42]");
8186   for (int i = 0; i < 5; i++) {
8187     CHECK(!access_other0->Run()->Equals(other_object));
8188     CHECK(access_other0->Run()->IsUndefined());
8189     CHECK(!access_other1->Run()->Equals(v8_num(87)));
8190     CHECK(access_other1->Run()->IsUndefined());
8191   }
8192
8193   // Create an object that has 'other' in its prototype chain and make
8194   // sure we cannot access the Object function indirectly through
8195   // that. Repeat in a loop to make sure to exercise the IC code.
8196   v8_compile("function F() { };"
8197              "F.prototype = other;"
8198              "var f = new F();")->Run();
8199   v8::Local<Script> access_f0 = v8_compile("f.Object");
8200   v8::Local<Script> access_f1 = v8_compile("f[42]");
8201   for (int j = 0; j < 5; j++) {
8202     CHECK(!access_f0->Run()->Equals(other_object));
8203     CHECK(access_f0->Run()->IsUndefined());
8204     CHECK(!access_f1->Run()->Equals(v8_num(87)));
8205     CHECK(access_f1->Run()->IsUndefined());
8206   }
8207
8208   // Now it gets hairy: Set the prototype for the other global object
8209   // to be the current global object. The prototype chain for 'f' now
8210   // goes through 'other' but ends up in the current global object.
8211   { Context::Scope scope(other);
8212     other->Global()->Set(v8_str("__proto__"), current->Global());
8213   }
8214   // Set a named and an index property on the current global
8215   // object. To force the lookup to go through the other global object,
8216   // the properties must not exist in the other global object.
8217   current->Global()->Set(v8_str("foo"), v8_num(100));
8218   current->Global()->Set(v8_num(99), v8_num(101));
8219   // Try to read the properties from f and make sure that the access
8220   // gets stopped by the security checks on the other global object.
8221   Local<Script> access_f2 = v8_compile("f.foo");
8222   Local<Script> access_f3 = v8_compile("f[99]");
8223   for (int k = 0; k < 5; k++) {
8224     CHECK(!access_f2->Run()->Equals(v8_num(100)));
8225     CHECK(access_f2->Run()->IsUndefined());
8226     CHECK(!access_f3->Run()->Equals(v8_num(101)));
8227     CHECK(access_f3->Run()->IsUndefined());
8228   }
8229 }
8230
8231
8232 THREADED_TEST(CrossDomainDelete) {
8233   LocalContext env1;
8234   v8::HandleScope handle_scope(env1->GetIsolate());
8235   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8236
8237   Local<Value> foo = v8_str("foo");
8238   Local<Value> bar = v8_str("bar");
8239
8240   // Set to the same domain.
8241   env1->SetSecurityToken(foo);
8242   env2->SetSecurityToken(foo);
8243
8244   env1->Global()->Set(v8_str("prop"), v8_num(3));
8245   env2->Global()->Set(v8_str("env1"), env1->Global());
8246
8247   // Change env2 to a different domain and delete env1.prop.
8248   env2->SetSecurityToken(bar);
8249   {
8250     Context::Scope scope_env2(env2);
8251     Local<Value> result =
8252         Script::Compile(v8_str("delete env1.prop"))->Run();
8253     CHECK(result->IsFalse());
8254   }
8255
8256   // Check that env1.prop still exists.
8257   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8258   CHECK(v->IsNumber());
8259   CHECK_EQ(3, v->Int32Value());
8260 }
8261
8262
8263 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8264   LocalContext env1;
8265   v8::HandleScope handle_scope(env1->GetIsolate());
8266   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8267
8268   Local<Value> foo = v8_str("foo");
8269   Local<Value> bar = v8_str("bar");
8270
8271   // Set to the same domain.
8272   env1->SetSecurityToken(foo);
8273   env2->SetSecurityToken(foo);
8274
8275   env1->Global()->Set(v8_str("prop"), v8_num(3));
8276   env2->Global()->Set(v8_str("env1"), env1->Global());
8277
8278   // env1.prop is enumerable in env2.
8279   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8280   {
8281     Context::Scope scope_env2(env2);
8282     Local<Value> result = Script::Compile(test)->Run();
8283     CHECK(result->IsTrue());
8284   }
8285
8286   // Change env2 to a different domain and test again.
8287   env2->SetSecurityToken(bar);
8288   {
8289     Context::Scope scope_env2(env2);
8290     Local<Value> result = Script::Compile(test)->Run();
8291     CHECK(result->IsFalse());
8292   }
8293 }
8294
8295
8296 THREADED_TEST(CrossDomainForIn) {
8297   LocalContext env1;
8298   v8::HandleScope handle_scope(env1->GetIsolate());
8299   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8300
8301   Local<Value> foo = v8_str("foo");
8302   Local<Value> bar = v8_str("bar");
8303
8304   // Set to the same domain.
8305   env1->SetSecurityToken(foo);
8306   env2->SetSecurityToken(foo);
8307
8308   env1->Global()->Set(v8_str("prop"), v8_num(3));
8309   env2->Global()->Set(v8_str("env1"), env1->Global());
8310
8311   // Change env2 to a different domain and set env1's global object
8312   // as the __proto__ of an object in env2 and enumerate properties
8313   // in for-in. It shouldn't enumerate properties on env1's global
8314   // object.
8315   env2->SetSecurityToken(bar);
8316   {
8317     Context::Scope scope_env2(env2);
8318     Local<Value> result =
8319         CompileRun("(function(){var obj = {'__proto__':env1};"
8320                    "for (var p in obj)"
8321                    "   if (p == 'prop') return false;"
8322                    "return true;})()");
8323     CHECK(result->IsTrue());
8324   }
8325 }
8326
8327
8328 TEST(ContextDetachGlobal) {
8329   LocalContext env1;
8330   v8::HandleScope handle_scope(env1->GetIsolate());
8331   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8332
8333   Local<v8::Object> global1 = env1->Global();
8334
8335   Local<Value> foo = v8_str("foo");
8336
8337   // Set to the same domain.
8338   env1->SetSecurityToken(foo);
8339   env2->SetSecurityToken(foo);
8340
8341   // Enter env2
8342   env2->Enter();
8343
8344   // Create a function in env2 and add a reference to it in env1.
8345   Local<v8::Object> global2 = env2->Global();
8346   global2->Set(v8_str("prop"), v8::Integer::New(1));
8347   CompileRun("function getProp() {return prop;}");
8348
8349   env1->Global()->Set(v8_str("getProp"),
8350                       global2->Get(v8_str("getProp")));
8351
8352   // Detach env2's global, and reuse the global object of env2
8353   env2->Exit();
8354   env2->DetachGlobal();
8355   // env2 has a new global object.
8356   CHECK(!env2->Global()->Equals(global2));
8357
8358   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8359                                           0,
8360                                           v8::Handle<v8::ObjectTemplate>(),
8361                                           global2);
8362   env3->SetSecurityToken(v8_str("bar"));
8363   env3->Enter();
8364
8365   Local<v8::Object> global3 = env3->Global();
8366   CHECK_EQ(global2, global3);
8367   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8368   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8369   global3->Set(v8_str("prop"), v8::Integer::New(-1));
8370   global3->Set(v8_str("prop2"), v8::Integer::New(2));
8371   env3->Exit();
8372
8373   // Call getProp in env1, and it should return the value 1
8374   {
8375     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8376     CHECK(get_prop->IsFunction());
8377     v8::TryCatch try_catch;
8378     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8379     CHECK(!try_catch.HasCaught());
8380     CHECK_EQ(1, r->Int32Value());
8381   }
8382
8383   // Check that env3 is not accessible from env1
8384   {
8385     Local<Value> r = global3->Get(v8_str("prop2"));
8386     CHECK(r->IsUndefined());
8387   }
8388 }
8389
8390
8391 TEST(DetachAndReattachGlobal) {
8392   LocalContext env1;
8393   v8::HandleScope scope(env1->GetIsolate());
8394
8395   // Create second environment.
8396   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8397
8398   Local<Value> foo = v8_str("foo");
8399
8400   // Set same security token for env1 and env2.
8401   env1->SetSecurityToken(foo);
8402   env2->SetSecurityToken(foo);
8403
8404   // Create a property on the global object in env2.
8405   {
8406     v8::Context::Scope scope(env2);
8407     env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
8408   }
8409
8410   // Create a reference to env2 global from env1 global.
8411   env1->Global()->Set(v8_str("other"), env2->Global());
8412
8413   // Check that we have access to other.p in env2 from env1.
8414   Local<Value> result = CompileRun("other.p");
8415   CHECK(result->IsInt32());
8416   CHECK_EQ(42, result->Int32Value());
8417
8418   // Hold on to global from env2 and detach global from env2.
8419   Local<v8::Object> global2 = env2->Global();
8420   env2->DetachGlobal();
8421
8422   // Check that the global has been detached. No other.p property can
8423   // be found.
8424   result = CompileRun("other.p");
8425   CHECK(result->IsUndefined());
8426
8427   // Reuse global2 for env3.
8428   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8429                                           0,
8430                                           v8::Handle<v8::ObjectTemplate>(),
8431                                           global2);
8432   CHECK_EQ(global2, env3->Global());
8433
8434   // Start by using the same security token for env3 as for env1 and env2.
8435   env3->SetSecurityToken(foo);
8436
8437   // Create a property on the global object in env3.
8438   {
8439     v8::Context::Scope scope(env3);
8440     env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
8441   }
8442
8443   // Check that other.p is now the property in env3 and that we have access.
8444   result = CompileRun("other.p");
8445   CHECK(result->IsInt32());
8446   CHECK_EQ(24, result->Int32Value());
8447
8448   // Change security token for env3 to something different from env1 and env2.
8449   env3->SetSecurityToken(v8_str("bar"));
8450
8451   // Check that we do not have access to other.p in env1. |other| is now
8452   // the global object for env3 which has a different security token,
8453   // so access should be blocked.
8454   result = CompileRun("other.p");
8455   CHECK(result->IsUndefined());
8456
8457   // Detach the global for env3 and reattach it to env2.
8458   env3->DetachGlobal();
8459   env2->ReattachGlobal(global2);
8460
8461   // Check that we have access to other.p again in env1.  |other| is now
8462   // the global object for env2 which has the same security token as env1.
8463   result = CompileRun("other.p");
8464   CHECK(result->IsInt32());
8465   CHECK_EQ(42, result->Int32Value());
8466 }
8467
8468
8469 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8470 static bool NamedAccessBlocker(Local<v8::Object> global,
8471                                Local<Value> name,
8472                                v8::AccessType type,
8473                                Local<Value> data) {
8474   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8475       allowed_access_type[type];
8476 }
8477
8478
8479 static bool IndexedAccessBlocker(Local<v8::Object> global,
8480                                  uint32_t key,
8481                                  v8::AccessType type,
8482                                  Local<Value> data) {
8483   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8484       allowed_access_type[type];
8485 }
8486
8487
8488 static int g_echo_value_1 = -1;
8489 static int g_echo_value_2 = -1;
8490
8491
8492 static void EchoGetter(
8493     Local<String> name,
8494     const v8::PropertyCallbackInfo<v8::Value>& info) {
8495   info.GetReturnValue().Set(v8_num(g_echo_value_1));
8496 }
8497
8498
8499 static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8500   info.GetReturnValue().Set(v8_num(g_echo_value_2));
8501 }
8502
8503
8504 static void EchoSetter(Local<String> name,
8505                        Local<Value> value,
8506                        const v8::PropertyCallbackInfo<void>&) {
8507   if (value->IsNumber())
8508     g_echo_value_1 = value->Int32Value();
8509 }
8510
8511
8512 static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
8513   v8::Handle<v8::Value> value = info[0];
8514   if (value->IsNumber())
8515     g_echo_value_2 = value->Int32Value();
8516 }
8517
8518
8519 static void UnreachableGetter(
8520     Local<String> name,
8521     const v8::PropertyCallbackInfo<v8::Value>& info) {
8522   CHECK(false);  // This function should not be called..
8523 }
8524
8525
8526 static void UnreachableSetter(Local<String>,
8527                               Local<Value>,
8528                               const v8::PropertyCallbackInfo<void>&) {
8529   CHECK(false);  // This function should nto be called.
8530 }
8531
8532
8533 static void UnreachableFunction(
8534     const v8::FunctionCallbackInfo<v8::Value>& info) {
8535   CHECK(false);  // This function should not be called..
8536 }
8537
8538
8539 TEST(AccessControl) {
8540   v8::Isolate* isolate = CcTest::isolate();
8541   v8::HandleScope handle_scope(isolate);
8542   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8543
8544   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8545                                            IndexedAccessBlocker);
8546
8547   // Add an accessor accessible by cross-domain JS code.
8548   global_template->SetAccessor(
8549       v8_str("accessible_prop"),
8550       EchoGetter, EchoSetter,
8551       v8::Handle<Value>(),
8552       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8553
8554
8555   global_template->SetAccessorProperty(
8556       v8_str("accessible_js_prop"),
8557       v8::FunctionTemplate::New(EchoGetter),
8558       v8::FunctionTemplate::New(EchoSetter),
8559       v8::None,
8560       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8561
8562   // Add an accessor that is not accessible by cross-domain JS code.
8563   global_template->SetAccessor(v8_str("blocked_prop"),
8564                                UnreachableGetter, UnreachableSetter,
8565                                v8::Handle<Value>(),
8566                                v8::DEFAULT);
8567
8568   global_template->SetAccessorProperty(
8569       v8_str("blocked_js_prop"),
8570       v8::FunctionTemplate::New(UnreachableFunction),
8571       v8::FunctionTemplate::New(UnreachableFunction),
8572       v8::None,
8573       v8::DEFAULT);
8574
8575   // Create an environment
8576   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8577   context0->Enter();
8578
8579   v8::Handle<v8::Object> global0 = context0->Global();
8580
8581   // Define a property with JS getter and setter.
8582   CompileRun(
8583       "function getter() { return 'getter'; };\n"
8584       "function setter() { return 'setter'; }\n"
8585       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8586
8587   Local<Value> getter = global0->Get(v8_str("getter"));
8588   Local<Value> setter = global0->Get(v8_str("setter"));
8589
8590   // And define normal element.
8591   global0->Set(239, v8_str("239"));
8592
8593   // Define an element with JS getter and setter.
8594   CompileRun(
8595       "function el_getter() { return 'el_getter'; };\n"
8596       "function el_setter() { return 'el_setter'; };\n"
8597       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8598
8599   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8600   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8601
8602   v8::HandleScope scope1(isolate);
8603
8604   v8::Local<Context> context1 = Context::New(isolate);
8605   context1->Enter();
8606
8607   v8::Handle<v8::Object> global1 = context1->Global();
8608   global1->Set(v8_str("other"), global0);
8609
8610   // Access blocked property.
8611   CompileRun("other.blocked_prop = 1");
8612
8613   ExpectUndefined("other.blocked_prop");
8614   ExpectUndefined(
8615       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8616   ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8617
8618   // Enable ACCESS_HAS
8619   allowed_access_type[v8::ACCESS_HAS] = true;
8620   ExpectUndefined("other.blocked_prop");
8621   // ... and now we can get the descriptor...
8622   ExpectUndefined(
8623       "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
8624   // ... and enumerate the property.
8625   ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
8626   allowed_access_type[v8::ACCESS_HAS] = false;
8627
8628   // Access blocked element.
8629   CompileRun("other[239] = 1");
8630
8631   ExpectUndefined("other[239]");
8632   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
8633   ExpectFalse("propertyIsEnumerable.call(other, '239')");
8634
8635   // Enable ACCESS_HAS
8636   allowed_access_type[v8::ACCESS_HAS] = true;
8637   ExpectUndefined("other[239]");
8638   // ... and now we can get the descriptor...
8639   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
8640   // ... and enumerate the property.
8641   ExpectTrue("propertyIsEnumerable.call(other, '239')");
8642   allowed_access_type[v8::ACCESS_HAS] = false;
8643
8644   // Access a property with JS accessor.
8645   CompileRun("other.js_accessor_p = 2");
8646
8647   ExpectUndefined("other.js_accessor_p");
8648   ExpectUndefined(
8649       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
8650
8651   // Enable ACCESS_HAS.
8652   allowed_access_type[v8::ACCESS_HAS] = true;
8653   ExpectUndefined("other.js_accessor_p");
8654   ExpectUndefined(
8655       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8656   ExpectUndefined(
8657       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8658   ExpectUndefined(
8659       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8660   allowed_access_type[v8::ACCESS_HAS] = false;
8661
8662   // Enable both ACCESS_HAS and ACCESS_GET.
8663   allowed_access_type[v8::ACCESS_HAS] = true;
8664   allowed_access_type[v8::ACCESS_GET] = true;
8665
8666   ExpectString("other.js_accessor_p", "getter");
8667   ExpectObject(
8668       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8669   ExpectUndefined(
8670       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8671   ExpectUndefined(
8672       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8673
8674   allowed_access_type[v8::ACCESS_GET] = false;
8675   allowed_access_type[v8::ACCESS_HAS] = false;
8676
8677   // Enable both ACCESS_HAS and ACCESS_SET.
8678   allowed_access_type[v8::ACCESS_HAS] = true;
8679   allowed_access_type[v8::ACCESS_SET] = true;
8680
8681   ExpectUndefined("other.js_accessor_p");
8682   ExpectUndefined(
8683       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8684   ExpectObject(
8685       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8686   ExpectUndefined(
8687       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8688
8689   allowed_access_type[v8::ACCESS_SET] = false;
8690   allowed_access_type[v8::ACCESS_HAS] = false;
8691
8692   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8693   allowed_access_type[v8::ACCESS_HAS] = true;
8694   allowed_access_type[v8::ACCESS_GET] = true;
8695   allowed_access_type[v8::ACCESS_SET] = true;
8696
8697   ExpectString("other.js_accessor_p", "getter");
8698   ExpectObject(
8699       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8700   ExpectObject(
8701       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8702   ExpectUndefined(
8703       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8704
8705   allowed_access_type[v8::ACCESS_SET] = false;
8706   allowed_access_type[v8::ACCESS_GET] = false;
8707   allowed_access_type[v8::ACCESS_HAS] = false;
8708
8709   // Access an element with JS accessor.
8710   CompileRun("other[42] = 2");
8711
8712   ExpectUndefined("other[42]");
8713   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
8714
8715   // Enable ACCESS_HAS.
8716   allowed_access_type[v8::ACCESS_HAS] = true;
8717   ExpectUndefined("other[42]");
8718   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8719   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8720   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8721   allowed_access_type[v8::ACCESS_HAS] = false;
8722
8723   // Enable both ACCESS_HAS and ACCESS_GET.
8724   allowed_access_type[v8::ACCESS_HAS] = true;
8725   allowed_access_type[v8::ACCESS_GET] = true;
8726
8727   ExpectString("other[42]", "el_getter");
8728   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8729   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8730   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8731
8732   allowed_access_type[v8::ACCESS_GET] = false;
8733   allowed_access_type[v8::ACCESS_HAS] = false;
8734
8735   // Enable both ACCESS_HAS and ACCESS_SET.
8736   allowed_access_type[v8::ACCESS_HAS] = true;
8737   allowed_access_type[v8::ACCESS_SET] = true;
8738
8739   ExpectUndefined("other[42]");
8740   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8741   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8742   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8743
8744   allowed_access_type[v8::ACCESS_SET] = false;
8745   allowed_access_type[v8::ACCESS_HAS] = false;
8746
8747   // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8748   allowed_access_type[v8::ACCESS_HAS] = true;
8749   allowed_access_type[v8::ACCESS_GET] = true;
8750   allowed_access_type[v8::ACCESS_SET] = true;
8751
8752   ExpectString("other[42]", "el_getter");
8753   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8754   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8755   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8756
8757   allowed_access_type[v8::ACCESS_SET] = false;
8758   allowed_access_type[v8::ACCESS_GET] = false;
8759   allowed_access_type[v8::ACCESS_HAS] = false;
8760
8761   v8::Handle<Value> value;
8762
8763   // Access accessible property
8764   value = CompileRun("other.accessible_prop = 3");
8765   CHECK(value->IsNumber());
8766   CHECK_EQ(3, value->Int32Value());
8767   CHECK_EQ(3, g_echo_value_1);
8768
8769   // Access accessible js property
8770   value = CompileRun("other.accessible_js_prop = 3");
8771   CHECK(value->IsNumber());
8772   CHECK_EQ(3, value->Int32Value());
8773   CHECK_EQ(3, g_echo_value_2);
8774
8775   value = CompileRun("other.accessible_prop");
8776   CHECK(value->IsNumber());
8777   CHECK_EQ(3, value->Int32Value());
8778
8779   value = CompileRun("other.accessible_js_prop");
8780   CHECK(value->IsNumber());
8781   CHECK_EQ(3, value->Int32Value());
8782
8783   value = CompileRun(
8784       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8785   CHECK(value->IsNumber());
8786   CHECK_EQ(3, value->Int32Value());
8787
8788   value = CompileRun(
8789       "Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
8790   CHECK(value->IsNumber());
8791   CHECK_EQ(3, value->Int32Value());
8792
8793   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8794   CHECK(value->IsTrue());
8795
8796   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
8797   CHECK(value->IsTrue());
8798
8799   // Enumeration doesn't enumerate accessors from inaccessible objects in
8800   // the prototype chain even if the accessors are in themselves accessible.
8801   value =
8802       CompileRun("(function(){var obj = {'__proto__':other};"
8803                  "for (var p in obj)"
8804                  "   if (p == 'accessible_prop' ||"
8805                  "       p == 'accessible_js_prop' ||"
8806                  "       p == 'blocked_js_prop' ||"
8807                  "       p == 'blocked_js_prop') {"
8808                  "     return false;"
8809                  "   }"
8810                  "return true;})()");
8811   CHECK(value->IsTrue());
8812
8813   context1->Exit();
8814   context0->Exit();
8815 }
8816
8817
8818 TEST(AccessControlES5) {
8819   v8::Isolate* isolate = CcTest::isolate();
8820   v8::HandleScope handle_scope(isolate);
8821   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8822
8823   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8824                                            IndexedAccessBlocker);
8825
8826   // Add accessible accessor.
8827   global_template->SetAccessor(
8828       v8_str("accessible_prop"),
8829       EchoGetter, EchoSetter,
8830       v8::Handle<Value>(),
8831       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8832
8833
8834   // Add an accessor that is not accessible by cross-domain JS code.
8835   global_template->SetAccessor(v8_str("blocked_prop"),
8836                                UnreachableGetter, UnreachableSetter,
8837                                v8::Handle<Value>(),
8838                                v8::DEFAULT);
8839
8840   // Create an environment
8841   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8842   context0->Enter();
8843
8844   v8::Handle<v8::Object> global0 = context0->Global();
8845
8846   v8::Local<Context> context1 = Context::New(isolate);
8847   context1->Enter();
8848   v8::Handle<v8::Object> global1 = context1->Global();
8849   global1->Set(v8_str("other"), global0);
8850
8851   // Regression test for issue 1154.
8852   ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
8853
8854   ExpectUndefined("other.blocked_prop");
8855
8856   // Regression test for issue 1027.
8857   CompileRun("Object.defineProperty(\n"
8858              "  other, 'blocked_prop', {configurable: false})");
8859   ExpectUndefined("other.blocked_prop");
8860   ExpectUndefined(
8861       "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8862
8863   // Regression test for issue 1171.
8864   ExpectTrue("Object.isExtensible(other)");
8865   CompileRun("Object.preventExtensions(other)");
8866   ExpectTrue("Object.isExtensible(other)");
8867
8868   // Object.seal and Object.freeze.
8869   CompileRun("Object.freeze(other)");
8870   ExpectTrue("Object.isExtensible(other)");
8871
8872   CompileRun("Object.seal(other)");
8873   ExpectTrue("Object.isExtensible(other)");
8874
8875   // Regression test for issue 1250.
8876   // Make sure that we can set the accessible accessors value using normal
8877   // assignment.
8878   CompileRun("other.accessible_prop = 42");
8879   CHECK_EQ(42, g_echo_value_1);
8880
8881   v8::Handle<Value> value;
8882   // We follow Safari in ignoring assignments to host object accessors.
8883   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8884   value = CompileRun("other.accessible_prop == 42");
8885   CHECK(value->IsTrue());
8886 }
8887
8888
8889 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
8890                                             Local<Value> name,
8891                                             v8::AccessType type,
8892                                             Local<Value> data) {
8893   return false;
8894 }
8895
8896
8897 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
8898                                               uint32_t key,
8899                                               v8::AccessType type,
8900                                               Local<Value> data) {
8901   return false;
8902 }
8903
8904
8905 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8906   v8::Isolate* isolate = CcTest::isolate();
8907   v8::HandleScope handle_scope(isolate);
8908   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8909
8910   obj_template->Set(v8_str("x"), v8::Integer::New(42));
8911   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
8912                                         GetOwnPropertyNamesIndexedBlocker);
8913
8914   // Create an environment
8915   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8916   context0->Enter();
8917
8918   v8::Handle<v8::Object> global0 = context0->Global();
8919
8920   v8::HandleScope scope1(CcTest::isolate());
8921
8922   v8::Local<Context> context1 = Context::New(isolate);
8923   context1->Enter();
8924
8925   v8::Handle<v8::Object> global1 = context1->Global();
8926   global1->Set(v8_str("other"), global0);
8927   global1->Set(v8_str("object"), obj_template->NewInstance());
8928
8929   v8::Handle<Value> value;
8930
8931   // Attempt to get the property names of the other global object and
8932   // of an object that requires access checks.  Accessing the other
8933   // global object should be blocked by access checks on the global
8934   // proxy object.  Accessing the object that requires access checks
8935   // is blocked by the access checks on the object itself.
8936   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8937   CHECK(value->IsTrue());
8938
8939   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8940   CHECK(value->IsTrue());
8941
8942   context1->Exit();
8943   context0->Exit();
8944 }
8945
8946
8947 static void IndexedPropertyEnumerator(
8948     const v8::PropertyCallbackInfo<v8::Array>& info) {
8949   v8::Handle<v8::Array> result = v8::Array::New(2);
8950   result->Set(0, v8::Integer::New(7));
8951   result->Set(1, v8::Object::New());
8952   info.GetReturnValue().Set(result);
8953 }
8954
8955
8956 static void NamedPropertyEnumerator(
8957     const v8::PropertyCallbackInfo<v8::Array>& info) {
8958   v8::Handle<v8::Array> result = v8::Array::New(2);
8959   result->Set(0, v8_str("x"));
8960   result->Set(1, v8::Object::New());
8961   info.GetReturnValue().Set(result);
8962 }
8963
8964
8965 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
8966   v8::HandleScope handle_scope(CcTest::isolate());
8967   v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8968
8969   obj_template->Set(v8_str("7"), v8::Integer::New(7));
8970   obj_template->Set(v8_str("x"), v8::Integer::New(42));
8971   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
8972                                           IndexedPropertyEnumerator);
8973   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
8974                                         NamedPropertyEnumerator);
8975
8976   LocalContext context;
8977   v8::Handle<v8::Object> global = context->Global();
8978   global->Set(v8_str("object"), obj_template->NewInstance());
8979
8980   v8::Handle<v8::Value> result =
8981       CompileRun("Object.getOwnPropertyNames(object)");
8982   CHECK(result->IsArray());
8983   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
8984   CHECK_EQ(3, result_array->Length());
8985   CHECK(result_array->Get(0)->IsString());
8986   CHECK(result_array->Get(1)->IsString());
8987   CHECK(result_array->Get(2)->IsString());
8988   CHECK_EQ(v8_str("7"), result_array->Get(0));
8989   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
8990   CHECK_EQ(v8_str("x"), result_array->Get(2));
8991 }
8992
8993
8994 static void ConstTenGetter(Local<String> name,
8995                            const v8::PropertyCallbackInfo<v8::Value>& info) {
8996   info.GetReturnValue().Set(v8_num(10));
8997 }
8998
8999
9000 THREADED_TEST(CrossDomainAccessors) {
9001   v8::Isolate* isolate = CcTest::isolate();
9002   v8::HandleScope handle_scope(isolate);
9003
9004   v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
9005
9006   v8::Handle<v8::ObjectTemplate> global_template =
9007       func_template->InstanceTemplate();
9008
9009   v8::Handle<v8::ObjectTemplate> proto_template =
9010       func_template->PrototypeTemplate();
9011
9012   // Add an accessor to proto that's accessible by cross-domain JS code.
9013   proto_template->SetAccessor(v8_str("accessible"),
9014                               ConstTenGetter, 0,
9015                               v8::Handle<Value>(),
9016                               v8::ALL_CAN_READ);
9017
9018   // Add an accessor that is not accessible by cross-domain JS code.
9019   global_template->SetAccessor(v8_str("unreachable"),
9020                                UnreachableGetter, 0,
9021                                v8::Handle<Value>(),
9022                                v8::DEFAULT);
9023
9024   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9025   context0->Enter();
9026
9027   Local<v8::Object> global = context0->Global();
9028   // Add a normal property that shadows 'accessible'
9029   global->Set(v8_str("accessible"), v8_num(11));
9030
9031   // Enter a new context.
9032   v8::HandleScope scope1(CcTest::isolate());
9033   v8::Local<Context> context1 = Context::New(isolate);
9034   context1->Enter();
9035
9036   v8::Handle<v8::Object> global1 = context1->Global();
9037   global1->Set(v8_str("other"), global);
9038
9039   // Should return 10, instead of 11
9040   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9041   CHECK(value->IsNumber());
9042   CHECK_EQ(10, value->Int32Value());
9043
9044   value = v8_compile("other.unreachable")->Run();
9045   CHECK(value->IsUndefined());
9046
9047   context1->Exit();
9048   context0->Exit();
9049 }
9050
9051
9052 static int named_access_count = 0;
9053 static int indexed_access_count = 0;
9054
9055 static bool NamedAccessCounter(Local<v8::Object> global,
9056                                Local<Value> name,
9057                                v8::AccessType type,
9058                                Local<Value> data) {
9059   named_access_count++;
9060   return true;
9061 }
9062
9063
9064 static bool IndexedAccessCounter(Local<v8::Object> global,
9065                                  uint32_t key,
9066                                  v8::AccessType type,
9067                                  Local<Value> data) {
9068   indexed_access_count++;
9069   return true;
9070 }
9071
9072
9073 // This one is too easily disturbed by other tests.
9074 TEST(AccessControlIC) {
9075   named_access_count = 0;
9076   indexed_access_count = 0;
9077
9078   v8::Isolate* isolate = CcTest::isolate();
9079   v8::HandleScope handle_scope(isolate);
9080
9081   // Create an environment.
9082   v8::Local<Context> context0 = Context::New(isolate);
9083   context0->Enter();
9084
9085   // Create an object that requires access-check functions to be
9086   // called for cross-domain access.
9087   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9088   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9089                                            IndexedAccessCounter);
9090   Local<v8::Object> object = object_template->NewInstance();
9091
9092   v8::HandleScope scope1(isolate);
9093
9094   // Create another environment.
9095   v8::Local<Context> context1 = Context::New(isolate);
9096   context1->Enter();
9097
9098   // Make easy access to the object from the other environment.
9099   v8::Handle<v8::Object> global1 = context1->Global();
9100   global1->Set(v8_str("obj"), object);
9101
9102   v8::Handle<Value> value;
9103
9104   // Check that the named access-control function is called every time.
9105   CompileRun("function testProp(obj) {"
9106              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9107              "  for (var j = 0; j < 10; j++) obj.prop;"
9108              "  return obj.prop"
9109              "}");
9110   value = CompileRun("testProp(obj)");
9111   CHECK(value->IsNumber());
9112   CHECK_EQ(1, value->Int32Value());
9113   CHECK_EQ(21, named_access_count);
9114
9115   // Check that the named access-control function is called every time.
9116   CompileRun("var p = 'prop';"
9117              "function testKeyed(obj) {"
9118              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9119              "  for (var j = 0; j < 10; j++) obj[p];"
9120              "  return obj[p];"
9121              "}");
9122   // Use obj which requires access checks.  No inline caching is used
9123   // in that case.
9124   value = CompileRun("testKeyed(obj)");
9125   CHECK(value->IsNumber());
9126   CHECK_EQ(1, value->Int32Value());
9127   CHECK_EQ(42, named_access_count);
9128   // Force the inline caches into generic state and try again.
9129   CompileRun("testKeyed({ a: 0 })");
9130   CompileRun("testKeyed({ b: 0 })");
9131   value = CompileRun("testKeyed(obj)");
9132   CHECK(value->IsNumber());
9133   CHECK_EQ(1, value->Int32Value());
9134   CHECK_EQ(63, named_access_count);
9135
9136   // Check that the indexed access-control function is called every time.
9137   CompileRun("function testIndexed(obj) {"
9138              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9139              "  for (var j = 0; j < 10; j++) obj[0];"
9140              "  return obj[0]"
9141              "}");
9142   value = CompileRun("testIndexed(obj)");
9143   CHECK(value->IsNumber());
9144   CHECK_EQ(1, value->Int32Value());
9145   CHECK_EQ(21, indexed_access_count);
9146   // Force the inline caches into generic state.
9147   CompileRun("testIndexed(new Array(1))");
9148   // Test that the indexed access check is called.
9149   value = CompileRun("testIndexed(obj)");
9150   CHECK(value->IsNumber());
9151   CHECK_EQ(1, value->Int32Value());
9152   CHECK_EQ(42, indexed_access_count);
9153
9154   // Check that the named access check is called when invoking
9155   // functions on an object that requires access checks.
9156   CompileRun("obj.f = function() {}");
9157   CompileRun("function testCallNormal(obj) {"
9158              "  for (var i = 0; i < 10; i++) obj.f();"
9159              "}");
9160   CompileRun("testCallNormal(obj)");
9161   CHECK_EQ(74, named_access_count);
9162
9163   // Force obj into slow case.
9164   value = CompileRun("delete obj.prop");
9165   CHECK(value->BooleanValue());
9166   // Force inline caches into dictionary probing mode.
9167   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9168   // Test that the named access check is called.
9169   value = CompileRun("testProp(obj);");
9170   CHECK(value->IsNumber());
9171   CHECK_EQ(1, value->Int32Value());
9172   CHECK_EQ(96, named_access_count);
9173
9174   // Force the call inline cache into dictionary probing mode.
9175   CompileRun("o.f = function() {}; testCallNormal(o)");
9176   // Test that the named access check is still called for each
9177   // invocation of the function.
9178   value = CompileRun("testCallNormal(obj)");
9179   CHECK_EQ(106, named_access_count);
9180
9181   context1->Exit();
9182   context0->Exit();
9183 }
9184
9185
9186 static bool NamedAccessFlatten(Local<v8::Object> global,
9187                                Local<Value> name,
9188                                v8::AccessType type,
9189                                Local<Value> data) {
9190   char buf[100];
9191   int len;
9192
9193   CHECK(name->IsString());
9194
9195   memset(buf, 0x1, sizeof(buf));
9196   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9197   CHECK_EQ(4, len);
9198
9199   uint16_t buf2[100];
9200
9201   memset(buf, 0x1, sizeof(buf));
9202   len = name.As<String>()->Write(buf2);
9203   CHECK_EQ(4, len);
9204
9205   return true;
9206 }
9207
9208
9209 static bool IndexedAccessFlatten(Local<v8::Object> global,
9210                                  uint32_t key,
9211                                  v8::AccessType type,
9212                                  Local<Value> data) {
9213   return true;
9214 }
9215
9216
9217 // Regression test.  In access checks, operations that may cause
9218 // garbage collection are not allowed.  It used to be the case that
9219 // using the Write operation on a string could cause a garbage
9220 // collection due to flattening of the string.  This is no longer the
9221 // case.
9222 THREADED_TEST(AccessControlFlatten) {
9223   named_access_count = 0;
9224   indexed_access_count = 0;
9225
9226   v8::Isolate* isolate = CcTest::isolate();
9227   v8::HandleScope handle_scope(isolate);
9228
9229   // Create an environment.
9230   v8::Local<Context> context0 = Context::New(isolate);
9231   context0->Enter();
9232
9233   // Create an object that requires access-check functions to be
9234   // called for cross-domain access.
9235   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9236   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9237                                            IndexedAccessFlatten);
9238   Local<v8::Object> object = object_template->NewInstance();
9239
9240   v8::HandleScope scope1(isolate);
9241
9242   // Create another environment.
9243   v8::Local<Context> context1 = Context::New(isolate);
9244   context1->Enter();
9245
9246   // Make easy access to the object from the other environment.
9247   v8::Handle<v8::Object> global1 = context1->Global();
9248   global1->Set(v8_str("obj"), object);
9249
9250   v8::Handle<Value> value;
9251
9252   value = v8_compile("var p = 'as' + 'df';")->Run();
9253   value = v8_compile("obj[p];")->Run();
9254
9255   context1->Exit();
9256   context0->Exit();
9257 }
9258
9259
9260 static void AccessControlNamedGetter(
9261     Local<String>,
9262     const v8::PropertyCallbackInfo<v8::Value>& info) {
9263   info.GetReturnValue().Set(42);
9264 }
9265
9266
9267 static void AccessControlNamedSetter(
9268     Local<String>,
9269     Local<Value> value,
9270     const v8::PropertyCallbackInfo<v8::Value>& info) {
9271   info.GetReturnValue().Set(value);
9272 }
9273
9274
9275 static void AccessControlIndexedGetter(
9276       uint32_t index,
9277       const v8::PropertyCallbackInfo<v8::Value>& info) {
9278   info.GetReturnValue().Set(v8_num(42));
9279 }
9280
9281
9282 static void AccessControlIndexedSetter(
9283     uint32_t,
9284     Local<Value> value,
9285     const v8::PropertyCallbackInfo<v8::Value>& info) {
9286   info.GetReturnValue().Set(value);
9287 }
9288
9289
9290 THREADED_TEST(AccessControlInterceptorIC) {
9291   named_access_count = 0;
9292   indexed_access_count = 0;
9293
9294   v8::Isolate* isolate = CcTest::isolate();
9295   v8::HandleScope handle_scope(isolate);
9296
9297   // Create an environment.
9298   v8::Local<Context> context0 = Context::New(isolate);
9299   context0->Enter();
9300
9301   // Create an object that requires access-check functions to be
9302   // called for cross-domain access.  The object also has interceptors
9303   // interceptor.
9304   v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
9305   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9306                                            IndexedAccessCounter);
9307   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9308                                            AccessControlNamedSetter);
9309   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9310                                              AccessControlIndexedSetter);
9311   Local<v8::Object> object = object_template->NewInstance();
9312
9313   v8::HandleScope scope1(isolate);
9314
9315   // Create another environment.
9316   v8::Local<Context> context1 = Context::New(isolate);
9317   context1->Enter();
9318
9319   // Make easy access to the object from the other environment.
9320   v8::Handle<v8::Object> global1 = context1->Global();
9321   global1->Set(v8_str("obj"), object);
9322
9323   v8::Handle<Value> value;
9324
9325   // Check that the named access-control function is called every time
9326   // eventhough there is an interceptor on the object.
9327   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9328   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9329                      "obj.x")->Run();
9330   CHECK(value->IsNumber());
9331   CHECK_EQ(42, value->Int32Value());
9332   CHECK_EQ(21, named_access_count);
9333
9334   value = v8_compile("var p = 'x';")->Run();
9335   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9336   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9337                      "obj[p]")->Run();
9338   CHECK(value->IsNumber());
9339   CHECK_EQ(42, value->Int32Value());
9340   CHECK_EQ(42, named_access_count);
9341
9342   // Check that the indexed access-control function is called every
9343   // time eventhough there is an interceptor on the object.
9344   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9345   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9346                      "obj[0]")->Run();
9347   CHECK(value->IsNumber());
9348   CHECK_EQ(42, value->Int32Value());
9349   CHECK_EQ(21, indexed_access_count);
9350
9351   context1->Exit();
9352   context0->Exit();
9353 }
9354
9355
9356 THREADED_TEST(Version) {
9357   v8::V8::GetVersion();
9358 }
9359
9360
9361 static void InstanceFunctionCallback(
9362     const v8::FunctionCallbackInfo<v8::Value>& args) {
9363   ApiTestFuzzer::Fuzz();
9364   args.GetReturnValue().Set(v8_num(12));
9365 }
9366
9367
9368 THREADED_TEST(InstanceProperties) {
9369   LocalContext context;
9370   v8::HandleScope handle_scope(context->GetIsolate());
9371
9372   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9373   Local<ObjectTemplate> instance = t->InstanceTemplate();
9374
9375   instance->Set(v8_str("x"), v8_num(42));
9376   instance->Set(v8_str("f"),
9377                 v8::FunctionTemplate::New(InstanceFunctionCallback));
9378
9379   Local<Value> o = t->GetFunction()->NewInstance();
9380
9381   context->Global()->Set(v8_str("i"), o);
9382   Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
9383   CHECK_EQ(42, value->Int32Value());
9384
9385   value = Script::Compile(v8_str("i.f()"))->Run();
9386   CHECK_EQ(12, value->Int32Value());
9387 }
9388
9389
9390 static void GlobalObjectInstancePropertiesGet(
9391     Local<String> key,
9392     const v8::PropertyCallbackInfo<v8::Value>&) {
9393   ApiTestFuzzer::Fuzz();
9394 }
9395
9396
9397 THREADED_TEST(GlobalObjectInstanceProperties) {
9398   v8::HandleScope handle_scope(CcTest::isolate());
9399
9400   Local<Value> global_object;
9401
9402   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9403   t->InstanceTemplate()->SetNamedPropertyHandler(
9404       GlobalObjectInstancePropertiesGet);
9405   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9406   instance_template->Set(v8_str("x"), v8_num(42));
9407   instance_template->Set(v8_str("f"),
9408                          v8::FunctionTemplate::New(InstanceFunctionCallback));
9409
9410   // The script to check how Crankshaft compiles missing global function
9411   // invocations.  function g is not defined and should throw on call.
9412   const char* script =
9413       "function wrapper(call) {"
9414       "  var x = 0, y = 1;"
9415       "  for (var i = 0; i < 1000; i++) {"
9416       "    x += i * 100;"
9417       "    y += i * 100;"
9418       "  }"
9419       "  if (call) g();"
9420       "}"
9421       "for (var i = 0; i < 17; i++) wrapper(false);"
9422       "var thrown = 0;"
9423       "try { wrapper(true); } catch (e) { thrown = 1; };"
9424       "thrown";
9425
9426   {
9427     LocalContext env(NULL, instance_template);
9428     // Hold on to the global object so it can be used again in another
9429     // environment initialization.
9430     global_object = env->Global();
9431
9432     Local<Value> value = Script::Compile(v8_str("x"))->Run();
9433     CHECK_EQ(42, value->Int32Value());
9434     value = Script::Compile(v8_str("f()"))->Run();
9435     CHECK_EQ(12, value->Int32Value());
9436     value = Script::Compile(v8_str(script))->Run();
9437     CHECK_EQ(1, value->Int32Value());
9438   }
9439
9440   {
9441     // Create new environment reusing the global object.
9442     LocalContext env(NULL, instance_template, global_object);
9443     Local<Value> value = Script::Compile(v8_str("x"))->Run();
9444     CHECK_EQ(42, value->Int32Value());
9445     value = Script::Compile(v8_str("f()"))->Run();
9446     CHECK_EQ(12, value->Int32Value());
9447     value = Script::Compile(v8_str(script))->Run();
9448     CHECK_EQ(1, value->Int32Value());
9449   }
9450 }
9451
9452
9453 THREADED_TEST(CallKnownGlobalReceiver) {
9454   v8::HandleScope handle_scope(CcTest::isolate());
9455
9456   Local<Value> global_object;
9457
9458   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9459   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9460
9461   // The script to check that we leave global object not
9462   // global object proxy on stack when we deoptimize from inside
9463   // arguments evaluation.
9464   // To provoke error we need to both force deoptimization
9465   // from arguments evaluation and to force CallIC to take
9466   // CallIC_Miss code path that can't cope with global proxy.
9467   const char* script =
9468       "function bar(x, y) { try { } finally { } }"
9469       "function baz(x) { try { } finally { } }"
9470       "function bom(x) { try { } finally { } }"
9471       "function foo(x) { bar([x], bom(2)); }"
9472       "for (var i = 0; i < 10000; i++) foo(1);"
9473       "foo";
9474
9475   Local<Value> foo;
9476   {
9477     LocalContext env(NULL, instance_template);
9478     // Hold on to the global object so it can be used again in another
9479     // environment initialization.
9480     global_object = env->Global();
9481     foo = Script::Compile(v8_str(script))->Run();
9482   }
9483
9484   {
9485     // Create new environment reusing the global object.
9486     LocalContext env(NULL, instance_template, global_object);
9487     env->Global()->Set(v8_str("foo"), foo);
9488     Script::Compile(v8_str("foo()"))->Run();
9489   }
9490 }
9491
9492
9493 static void ShadowFunctionCallback(
9494     const v8::FunctionCallbackInfo<v8::Value>& args) {
9495   ApiTestFuzzer::Fuzz();
9496   args.GetReturnValue().Set(v8_num(42));
9497 }
9498
9499
9500 static int shadow_y;
9501 static int shadow_y_setter_call_count;
9502 static int shadow_y_getter_call_count;
9503
9504
9505 static void ShadowYSetter(Local<String>,
9506                           Local<Value>,
9507                           const v8::PropertyCallbackInfo<void>&) {
9508   shadow_y_setter_call_count++;
9509   shadow_y = 42;
9510 }
9511
9512
9513 static void ShadowYGetter(Local<String> name,
9514                           const v8::PropertyCallbackInfo<v8::Value>& info) {
9515   ApiTestFuzzer::Fuzz();
9516   shadow_y_getter_call_count++;
9517   info.GetReturnValue().Set(v8_num(shadow_y));
9518 }
9519
9520
9521 static void ShadowIndexedGet(uint32_t index,
9522                              const v8::PropertyCallbackInfo<v8::Value>&) {
9523 }
9524
9525
9526 static void ShadowNamedGet(Local<String> key,
9527                            const v8::PropertyCallbackInfo<v8::Value>&) {
9528 }
9529
9530
9531 THREADED_TEST(ShadowObject) {
9532   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9533   v8::HandleScope handle_scope(CcTest::isolate());
9534
9535   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
9536   LocalContext context(NULL, global_template);
9537
9538   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9539   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9540   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9541   Local<ObjectTemplate> proto = t->PrototypeTemplate();
9542   Local<ObjectTemplate> instance = t->InstanceTemplate();
9543
9544   proto->Set(v8_str("f"),
9545              v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
9546   proto->Set(v8_str("x"), v8_num(12));
9547
9548   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9549
9550   Local<Value> o = t->GetFunction()->NewInstance();
9551   context->Global()->Set(v8_str("__proto__"), o);
9552
9553   Local<Value> value =
9554       Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9555   CHECK(value->IsBoolean());
9556   CHECK(!value->BooleanValue());
9557
9558   value = Script::Compile(v8_str("x"))->Run();
9559   CHECK_EQ(12, value->Int32Value());
9560
9561   value = Script::Compile(v8_str("f()"))->Run();
9562   CHECK_EQ(42, value->Int32Value());
9563
9564   Script::Compile(v8_str("y = 43"))->Run();
9565   CHECK_EQ(1, shadow_y_setter_call_count);
9566   value = Script::Compile(v8_str("y"))->Run();
9567   CHECK_EQ(1, shadow_y_getter_call_count);
9568   CHECK_EQ(42, value->Int32Value());
9569 }
9570
9571
9572 THREADED_TEST(HiddenPrototype) {
9573   LocalContext context;
9574   v8::HandleScope handle_scope(context->GetIsolate());
9575
9576   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9577   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9578   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9579   t1->SetHiddenPrototype(true);
9580   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9581   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9582   t2->SetHiddenPrototype(true);
9583   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9584   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9585   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9586
9587   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9588   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9589   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9590   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9591
9592   // Setting the prototype on an object skips hidden prototypes.
9593   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9594   o0->Set(v8_str("__proto__"), o1);
9595   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9596   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9597   o0->Set(v8_str("__proto__"), o2);
9598   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9599   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9600   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9601   o0->Set(v8_str("__proto__"), o3);
9602   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9603   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9604   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9605   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9606
9607   // Getting the prototype of o0 should get the first visible one
9608   // which is o3.  Therefore, z should not be defined on the prototype
9609   // object.
9610   Local<Value> proto = o0->Get(v8_str("__proto__"));
9611   CHECK(proto->IsObject());
9612   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9613 }
9614
9615
9616 THREADED_TEST(HiddenPrototypeSet) {
9617   LocalContext context;
9618   v8::HandleScope handle_scope(context->GetIsolate());
9619
9620   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
9621   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
9622   ht->SetHiddenPrototype(true);
9623   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
9624   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9625
9626   Local<v8::Object> o = ot->GetFunction()->NewInstance();
9627   Local<v8::Object> h = ht->GetFunction()->NewInstance();
9628   Local<v8::Object> p = pt->GetFunction()->NewInstance();
9629   o->Set(v8_str("__proto__"), h);
9630   h->Set(v8_str("__proto__"), p);
9631
9632   // Setting a property that exists on the hidden prototype goes there.
9633   o->Set(v8_str("x"), v8_num(7));
9634   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9635   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9636   CHECK(p->Get(v8_str("x"))->IsUndefined());
9637
9638   // Setting a new property should not be forwarded to the hidden prototype.
9639   o->Set(v8_str("y"), v8_num(6));
9640   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9641   CHECK(h->Get(v8_str("y"))->IsUndefined());
9642   CHECK(p->Get(v8_str("y"))->IsUndefined());
9643
9644   // Setting a property that only exists on a prototype of the hidden prototype
9645   // is treated normally again.
9646   p->Set(v8_str("z"), v8_num(8));
9647   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9648   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9649   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9650   o->Set(v8_str("z"), v8_num(9));
9651   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9652   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9653   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9654 }
9655
9656
9657 // Regression test for issue 2457.
9658 THREADED_TEST(HiddenPrototypeIdentityHash) {
9659   LocalContext context;
9660   v8::HandleScope handle_scope(context->GetIsolate());
9661
9662   Handle<FunctionTemplate> t = FunctionTemplate::New();
9663   t->SetHiddenPrototype(true);
9664   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9665   Handle<Object> p = t->GetFunction()->NewInstance();
9666   Handle<Object> o = Object::New();
9667   o->SetPrototype(p);
9668
9669   int hash = o->GetIdentityHash();
9670   USE(hash);
9671   o->Set(v8_str("foo"), v8_num(42));
9672   ASSERT_EQ(hash, o->GetIdentityHash());
9673 }
9674
9675
9676 THREADED_TEST(SetPrototype) {
9677   LocalContext context;
9678   v8::HandleScope handle_scope(context->GetIsolate());
9679
9680   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9681   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9682   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9683   t1->SetHiddenPrototype(true);
9684   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9685   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9686   t2->SetHiddenPrototype(true);
9687   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9688   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9689   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9690
9691   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9692   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9693   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9694   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9695
9696   // Setting the prototype on an object does not skip hidden prototypes.
9697   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9698   CHECK(o0->SetPrototype(o1));
9699   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9700   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9701   CHECK(o1->SetPrototype(o2));
9702   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9703   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9704   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9705   CHECK(o2->SetPrototype(o3));
9706   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9707   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9708   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9709   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9710
9711   // Getting the prototype of o0 should get the first visible one
9712   // which is o3.  Therefore, z should not be defined on the prototype
9713   // object.
9714   Local<Value> proto = o0->Get(v8_str("__proto__"));
9715   CHECK(proto->IsObject());
9716   CHECK_EQ(proto.As<v8::Object>(), o3);
9717
9718   // However, Object::GetPrototype ignores hidden prototype.
9719   Local<Value> proto0 = o0->GetPrototype();
9720   CHECK(proto0->IsObject());
9721   CHECK_EQ(proto0.As<v8::Object>(), o1);
9722
9723   Local<Value> proto1 = o1->GetPrototype();
9724   CHECK(proto1->IsObject());
9725   CHECK_EQ(proto1.As<v8::Object>(), o2);
9726
9727   Local<Value> proto2 = o2->GetPrototype();
9728   CHECK(proto2->IsObject());
9729   CHECK_EQ(proto2.As<v8::Object>(), o3);
9730 }
9731
9732
9733 // Getting property names of an object with a prototype chain that
9734 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
9735 // crash the runtime.
9736 THREADED_TEST(Regress91517) {
9737   i::FLAG_allow_natives_syntax = true;
9738   LocalContext context;
9739   v8::HandleScope handle_scope(context->GetIsolate());
9740
9741   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9742   t1->SetHiddenPrototype(true);
9743   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9744   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9745   t2->SetHiddenPrototype(true);
9746   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9747   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
9748   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9749   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9750   t3->SetHiddenPrototype(true);
9751   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9752   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
9753   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9754
9755   // Force dictionary-based properties.
9756   i::ScopedVector<char> name_buf(1024);
9757   for (int i = 1; i <= 1000; i++) {
9758     i::OS::SNPrintF(name_buf, "sdf%d", i);
9759     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9760   }
9761
9762   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9763   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9764   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9765   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9766
9767   // Create prototype chain of hidden prototypes.
9768   CHECK(o4->SetPrototype(o3));
9769   CHECK(o3->SetPrototype(o2));
9770   CHECK(o2->SetPrototype(o1));
9771
9772   // Call the runtime version of GetLocalPropertyNames() on the natively
9773   // created object through JavaScript.
9774   context->Global()->Set(v8_str("obj"), o4);
9775   CompileRun("var names = %GetLocalPropertyNames(obj, true);");
9776
9777   ExpectInt32("names.length", 1006);
9778   ExpectTrue("names.indexOf(\"baz\") >= 0");
9779   ExpectTrue("names.indexOf(\"boo\") >= 0");
9780   ExpectTrue("names.indexOf(\"foo\") >= 0");
9781   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9782   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9783   ExpectFalse("names[1005] == undefined");
9784 }
9785
9786
9787 THREADED_TEST(FunctionReadOnlyPrototype) {
9788   LocalContext context;
9789   v8::HandleScope handle_scope(context->GetIsolate());
9790
9791   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9792   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9793   t1->ReadOnlyPrototype();
9794   context->Global()->Set(v8_str("func1"), t1->GetFunction());
9795   // Configured value of ReadOnly flag.
9796   CHECK(CompileRun(
9797       "(function() {"
9798       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9799       "  return (descriptor['writable'] == false);"
9800       "})()")->BooleanValue());
9801   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9802   CHECK_EQ(42,
9803            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9804
9805   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9806   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9807   context->Global()->Set(v8_str("func2"), t2->GetFunction());
9808   // Default value of ReadOnly flag.
9809   CHECK(CompileRun(
9810       "(function() {"
9811       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9812       "  return (descriptor['writable'] == true);"
9813       "})()")->BooleanValue());
9814   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9815 }
9816
9817
9818 THREADED_TEST(SetPrototypeThrows) {
9819   LocalContext context;
9820   v8::HandleScope handle_scope(context->GetIsolate());
9821
9822   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9823
9824   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9825   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9826
9827   CHECK(o0->SetPrototype(o1));
9828   // If setting the prototype leads to the cycle, SetPrototype should
9829   // return false and keep VM in sane state.
9830   v8::TryCatch try_catch;
9831   CHECK(!o1->SetPrototype(o0));
9832   CHECK(!try_catch.HasCaught());
9833   ASSERT(!CcTest::i_isolate()->has_pending_exception());
9834
9835   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9836 }
9837
9838
9839 THREADED_TEST(FunctionRemovePrototype) {
9840   LocalContext context;
9841   v8::HandleScope handle_scope(context->GetIsolate());
9842
9843   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9844   t1->RemovePrototype();
9845   Local<v8::Function> fun = t1->GetFunction();
9846   context->Global()->Set(v8_str("fun"), fun);
9847   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9848
9849   v8::TryCatch try_catch;
9850   CompileRun("new fun()");
9851   CHECK(try_catch.HasCaught());
9852
9853   try_catch.Reset();
9854   fun->NewInstance();
9855   CHECK(try_catch.HasCaught());
9856 }
9857
9858
9859 THREADED_TEST(GetterSetterExceptions) {
9860   LocalContext context;
9861   v8::HandleScope handle_scope(context->GetIsolate());
9862   CompileRun(
9863     "function Foo() { };"
9864     "function Throw() { throw 5; };"
9865     "var x = { };"
9866     "x.__defineSetter__('set', Throw);"
9867     "x.__defineGetter__('get', Throw);");
9868   Local<v8::Object> x =
9869       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9870   v8::TryCatch try_catch;
9871   x->Set(v8_str("set"), v8::Integer::New(8));
9872   x->Get(v8_str("get"));
9873   x->Set(v8_str("set"), v8::Integer::New(8));
9874   x->Get(v8_str("get"));
9875   x->Set(v8_str("set"), v8::Integer::New(8));
9876   x->Get(v8_str("get"));
9877   x->Set(v8_str("set"), v8::Integer::New(8));
9878   x->Get(v8_str("get"));
9879 }
9880
9881
9882 THREADED_TEST(Constructor) {
9883   LocalContext context;
9884   v8::HandleScope handle_scope(context->GetIsolate());
9885   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9886   templ->SetClassName(v8_str("Fun"));
9887   Local<Function> cons = templ->GetFunction();
9888   context->Global()->Set(v8_str("Fun"), cons);
9889   Local<v8::Object> inst = cons->NewInstance();
9890   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9891   CHECK(obj->IsJSObject());
9892   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9893   CHECK(value->BooleanValue());
9894 }
9895
9896
9897 static void ConstructorCallback(
9898     const v8::FunctionCallbackInfo<v8::Value>& args) {
9899   ApiTestFuzzer::Fuzz();
9900   Local<Object> This;
9901
9902   if (args.IsConstructCall()) {
9903     Local<Object> Holder = args.Holder();
9904     This = Object::New();
9905     Local<Value> proto = Holder->GetPrototype();
9906     if (proto->IsObject()) {
9907       This->SetPrototype(proto);
9908     }
9909   } else {
9910     This = args.This();
9911   }
9912
9913   This->Set(v8_str("a"), args[0]);
9914   args.GetReturnValue().Set(This);
9915 }
9916
9917
9918 static void FakeConstructorCallback(
9919     const v8::FunctionCallbackInfo<v8::Value>& args) {
9920   ApiTestFuzzer::Fuzz();
9921   args.GetReturnValue().Set(args[0]);
9922 }
9923
9924
9925 THREADED_TEST(ConstructorForObject) {
9926   LocalContext context;
9927   v8::Isolate* isolate = context->GetIsolate();
9928   v8::HandleScope handle_scope(isolate);
9929
9930   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9931     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9932     Local<Object> instance = instance_template->NewInstance();
9933     context->Global()->Set(v8_str("obj"), instance);
9934     v8::TryCatch try_catch;
9935     Local<Value> value;
9936     CHECK(!try_catch.HasCaught());
9937
9938     // Call the Object's constructor with a 32-bit signed integer.
9939     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9940     CHECK(!try_catch.HasCaught());
9941     CHECK(value->IsInt32());
9942     CHECK_EQ(28, value->Int32Value());
9943
9944     Local<Value> args1[] = { v8_num(28) };
9945     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9946     CHECK(value_obj1->IsObject());
9947     Local<Object> object1 = Local<Object>::Cast(value_obj1);
9948     value = object1->Get(v8_str("a"));
9949     CHECK(value->IsInt32());
9950     CHECK(!try_catch.HasCaught());
9951     CHECK_EQ(28, value->Int32Value());
9952
9953     // Call the Object's constructor with a String.
9954     value = CompileRun(
9955         "(function() { var o = new obj('tipli'); return o.a; })()");
9956     CHECK(!try_catch.HasCaught());
9957     CHECK(value->IsString());
9958     String::Utf8Value string_value1(value->ToString());
9959     CHECK_EQ("tipli", *string_value1);
9960
9961     Local<Value> args2[] = { v8_str("tipli") };
9962     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9963     CHECK(value_obj2->IsObject());
9964     Local<Object> object2 = Local<Object>::Cast(value_obj2);
9965     value = object2->Get(v8_str("a"));
9966     CHECK(!try_catch.HasCaught());
9967     CHECK(value->IsString());
9968     String::Utf8Value string_value2(value->ToString());
9969     CHECK_EQ("tipli", *string_value2);
9970
9971     // Call the Object's constructor with a Boolean.
9972     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9973     CHECK(!try_catch.HasCaught());
9974     CHECK(value->IsBoolean());
9975     CHECK_EQ(true, value->BooleanValue());
9976
9977     Handle<Value> args3[] = { v8::True(isolate) };
9978     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9979     CHECK(value_obj3->IsObject());
9980     Local<Object> object3 = Local<Object>::Cast(value_obj3);
9981     value = object3->Get(v8_str("a"));
9982     CHECK(!try_catch.HasCaught());
9983     CHECK(value->IsBoolean());
9984     CHECK_EQ(true, value->BooleanValue());
9985
9986     // Call the Object's constructor with undefined.
9987     Handle<Value> args4[] = { v8::Undefined(isolate) };
9988     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9989     CHECK(value_obj4->IsObject());
9990     Local<Object> object4 = Local<Object>::Cast(value_obj4);
9991     value = object4->Get(v8_str("a"));
9992     CHECK(!try_catch.HasCaught());
9993     CHECK(value->IsUndefined());
9994
9995     // Call the Object's constructor with null.
9996     Handle<Value> args5[] = { v8::Null(isolate) };
9997     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9998     CHECK(value_obj5->IsObject());
9999     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10000     value = object5->Get(v8_str("a"));
10001     CHECK(!try_catch.HasCaught());
10002     CHECK(value->IsNull());
10003   }
10004
10005   // Check exception handling when there is no constructor set for the Object.
10006   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10007     Local<Object> instance = instance_template->NewInstance();
10008     context->Global()->Set(v8_str("obj2"), instance);
10009     v8::TryCatch try_catch;
10010     Local<Value> value;
10011     CHECK(!try_catch.HasCaught());
10012
10013     value = CompileRun("new obj2(28)");
10014     CHECK(try_catch.HasCaught());
10015     String::Utf8Value exception_value1(try_catch.Exception());
10016     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10017     try_catch.Reset();
10018
10019     Local<Value> args[] = { v8_num(29) };
10020     value = instance->CallAsConstructor(1, args);
10021     CHECK(try_catch.HasCaught());
10022     String::Utf8Value exception_value2(try_catch.Exception());
10023     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10024     try_catch.Reset();
10025   }
10026
10027   // Check the case when constructor throws exception.
10028   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10029     instance_template->SetCallAsFunctionHandler(ThrowValue);
10030     Local<Object> instance = instance_template->NewInstance();
10031     context->Global()->Set(v8_str("obj3"), instance);
10032     v8::TryCatch try_catch;
10033     Local<Value> value;
10034     CHECK(!try_catch.HasCaught());
10035
10036     value = CompileRun("new obj3(22)");
10037     CHECK(try_catch.HasCaught());
10038     String::Utf8Value exception_value1(try_catch.Exception());
10039     CHECK_EQ("22", *exception_value1);
10040     try_catch.Reset();
10041
10042     Local<Value> args[] = { v8_num(23) };
10043     value = instance->CallAsConstructor(1, args);
10044     CHECK(try_catch.HasCaught());
10045     String::Utf8Value exception_value2(try_catch.Exception());
10046     CHECK_EQ("23", *exception_value2);
10047     try_catch.Reset();
10048   }
10049
10050   // Check whether constructor returns with an object or non-object.
10051   { Local<FunctionTemplate> function_template =
10052         FunctionTemplate::New(FakeConstructorCallback);
10053     Local<Function> function = function_template->GetFunction();
10054     Local<Object> instance1 = function;
10055     context->Global()->Set(v8_str("obj4"), instance1);
10056     v8::TryCatch try_catch;
10057     Local<Value> value;
10058     CHECK(!try_catch.HasCaught());
10059
10060     CHECK(instance1->IsObject());
10061     CHECK(instance1->IsFunction());
10062
10063     value = CompileRun("new obj4(28)");
10064     CHECK(!try_catch.HasCaught());
10065     CHECK(value->IsObject());
10066
10067     Local<Value> args1[] = { v8_num(28) };
10068     value = instance1->CallAsConstructor(1, args1);
10069     CHECK(!try_catch.HasCaught());
10070     CHECK(value->IsObject());
10071
10072     Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10073     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10074     Local<Object> instance2 = instance_template->NewInstance();
10075     context->Global()->Set(v8_str("obj5"), instance2);
10076     CHECK(!try_catch.HasCaught());
10077
10078     CHECK(instance2->IsObject());
10079     CHECK(!instance2->IsFunction());
10080
10081     value = CompileRun("new obj5(28)");
10082     CHECK(!try_catch.HasCaught());
10083     CHECK(!value->IsObject());
10084
10085     Local<Value> args2[] = { v8_num(28) };
10086     value = instance2->CallAsConstructor(1, args2);
10087     CHECK(!try_catch.HasCaught());
10088     CHECK(!value->IsObject());
10089   }
10090 }
10091
10092
10093 THREADED_TEST(FunctionDescriptorException) {
10094   LocalContext context;
10095   v8::HandleScope handle_scope(context->GetIsolate());
10096   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
10097   templ->SetClassName(v8_str("Fun"));
10098   Local<Function> cons = templ->GetFunction();
10099   context->Global()->Set(v8_str("Fun"), cons);
10100   Local<Value> value = CompileRun(
10101     "function test() {"
10102     "  try {"
10103     "    (new Fun()).blah()"
10104     "  } catch (e) {"
10105     "    var str = String(e);"
10106     "    if (str.indexOf('TypeError') == -1) return 1;"
10107     "    if (str.indexOf('[object Fun]') != -1) return 2;"
10108     "    if (str.indexOf('#<Fun>') == -1) return 3;"
10109     "    return 0;"
10110     "  }"
10111     "  return 4;"
10112     "}"
10113     "test();");
10114   CHECK_EQ(0, value->Int32Value());
10115 }
10116
10117
10118 THREADED_TEST(EvalAliasedDynamic) {
10119   LocalContext current;
10120   v8::HandleScope scope(current->GetIsolate());
10121
10122   // Tests where aliased eval can only be resolved dynamically.
10123   Local<Script> script =
10124       Script::Compile(v8_str("function f(x) { "
10125                              "  var foo = 2;"
10126                              "  with (x) { return eval('foo'); }"
10127                              "}"
10128                              "foo = 0;"
10129                              "result1 = f(new Object());"
10130                              "result2 = f(this);"
10131                              "var x = new Object();"
10132                              "x.eval = function(x) { return 1; };"
10133                              "result3 = f(x);"));
10134   script->Run();
10135   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10136   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10137   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10138
10139   v8::TryCatch try_catch;
10140   script =
10141     Script::Compile(v8_str("function f(x) { "
10142                            "  var bar = 2;"
10143                            "  with (x) { return eval('bar'); }"
10144                            "}"
10145                            "result4 = f(this)"));
10146   script->Run();
10147   CHECK(!try_catch.HasCaught());
10148   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10149
10150   try_catch.Reset();
10151 }
10152
10153
10154 THREADED_TEST(CrossEval) {
10155   v8::HandleScope scope(CcTest::isolate());
10156   LocalContext other;
10157   LocalContext current;
10158
10159   Local<String> token = v8_str("<security token>");
10160   other->SetSecurityToken(token);
10161   current->SetSecurityToken(token);
10162
10163   // Set up reference from current to other.
10164   current->Global()->Set(v8_str("other"), other->Global());
10165
10166   // Check that new variables are introduced in other context.
10167   Local<Script> script =
10168       Script::Compile(v8_str("other.eval('var foo = 1234')"));
10169   script->Run();
10170   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10171   CHECK_EQ(1234, foo->Int32Value());
10172   CHECK(!current->Global()->Has(v8_str("foo")));
10173
10174   // Check that writing to non-existing properties introduces them in
10175   // the other context.
10176   script =
10177       Script::Compile(v8_str("other.eval('na = 1234')"));
10178   script->Run();
10179   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10180   CHECK(!current->Global()->Has(v8_str("na")));
10181
10182   // Check that global variables in current context are not visible in other
10183   // context.
10184   v8::TryCatch try_catch;
10185   script =
10186       Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
10187   Local<Value> result = script->Run();
10188   CHECK(try_catch.HasCaught());
10189   try_catch.Reset();
10190
10191   // Check that local variables in current context are not visible in other
10192   // context.
10193   script =
10194       Script::Compile(v8_str("(function() { "
10195                              "  var baz = 87;"
10196                              "  return other.eval('baz');"
10197                              "})();"));
10198   result = script->Run();
10199   CHECK(try_catch.HasCaught());
10200   try_catch.Reset();
10201
10202   // Check that global variables in the other environment are visible
10203   // when evaluting code.
10204   other->Global()->Set(v8_str("bis"), v8_num(1234));
10205   script = Script::Compile(v8_str("other.eval('bis')"));
10206   CHECK_EQ(1234, script->Run()->Int32Value());
10207   CHECK(!try_catch.HasCaught());
10208
10209   // Check that the 'this' pointer points to the global object evaluating
10210   // code.
10211   other->Global()->Set(v8_str("t"), other->Global());
10212   script = Script::Compile(v8_str("other.eval('this == t')"));
10213   result = script->Run();
10214   CHECK(result->IsTrue());
10215   CHECK(!try_catch.HasCaught());
10216
10217   // Check that variables introduced in with-statement are not visible in
10218   // other context.
10219   script =
10220       Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
10221   result = script->Run();
10222   CHECK(try_catch.HasCaught());
10223   try_catch.Reset();
10224
10225   // Check that you cannot use 'eval.call' with another object than the
10226   // current global object.
10227   script =
10228       Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
10229   result = script->Run();
10230   CHECK(try_catch.HasCaught());
10231 }
10232
10233
10234 // Test that calling eval in a context which has been detached from
10235 // its global throws an exception.  This behavior is consistent with
10236 // other JavaScript implementations.
10237 THREADED_TEST(EvalInDetachedGlobal) {
10238   v8::Isolate* isolate = CcTest::isolate();
10239   v8::HandleScope scope(isolate);
10240
10241   v8::Local<Context> context0 = Context::New(isolate);
10242   v8::Local<Context> context1 = Context::New(isolate);
10243
10244   // Set up function in context0 that uses eval from context0.
10245   context0->Enter();
10246   v8::Handle<v8::Value> fun =
10247       CompileRun("var x = 42;"
10248                  "(function() {"
10249                  "  var e = eval;"
10250                  "  return function(s) { return e(s); }"
10251                  "})()");
10252   context0->Exit();
10253
10254   // Put the function into context1 and call it before and after
10255   // detaching the global.  Before detaching, the call succeeds and
10256   // after detaching and exception is thrown.
10257   context1->Enter();
10258   context1->Global()->Set(v8_str("fun"), fun);
10259   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10260   CHECK_EQ(42, x_value->Int32Value());
10261   context0->DetachGlobal();
10262   v8::TryCatch catcher;
10263   x_value = CompileRun("fun('x')");
10264   CHECK(x_value.IsEmpty());
10265   CHECK(catcher.HasCaught());
10266   context1->Exit();
10267 }
10268
10269
10270 THREADED_TEST(CrossLazyLoad) {
10271   v8::HandleScope scope(CcTest::isolate());
10272   LocalContext other;
10273   LocalContext current;
10274
10275   Local<String> token = v8_str("<security token>");
10276   other->SetSecurityToken(token);
10277   current->SetSecurityToken(token);
10278
10279   // Set up reference from current to other.
10280   current->Global()->Set(v8_str("other"), other->Global());
10281
10282   // Trigger lazy loading in other context.
10283   Local<Script> script =
10284       Script::Compile(v8_str("other.eval('new Date(42)')"));
10285   Local<Value> value = script->Run();
10286   CHECK_EQ(42.0, value->NumberValue());
10287 }
10288
10289
10290 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10291   ApiTestFuzzer::Fuzz();
10292   if (args.IsConstructCall()) {
10293     if (args[0]->IsInt32()) {
10294       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10295       return;
10296     }
10297   }
10298
10299   args.GetReturnValue().Set(args[0]);
10300 }
10301
10302
10303 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10304   args.GetReturnValue().Set(args.This());
10305 }
10306
10307
10308 // Test that a call handler can be set for objects which will allow
10309 // non-function objects created through the API to be called as
10310 // functions.
10311 THREADED_TEST(CallAsFunction) {
10312   LocalContext context;
10313   v8::HandleScope scope(context->GetIsolate());
10314
10315   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10316     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10317     instance_template->SetCallAsFunctionHandler(call_as_function);
10318     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10319     context->Global()->Set(v8_str("obj"), instance);
10320     v8::TryCatch try_catch;
10321     Local<Value> value;
10322     CHECK(!try_catch.HasCaught());
10323
10324     value = CompileRun("obj(42)");
10325     CHECK(!try_catch.HasCaught());
10326     CHECK_EQ(42, value->Int32Value());
10327
10328     value = CompileRun("(function(o){return o(49)})(obj)");
10329     CHECK(!try_catch.HasCaught());
10330     CHECK_EQ(49, value->Int32Value());
10331
10332     // test special case of call as function
10333     value = CompileRun("[obj]['0'](45)");
10334     CHECK(!try_catch.HasCaught());
10335     CHECK_EQ(45, value->Int32Value());
10336
10337     value = CompileRun("obj.call = Function.prototype.call;"
10338                        "obj.call(null, 87)");
10339     CHECK(!try_catch.HasCaught());
10340     CHECK_EQ(87, value->Int32Value());
10341
10342     // Regression tests for bug #1116356: Calling call through call/apply
10343     // must work for non-function receivers.
10344     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10345     value = CompileRun(apply_99);
10346     CHECK(!try_catch.HasCaught());
10347     CHECK_EQ(99, value->Int32Value());
10348
10349     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10350     value = CompileRun(call_17);
10351     CHECK(!try_catch.HasCaught());
10352     CHECK_EQ(17, value->Int32Value());
10353
10354     // Check that the call-as-function handler can be called through
10355     // new.
10356     value = CompileRun("new obj(43)");
10357     CHECK(!try_catch.HasCaught());
10358     CHECK_EQ(-43, value->Int32Value());
10359
10360     // Check that the call-as-function handler can be called through
10361     // the API.
10362     v8::Handle<Value> args[] = { v8_num(28) };
10363     value = instance->CallAsFunction(instance, 1, args);
10364     CHECK(!try_catch.HasCaught());
10365     CHECK_EQ(28, value->Int32Value());
10366   }
10367
10368   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10369     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10370     USE(instance_template);
10371     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10372     context->Global()->Set(v8_str("obj2"), instance);
10373     v8::TryCatch try_catch;
10374     Local<Value> value;
10375     CHECK(!try_catch.HasCaught());
10376
10377     // Call an object without call-as-function handler through the JS
10378     value = CompileRun("obj2(28)");
10379     CHECK(value.IsEmpty());
10380     CHECK(try_catch.HasCaught());
10381     String::Utf8Value exception_value1(try_catch.Exception());
10382     CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
10383              *exception_value1);
10384     try_catch.Reset();
10385
10386     // Call an object without call-as-function handler through the API
10387     value = CompileRun("obj2(28)");
10388     v8::Handle<Value> args[] = { v8_num(28) };
10389     value = instance->CallAsFunction(instance, 1, args);
10390     CHECK(value.IsEmpty());
10391     CHECK(try_catch.HasCaught());
10392     String::Utf8Value exception_value2(try_catch.Exception());
10393     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10394     try_catch.Reset();
10395   }
10396
10397   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10398     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10399     instance_template->SetCallAsFunctionHandler(ThrowValue);
10400     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10401     context->Global()->Set(v8_str("obj3"), instance);
10402     v8::TryCatch try_catch;
10403     Local<Value> value;
10404     CHECK(!try_catch.HasCaught());
10405
10406     // Catch the exception which is thrown by call-as-function handler
10407     value = CompileRun("obj3(22)");
10408     CHECK(try_catch.HasCaught());
10409     String::Utf8Value exception_value1(try_catch.Exception());
10410     CHECK_EQ("22", *exception_value1);
10411     try_catch.Reset();
10412
10413     v8::Handle<Value> args[] = { v8_num(23) };
10414     value = instance->CallAsFunction(instance, 1, args);
10415     CHECK(try_catch.HasCaught());
10416     String::Utf8Value exception_value2(try_catch.Exception());
10417     CHECK_EQ("23", *exception_value2);
10418     try_catch.Reset();
10419   }
10420
10421   { v8::Isolate* isolate = context->GetIsolate();
10422     Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
10423     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10424     instance_template->SetCallAsFunctionHandler(ReturnThis);
10425     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10426
10427     Local<v8::Value> a1 =
10428         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10429     CHECK(a1->StrictEquals(instance));
10430     Local<v8::Value> a2 =
10431         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10432     CHECK(a2->StrictEquals(instance));
10433     Local<v8::Value> a3 =
10434         instance->CallAsFunction(v8_num(42), 0, NULL);
10435     CHECK(a3->StrictEquals(instance));
10436     Local<v8::Value> a4 =
10437         instance->CallAsFunction(v8_str("hello"), 0, NULL);
10438     CHECK(a4->StrictEquals(instance));
10439     Local<v8::Value> a5 =
10440         instance->CallAsFunction(v8::True(isolate), 0, NULL);
10441     CHECK(a5->StrictEquals(instance));
10442   }
10443
10444   { v8::Isolate* isolate = context->GetIsolate();
10445     CompileRun(
10446       "function ReturnThisSloppy() {"
10447       "  return this;"
10448       "}"
10449       "function ReturnThisStrict() {"
10450       "  'use strict';"
10451       "  return this;"
10452       "}");
10453     Local<Function> ReturnThisSloppy =
10454         Local<Function>::Cast(
10455             context->Global()->Get(v8_str("ReturnThisSloppy")));
10456     Local<Function> ReturnThisStrict =
10457         Local<Function>::Cast(
10458             context->Global()->Get(v8_str("ReturnThisStrict")));
10459
10460     Local<v8::Value> a1 =
10461         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10462     CHECK(a1->StrictEquals(context->Global()));
10463     Local<v8::Value> a2 =
10464         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10465     CHECK(a2->StrictEquals(context->Global()));
10466     Local<v8::Value> a3 =
10467         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10468     CHECK(a3->IsNumberObject());
10469     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10470     Local<v8::Value> a4 =
10471         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10472     CHECK(a4->IsStringObject());
10473     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10474     Local<v8::Value> a5 =
10475         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10476     CHECK(a5->IsBooleanObject());
10477     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10478
10479     Local<v8::Value> a6 =
10480         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10481     CHECK(a6->IsUndefined());
10482     Local<v8::Value> a7 =
10483         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10484     CHECK(a7->IsNull());
10485     Local<v8::Value> a8 =
10486         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10487     CHECK(a8->StrictEquals(v8_num(42)));
10488     Local<v8::Value> a9 =
10489         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10490     CHECK(a9->StrictEquals(v8_str("hello")));
10491     Local<v8::Value> a10 =
10492         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10493     CHECK(a10->StrictEquals(v8::True(isolate)));
10494   }
10495 }
10496
10497
10498 // Check whether a non-function object is callable.
10499 THREADED_TEST(CallableObject) {
10500   LocalContext context;
10501   v8::HandleScope scope(context->GetIsolate());
10502
10503   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10504     instance_template->SetCallAsFunctionHandler(call_as_function);
10505     Local<Object> instance = instance_template->NewInstance();
10506     v8::TryCatch try_catch;
10507
10508     CHECK(instance->IsCallable());
10509     CHECK(!try_catch.HasCaught());
10510   }
10511
10512   { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
10513     Local<Object> instance = instance_template->NewInstance();
10514     v8::TryCatch try_catch;
10515
10516     CHECK(!instance->IsCallable());
10517     CHECK(!try_catch.HasCaught());
10518   }
10519
10520   { Local<FunctionTemplate> function_template =
10521         FunctionTemplate::New(call_as_function);
10522     Local<Function> function = function_template->GetFunction();
10523     Local<Object> instance = function;
10524     v8::TryCatch try_catch;
10525
10526     CHECK(instance->IsCallable());
10527     CHECK(!try_catch.HasCaught());
10528   }
10529
10530   { Local<FunctionTemplate> function_template = FunctionTemplate::New();
10531     Local<Function> function = function_template->GetFunction();
10532     Local<Object> instance = function;
10533     v8::TryCatch try_catch;
10534
10535     CHECK(instance->IsCallable());
10536     CHECK(!try_catch.HasCaught());
10537   }
10538 }
10539
10540
10541 static int CountHandles() {
10542   return v8::HandleScope::NumberOfHandles();
10543 }
10544
10545
10546 static int Recurse(int depth, int iterations) {
10547   v8::HandleScope scope(CcTest::isolate());
10548   if (depth == 0) return CountHandles();
10549   for (int i = 0; i < iterations; i++) {
10550     Local<v8::Number> n(v8::Integer::New(42));
10551   }
10552   return Recurse(depth - 1, iterations);
10553 }
10554
10555
10556 THREADED_TEST(HandleIteration) {
10557   static const int kIterations = 500;
10558   static const int kNesting = 200;
10559   CHECK_EQ(0, CountHandles());
10560   {
10561     v8::HandleScope scope1(CcTest::isolate());
10562     CHECK_EQ(0, CountHandles());
10563     for (int i = 0; i < kIterations; i++) {
10564       Local<v8::Number> n(v8::Integer::New(42));
10565       CHECK_EQ(i + 1, CountHandles());
10566     }
10567
10568     CHECK_EQ(kIterations, CountHandles());
10569     {
10570       v8::HandleScope scope2(CcTest::isolate());
10571       for (int j = 0; j < kIterations; j++) {
10572         Local<v8::Number> n(v8::Integer::New(42));
10573         CHECK_EQ(j + 1 + kIterations, CountHandles());
10574       }
10575     }
10576     CHECK_EQ(kIterations, CountHandles());
10577   }
10578   CHECK_EQ(0, CountHandles());
10579   CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
10580 }
10581
10582
10583 static void InterceptorHasOwnPropertyGetter(
10584     Local<String> name,
10585     const v8::PropertyCallbackInfo<v8::Value>& info) {
10586   ApiTestFuzzer::Fuzz();
10587 }
10588
10589
10590 THREADED_TEST(InterceptorHasOwnProperty) {
10591   LocalContext context;
10592   v8::HandleScope scope(context->GetIsolate());
10593   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10594   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10595   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
10596   Local<Function> function = fun_templ->GetFunction();
10597   context->Global()->Set(v8_str("constructor"), function);
10598   v8::Handle<Value> value = CompileRun(
10599       "var o = new constructor();"
10600       "o.hasOwnProperty('ostehaps');");
10601   CHECK_EQ(false, value->BooleanValue());
10602   value = CompileRun(
10603       "o.ostehaps = 42;"
10604       "o.hasOwnProperty('ostehaps');");
10605   CHECK_EQ(true, value->BooleanValue());
10606   value = CompileRun(
10607       "var p = new constructor();"
10608       "p.hasOwnProperty('ostehaps');");
10609   CHECK_EQ(false, value->BooleanValue());
10610 }
10611
10612
10613 static void InterceptorHasOwnPropertyGetterGC(
10614     Local<String> name,
10615     const v8::PropertyCallbackInfo<v8::Value>& info) {
10616   ApiTestFuzzer::Fuzz();
10617   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
10618 }
10619
10620
10621 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
10622   LocalContext context;
10623   v8::HandleScope scope(context->GetIsolate());
10624   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10625   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10626   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
10627   Local<Function> function = fun_templ->GetFunction();
10628   context->Global()->Set(v8_str("constructor"), function);
10629   // Let's first make some stuff so we can be sure to get a good GC.
10630   CompileRun(
10631       "function makestr(size) {"
10632       "  switch (size) {"
10633       "    case 1: return 'f';"
10634       "    case 2: return 'fo';"
10635       "    case 3: return 'foo';"
10636       "  }"
10637       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
10638       "}"
10639       "var x = makestr(12345);"
10640       "x = makestr(31415);"
10641       "x = makestr(23456);");
10642   v8::Handle<Value> value = CompileRun(
10643       "var o = new constructor();"
10644       "o.__proto__ = new String(x);"
10645       "o.hasOwnProperty('ostehaps');");
10646   CHECK_EQ(false, value->BooleanValue());
10647 }
10648
10649
10650 typedef void (*NamedPropertyGetter)(
10651     Local<String> property,
10652     const v8::PropertyCallbackInfo<v8::Value>& info);
10653
10654
10655 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
10656                                    const char* source,
10657                                    int expected) {
10658   v8::HandleScope scope(CcTest::isolate());
10659   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10660   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
10661   LocalContext context;
10662   context->Global()->Set(v8_str("o"), templ->NewInstance());
10663   v8::Handle<Value> value = CompileRun(source);
10664   CHECK_EQ(expected, value->Int32Value());
10665 }
10666
10667
10668 static void InterceptorLoadICGetter(
10669     Local<String> name,
10670     const v8::PropertyCallbackInfo<v8::Value>& info) {
10671   ApiTestFuzzer::Fuzz();
10672   v8::Isolate* isolate = CcTest::isolate();
10673   CHECK_EQ(isolate, info.GetIsolate());
10674   CHECK_EQ(v8_str("data"), info.Data());
10675   CHECK_EQ(v8_str("x"), name);
10676   info.GetReturnValue().Set(v8::Integer::New(42));
10677 }
10678
10679
10680 // This test should hit the load IC for the interceptor case.
10681 THREADED_TEST(InterceptorLoadIC) {
10682   CheckInterceptorLoadIC(InterceptorLoadICGetter,
10683     "var result = 0;"
10684     "for (var i = 0; i < 1000; i++) {"
10685     "  result = o.x;"
10686     "}",
10687     42);
10688 }
10689
10690
10691 // Below go several tests which verify that JITing for various
10692 // configurations of interceptor and explicit fields works fine
10693 // (those cases are special cased to get better performance).
10694
10695 static void InterceptorLoadXICGetter(
10696     Local<String> name,
10697     const v8::PropertyCallbackInfo<v8::Value>& info) {
10698   ApiTestFuzzer::Fuzz();
10699   info.GetReturnValue().Set(
10700       v8_str("x")->Equals(name) ?
10701           v8::Handle<v8::Value>(v8::Integer::New(42)) :
10702           v8::Handle<v8::Value>());
10703 }
10704
10705
10706 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
10707   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10708     "var result = 0;"
10709     "o.y = 239;"
10710     "for (var i = 0; i < 1000; i++) {"
10711     "  result = o.y;"
10712     "}",
10713     239);
10714 }
10715
10716
10717 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
10718   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10719     "var result = 0;"
10720     "o.__proto__ = { 'y': 239 };"
10721     "for (var i = 0; i < 1000; i++) {"
10722     "  result = o.y + o.x;"
10723     "}",
10724     239 + 42);
10725 }
10726
10727
10728 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
10729   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10730     "var result = 0;"
10731     "o.__proto__.y = 239;"
10732     "for (var i = 0; i < 1000; i++) {"
10733     "  result = o.y + o.x;"
10734     "}",
10735     239 + 42);
10736 }
10737
10738
10739 THREADED_TEST(InterceptorLoadICUndefined) {
10740   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10741     "var result = 0;"
10742     "for (var i = 0; i < 1000; i++) {"
10743     "  result = (o.y == undefined) ? 239 : 42;"
10744     "}",
10745     239);
10746 }
10747
10748
10749 THREADED_TEST(InterceptorLoadICWithOverride) {
10750   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10751     "fst = new Object();  fst.__proto__ = o;"
10752     "snd = new Object();  snd.__proto__ = fst;"
10753     "var result1 = 0;"
10754     "for (var i = 0; i < 1000;  i++) {"
10755     "  result1 = snd.x;"
10756     "}"
10757     "fst.x = 239;"
10758     "var result = 0;"
10759     "for (var i = 0; i < 1000; i++) {"
10760     "  result = snd.x;"
10761     "}"
10762     "result + result1",
10763     239 + 42);
10764 }
10765
10766
10767 // Test the case when we stored field into
10768 // a stub, but interceptor produced value on its own.
10769 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
10770   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10771     "proto = new Object();"
10772     "o.__proto__ = proto;"
10773     "proto.x = 239;"
10774     "for (var i = 0; i < 1000; i++) {"
10775     "  o.x;"
10776     // Now it should be ICed and keep a reference to x defined on proto
10777     "}"
10778     "var result = 0;"
10779     "for (var i = 0; i < 1000; i++) {"
10780     "  result += o.x;"
10781     "}"
10782     "result;",
10783     42 * 1000);
10784 }
10785
10786
10787 // Test the case when we stored field into
10788 // a stub, but it got invalidated later on.
10789 THREADED_TEST(InterceptorLoadICInvalidatedField) {
10790   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10791     "proto1 = new Object();"
10792     "proto2 = new Object();"
10793     "o.__proto__ = proto1;"
10794     "proto1.__proto__ = proto2;"
10795     "proto2.y = 239;"
10796     "for (var i = 0; i < 1000; i++) {"
10797     "  o.y;"
10798     // Now it should be ICed and keep a reference to y defined on proto2
10799     "}"
10800     "proto1.y = 42;"
10801     "var result = 0;"
10802     "for (var i = 0; i < 1000; i++) {"
10803     "  result += o.y;"
10804     "}"
10805     "result;",
10806     42 * 1000);
10807 }
10808
10809
10810 static int interceptor_load_not_handled_calls = 0;
10811 static void InterceptorLoadNotHandled(
10812     Local<String> name,
10813     const v8::PropertyCallbackInfo<v8::Value>& info) {
10814   ++interceptor_load_not_handled_calls;
10815 }
10816
10817
10818 // Test how post-interceptor lookups are done in the non-cacheable
10819 // case: the interceptor should not be invoked during this lookup.
10820 THREADED_TEST(InterceptorLoadICPostInterceptor) {
10821   interceptor_load_not_handled_calls = 0;
10822   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
10823     "receiver = new Object();"
10824     "receiver.__proto__ = o;"
10825     "proto = new Object();"
10826     "/* Make proto a slow-case object. */"
10827     "for (var i = 0; i < 1000; i++) {"
10828     "  proto[\"xxxxxxxx\" + i] = [];"
10829     "}"
10830     "proto.x = 17;"
10831     "o.__proto__ = proto;"
10832     "var result = 0;"
10833     "for (var i = 0; i < 1000; i++) {"
10834     "  result += receiver.x;"
10835     "}"
10836     "result;",
10837     17 * 1000);
10838   CHECK_EQ(1000, interceptor_load_not_handled_calls);
10839 }
10840
10841
10842 // Test the case when we stored field into
10843 // a stub, but it got invalidated later on due to override on
10844 // global object which is between interceptor and fields' holders.
10845 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
10846   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10847     "o.__proto__ = this;"  // set a global to be a proto of o.
10848     "this.__proto__.y = 239;"
10849     "for (var i = 0; i < 10; i++) {"
10850     "  if (o.y != 239) throw 'oops: ' + o.y;"
10851     // Now it should be ICed and keep a reference to y defined on field_holder.
10852     "}"
10853     "this.y = 42;"  // Assign on a global.
10854     "var result = 0;"
10855     "for (var i = 0; i < 10; i++) {"
10856     "  result += o.y;"
10857     "}"
10858     "result;",
10859     42 * 10);
10860 }
10861
10862
10863 static void SetOnThis(Local<String> name,
10864                       Local<Value> value,
10865                       const v8::PropertyCallbackInfo<void>& info) {
10866   info.This()->ForceSet(name, value);
10867 }
10868
10869
10870 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
10871   v8::HandleScope scope(CcTest::isolate());
10872   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10873   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10874   templ->SetAccessor(v8_str("y"), Return239Callback);
10875   LocalContext context;
10876   context->Global()->Set(v8_str("o"), templ->NewInstance());
10877
10878   // Check the case when receiver and interceptor's holder
10879   // are the same objects.
10880   v8::Handle<Value> value = CompileRun(
10881       "var result = 0;"
10882       "for (var i = 0; i < 7; i++) {"
10883       "  result = o.y;"
10884       "}");
10885   CHECK_EQ(239, value->Int32Value());
10886
10887   // Check the case when interceptor's holder is in proto chain
10888   // of receiver.
10889   value = CompileRun(
10890       "r = { __proto__: o };"
10891       "var result = 0;"
10892       "for (var i = 0; i < 7; i++) {"
10893       "  result = r.y;"
10894       "}");
10895   CHECK_EQ(239, value->Int32Value());
10896 }
10897
10898
10899 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
10900   v8::HandleScope scope(CcTest::isolate());
10901   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10902   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10903   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10904   templ_p->SetAccessor(v8_str("y"), Return239Callback);
10905
10906   LocalContext context;
10907   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10908   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10909
10910   // Check the case when receiver and interceptor's holder
10911   // are the same objects.
10912   v8::Handle<Value> value = CompileRun(
10913       "o.__proto__ = p;"
10914       "var result = 0;"
10915       "for (var i = 0; i < 7; i++) {"
10916       "  result = o.x + o.y;"
10917       "}");
10918   CHECK_EQ(239 + 42, value->Int32Value());
10919
10920   // Check the case when interceptor's holder is in proto chain
10921   // of receiver.
10922   value = CompileRun(
10923       "r = { __proto__: o };"
10924       "var result = 0;"
10925       "for (var i = 0; i < 7; i++) {"
10926       "  result = r.x + r.y;"
10927       "}");
10928   CHECK_EQ(239 + 42, value->Int32Value());
10929 }
10930
10931
10932 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
10933   v8::HandleScope scope(CcTest::isolate());
10934   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10935   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10936   templ->SetAccessor(v8_str("y"), Return239Callback);
10937
10938   LocalContext context;
10939   context->Global()->Set(v8_str("o"), templ->NewInstance());
10940
10941   v8::Handle<Value> value = CompileRun(
10942     "fst = new Object();  fst.__proto__ = o;"
10943     "snd = new Object();  snd.__proto__ = fst;"
10944     "var result1 = 0;"
10945     "for (var i = 0; i < 7;  i++) {"
10946     "  result1 = snd.x;"
10947     "}"
10948     "fst.x = 239;"
10949     "var result = 0;"
10950     "for (var i = 0; i < 7; i++) {"
10951     "  result = snd.x;"
10952     "}"
10953     "result + result1");
10954   CHECK_EQ(239 + 42, value->Int32Value());
10955 }
10956
10957
10958 // Test the case when we stored callback into
10959 // a stub, but interceptor produced value on its own.
10960 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
10961   v8::HandleScope scope(CcTest::isolate());
10962   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10963   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10964   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10965   templ_p->SetAccessor(v8_str("y"), Return239Callback);
10966
10967   LocalContext context;
10968   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10969   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10970
10971   v8::Handle<Value> value = CompileRun(
10972     "o.__proto__ = p;"
10973     "for (var i = 0; i < 7; i++) {"
10974     "  o.x;"
10975     // Now it should be ICed and keep a reference to x defined on p
10976     "}"
10977     "var result = 0;"
10978     "for (var i = 0; i < 7; i++) {"
10979     "  result += o.x;"
10980     "}"
10981     "result");
10982   CHECK_EQ(42 * 7, value->Int32Value());
10983 }
10984
10985
10986 // Test the case when we stored callback into
10987 // a stub, but it got invalidated later on.
10988 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
10989   v8::HandleScope scope(CcTest::isolate());
10990   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10991   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10992   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10993   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10994
10995   LocalContext context;
10996   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10997   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10998
10999   v8::Handle<Value> value = CompileRun(
11000     "inbetween = new Object();"
11001     "o.__proto__ = inbetween;"
11002     "inbetween.__proto__ = p;"
11003     "for (var i = 0; i < 10; i++) {"
11004     "  o.y;"
11005     // Now it should be ICed and keep a reference to y defined on p
11006     "}"
11007     "inbetween.y = 42;"
11008     "var result = 0;"
11009     "for (var i = 0; i < 10; i++) {"
11010     "  result += o.y;"
11011     "}"
11012     "result");
11013   CHECK_EQ(42 * 10, value->Int32Value());
11014 }
11015
11016
11017 // Test the case when we stored callback into
11018 // a stub, but it got invalidated later on due to override on
11019 // global object which is between interceptor and callbacks' holders.
11020 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11021   v8::HandleScope scope(CcTest::isolate());
11022   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11023   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11024   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
11025   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11026
11027   LocalContext context;
11028   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11029   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11030
11031   v8::Handle<Value> value = CompileRun(
11032     "o.__proto__ = this;"
11033     "this.__proto__ = p;"
11034     "for (var i = 0; i < 10; i++) {"
11035     "  if (o.y != 239) throw 'oops: ' + o.y;"
11036     // Now it should be ICed and keep a reference to y defined on p
11037     "}"
11038     "this.y = 42;"
11039     "var result = 0;"
11040     "for (var i = 0; i < 10; i++) {"
11041     "  result += o.y;"
11042     "}"
11043     "result");
11044   CHECK_EQ(42 * 10, value->Int32Value());
11045 }
11046
11047
11048 static void InterceptorLoadICGetter0(
11049     Local<String> name,
11050     const v8::PropertyCallbackInfo<v8::Value>& info) {
11051   ApiTestFuzzer::Fuzz();
11052   CHECK(v8_str("x")->Equals(name));
11053   info.GetReturnValue().Set(v8::Integer::New(0));
11054 }
11055
11056
11057 THREADED_TEST(InterceptorReturningZero) {
11058   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11059      "o.x == undefined ? 1 : 0",
11060      0);
11061 }
11062
11063
11064 static void InterceptorStoreICSetter(
11065     Local<String> key,
11066     Local<Value> value,
11067     const v8::PropertyCallbackInfo<v8::Value>& info) {
11068   CHECK(v8_str("x")->Equals(key));
11069   CHECK_EQ(42, value->Int32Value());
11070   info.GetReturnValue().Set(value);
11071 }
11072
11073
11074 // This test should hit the store IC for the interceptor case.
11075 THREADED_TEST(InterceptorStoreIC) {
11076   v8::HandleScope scope(CcTest::isolate());
11077   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11078   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11079                                  InterceptorStoreICSetter,
11080                                  0, 0, 0, v8_str("data"));
11081   LocalContext context;
11082   context->Global()->Set(v8_str("o"), templ->NewInstance());
11083   CompileRun(
11084       "for (var i = 0; i < 1000; i++) {"
11085       "  o.x = 42;"
11086       "}");
11087 }
11088
11089
11090 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11091   v8::HandleScope scope(CcTest::isolate());
11092   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11093   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11094   LocalContext context;
11095   context->Global()->Set(v8_str("o"), templ->NewInstance());
11096   v8::Handle<Value> value = CompileRun(
11097     "for (var i = 0; i < 1000; i++) {"
11098     "  o.y = 239;"
11099     "}"
11100     "42 + o.y");
11101   CHECK_EQ(239 + 42, value->Int32Value());
11102 }
11103
11104
11105
11106
11107 v8::Handle<Value> call_ic_function;
11108 v8::Handle<Value> call_ic_function2;
11109 v8::Handle<Value> call_ic_function3;
11110
11111 static void InterceptorCallICGetter(
11112     Local<String> name,
11113     const v8::PropertyCallbackInfo<v8::Value>& info) {
11114   ApiTestFuzzer::Fuzz();
11115   CHECK(v8_str("x")->Equals(name));
11116   info.GetReturnValue().Set(call_ic_function);
11117 }
11118
11119
11120 // This test should hit the call IC for the interceptor case.
11121 THREADED_TEST(InterceptorCallIC) {
11122   v8::HandleScope scope(CcTest::isolate());
11123   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11124   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11125   LocalContext context;
11126   context->Global()->Set(v8_str("o"), templ->NewInstance());
11127   call_ic_function =
11128       v8_compile("function f(x) { return x + 1; }; f")->Run();
11129   v8::Handle<Value> value = CompileRun(
11130     "var result = 0;"
11131     "for (var i = 0; i < 1000; i++) {"
11132     "  result = o.x(41);"
11133     "}");
11134   CHECK_EQ(42, value->Int32Value());
11135 }
11136
11137
11138 // This test checks that if interceptor doesn't provide
11139 // a value, we can fetch regular value.
11140 THREADED_TEST(InterceptorCallICSeesOthers) {
11141   v8::HandleScope scope(CcTest::isolate());
11142   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11143   templ->SetNamedPropertyHandler(NoBlockGetterX);
11144   LocalContext context;
11145   context->Global()->Set(v8_str("o"), templ->NewInstance());
11146   v8::Handle<Value> value = CompileRun(
11147     "o.x = function f(x) { return x + 1; };"
11148     "var result = 0;"
11149     "for (var i = 0; i < 7; i++) {"
11150     "  result = o.x(41);"
11151     "}");
11152   CHECK_EQ(42, value->Int32Value());
11153 }
11154
11155
11156 static v8::Handle<Value> call_ic_function4;
11157 static void InterceptorCallICGetter4(
11158     Local<String> name,
11159     const v8::PropertyCallbackInfo<v8::Value>& info) {
11160   ApiTestFuzzer::Fuzz();
11161   CHECK(v8_str("x")->Equals(name));
11162   info.GetReturnValue().Set(call_ic_function4);
11163 }
11164
11165
11166 // This test checks that if interceptor provides a function,
11167 // even if we cached shadowed variant, interceptor's function
11168 // is invoked
11169 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11170   v8::HandleScope scope(CcTest::isolate());
11171   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11172   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11173   LocalContext context;
11174   context->Global()->Set(v8_str("o"), templ->NewInstance());
11175   call_ic_function4 =
11176       v8_compile("function f(x) { return x - 1; }; f")->Run();
11177   v8::Handle<Value> value = CompileRun(
11178     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11179     "var result = 0;"
11180     "for (var i = 0; i < 1000; i++) {"
11181     "  result = o.x(42);"
11182     "}");
11183   CHECK_EQ(41, value->Int32Value());
11184 }
11185
11186
11187 // Test the case when we stored cacheable lookup into
11188 // a stub, but it got invalidated later on
11189 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11190   v8::HandleScope scope(CcTest::isolate());
11191   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11192   templ->SetNamedPropertyHandler(NoBlockGetterX);
11193   LocalContext context;
11194   context->Global()->Set(v8_str("o"), templ->NewInstance());
11195   v8::Handle<Value> value = CompileRun(
11196     "proto1 = new Object();"
11197     "proto2 = new Object();"
11198     "o.__proto__ = proto1;"
11199     "proto1.__proto__ = proto2;"
11200     "proto2.y = function(x) { return x + 1; };"
11201     // Invoke it many times to compile a stub
11202     "for (var i = 0; i < 7; i++) {"
11203     "  o.y(42);"
11204     "}"
11205     "proto1.y = function(x) { return x - 1; };"
11206     "var result = 0;"
11207     "for (var i = 0; i < 7; i++) {"
11208     "  result += o.y(42);"
11209     "}");
11210   CHECK_EQ(41 * 7, value->Int32Value());
11211 }
11212
11213
11214 // This test checks that if interceptor doesn't provide a function,
11215 // cached constant function is used
11216 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11217   v8::HandleScope scope(CcTest::isolate());
11218   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11219   templ->SetNamedPropertyHandler(NoBlockGetterX);
11220   LocalContext context;
11221   context->Global()->Set(v8_str("o"), templ->NewInstance());
11222   v8::Handle<Value> value = CompileRun(
11223     "function inc(x) { return x + 1; };"
11224     "inc(1);"
11225     "o.x = inc;"
11226     "var result = 0;"
11227     "for (var i = 0; i < 1000; i++) {"
11228     "  result = o.x(42);"
11229     "}");
11230   CHECK_EQ(43, value->Int32Value());
11231 }
11232
11233
11234 static v8::Handle<Value> call_ic_function5;
11235 static void InterceptorCallICGetter5(
11236     Local<String> name,
11237     const v8::PropertyCallbackInfo<v8::Value>& info) {
11238   ApiTestFuzzer::Fuzz();
11239   if (v8_str("x")->Equals(name))
11240     info.GetReturnValue().Set(call_ic_function5);
11241 }
11242
11243
11244 // This test checks that if interceptor provides a function,
11245 // even if we cached constant function, interceptor's function
11246 // is invoked
11247 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11248   v8::HandleScope scope(CcTest::isolate());
11249   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11250   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11251   LocalContext context;
11252   context->Global()->Set(v8_str("o"), templ->NewInstance());
11253   call_ic_function5 =
11254       v8_compile("function f(x) { return x - 1; }; f")->Run();
11255   v8::Handle<Value> value = CompileRun(
11256     "function inc(x) { return x + 1; };"
11257     "inc(1);"
11258     "o.x = inc;"
11259     "var result = 0;"
11260     "for (var i = 0; i < 1000; i++) {"
11261     "  result = o.x(42);"
11262     "}");
11263   CHECK_EQ(41, value->Int32Value());
11264 }
11265
11266
11267 static v8::Handle<Value> call_ic_function6;
11268 static void InterceptorCallICGetter6(
11269     Local<String> name,
11270     const v8::PropertyCallbackInfo<v8::Value>& info) {
11271   ApiTestFuzzer::Fuzz();
11272   if (v8_str("x")->Equals(name))
11273     info.GetReturnValue().Set(call_ic_function6);
11274 }
11275
11276
11277 // Same test as above, except the code is wrapped in a function
11278 // to test the optimized compiler.
11279 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11280   i::FLAG_allow_natives_syntax = true;
11281   v8::HandleScope scope(CcTest::isolate());
11282   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11283   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11284   LocalContext context;
11285   context->Global()->Set(v8_str("o"), templ->NewInstance());
11286   call_ic_function6 =
11287       v8_compile("function f(x) { return x - 1; }; f")->Run();
11288   v8::Handle<Value> value = CompileRun(
11289     "function inc(x) { return x + 1; };"
11290     "inc(1);"
11291     "o.x = inc;"
11292     "function test() {"
11293     "  var result = 0;"
11294     "  for (var i = 0; i < 1000; i++) {"
11295     "    result = o.x(42);"
11296     "  }"
11297     "  return result;"
11298     "};"
11299     "test();"
11300     "test();"
11301     "test();"
11302     "%OptimizeFunctionOnNextCall(test);"
11303     "test()");
11304   CHECK_EQ(41, value->Int32Value());
11305 }
11306
11307
11308 // Test the case when we stored constant function into
11309 // a stub, but it got invalidated later on
11310 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11311   v8::HandleScope scope(CcTest::isolate());
11312   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11313   templ->SetNamedPropertyHandler(NoBlockGetterX);
11314   LocalContext context;
11315   context->Global()->Set(v8_str("o"), templ->NewInstance());
11316   v8::Handle<Value> value = CompileRun(
11317     "function inc(x) { return x + 1; };"
11318     "inc(1);"
11319     "proto1 = new Object();"
11320     "proto2 = new Object();"
11321     "o.__proto__ = proto1;"
11322     "proto1.__proto__ = proto2;"
11323     "proto2.y = inc;"
11324     // Invoke it many times to compile a stub
11325     "for (var i = 0; i < 7; i++) {"
11326     "  o.y(42);"
11327     "}"
11328     "proto1.y = function(x) { return x - 1; };"
11329     "var result = 0;"
11330     "for (var i = 0; i < 7; i++) {"
11331     "  result += o.y(42);"
11332     "}");
11333   CHECK_EQ(41 * 7, value->Int32Value());
11334 }
11335
11336
11337 // Test the case when we stored constant function into
11338 // a stub, but it got invalidated later on due to override on
11339 // global object which is between interceptor and constant function' holders.
11340 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11341   v8::HandleScope scope(CcTest::isolate());
11342   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11343   templ->SetNamedPropertyHandler(NoBlockGetterX);
11344   LocalContext context;
11345   context->Global()->Set(v8_str("o"), templ->NewInstance());
11346   v8::Handle<Value> value = CompileRun(
11347     "function inc(x) { return x + 1; };"
11348     "inc(1);"
11349     "o.__proto__ = this;"
11350     "this.__proto__.y = inc;"
11351     // Invoke it many times to compile a stub
11352     "for (var i = 0; i < 7; i++) {"
11353     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11354     "}"
11355     "this.y = function(x) { return x - 1; };"
11356     "var result = 0;"
11357     "for (var i = 0; i < 7; i++) {"
11358     "  result += o.y(42);"
11359     "}");
11360   CHECK_EQ(41 * 7, value->Int32Value());
11361 }
11362
11363
11364 // Test the case when actual function to call sits on global object.
11365 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11366   v8::HandleScope scope(CcTest::isolate());
11367   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11368   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11369
11370   LocalContext context;
11371   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11372
11373   v8::Handle<Value> value = CompileRun(
11374     "try {"
11375     "  o.__proto__ = this;"
11376     "  for (var i = 0; i < 10; i++) {"
11377     "    var v = o.parseFloat('239');"
11378     "    if (v != 239) throw v;"
11379       // Now it should be ICed and keep a reference to parseFloat.
11380     "  }"
11381     "  var result = 0;"
11382     "  for (var i = 0; i < 10; i++) {"
11383     "    result += o.parseFloat('239');"
11384     "  }"
11385     "  result"
11386     "} catch(e) {"
11387     "  e"
11388     "};");
11389   CHECK_EQ(239 * 10, value->Int32Value());
11390 }
11391
11392 static void InterceptorCallICFastApi(
11393     Local<String> name,
11394     const v8::PropertyCallbackInfo<v8::Value>& info) {
11395   ApiTestFuzzer::Fuzz();
11396   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
11397   int* call_count =
11398       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
11399   ++(*call_count);
11400   if ((*call_count) % 20 == 0) {
11401     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11402   }
11403 }
11404
11405 static void FastApiCallback_TrivialSignature(
11406     const v8::FunctionCallbackInfo<v8::Value>& args) {
11407   ApiTestFuzzer::Fuzz();
11408   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
11409   v8::Isolate* isolate = CcTest::isolate();
11410   CHECK_EQ(isolate, args.GetIsolate());
11411   CHECK_EQ(args.This(), args.Holder());
11412   CHECK(args.Data()->Equals(v8_str("method_data")));
11413   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11414 }
11415
11416 static void FastApiCallback_SimpleSignature(
11417     const v8::FunctionCallbackInfo<v8::Value>& args) {
11418   ApiTestFuzzer::Fuzz();
11419   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
11420   v8::Isolate* isolate = CcTest::isolate();
11421   CHECK_EQ(isolate, args.GetIsolate());
11422   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
11423   CHECK(args.Data()->Equals(v8_str("method_data")));
11424   // Note, we're using HasRealNamedProperty instead of Has to avoid
11425   // invoking the interceptor again.
11426   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
11427   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
11428 }
11429
11430
11431 // Helper to maximize the odds of object moving.
11432 static void GenerateSomeGarbage() {
11433   CompileRun(
11434       "var garbage;"
11435       "for (var i = 0; i < 1000; i++) {"
11436       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
11437       "}"
11438       "garbage = undefined;");
11439 }
11440
11441
11442 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11443   static int count = 0;
11444   if (count++ % 3 == 0) {
11445     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11446         // This should move the stub
11447     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
11448   }
11449 }
11450
11451
11452 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
11453   LocalContext context;
11454   v8::HandleScope scope(context->GetIsolate());
11455   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
11456   nativeobject_templ->Set("callback",
11457                           v8::FunctionTemplate::New(DirectApiCallback));
11458   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11459   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11460   // call the api function multiple times to ensure direct call stub creation.
11461   CompileRun(
11462         "function f() {"
11463         "  for (var i = 1; i <= 30; i++) {"
11464         "    nativeobject.callback();"
11465         "  }"
11466         "}"
11467         "f();");
11468 }
11469
11470
11471 void ThrowingDirectApiCallback(
11472     const v8::FunctionCallbackInfo<v8::Value>& args) {
11473   args.GetIsolate()->ThrowException(v8_str("g"));
11474 }
11475
11476
11477 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
11478   LocalContext context;
11479   v8::HandleScope scope(context->GetIsolate());
11480   v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
11481   nativeobject_templ->Set("callback",
11482                           v8::FunctionTemplate::New(ThrowingDirectApiCallback));
11483   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
11484   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
11485   // call the api function multiple times to ensure direct call stub creation.
11486   v8::Handle<Value> result = CompileRun(
11487       "var result = '';"
11488       "function f() {"
11489       "  for (var i = 1; i <= 5; i++) {"
11490       "    try { nativeobject.callback(); } catch (e) { result += e; }"
11491       "  }"
11492       "}"
11493       "f(); result;");
11494   CHECK_EQ(v8_str("ggggg"), result);
11495 }
11496
11497
11498 static Handle<Value> DoDirectGetter() {
11499   if (++p_getter_count % 3 == 0) {
11500     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11501     GenerateSomeGarbage();
11502   }
11503   return v8_str("Direct Getter Result");
11504 }
11505
11506 static void DirectGetterCallback(
11507     Local<String> name,
11508     const v8::PropertyCallbackInfo<v8::Value>& info) {
11509   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
11510   info.GetReturnValue().Set(DoDirectGetter());
11511 }
11512
11513
11514 template<typename Accessor>
11515 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
11516   LocalContext context;
11517   v8::HandleScope scope(context->GetIsolate());
11518   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
11519   obj->SetAccessor(v8_str("p1"), accessor);
11520   context->Global()->Set(v8_str("o1"), obj->NewInstance());
11521   p_getter_count = 0;
11522   v8::Handle<v8::Value> result = CompileRun(
11523       "function f() {"
11524       "  for (var i = 0; i < 30; i++) o1.p1;"
11525       "  return o1.p1"
11526       "}"
11527       "f();");
11528   CHECK_EQ(v8_str("Direct Getter Result"), result);
11529   CHECK_EQ(31, p_getter_count);
11530 }
11531
11532
11533 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
11534   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
11535 }
11536
11537
11538 void ThrowingDirectGetterCallback(
11539     Local<String> name,
11540     const v8::PropertyCallbackInfo<v8::Value>& info) {
11541   info.GetIsolate()->ThrowException(v8_str("g"));
11542 }
11543
11544
11545 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
11546   LocalContext context;
11547   v8::HandleScope scope(context->GetIsolate());
11548   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
11549   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
11550   context->Global()->Set(v8_str("o1"), obj->NewInstance());
11551   v8::Handle<Value> result = CompileRun(
11552       "var result = '';"
11553       "for (var i = 0; i < 5; i++) {"
11554       "    try { o1.p1; } catch (e) { result += e; }"
11555       "}"
11556       "result;");
11557   CHECK_EQ(v8_str("ggggg"), result);
11558 }
11559
11560
11561 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
11562   int interceptor_call_count = 0;
11563   v8::HandleScope scope(CcTest::isolate());
11564   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11565   v8::Handle<v8::FunctionTemplate> method_templ =
11566       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11567                                 v8_str("method_data"),
11568                                 v8::Handle<v8::Signature>());
11569   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11570   proto_templ->Set(v8_str("method"), method_templ);
11571   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11572   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11573                                  NULL, NULL, NULL, NULL,
11574                                  v8::External::New(&interceptor_call_count));
11575   LocalContext context;
11576   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11577   GenerateSomeGarbage();
11578   context->Global()->Set(v8_str("o"), fun->NewInstance());
11579   CompileRun(
11580       "var result = 0;"
11581       "for (var i = 0; i < 100; i++) {"
11582       "  result = o.method(41);"
11583       "}");
11584   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11585   CHECK_EQ(100, interceptor_call_count);
11586 }
11587
11588
11589 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
11590   int interceptor_call_count = 0;
11591   v8::HandleScope scope(CcTest::isolate());
11592   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11593   v8::Handle<v8::FunctionTemplate> method_templ =
11594       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11595                                 v8_str("method_data"),
11596                                 v8::Signature::New(fun_templ));
11597   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11598   proto_templ->Set(v8_str("method"), method_templ);
11599   fun_templ->SetHiddenPrototype(true);
11600   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11601   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11602                                  NULL, NULL, NULL, NULL,
11603                                  v8::External::New(&interceptor_call_count));
11604   LocalContext context;
11605   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11606   GenerateSomeGarbage();
11607   context->Global()->Set(v8_str("o"), fun->NewInstance());
11608   CompileRun(
11609       "o.foo = 17;"
11610       "var receiver = {};"
11611       "receiver.__proto__ = o;"
11612       "var result = 0;"
11613       "for (var i = 0; i < 100; i++) {"
11614       "  result = receiver.method(41);"
11615       "}");
11616   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11617   CHECK_EQ(100, interceptor_call_count);
11618 }
11619
11620
11621 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
11622   int interceptor_call_count = 0;
11623   v8::HandleScope scope(CcTest::isolate());
11624   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11625   v8::Handle<v8::FunctionTemplate> method_templ =
11626       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11627                                 v8_str("method_data"),
11628                                 v8::Signature::New(fun_templ));
11629   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11630   proto_templ->Set(v8_str("method"), method_templ);
11631   fun_templ->SetHiddenPrototype(true);
11632   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11633   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11634                                  NULL, NULL, NULL, NULL,
11635                                  v8::External::New(&interceptor_call_count));
11636   LocalContext context;
11637   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11638   GenerateSomeGarbage();
11639   context->Global()->Set(v8_str("o"), fun->NewInstance());
11640   CompileRun(
11641       "o.foo = 17;"
11642       "var receiver = {};"
11643       "receiver.__proto__ = o;"
11644       "var result = 0;"
11645       "var saved_result = 0;"
11646       "for (var i = 0; i < 100; i++) {"
11647       "  result = receiver.method(41);"
11648       "  if (i == 50) {"
11649       "    saved_result = result;"
11650       "    receiver = {method: function(x) { return x - 1 }};"
11651       "  }"
11652       "}");
11653   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11654   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11655   CHECK_GE(interceptor_call_count, 50);
11656 }
11657
11658
11659 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
11660   int interceptor_call_count = 0;
11661   v8::HandleScope scope(CcTest::isolate());
11662   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11663   v8::Handle<v8::FunctionTemplate> method_templ =
11664       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11665                                 v8_str("method_data"),
11666                                 v8::Signature::New(fun_templ));
11667   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11668   proto_templ->Set(v8_str("method"), method_templ);
11669   fun_templ->SetHiddenPrototype(true);
11670   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11671   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11672                                  NULL, NULL, NULL, NULL,
11673                                  v8::External::New(&interceptor_call_count));
11674   LocalContext context;
11675   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11676   GenerateSomeGarbage();
11677   context->Global()->Set(v8_str("o"), fun->NewInstance());
11678   CompileRun(
11679       "o.foo = 17;"
11680       "var receiver = {};"
11681       "receiver.__proto__ = o;"
11682       "var result = 0;"
11683       "var saved_result = 0;"
11684       "for (var i = 0; i < 100; i++) {"
11685       "  result = receiver.method(41);"
11686       "  if (i == 50) {"
11687       "    saved_result = result;"
11688       "    o.method = function(x) { return x - 1 };"
11689       "  }"
11690       "}");
11691   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11692   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11693   CHECK_GE(interceptor_call_count, 50);
11694 }
11695
11696
11697 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
11698   int interceptor_call_count = 0;
11699   v8::HandleScope scope(CcTest::isolate());
11700   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11701   v8::Handle<v8::FunctionTemplate> method_templ =
11702       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11703                                 v8_str("method_data"),
11704                                 v8::Signature::New(fun_templ));
11705   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11706   proto_templ->Set(v8_str("method"), method_templ);
11707   fun_templ->SetHiddenPrototype(true);
11708   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11709   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11710                                  NULL, NULL, NULL, NULL,
11711                                  v8::External::New(&interceptor_call_count));
11712   LocalContext context;
11713   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11714   GenerateSomeGarbage();
11715   context->Global()->Set(v8_str("o"), fun->NewInstance());
11716   v8::TryCatch try_catch;
11717   CompileRun(
11718       "o.foo = 17;"
11719       "var receiver = {};"
11720       "receiver.__proto__ = o;"
11721       "var result = 0;"
11722       "var saved_result = 0;"
11723       "for (var i = 0; i < 100; i++) {"
11724       "  result = receiver.method(41);"
11725       "  if (i == 50) {"
11726       "    saved_result = result;"
11727       "    receiver = 333;"
11728       "  }"
11729       "}");
11730   CHECK(try_catch.HasCaught());
11731   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11732            try_catch.Exception()->ToString());
11733   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11734   CHECK_GE(interceptor_call_count, 50);
11735 }
11736
11737
11738 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
11739   int interceptor_call_count = 0;
11740   v8::HandleScope scope(CcTest::isolate());
11741   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11742   v8::Handle<v8::FunctionTemplate> method_templ =
11743       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11744                                 v8_str("method_data"),
11745                                 v8::Signature::New(fun_templ));
11746   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11747   proto_templ->Set(v8_str("method"), method_templ);
11748   fun_templ->SetHiddenPrototype(true);
11749   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11750   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11751                                  NULL, NULL, NULL, NULL,
11752                                  v8::External::New(&interceptor_call_count));
11753   LocalContext context;
11754   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11755   GenerateSomeGarbage();
11756   context->Global()->Set(v8_str("o"), fun->NewInstance());
11757   v8::TryCatch try_catch;
11758   CompileRun(
11759       "o.foo = 17;"
11760       "var receiver = {};"
11761       "receiver.__proto__ = o;"
11762       "var result = 0;"
11763       "var saved_result = 0;"
11764       "for (var i = 0; i < 100; i++) {"
11765       "  result = receiver.method(41);"
11766       "  if (i == 50) {"
11767       "    saved_result = result;"
11768       "    receiver = {method: receiver.method};"
11769       "  }"
11770       "}");
11771   CHECK(try_catch.HasCaught());
11772   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11773            try_catch.Exception()->ToString());
11774   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11775   CHECK_GE(interceptor_call_count, 50);
11776 }
11777
11778
11779 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
11780   v8::HandleScope scope(CcTest::isolate());
11781   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11782   v8::Handle<v8::FunctionTemplate> method_templ =
11783       v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11784                                 v8_str("method_data"),
11785                                 v8::Handle<v8::Signature>());
11786   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11787   proto_templ->Set(v8_str("method"), method_templ);
11788   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11789   USE(templ);
11790   LocalContext context;
11791   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11792   GenerateSomeGarbage();
11793   context->Global()->Set(v8_str("o"), fun->NewInstance());
11794   CompileRun(
11795       "var result = 0;"
11796       "for (var i = 0; i < 100; i++) {"
11797       "  result = o.method(41);"
11798       "}");
11799
11800   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11801 }
11802
11803
11804 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
11805   v8::HandleScope scope(CcTest::isolate());
11806   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11807   v8::Handle<v8::FunctionTemplate> method_templ =
11808       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11809                                 v8_str("method_data"),
11810                                 v8::Signature::New(fun_templ));
11811   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11812   proto_templ->Set(v8_str("method"), method_templ);
11813   fun_templ->SetHiddenPrototype(true);
11814   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11815   CHECK(!templ.IsEmpty());
11816   LocalContext context;
11817   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11818   GenerateSomeGarbage();
11819   context->Global()->Set(v8_str("o"), fun->NewInstance());
11820   CompileRun(
11821       "o.foo = 17;"
11822       "var receiver = {};"
11823       "receiver.__proto__ = o;"
11824       "var result = 0;"
11825       "for (var i = 0; i < 100; i++) {"
11826       "  result = receiver.method(41);"
11827       "}");
11828
11829   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11830 }
11831
11832
11833 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
11834   v8::HandleScope scope(CcTest::isolate());
11835   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11836   v8::Handle<v8::FunctionTemplate> method_templ =
11837       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11838                                 v8_str("method_data"),
11839                                 v8::Signature::New(fun_templ));
11840   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11841   proto_templ->Set(v8_str("method"), method_templ);
11842   fun_templ->SetHiddenPrototype(true);
11843   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11844   CHECK(!templ.IsEmpty());
11845   LocalContext context;
11846   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11847   GenerateSomeGarbage();
11848   context->Global()->Set(v8_str("o"), fun->NewInstance());
11849   CompileRun(
11850       "o.foo = 17;"
11851       "var receiver = {};"
11852       "receiver.__proto__ = o;"
11853       "var result = 0;"
11854       "var saved_result = 0;"
11855       "for (var i = 0; i < 100; i++) {"
11856       "  result = receiver.method(41);"
11857       "  if (i == 50) {"
11858       "    saved_result = result;"
11859       "    receiver = {method: function(x) { return x - 1 }};"
11860       "  }"
11861       "}");
11862   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11863   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11864 }
11865
11866
11867 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
11868   v8::HandleScope scope(CcTest::isolate());
11869   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11870   v8::Handle<v8::FunctionTemplate> method_templ =
11871       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11872                                 v8_str("method_data"),
11873                                 v8::Signature::New(fun_templ));
11874   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11875   proto_templ->Set(v8_str("method"), method_templ);
11876   fun_templ->SetHiddenPrototype(true);
11877   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11878   CHECK(!templ.IsEmpty());
11879   LocalContext context;
11880   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11881   GenerateSomeGarbage();
11882   context->Global()->Set(v8_str("o"), fun->NewInstance());
11883   v8::TryCatch try_catch;
11884   CompileRun(
11885       "o.foo = 17;"
11886       "var receiver = {};"
11887       "receiver.__proto__ = o;"
11888       "var result = 0;"
11889       "var saved_result = 0;"
11890       "for (var i = 0; i < 100; i++) {"
11891       "  result = receiver.method(41);"
11892       "  if (i == 50) {"
11893       "    saved_result = result;"
11894       "    receiver = 333;"
11895       "  }"
11896       "}");
11897   CHECK(try_catch.HasCaught());
11898   CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11899            try_catch.Exception()->ToString());
11900   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11901 }
11902
11903
11904 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
11905   v8::HandleScope scope(CcTest::isolate());
11906   v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11907   v8::Handle<v8::FunctionTemplate> method_templ =
11908       v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11909                                 v8_str("method_data"),
11910                                 v8::Signature::New(fun_templ));
11911   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11912   proto_templ->Set(v8_str("method"), method_templ);
11913   fun_templ->SetHiddenPrototype(true);
11914   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11915   CHECK(!templ.IsEmpty());
11916   LocalContext context;
11917   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11918   GenerateSomeGarbage();
11919   context->Global()->Set(v8_str("o"), fun->NewInstance());
11920   v8::TryCatch try_catch;
11921   CompileRun(
11922       "o.foo = 17;"
11923       "var receiver = {};"
11924       "receiver.__proto__ = o;"
11925       "var result = 0;"
11926       "var saved_result = 0;"
11927       "for (var i = 0; i < 100; i++) {"
11928       "  result = receiver.method(41);"
11929       "  if (i == 50) {"
11930       "    saved_result = result;"
11931       "    receiver = Object.create(receiver);"
11932       "  }"
11933       "}");
11934   CHECK(try_catch.HasCaught());
11935   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11936            try_catch.Exception()->ToString());
11937   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11938 }
11939
11940
11941 v8::Handle<Value> keyed_call_ic_function;
11942
11943 static void InterceptorKeyedCallICGetter(
11944     Local<String> name,
11945     const v8::PropertyCallbackInfo<v8::Value>& info) {
11946   ApiTestFuzzer::Fuzz();
11947   if (v8_str("x")->Equals(name)) {
11948     info.GetReturnValue().Set(keyed_call_ic_function);
11949   }
11950 }
11951
11952
11953 // Test the case when we stored cacheable lookup into
11954 // a stub, but the function name changed (to another cacheable function).
11955 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
11956   v8::HandleScope scope(CcTest::isolate());
11957   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11958   templ->SetNamedPropertyHandler(NoBlockGetterX);
11959   LocalContext context;
11960   context->Global()->Set(v8_str("o"), templ->NewInstance());
11961   CompileRun(
11962     "proto = new Object();"
11963     "proto.y = function(x) { return x + 1; };"
11964     "proto.z = function(x) { return x - 1; };"
11965     "o.__proto__ = proto;"
11966     "var result = 0;"
11967     "var method = 'y';"
11968     "for (var i = 0; i < 10; i++) {"
11969     "  if (i == 5) { method = 'z'; };"
11970     "  result += o[method](41);"
11971     "}");
11972   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11973 }
11974
11975
11976 // Test the case when we stored cacheable lookup into
11977 // a stub, but the function name changed (and the new function is present
11978 // both before and after the interceptor in the prototype chain).
11979 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
11980   v8::HandleScope scope(CcTest::isolate());
11981   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11982   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
11983   LocalContext context;
11984   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
11985   keyed_call_ic_function =
11986       v8_compile("function f(x) { return x - 1; }; f")->Run();
11987   CompileRun(
11988     "o = new Object();"
11989     "proto2 = new Object();"
11990     "o.y = function(x) { return x + 1; };"
11991     "proto2.y = function(x) { return x + 2; };"
11992     "o.__proto__ = proto1;"
11993     "proto1.__proto__ = proto2;"
11994     "var result = 0;"
11995     "var method = 'x';"
11996     "for (var i = 0; i < 10; i++) {"
11997     "  if (i == 5) { method = 'y'; };"
11998     "  result += o[method](41);"
11999     "}");
12000   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12001 }
12002
12003
12004 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12005 // on the global object.
12006 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12007   v8::HandleScope scope(CcTest::isolate());
12008   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12009   templ->SetNamedPropertyHandler(NoBlockGetterX);
12010   LocalContext context;
12011   context->Global()->Set(v8_str("o"), templ->NewInstance());
12012   CompileRun(
12013     "function inc(x) { return x + 1; };"
12014     "inc(1);"
12015     "function dec(x) { return x - 1; };"
12016     "dec(1);"
12017     "o.__proto__ = this;"
12018     "this.__proto__.x = inc;"
12019     "this.__proto__.y = dec;"
12020     "var result = 0;"
12021     "var method = 'x';"
12022     "for (var i = 0; i < 10; i++) {"
12023     "  if (i == 5) { method = 'y'; };"
12024     "  result += o[method](41);"
12025     "}");
12026   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12027 }
12028
12029
12030 // Test the case when actual function to call sits on global object.
12031 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12032   v8::HandleScope scope(CcTest::isolate());
12033   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
12034   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12035   LocalContext context;
12036   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12037
12038   CompileRun(
12039     "function len(x) { return x.length; };"
12040     "o.__proto__ = this;"
12041     "var m = 'parseFloat';"
12042     "var result = 0;"
12043     "for (var i = 0; i < 10; i++) {"
12044     "  if (i == 5) {"
12045     "    m = 'len';"
12046     "    saved_result = result;"
12047     "  };"
12048     "  result = o[m]('239');"
12049     "}");
12050   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12051   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12052 }
12053
12054
12055 // Test the map transition before the interceptor.
12056 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12057   v8::HandleScope scope(CcTest::isolate());
12058   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
12059   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12060   LocalContext context;
12061   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12062
12063   CompileRun(
12064     "var o = new Object();"
12065     "o.__proto__ = proto;"
12066     "o.method = function(x) { return x + 1; };"
12067     "var m = 'method';"
12068     "var result = 0;"
12069     "for (var i = 0; i < 10; i++) {"
12070     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12071     "  result += o[m](41);"
12072     "}");
12073   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12074 }
12075
12076
12077 // Test the map transition after the interceptor.
12078 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12079   v8::HandleScope scope(CcTest::isolate());
12080   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
12081   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12082   LocalContext context;
12083   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12084
12085   CompileRun(
12086     "var proto = new Object();"
12087     "o.__proto__ = proto;"
12088     "proto.method = function(x) { return x + 1; };"
12089     "var m = 'method';"
12090     "var result = 0;"
12091     "for (var i = 0; i < 10; i++) {"
12092     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12093     "  result += o[m](41);"
12094     "}");
12095   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12096 }
12097
12098
12099 static int interceptor_call_count = 0;
12100
12101 static void InterceptorICRefErrorGetter(
12102     Local<String> name,
12103     const v8::PropertyCallbackInfo<v8::Value>& info) {
12104   ApiTestFuzzer::Fuzz();
12105   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12106     info.GetReturnValue().Set(call_ic_function2);
12107   }
12108 }
12109
12110
12111 // This test should hit load and call ICs for the interceptor case.
12112 // Once in a while, the interceptor will reply that a property was not
12113 // found in which case we should get a reference error.
12114 THREADED_TEST(InterceptorICReferenceErrors) {
12115   v8::HandleScope scope(CcTest::isolate());
12116   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12117   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12118   LocalContext context(0, templ, v8::Handle<Value>());
12119   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12120   v8::Handle<Value> value = CompileRun(
12121     "function f() {"
12122     "  for (var i = 0; i < 1000; i++) {"
12123     "    try { x; } catch(e) { return true; }"
12124     "  }"
12125     "  return false;"
12126     "};"
12127     "f();");
12128   CHECK_EQ(true, value->BooleanValue());
12129   interceptor_call_count = 0;
12130   value = CompileRun(
12131     "function g() {"
12132     "  for (var i = 0; i < 1000; i++) {"
12133     "    try { x(42); } catch(e) { return true; }"
12134     "  }"
12135     "  return false;"
12136     "};"
12137     "g();");
12138   CHECK_EQ(true, value->BooleanValue());
12139 }
12140
12141
12142 static int interceptor_ic_exception_get_count = 0;
12143
12144 static void InterceptorICExceptionGetter(
12145     Local<String> name,
12146     const v8::PropertyCallbackInfo<v8::Value>& info) {
12147   ApiTestFuzzer::Fuzz();
12148   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12149     info.GetReturnValue().Set(call_ic_function3);
12150   }
12151   if (interceptor_ic_exception_get_count == 20) {
12152     info.GetIsolate()->ThrowException(v8_num(42));
12153     return;
12154   }
12155 }
12156
12157
12158 // Test interceptor load/call IC where the interceptor throws an
12159 // exception once in a while.
12160 THREADED_TEST(InterceptorICGetterExceptions) {
12161   interceptor_ic_exception_get_count = 0;
12162   v8::HandleScope scope(CcTest::isolate());
12163   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12164   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12165   LocalContext context(0, templ, v8::Handle<Value>());
12166   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12167   v8::Handle<Value> value = CompileRun(
12168     "function f() {"
12169     "  for (var i = 0; i < 100; i++) {"
12170     "    try { x; } catch(e) { return true; }"
12171     "  }"
12172     "  return false;"
12173     "};"
12174     "f();");
12175   CHECK_EQ(true, value->BooleanValue());
12176   interceptor_ic_exception_get_count = 0;
12177   value = CompileRun(
12178     "function f() {"
12179     "  for (var i = 0; i < 100; i++) {"
12180     "    try { x(42); } catch(e) { return true; }"
12181     "  }"
12182     "  return false;"
12183     "};"
12184     "f();");
12185   CHECK_EQ(true, value->BooleanValue());
12186 }
12187
12188
12189 static int interceptor_ic_exception_set_count = 0;
12190
12191 static void InterceptorICExceptionSetter(
12192       Local<String> key,
12193       Local<Value> value,
12194       const v8::PropertyCallbackInfo<v8::Value>& info) {
12195   ApiTestFuzzer::Fuzz();
12196   if (++interceptor_ic_exception_set_count > 20) {
12197     info.GetIsolate()->ThrowException(v8_num(42));
12198   }
12199 }
12200
12201
12202 // Test interceptor store IC where the interceptor throws an exception
12203 // once in a while.
12204 THREADED_TEST(InterceptorICSetterExceptions) {
12205   interceptor_ic_exception_set_count = 0;
12206   v8::HandleScope scope(CcTest::isolate());
12207   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12208   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12209   LocalContext context(0, templ, v8::Handle<Value>());
12210   v8::Handle<Value> value = CompileRun(
12211     "function f() {"
12212     "  for (var i = 0; i < 100; i++) {"
12213     "    try { x = 42; } catch(e) { return true; }"
12214     "  }"
12215     "  return false;"
12216     "};"
12217     "f();");
12218   CHECK_EQ(true, value->BooleanValue());
12219 }
12220
12221
12222 // Test that we ignore null interceptors.
12223 THREADED_TEST(NullNamedInterceptor) {
12224   v8::HandleScope scope(CcTest::isolate());
12225   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12226   templ->SetNamedPropertyHandler(
12227       static_cast<v8::NamedPropertyGetterCallback>(0));
12228   LocalContext context;
12229   templ->Set("x", v8_num(42));
12230   v8::Handle<v8::Object> obj = templ->NewInstance();
12231   context->Global()->Set(v8_str("obj"), obj);
12232   v8::Handle<Value> value = CompileRun("obj.x");
12233   CHECK(value->IsInt32());
12234   CHECK_EQ(42, value->Int32Value());
12235 }
12236
12237
12238 // Test that we ignore null interceptors.
12239 THREADED_TEST(NullIndexedInterceptor) {
12240   v8::HandleScope scope(CcTest::isolate());
12241   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
12242   templ->SetIndexedPropertyHandler(
12243       static_cast<v8::IndexedPropertyGetterCallback>(0));
12244   LocalContext context;
12245   templ->Set("42", v8_num(42));
12246   v8::Handle<v8::Object> obj = templ->NewInstance();
12247   context->Global()->Set(v8_str("obj"), obj);
12248   v8::Handle<Value> value = CompileRun("obj[42]");
12249   CHECK(value->IsInt32());
12250   CHECK_EQ(42, value->Int32Value());
12251 }
12252
12253
12254 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12255   v8::HandleScope scope(CcTest::isolate());
12256   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12257   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12258   LocalContext env;
12259   env->Global()->Set(v8_str("obj"),
12260                      templ->GetFunction()->NewInstance());
12261   ExpectTrue("obj.x === 42");
12262   ExpectTrue("!obj.propertyIsEnumerable('x')");
12263 }
12264
12265
12266 static void ThrowingGetter(Local<String> name,
12267                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12268   ApiTestFuzzer::Fuzz();
12269   info.GetIsolate()->ThrowException(Handle<Value>());
12270   info.GetReturnValue().SetUndefined();
12271 }
12272
12273
12274 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12275   LocalContext context;
12276   HandleScope scope(context->GetIsolate());
12277
12278   Local<FunctionTemplate> templ = FunctionTemplate::New();
12279   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12280   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12281
12282   Local<Object> instance = templ->GetFunction()->NewInstance();
12283
12284   Local<Object> another = Object::New();
12285   another->SetPrototype(instance);
12286
12287   Local<Object> with_js_getter = CompileRun(
12288       "o = {};\n"
12289       "o.__defineGetter__('f', function() { throw undefined; });\n"
12290       "o\n").As<Object>();
12291   CHECK(!with_js_getter.IsEmpty());
12292
12293   TryCatch try_catch;
12294
12295   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12296   CHECK(try_catch.HasCaught());
12297   try_catch.Reset();
12298   CHECK(result.IsEmpty());
12299
12300   result = another->GetRealNamedProperty(v8_str("f"));
12301   CHECK(try_catch.HasCaught());
12302   try_catch.Reset();
12303   CHECK(result.IsEmpty());
12304
12305   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12306   CHECK(try_catch.HasCaught());
12307   try_catch.Reset();
12308   CHECK(result.IsEmpty());
12309
12310   result = another->Get(v8_str("f"));
12311   CHECK(try_catch.HasCaught());
12312   try_catch.Reset();
12313   CHECK(result.IsEmpty());
12314
12315   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12316   CHECK(try_catch.HasCaught());
12317   try_catch.Reset();
12318   CHECK(result.IsEmpty());
12319
12320   result = with_js_getter->Get(v8_str("f"));
12321   CHECK(try_catch.HasCaught());
12322   try_catch.Reset();
12323   CHECK(result.IsEmpty());
12324 }
12325
12326
12327 static void ThrowingCallbackWithTryCatch(
12328     const v8::FunctionCallbackInfo<v8::Value>& args) {
12329   TryCatch try_catch;
12330   // Verboseness is important: it triggers message delivery which can call into
12331   // external code.
12332   try_catch.SetVerbose(true);
12333   CompileRun("throw 'from JS';");
12334   CHECK(try_catch.HasCaught());
12335   CHECK(!CcTest::i_isolate()->has_pending_exception());
12336   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12337 }
12338
12339
12340 static int call_depth;
12341
12342
12343 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
12344   TryCatch try_catch;
12345 }
12346
12347
12348 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
12349   if (--call_depth) CompileRun("throw 'ThrowInJS';");
12350 }
12351
12352
12353 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
12354   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
12355 }
12356
12357
12358 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
12359   Handle<String> errorMessageString = message->Get();
12360   CHECK(!errorMessageString.IsEmpty());
12361   message->GetStackTrace();
12362   message->GetScriptResourceName();
12363 }
12364
12365
12366 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
12367   LocalContext context;
12368   HandleScope scope(context->GetIsolate());
12369
12370   Local<Function> func =
12371       FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
12372   context->Global()->Set(v8_str("func"), func);
12373
12374   MessageCallback callbacks[] =
12375       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
12376   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
12377     MessageCallback callback = callbacks[i];
12378     if (callback != NULL) {
12379       V8::AddMessageListener(callback);
12380     }
12381     // Some small number to control number of times message handler should
12382     // throw an exception.
12383     call_depth = 5;
12384     ExpectFalse(
12385         "var thrown = false;\n"
12386         "try { func(); } catch(e) { thrown = true; }\n"
12387         "thrown\n");
12388     if (callback != NULL) {
12389       V8::RemoveMessageListeners(callback);
12390     }
12391   }
12392 }
12393
12394
12395 static void ParentGetter(Local<String> name,
12396                          const v8::PropertyCallbackInfo<v8::Value>& info) {
12397   ApiTestFuzzer::Fuzz();
12398   info.GetReturnValue().Set(v8_num(1));
12399 }
12400
12401
12402 static void ChildGetter(Local<String> name,
12403                         const v8::PropertyCallbackInfo<v8::Value>& info) {
12404   ApiTestFuzzer::Fuzz();
12405   info.GetReturnValue().Set(v8_num(42));
12406 }
12407
12408
12409 THREADED_TEST(Overriding) {
12410   i::FLAG_es5_readonly = true;
12411   LocalContext context;
12412   v8::HandleScope scope(context->GetIsolate());
12413
12414   // Parent template.
12415   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
12416   Local<ObjectTemplate> parent_instance_templ =
12417       parent_templ->InstanceTemplate();
12418   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
12419
12420   // Template that inherits from the parent template.
12421   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
12422   Local<ObjectTemplate> child_instance_templ =
12423       child_templ->InstanceTemplate();
12424   child_templ->Inherit(parent_templ);
12425   // Override 'f'.  The child version of 'f' should get called for child
12426   // instances.
12427   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
12428   // Add 'g' twice.  The 'g' added last should get called for instances.
12429   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
12430   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
12431
12432   // Add 'h' as an accessor to the proto template with ReadOnly attributes
12433   // so 'h' can be shadowed on the instance object.
12434   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
12435   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
12436       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12437
12438   // Add 'i' as an accessor to the instance template with ReadOnly attributes
12439   // but the attribute does not have effect because it is duplicated with
12440   // NULL setter.
12441   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
12442       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
12443
12444
12445
12446   // Instantiate the child template.
12447   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
12448
12449   // Check that the child function overrides the parent one.
12450   context->Global()->Set(v8_str("o"), instance);
12451   Local<Value> value = v8_compile("o.f")->Run();
12452   // Check that the 'g' that was added last is hit.
12453   CHECK_EQ(42, value->Int32Value());
12454   value = v8_compile("o.g")->Run();
12455   CHECK_EQ(42, value->Int32Value());
12456
12457   // Check that 'h' cannot be shadowed.
12458   value = v8_compile("o.h = 3; o.h")->Run();
12459   CHECK_EQ(1, value->Int32Value());
12460
12461   // Check that 'i' cannot be shadowed or changed.
12462   value = v8_compile("o.i = 3; o.i")->Run();
12463   CHECK_EQ(42, value->Int32Value());
12464 }
12465
12466
12467 static void IsConstructHandler(
12468     const v8::FunctionCallbackInfo<v8::Value>& args) {
12469   ApiTestFuzzer::Fuzz();
12470   args.GetReturnValue().Set(args.IsConstructCall());
12471 }
12472
12473
12474 THREADED_TEST(IsConstructCall) {
12475   v8::HandleScope scope(CcTest::isolate());
12476
12477   // Function template with call handler.
12478   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12479   templ->SetCallHandler(IsConstructHandler);
12480
12481   LocalContext context;
12482
12483   context->Global()->Set(v8_str("f"), templ->GetFunction());
12484   Local<Value> value = v8_compile("f()")->Run();
12485   CHECK(!value->BooleanValue());
12486   value = v8_compile("new f()")->Run();
12487   CHECK(value->BooleanValue());
12488 }
12489
12490
12491 THREADED_TEST(ObjectProtoToString) {
12492   v8::HandleScope scope(CcTest::isolate());
12493   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
12494   templ->SetClassName(v8_str("MyClass"));
12495
12496   LocalContext context;
12497
12498   Local<String> customized_tostring = v8_str("customized toString");
12499
12500   // Replace Object.prototype.toString
12501   v8_compile("Object.prototype.toString = function() {"
12502                   "  return 'customized toString';"
12503                   "}")->Run();
12504
12505   // Normal ToString call should call replaced Object.prototype.toString
12506   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
12507   Local<String> value = instance->ToString();
12508   CHECK(value->IsString() && value->Equals(customized_tostring));
12509
12510   // ObjectProtoToString should not call replace toString function.
12511   value = instance->ObjectProtoToString();
12512   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
12513
12514   // Check global
12515   value = context->Global()->ObjectProtoToString();
12516   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
12517
12518   // Check ordinary object
12519   Local<Value> object = v8_compile("new Object()")->Run();
12520   value = object.As<v8::Object>()->ObjectProtoToString();
12521   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
12522 }
12523
12524
12525 THREADED_TEST(ObjectGetConstructorName) {
12526   LocalContext context;
12527   v8::HandleScope scope(context->GetIsolate());
12528   v8_compile("function Parent() {};"
12529              "function Child() {};"
12530              "Child.prototype = new Parent();"
12531              "var outer = { inner: function() { } };"
12532              "var p = new Parent();"
12533              "var c = new Child();"
12534              "var x = new outer.inner();")->Run();
12535
12536   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
12537   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
12538       v8_str("Parent")));
12539
12540   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
12541   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
12542       v8_str("Child")));
12543
12544   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
12545   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
12546       v8_str("outer.inner")));
12547 }
12548
12549
12550 bool ApiTestFuzzer::fuzzing_ = false;
12551 i::Semaphore ApiTestFuzzer::all_tests_done_(0);
12552 int ApiTestFuzzer::active_tests_;
12553 int ApiTestFuzzer::tests_being_run_;
12554 int ApiTestFuzzer::current_;
12555
12556
12557 // We are in a callback and want to switch to another thread (if we
12558 // are currently running the thread fuzzing test).
12559 void ApiTestFuzzer::Fuzz() {
12560   if (!fuzzing_) return;
12561   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
12562   test->ContextSwitch();
12563 }
12564
12565
12566 // Let the next thread go.  Since it is also waiting on the V8 lock it may
12567 // not start immediately.
12568 bool ApiTestFuzzer::NextThread() {
12569   int test_position = GetNextTestNumber();
12570   const char* test_name = RegisterThreadedTest::nth(current_)->name();
12571   if (test_position == current_) {
12572     if (kLogThreading)
12573       printf("Stay with %s\n", test_name);
12574     return false;
12575   }
12576   if (kLogThreading) {
12577     printf("Switch from %s to %s\n",
12578            test_name,
12579            RegisterThreadedTest::nth(test_position)->name());
12580   }
12581   current_ = test_position;
12582   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
12583   return true;
12584 }
12585
12586
12587 void ApiTestFuzzer::Run() {
12588   // When it is our turn...
12589   gate_.Wait();
12590   {
12591     // ... get the V8 lock and start running the test.
12592     v8::Locker locker(CcTest::isolate());
12593     CallTest();
12594   }
12595   // This test finished.
12596   active_ = false;
12597   active_tests_--;
12598   // If it was the last then signal that fact.
12599   if (active_tests_ == 0) {
12600     all_tests_done_.Signal();
12601   } else {
12602     // Otherwise select a new test and start that.
12603     NextThread();
12604   }
12605 }
12606
12607
12608 static unsigned linear_congruential_generator;
12609
12610
12611 void ApiTestFuzzer::SetUp(PartOfTest part) {
12612   linear_congruential_generator = i::FLAG_testing_prng_seed;
12613   fuzzing_ = true;
12614   int count = RegisterThreadedTest::count();
12615   int start =  count * part / (LAST_PART + 1);
12616   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
12617   active_tests_ = tests_being_run_ = end - start + 1;
12618   for (int i = 0; i < tests_being_run_; i++) {
12619     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
12620   }
12621   for (int i = 0; i < active_tests_; i++) {
12622     RegisterThreadedTest::nth(i)->fuzzer_->Start();
12623   }
12624 }
12625
12626
12627 static void CallTestNumber(int test_number) {
12628   (RegisterThreadedTest::nth(test_number)->callback())();
12629 }
12630
12631
12632 void ApiTestFuzzer::RunAllTests() {
12633   // Set off the first test.
12634   current_ = -1;
12635   NextThread();
12636   // Wait till they are all done.
12637   all_tests_done_.Wait();
12638 }
12639
12640
12641 int ApiTestFuzzer::GetNextTestNumber() {
12642   int next_test;
12643   do {
12644     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
12645     linear_congruential_generator *= 1664525u;
12646     linear_congruential_generator += 1013904223u;
12647   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
12648   return next_test;
12649 }
12650
12651
12652 void ApiTestFuzzer::ContextSwitch() {
12653   // If the new thread is the same as the current thread there is nothing to do.
12654   if (NextThread()) {
12655     // Now it can start.
12656     v8::Unlocker unlocker(CcTest::isolate());
12657     // Wait till someone starts us again.
12658     gate_.Wait();
12659     // And we're off.
12660   }
12661 }
12662
12663
12664 void ApiTestFuzzer::TearDown() {
12665   fuzzing_ = false;
12666   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
12667     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
12668     if (fuzzer != NULL) fuzzer->Join();
12669   }
12670 }
12671
12672
12673 // Lets not be needlessly self-referential.
12674 TEST(Threading1) {
12675   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
12676   ApiTestFuzzer::RunAllTests();
12677   ApiTestFuzzer::TearDown();
12678 }
12679
12680
12681 TEST(Threading2) {
12682   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
12683   ApiTestFuzzer::RunAllTests();
12684   ApiTestFuzzer::TearDown();
12685 }
12686
12687
12688 TEST(Threading3) {
12689   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
12690   ApiTestFuzzer::RunAllTests();
12691   ApiTestFuzzer::TearDown();
12692 }
12693
12694
12695 TEST(Threading4) {
12696   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
12697   ApiTestFuzzer::RunAllTests();
12698   ApiTestFuzzer::TearDown();
12699 }
12700
12701
12702 void ApiTestFuzzer::CallTest() {
12703   v8::Isolate::Scope scope(CcTest::isolate());
12704   if (kLogThreading)
12705     printf("Start test %d\n", test_number_);
12706   CallTestNumber(test_number_);
12707   if (kLogThreading)
12708     printf("End test %d\n", test_number_);
12709 }
12710
12711
12712 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
12713   v8::Isolate* isolate = args.GetIsolate();
12714   CHECK(v8::Locker::IsLocked(isolate));
12715   ApiTestFuzzer::Fuzz();
12716   v8::Unlocker unlocker(isolate);
12717   const char* code = "throw 7;";
12718   {
12719     v8::Locker nested_locker(isolate);
12720     v8::HandleScope scope(isolate);
12721     v8::Handle<Value> exception;
12722     { v8::TryCatch try_catch;
12723       v8::Handle<Value> value = CompileRun(code);
12724       CHECK(value.IsEmpty());
12725       CHECK(try_catch.HasCaught());
12726       // Make sure to wrap the exception in a new handle because
12727       // the handle returned from the TryCatch is destroyed
12728       // when the TryCatch is destroyed.
12729       exception = Local<Value>::New(isolate, try_catch.Exception());
12730     }
12731     args.GetIsolate()->ThrowException(exception);
12732   }
12733 }
12734
12735
12736 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
12737   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
12738   ApiTestFuzzer::Fuzz();
12739   v8::Unlocker unlocker(CcTest::isolate());
12740   const char* code = "throw 7;";
12741   {
12742     v8::Locker nested_locker(CcTest::isolate());
12743     v8::HandleScope scope(args.GetIsolate());
12744     v8::Handle<Value> value = CompileRun(code);
12745     CHECK(value.IsEmpty());
12746     args.GetReturnValue().Set(v8_str("foo"));
12747   }
12748 }
12749
12750
12751 // These are locking tests that don't need to be run again
12752 // as part of the locking aggregation tests.
12753 TEST(NestedLockers) {
12754   v8::Locker locker(CcTest::isolate());
12755   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
12756   LocalContext env;
12757   v8::HandleScope scope(env->GetIsolate());
12758   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
12759   Local<Function> fun = fun_templ->GetFunction();
12760   env->Global()->Set(v8_str("throw_in_js"), fun);
12761   Local<Script> script = v8_compile("(function () {"
12762                                     "  try {"
12763                                     "    throw_in_js();"
12764                                     "    return 42;"
12765                                     "  } catch (e) {"
12766                                     "    return e * 13;"
12767                                     "  }"
12768                                     "})();");
12769   CHECK_EQ(91, script->Run()->Int32Value());
12770 }
12771
12772
12773 // These are locking tests that don't need to be run again
12774 // as part of the locking aggregation tests.
12775 TEST(NestedLockersNoTryCatch) {
12776   v8::Locker locker(CcTest::isolate());
12777   LocalContext env;
12778   v8::HandleScope scope(env->GetIsolate());
12779   Local<v8::FunctionTemplate> fun_templ =
12780       v8::FunctionTemplate::New(ThrowInJSNoCatch);
12781   Local<Function> fun = fun_templ->GetFunction();
12782   env->Global()->Set(v8_str("throw_in_js"), fun);
12783   Local<Script> script = v8_compile("(function () {"
12784                                     "  try {"
12785                                     "    throw_in_js();"
12786                                     "    return 42;"
12787                                     "  } catch (e) {"
12788                                     "    return e * 13;"
12789                                     "  }"
12790                                     "})();");
12791   CHECK_EQ(91, script->Run()->Int32Value());
12792 }
12793
12794
12795 THREADED_TEST(RecursiveLocking) {
12796   v8::Locker locker(CcTest::isolate());
12797   {
12798     v8::Locker locker2(CcTest::isolate());
12799     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
12800   }
12801 }
12802
12803
12804 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
12805   ApiTestFuzzer::Fuzz();
12806   v8::Unlocker unlocker(CcTest::isolate());
12807 }
12808
12809
12810 THREADED_TEST(LockUnlockLock) {
12811   {
12812     v8::Locker locker(CcTest::isolate());
12813     v8::HandleScope scope(CcTest::isolate());
12814     LocalContext env;
12815     Local<v8::FunctionTemplate> fun_templ =
12816         v8::FunctionTemplate::New(UnlockForAMoment);
12817     Local<Function> fun = fun_templ->GetFunction();
12818     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12819     Local<Script> script = v8_compile("(function () {"
12820                                       "  unlock_for_a_moment();"
12821                                       "  return 42;"
12822                                       "})();");
12823     CHECK_EQ(42, script->Run()->Int32Value());
12824   }
12825   {
12826     v8::Locker locker(CcTest::isolate());
12827     v8::HandleScope scope(CcTest::isolate());
12828     LocalContext env;
12829     Local<v8::FunctionTemplate> fun_templ =
12830         v8::FunctionTemplate::New(UnlockForAMoment);
12831     Local<Function> fun = fun_templ->GetFunction();
12832     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12833     Local<Script> script = v8_compile("(function () {"
12834                                       "  unlock_for_a_moment();"
12835                                       "  return 42;"
12836                                       "})();");
12837     CHECK_EQ(42, script->Run()->Int32Value());
12838   }
12839 }
12840
12841
12842 static int GetGlobalObjectsCount() {
12843   CcTest::heap()->EnsureHeapIsIterable();
12844   int count = 0;
12845   i::HeapIterator it(CcTest::heap());
12846   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
12847     if (object->IsJSGlobalObject()) count++;
12848   return count;
12849 }
12850
12851
12852 static void CheckSurvivingGlobalObjectsCount(int expected) {
12853   // We need to collect all garbage twice to be sure that everything
12854   // has been collected.  This is because inline caches are cleared in
12855   // the first garbage collection but some of the maps have already
12856   // been marked at that point.  Therefore some of the maps are not
12857   // collected until the second garbage collection.
12858   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12859   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
12860   int count = GetGlobalObjectsCount();
12861 #ifdef DEBUG
12862   if (count != expected) CcTest::heap()->TracePathToGlobal();
12863 #endif
12864   CHECK_EQ(expected, count);
12865 }
12866
12867
12868 TEST(DontLeakGlobalObjects) {
12869   // Regression test for issues 1139850 and 1174891.
12870
12871   v8::V8::Initialize();
12872
12873   for (int i = 0; i < 5; i++) {
12874     { v8::HandleScope scope(CcTest::isolate());
12875       LocalContext context;
12876     }
12877     v8::V8::ContextDisposedNotification();
12878     CheckSurvivingGlobalObjectsCount(0);
12879
12880     { v8::HandleScope scope(CcTest::isolate());
12881       LocalContext context;
12882       v8_compile("Date")->Run();
12883     }
12884     v8::V8::ContextDisposedNotification();
12885     CheckSurvivingGlobalObjectsCount(0);
12886
12887     { v8::HandleScope scope(CcTest::isolate());
12888       LocalContext context;
12889       v8_compile("/aaa/")->Run();
12890     }
12891     v8::V8::ContextDisposedNotification();
12892     CheckSurvivingGlobalObjectsCount(0);
12893
12894     { v8::HandleScope scope(CcTest::isolate());
12895       const char* extension_list[] = { "v8/gc" };
12896       v8::ExtensionConfiguration extensions(1, extension_list);
12897       LocalContext context(&extensions);
12898       v8_compile("gc();")->Run();
12899     }
12900     v8::V8::ContextDisposedNotification();
12901     CheckSurvivingGlobalObjectsCount(0);
12902   }
12903 }
12904
12905
12906 TEST(CopyablePersistent) {
12907   LocalContext context;
12908   v8::Isolate* isolate = context->GetIsolate();
12909   i::GlobalHandles* globals =
12910       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
12911   int initial_handles = globals->global_handles_count();
12912   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
12913       CopyableObject;
12914   {
12915     CopyableObject handle1;
12916     {
12917       v8::HandleScope scope(isolate);
12918       handle1.Reset(isolate, v8::Object::New());
12919     }
12920     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
12921     CopyableObject  handle2;
12922     handle2 = handle1;
12923     CHECK(handle1 == handle2);
12924     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
12925     CopyableObject handle3(handle2);
12926     CHECK(handle1 == handle3);
12927     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
12928   }
12929   // Verify autodispose
12930   CHECK_EQ(initial_handles, globals->global_handles_count());
12931 }
12932
12933
12934 static void WeakApiCallback(
12935     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
12936   Local<Value> value = data.GetValue()->Get(v8_str("key"));
12937   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
12938   data.GetParameter()->Reset();
12939   delete data.GetParameter();
12940 }
12941
12942
12943 TEST(WeakCallbackApi) {
12944   LocalContext context;
12945   v8::Isolate* isolate = context->GetIsolate();
12946   i::GlobalHandles* globals =
12947       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
12948   int initial_handles = globals->global_handles_count();
12949   {
12950     v8::HandleScope scope(isolate);
12951     v8::Local<v8::Object> obj = v8::Object::New();
12952     obj->Set(v8_str("key"), v8::Integer::New(231, isolate));
12953     v8::Persistent<v8::Object>* handle =
12954         new v8::Persistent<v8::Object>(isolate, obj);
12955     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
12956                                                              WeakApiCallback);
12957   }
12958   reinterpret_cast<i::Isolate*>(isolate)->heap()->
12959       CollectAllGarbage(i::Heap::kNoGCFlags);
12960   // Verify disposed.
12961   CHECK_EQ(initial_handles, globals->global_handles_count());
12962 }
12963
12964
12965 v8::Persistent<v8::Object> some_object;
12966 v8::Persistent<v8::Object> bad_handle;
12967
12968 void NewPersistentHandleCallback(v8::Isolate* isolate,
12969                                  v8::Persistent<v8::Value>* handle,
12970                                  void*) {
12971   v8::HandleScope scope(isolate);
12972   bad_handle.Reset(isolate, some_object);
12973   handle->Dispose();
12974 }
12975
12976
12977 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
12978   LocalContext context;
12979   v8::Isolate* isolate = context->GetIsolate();
12980
12981   v8::Persistent<v8::Object> handle1, handle2;
12982   {
12983     v8::HandleScope scope(isolate);
12984     some_object.Reset(isolate, v8::Object::New());
12985     handle1.Reset(isolate, v8::Object::New());
12986     handle2.Reset(isolate, v8::Object::New());
12987   }
12988   // Note: order is implementation dependent alas: currently
12989   // global handle nodes are processed by PostGarbageCollectionProcessing
12990   // in reverse allocation order, so if second allocated handle is deleted,
12991   // weak callback of the first handle would be able to 'reallocate' it.
12992   handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback);
12993   handle2.Dispose();
12994   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12995 }
12996
12997
12998 v8::Persistent<v8::Object> to_be_disposed;
12999
13000 void DisposeAndForceGcCallback(v8::Isolate* isolate,
13001                                v8::Persistent<v8::Value>* handle,
13002                                void*) {
13003   to_be_disposed.Dispose();
13004   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13005   handle->Dispose();
13006 }
13007
13008
13009 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13010   LocalContext context;
13011   v8::Isolate* isolate = context->GetIsolate();
13012
13013   v8::Persistent<v8::Object> handle1, handle2;
13014   {
13015     v8::HandleScope scope(isolate);
13016     handle1.Reset(isolate, v8::Object::New());
13017     handle2.Reset(isolate, v8::Object::New());
13018   }
13019   handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback);
13020   to_be_disposed.Reset(isolate, handle2);
13021   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13022 }
13023
13024 void DisposingCallback(v8::Isolate* isolate,
13025                        v8::Persistent<v8::Value>* handle,
13026                        void*) {
13027   handle->Dispose();
13028 }
13029
13030 void HandleCreatingCallback(v8::Isolate* isolate,
13031                             v8::Persistent<v8::Value>* handle,
13032                             void*) {
13033   v8::HandleScope scope(isolate);
13034   v8::Persistent<v8::Object>(isolate, v8::Object::New());
13035   handle->Dispose();
13036 }
13037
13038
13039 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13040   LocalContext context;
13041   v8::Isolate* isolate = context->GetIsolate();
13042
13043   v8::Persistent<v8::Object> handle1, handle2, handle3;
13044   {
13045     v8::HandleScope scope(isolate);
13046     handle3.Reset(isolate, v8::Object::New());
13047     handle2.Reset(isolate, v8::Object::New());
13048     handle1.Reset(isolate, v8::Object::New());
13049   }
13050   handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback);
13051   handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback);
13052   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13053 }
13054
13055
13056 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13057   v8::V8::Initialize();
13058
13059   const int nof = 2;
13060   const char* sources[nof] = {
13061     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13062     "Object()"
13063   };
13064
13065   for (int i = 0; i < nof; i++) {
13066     const char* source = sources[i];
13067     { v8::HandleScope scope(CcTest::isolate());
13068       LocalContext context;
13069       CompileRun(source);
13070     }
13071     { v8::HandleScope scope(CcTest::isolate());
13072       LocalContext context;
13073       CompileRun(source);
13074     }
13075   }
13076 }
13077
13078
13079 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13080   v8::HandleScope inner(env->GetIsolate());
13081   env->Enter();
13082   v8::Handle<Value> three = v8_num(3);
13083   v8::Handle<Value> value = inner.Close(three);
13084   env->Exit();
13085   return value;
13086 }
13087
13088
13089 THREADED_TEST(NestedHandleScopeAndContexts) {
13090   v8::Isolate* isolate = CcTest::isolate();
13091   v8::HandleScope outer(isolate);
13092   v8::Local<Context> env = Context::New(isolate);
13093   env->Enter();
13094   v8::Handle<Value> value = NestedScope(env);
13095   v8::Handle<String> str(value->ToString());
13096   CHECK(!str.IsEmpty());
13097   env->Exit();
13098 }
13099
13100
13101 static bool MatchPointers(void* key1, void* key2) {
13102   return key1 == key2;
13103 }
13104
13105
13106 struct SymbolInfo {
13107   size_t id;
13108   size_t size;
13109   std::string name;
13110 };
13111
13112
13113 class SetFunctionEntryHookTest {
13114  public:
13115   SetFunctionEntryHookTest() {
13116     CHECK(instance_ == NULL);
13117     instance_ = this;
13118   }
13119   ~SetFunctionEntryHookTest() {
13120     CHECK(instance_ == this);
13121     instance_ = NULL;
13122   }
13123   void Reset() {
13124     symbols_.clear();
13125     symbol_locations_.clear();
13126     invocations_.clear();
13127   }
13128   void RunTest();
13129   void OnJitEvent(const v8::JitCodeEvent* event);
13130   static void JitEvent(const v8::JitCodeEvent* event) {
13131     CHECK(instance_ != NULL);
13132     instance_->OnJitEvent(event);
13133   }
13134
13135   void OnEntryHook(uintptr_t function,
13136                    uintptr_t return_addr_location);
13137   static void EntryHook(uintptr_t function,
13138                         uintptr_t return_addr_location) {
13139     CHECK(instance_ != NULL);
13140     instance_->OnEntryHook(function, return_addr_location);
13141   }
13142
13143   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13144     CHECK(instance_ != NULL);
13145     args.GetReturnValue().Set(v8_num(42));
13146   }
13147   void RunLoopInNewEnv(v8::Isolate* isolate);
13148
13149   // Records addr as location of symbol.
13150   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13151
13152   // Finds the symbol containing addr
13153   SymbolInfo* FindSymbolForAddr(i::Address addr);
13154   // Returns the number of invocations where the caller name contains
13155   // \p caller_name and the function name contains \p function_name.
13156   int CountInvocations(const char* caller_name,
13157                        const char* function_name);
13158
13159   i::Handle<i::JSFunction> foo_func_;
13160   i::Handle<i::JSFunction> bar_func_;
13161
13162   typedef std::map<size_t, SymbolInfo> SymbolMap;
13163   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13164   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13165   SymbolMap symbols_;
13166   SymbolLocationMap symbol_locations_;
13167   InvocationMap invocations_;
13168
13169   static SetFunctionEntryHookTest* instance_;
13170 };
13171 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13172
13173
13174 // Returns true if addr is in the range [start, start+len).
13175 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13176   if (start <= addr && start + len > addr)
13177     return true;
13178
13179   return false;
13180 }
13181
13182 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13183                                               SymbolInfo* symbol) {
13184   // Insert the symbol at the new location.
13185   SymbolLocationMap::iterator it =
13186       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13187   // Now erase symbols to the left and right that overlap this one.
13188   while (it != symbol_locations_.begin()) {
13189     SymbolLocationMap::iterator left = it;
13190     --left;
13191     if (!Overlaps(left->first, left->second->size, addr))
13192       break;
13193     symbol_locations_.erase(left);
13194   }
13195
13196   // Now erase symbols to the left and right that overlap this one.
13197   while (true) {
13198     SymbolLocationMap::iterator right = it;
13199     ++right;
13200     if (right == symbol_locations_.end())
13201         break;
13202     if (!Overlaps(addr, symbol->size, right->first))
13203       break;
13204     symbol_locations_.erase(right);
13205   }
13206 }
13207
13208
13209 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13210   switch (event->type) {
13211     case v8::JitCodeEvent::CODE_ADDED: {
13212         CHECK(event->code_start != NULL);
13213         CHECK_NE(0, static_cast<int>(event->code_len));
13214         CHECK(event->name.str != NULL);
13215         size_t symbol_id = symbols_.size();
13216
13217         // Record the new symbol.
13218         SymbolInfo& info = symbols_[symbol_id];
13219         info.id = symbol_id;
13220         info.size = event->code_len;
13221         info.name.assign(event->name.str, event->name.str + event->name.len);
13222
13223         // And record it's location.
13224         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13225       }
13226       break;
13227
13228     case v8::JitCodeEvent::CODE_MOVED: {
13229         // We would like to never see code move that we haven't seen before,
13230         // but the code creation event does not happen until the line endings
13231         // have been calculated (this is so that we can report the line in the
13232         // script at which the function source is found, see
13233         // Compiler::RecordFunctionCompilation) and the line endings
13234         // calculations can cause a GC, which can move the newly created code
13235         // before its existence can be logged.
13236         SymbolLocationMap::iterator it(
13237             symbol_locations_.find(
13238                 reinterpret_cast<i::Address>(event->code_start)));
13239         if (it != symbol_locations_.end()) {
13240           // Found a symbol at this location, move it.
13241           SymbolInfo* info = it->second;
13242           symbol_locations_.erase(it);
13243           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13244                          info);
13245         }
13246       }
13247     default:
13248       break;
13249   }
13250 }
13251
13252 void SetFunctionEntryHookTest::OnEntryHook(
13253     uintptr_t function, uintptr_t return_addr_location) {
13254   // Get the function's code object.
13255   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13256       reinterpret_cast<i::Address>(function));
13257   CHECK(function_code != NULL);
13258
13259   // Then try and look up the caller's code object.
13260   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13261
13262   // Count the invocation.
13263   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13264   SymbolInfo* function_symbol =
13265       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13266   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13267
13268   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13269     // Check that we have a symbol for the "bar" function at the right location.
13270     SymbolLocationMap::iterator it(
13271         symbol_locations_.find(function_code->instruction_start()));
13272     CHECK(it != symbol_locations_.end());
13273   }
13274
13275   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13276     // Check that we have a symbol for "foo" at the right location.
13277     SymbolLocationMap::iterator it(
13278         symbol_locations_.find(function_code->instruction_start()));
13279     CHECK(it != symbol_locations_.end());
13280   }
13281 }
13282
13283
13284 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13285   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13286   // Do we have a direct hit on a symbol?
13287   if (it != symbol_locations_.end()) {
13288     if (it->first == addr)
13289       return it->second;
13290   }
13291
13292   // If not a direct hit, it'll have to be the previous symbol.
13293   if (it == symbol_locations_.begin())
13294     return NULL;
13295
13296   --it;
13297   size_t offs = addr - it->first;
13298   if (offs < it->second->size)
13299     return it->second;
13300
13301   return NULL;
13302 }
13303
13304
13305 int SetFunctionEntryHookTest::CountInvocations(
13306     const char* caller_name, const char* function_name) {
13307   InvocationMap::iterator it(invocations_.begin());
13308   int invocations = 0;
13309   for (; it != invocations_.end(); ++it) {
13310     SymbolInfo* caller = it->first.first;
13311     SymbolInfo* function = it->first.second;
13312
13313     // Filter out non-matching functions.
13314     if (function_name != NULL) {
13315       if (function->name.find(function_name) == std::string::npos)
13316         continue;
13317     }
13318
13319     // Filter out non-matching callers.
13320     if (caller_name != NULL) {
13321       if (caller == NULL)
13322         continue;
13323       if (caller->name.find(caller_name) == std::string::npos)
13324         continue;
13325     }
13326
13327     // It matches add the invocation count to the tally.
13328     invocations += it->second;
13329   }
13330
13331   return invocations;
13332 }
13333
13334
13335 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13336   v8::HandleScope outer(isolate);
13337   v8::Local<Context> env = Context::New(isolate);
13338   env->Enter();
13339
13340   Local<ObjectTemplate> t = ObjectTemplate::New();
13341   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback));
13342   env->Global()->Set(v8_str("obj"), t->NewInstance());
13343
13344   const char* script =
13345       "function bar() {\n"
13346       "  var sum = 0;\n"
13347       "  for (i = 0; i < 100; ++i)\n"
13348       "    sum = foo(i);\n"
13349       "  return sum;\n"
13350       "}\n"
13351       "function foo(i) { return i * i; }\n"
13352       "// Invoke on the runtime function.\n"
13353       "obj.asdf()";
13354   CompileRun(script);
13355   bar_func_ = i::Handle<i::JSFunction>::cast(
13356           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
13357   ASSERT(!bar_func_.is_null());
13358
13359   foo_func_ =
13360       i::Handle<i::JSFunction>::cast(
13361            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
13362   ASSERT(!foo_func_.is_null());
13363
13364   v8::Handle<v8::Value> value = CompileRun("bar();");
13365   CHECK(value->IsNumber());
13366   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13367
13368   // Test the optimized codegen path.
13369   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
13370                      "bar();");
13371   CHECK(value->IsNumber());
13372   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
13373
13374   env->Exit();
13375 }
13376
13377
13378 void SetFunctionEntryHookTest::RunTest() {
13379   // Work in a new isolate throughout.
13380   v8::Isolate* isolate = v8::Isolate::New();
13381
13382   // Test setting the entry hook on the new isolate.
13383   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13384
13385   // Replacing the hook, once set should fail.
13386   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13387
13388   {
13389     v8::Isolate::Scope scope(isolate);
13390
13391     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
13392
13393     RunLoopInNewEnv(isolate);
13394
13395     // Check the exepected invocation counts.
13396     CHECK_EQ(2, CountInvocations(NULL, "bar"));
13397     CHECK_EQ(200, CountInvocations("bar", "foo"));
13398     CHECK_EQ(200, CountInvocations(NULL, "foo"));
13399
13400     // Verify that we have an entry hook on some specific stubs.
13401     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
13402     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
13403     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
13404   }
13405   isolate->Dispose();
13406
13407   Reset();
13408
13409   // Make sure a second isolate is unaffected by the previous entry hook.
13410   isolate = v8::Isolate::New();
13411   {
13412     v8::Isolate::Scope scope(isolate);
13413
13414     // Reset the entry count to zero and set the entry hook.
13415     RunLoopInNewEnv(isolate);
13416
13417     // We should record no invocations in this isolate.
13418     CHECK_EQ(0, static_cast<int>(invocations_.size()));
13419   }
13420   // Since the isolate has been used, we shouldn't be able to set an entry
13421   // hook anymore.
13422   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
13423
13424   isolate->Dispose();
13425 }
13426
13427
13428 TEST(SetFunctionEntryHook) {
13429   // FunctionEntryHook does not work well with experimental natives.
13430   // Experimental natives are compiled during snapshot deserialization.
13431   // This test breaks because InstallGetter (function from snapshot that
13432   // only gets called from experimental natives) is compiled with entry hooks.
13433   i::FLAG_allow_natives_syntax = true;
13434   i::FLAG_use_inlining = false;
13435
13436   SetFunctionEntryHookTest test;
13437   test.RunTest();
13438 }
13439
13440
13441 static i::HashMap* code_map = NULL;
13442 static i::HashMap* jitcode_line_info = NULL;
13443 static int saw_bar = 0;
13444 static int move_events = 0;
13445
13446
13447 static bool FunctionNameIs(const char* expected,
13448                            const v8::JitCodeEvent* event) {
13449   // Log lines for functions are of the general form:
13450   // "LazyCompile:<type><function_name>", where the type is one of
13451   // "*", "~" or "".
13452   static const char kPreamble[] = "LazyCompile:";
13453   static size_t kPreambleLen = sizeof(kPreamble) - 1;
13454
13455   if (event->name.len < sizeof(kPreamble) - 1 ||
13456       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
13457     return false;
13458   }
13459
13460   const char* tail = event->name.str + kPreambleLen;
13461   size_t tail_len = event->name.len - kPreambleLen;
13462   size_t expected_len = strlen(expected);
13463   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
13464     --tail_len;
13465     ++tail;
13466   }
13467
13468   // Check for tails like 'bar :1'.
13469   if (tail_len > expected_len + 2 &&
13470       tail[expected_len] == ' ' &&
13471       tail[expected_len + 1] == ':' &&
13472       tail[expected_len + 2] &&
13473       !strncmp(tail, expected, expected_len)) {
13474     return true;
13475   }
13476
13477   if (tail_len != expected_len)
13478     return false;
13479
13480   return strncmp(tail, expected, expected_len) == 0;
13481 }
13482
13483
13484 static void event_handler(const v8::JitCodeEvent* event) {
13485   CHECK(event != NULL);
13486   CHECK(code_map != NULL);
13487   CHECK(jitcode_line_info != NULL);
13488
13489   class DummyJitCodeLineInfo {
13490   };
13491
13492   switch (event->type) {
13493     case v8::JitCodeEvent::CODE_ADDED: {
13494         CHECK(event->code_start != NULL);
13495         CHECK_NE(0, static_cast<int>(event->code_len));
13496         CHECK(event->name.str != NULL);
13497         i::HashMap::Entry* entry =
13498             code_map->Lookup(event->code_start,
13499                              i::ComputePointerHash(event->code_start),
13500                              true);
13501         entry->value = reinterpret_cast<void*>(event->code_len);
13502
13503         if (FunctionNameIs("bar", event)) {
13504           ++saw_bar;
13505         }
13506       }
13507       break;
13508
13509     case v8::JitCodeEvent::CODE_MOVED: {
13510         uint32_t hash = i::ComputePointerHash(event->code_start);
13511         // We would like to never see code move that we haven't seen before,
13512         // but the code creation event does not happen until the line endings
13513         // have been calculated (this is so that we can report the line in the
13514         // script at which the function source is found, see
13515         // Compiler::RecordFunctionCompilation) and the line endings
13516         // calculations can cause a GC, which can move the newly created code
13517         // before its existence can be logged.
13518         i::HashMap::Entry* entry =
13519             code_map->Lookup(event->code_start, hash, false);
13520         if (entry != NULL) {
13521           ++move_events;
13522
13523           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
13524           code_map->Remove(event->code_start, hash);
13525
13526           entry = code_map->Lookup(event->new_code_start,
13527                                    i::ComputePointerHash(event->new_code_start),
13528                                    true);
13529           CHECK(entry != NULL);
13530           entry->value = reinterpret_cast<void*>(event->code_len);
13531         }
13532       }
13533       break;
13534
13535     case v8::JitCodeEvent::CODE_REMOVED:
13536       // Object/code removal events are currently not dispatched from the GC.
13537       CHECK(false);
13538       break;
13539
13540     // For CODE_START_LINE_INFO_RECORDING event, we will create one
13541     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
13542     // record it in jitcode_line_info.
13543     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
13544         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
13545         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
13546         temp_event->user_data = line_info;
13547         i::HashMap::Entry* entry =
13548             jitcode_line_info->Lookup(line_info,
13549                                       i::ComputePointerHash(line_info),
13550                                       true);
13551         entry->value = reinterpret_cast<void*>(line_info);
13552       }
13553       break;
13554     // For these two events, we will check whether the event->user_data
13555     // data structure is created before during CODE_START_LINE_INFO_RECORDING
13556     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
13557     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
13558         CHECK(event->user_data != NULL);
13559         uint32_t hash = i::ComputePointerHash(event->user_data);
13560         i::HashMap::Entry* entry =
13561             jitcode_line_info->Lookup(event->user_data, hash, false);
13562         CHECK(entry != NULL);
13563         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
13564       }
13565       break;
13566
13567     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
13568         CHECK(event->user_data != NULL);
13569         uint32_t hash = i::ComputePointerHash(event->user_data);
13570         i::HashMap::Entry* entry =
13571             jitcode_line_info->Lookup(event->user_data, hash, false);
13572         CHECK(entry != NULL);
13573       }
13574       break;
13575
13576     default:
13577       // Impossible event.
13578       CHECK(false);
13579       break;
13580   }
13581 }
13582
13583
13584 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
13585   i::FLAG_stress_compaction = true;
13586   i::FLAG_incremental_marking = false;
13587   const char* script =
13588     "function bar() {"
13589     "  var sum = 0;"
13590     "  for (i = 0; i < 100; ++i)"
13591     "    sum = foo(i);"
13592     "  return sum;"
13593     "}"
13594     "function foo(i) { return i * i; };"
13595     "bar();";
13596
13597   // Run this test in a new isolate to make sure we don't
13598   // have remnants of state from other code.
13599   v8::Isolate* isolate = v8::Isolate::New();
13600   isolate->Enter();
13601   i::Heap* heap = reinterpret_cast<i::Isolate*>(isolate)->heap();
13602
13603   {
13604     v8::HandleScope scope(isolate);
13605     i::HashMap code(MatchPointers);
13606     code_map = &code;
13607
13608     i::HashMap lineinfo(MatchPointers);
13609     jitcode_line_info = &lineinfo;
13610
13611     saw_bar = 0;
13612     move_events = 0;
13613
13614     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
13615
13616     // Generate new code objects sparsely distributed across several
13617     // different fragmented code-space pages.
13618     const int kIterations = 10;
13619     for (int i = 0; i < kIterations; ++i) {
13620       LocalContext env(isolate);
13621       i::AlwaysAllocateScope always_allocate;
13622       SimulateFullSpace(heap->code_space());
13623       CompileRun(script);
13624
13625       // Keep a strong reference to the code object in the handle scope.
13626       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
13627           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
13628       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
13629           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
13630
13631       // Clear the compilation cache to get more wastage.
13632       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
13633     }
13634
13635     // Force code movement.
13636     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
13637
13638     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13639
13640     CHECK_LE(kIterations, saw_bar);
13641     CHECK_LT(0, move_events);
13642
13643     code_map = NULL;
13644     jitcode_line_info = NULL;
13645   }
13646
13647   isolate->Exit();
13648   isolate->Dispose();
13649
13650   // Do this in a new isolate.
13651   isolate = v8::Isolate::New();
13652   isolate->Enter();
13653
13654   // Verify that we get callbacks for existing code objects when we
13655   // request enumeration of existing code.
13656   {
13657     v8::HandleScope scope(isolate);
13658     LocalContext env(isolate);
13659     CompileRun(script);
13660
13661     // Now get code through initial iteration.
13662     i::HashMap code(MatchPointers);
13663     code_map = &code;
13664
13665     i::HashMap lineinfo(MatchPointers);
13666     jitcode_line_info = &lineinfo;
13667
13668     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
13669     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13670
13671     jitcode_line_info = NULL;
13672     // We expect that we got some events. Note that if we could get code removal
13673     // notifications, we could compare two collections, one created by listening
13674     // from the time of creation of an isolate, and the other by subscribing
13675     // with EnumExisting.
13676     CHECK_LT(0, code.occupancy());
13677
13678     code_map = NULL;
13679   }
13680
13681   isolate->Exit();
13682   isolate->Dispose();
13683 }
13684
13685
13686 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
13687
13688
13689 THREADED_TEST(ExternalAllocatedMemory) {
13690   v8::Isolate* isolate = CcTest::isolate();
13691   v8::HandleScope outer(isolate);
13692   v8::Local<Context> env(Context::New(isolate));
13693   CHECK(!env.IsEmpty());
13694   const intptr_t kSize = 1024*1024;
13695   int64_t baseline = cast(isolate->AdjustAmountOfExternalAllocatedMemory(0));
13696   CHECK_EQ(baseline + cast(kSize),
13697            cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize)));
13698   CHECK_EQ(baseline,
13699            cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)));
13700 }
13701
13702
13703 // Regression test for issue 54, object templates with internal fields
13704 // but no accessors or interceptors did not get their internal field
13705 // count set on instances.
13706 THREADED_TEST(Regress54) {
13707   LocalContext context;
13708   v8::Isolate* isolate = context->GetIsolate();
13709   v8::HandleScope outer(isolate);
13710   static v8::Persistent<v8::ObjectTemplate> templ;
13711   if (templ.IsEmpty()) {
13712     v8::HandleScope inner(isolate);
13713     v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
13714     local->SetInternalFieldCount(1);
13715     templ.Reset(isolate, inner.Close(local));
13716   }
13717   v8::Handle<v8::Object> result =
13718       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
13719   CHECK_EQ(1, result->InternalFieldCount());
13720 }
13721
13722
13723 // If part of the threaded tests, this test makes ThreadingTest fail
13724 // on mac.
13725 TEST(CatchStackOverflow) {
13726   LocalContext context;
13727   v8::HandleScope scope(context->GetIsolate());
13728   v8::TryCatch try_catch;
13729   v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
13730     "function f() {"
13731     "  return f();"
13732     "}"
13733     ""
13734     "f();"));
13735   v8::Handle<v8::Value> result = script->Run();
13736   CHECK(result.IsEmpty());
13737 }
13738
13739
13740 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
13741                                     const char* resource_name,
13742                                     int line_offset) {
13743   v8::HandleScope scope(CcTest::isolate());
13744   v8::TryCatch try_catch;
13745   v8::Handle<v8::Value> result = script->Run();
13746   CHECK(result.IsEmpty());
13747   CHECK(try_catch.HasCaught());
13748   v8::Handle<v8::Message> message = try_catch.Message();
13749   CHECK(!message.IsEmpty());
13750   CHECK_EQ(10 + line_offset, message->GetLineNumber());
13751   CHECK_EQ(91, message->GetStartPosition());
13752   CHECK_EQ(92, message->GetEndPosition());
13753   CHECK_EQ(2, message->GetStartColumn());
13754   CHECK_EQ(3, message->GetEndColumn());
13755   v8::String::Utf8Value line(message->GetSourceLine());
13756   CHECK_EQ("  throw 'nirk';", *line);
13757   v8::String::Utf8Value name(message->GetScriptResourceName());
13758   CHECK_EQ(resource_name, *name);
13759 }
13760
13761
13762 THREADED_TEST(TryCatchSourceInfo) {
13763   LocalContext context;
13764   v8::HandleScope scope(context->GetIsolate());
13765   v8::Handle<v8::String> source = v8::String::New(
13766       "function Foo() {\n"
13767       "  return Bar();\n"
13768       "}\n"
13769       "\n"
13770       "function Bar() {\n"
13771       "  return Baz();\n"
13772       "}\n"
13773       "\n"
13774       "function Baz() {\n"
13775       "  throw 'nirk';\n"
13776       "}\n"
13777       "\n"
13778       "Foo();\n");
13779
13780   const char* resource_name;
13781   v8::Handle<v8::Script> script;
13782   resource_name = "test.js";
13783   script = v8::Script::Compile(source, v8::String::New(resource_name));
13784   CheckTryCatchSourceInfo(script, resource_name, 0);
13785
13786   resource_name = "test1.js";
13787   v8::ScriptOrigin origin1(v8::String::New(resource_name));
13788   script = v8::Script::Compile(source, &origin1);
13789   CheckTryCatchSourceInfo(script, resource_name, 0);
13790
13791   resource_name = "test2.js";
13792   v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
13793   script = v8::Script::Compile(source, &origin2);
13794   CheckTryCatchSourceInfo(script, resource_name, 7);
13795 }
13796
13797
13798 THREADED_TEST(CompilationCache) {
13799   LocalContext context;
13800   v8::HandleScope scope(context->GetIsolate());
13801   v8::Handle<v8::String> source0 = v8::String::New("1234");
13802   v8::Handle<v8::String> source1 = v8::String::New("1234");
13803   v8::Handle<v8::Script> script0 =
13804       v8::Script::Compile(source0, v8::String::New("test.js"));
13805   v8::Handle<v8::Script> script1 =
13806       v8::Script::Compile(source1, v8::String::New("test.js"));
13807   v8::Handle<v8::Script> script2 =
13808       v8::Script::Compile(source0);  // different origin
13809   CHECK_EQ(1234, script0->Run()->Int32Value());
13810   CHECK_EQ(1234, script1->Run()->Int32Value());
13811   CHECK_EQ(1234, script2->Run()->Int32Value());
13812 }
13813
13814
13815 static void FunctionNameCallback(
13816     const v8::FunctionCallbackInfo<v8::Value>& args) {
13817   ApiTestFuzzer::Fuzz();
13818   args.GetReturnValue().Set(v8_num(42));
13819 }
13820
13821
13822 THREADED_TEST(CallbackFunctionName) {
13823   LocalContext context;
13824   v8::HandleScope scope(context->GetIsolate());
13825   Local<ObjectTemplate> t = ObjectTemplate::New();
13826   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
13827   context->Global()->Set(v8_str("obj"), t->NewInstance());
13828   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
13829   CHECK(value->IsString());
13830   v8::String::Utf8Value name(value);
13831   CHECK_EQ("asdf", *name);
13832 }
13833
13834
13835 THREADED_TEST(DateAccess) {
13836   LocalContext context;
13837   v8::HandleScope scope(context->GetIsolate());
13838   v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
13839   CHECK(date->IsDate());
13840   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
13841 }
13842
13843
13844 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
13845   v8::Handle<v8::Object> obj = val.As<v8::Object>();
13846   v8::Handle<v8::Array> props = obj->GetPropertyNames();
13847   CHECK_EQ(elmc, props->Length());
13848   for (int i = 0; i < elmc; i++) {
13849     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13850     CHECK_EQ(elmv[i], *elm);
13851   }
13852 }
13853
13854
13855 void CheckOwnProperties(v8::Handle<v8::Value> val,
13856                         int elmc,
13857                         const char* elmv[]) {
13858   v8::Handle<v8::Object> obj = val.As<v8::Object>();
13859   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
13860   CHECK_EQ(elmc, props->Length());
13861   for (int i = 0; i < elmc; i++) {
13862     v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13863     CHECK_EQ(elmv[i], *elm);
13864   }
13865 }
13866
13867
13868 THREADED_TEST(PropertyEnumeration) {
13869   LocalContext context;
13870   v8::HandleScope scope(context->GetIsolate());
13871   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13872       "var result = [];"
13873       "result[0] = {};"
13874       "result[1] = {a: 1, b: 2};"
13875       "result[2] = [1, 2, 3];"
13876       "var proto = {x: 1, y: 2, z: 3};"
13877       "var x = { __proto__: proto, w: 0, z: 1 };"
13878       "result[3] = x;"
13879       "result;"))->Run();
13880   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13881   CHECK_EQ(4, elms->Length());
13882   int elmc0 = 0;
13883   const char** elmv0 = NULL;
13884   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13885   CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13886   int elmc1 = 2;
13887   const char* elmv1[] = {"a", "b"};
13888   CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13889   CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13890   int elmc2 = 3;
13891   const char* elmv2[] = {"0", "1", "2"};
13892   CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13893   CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13894   int elmc3 = 4;
13895   const char* elmv3[] = {"w", "z", "x", "y"};
13896   CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
13897   int elmc4 = 2;
13898   const char* elmv4[] = {"w", "z"};
13899   CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
13900 }
13901
13902
13903 THREADED_TEST(PropertyEnumeration2) {
13904   LocalContext context;
13905   v8::HandleScope scope(context->GetIsolate());
13906   v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13907       "var result = [];"
13908       "result[0] = {};"
13909       "result[1] = {a: 1, b: 2};"
13910       "result[2] = [1, 2, 3];"
13911       "var proto = {x: 1, y: 2, z: 3};"
13912       "var x = { __proto__: proto, w: 0, z: 1 };"
13913       "result[3] = x;"
13914       "result;"))->Run();
13915   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13916   CHECK_EQ(4, elms->Length());
13917   int elmc0 = 0;
13918   const char** elmv0 = NULL;
13919   CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13920
13921   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
13922   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
13923   CHECK_EQ(0, props->Length());
13924   for (uint32_t i = 0; i < props->Length(); i++) {
13925     printf("p[%d]\n", i);
13926   }
13927 }
13928
13929 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
13930                                   Local<Value> name,
13931                                   v8::AccessType type,
13932                                   Local<Value> data) {
13933   return type != v8::ACCESS_SET;
13934 }
13935
13936
13937 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
13938                                     uint32_t key,
13939                                     v8::AccessType type,
13940                                     Local<Value> data) {
13941   return type != v8::ACCESS_SET;
13942 }
13943
13944
13945 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
13946   LocalContext context;
13947   v8::Isolate* isolate = context->GetIsolate();
13948   v8::HandleScope scope(isolate);
13949   Local<ObjectTemplate> templ = ObjectTemplate::New();
13950   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13951                                  IndexedSetAccessBlocker);
13952   templ->Set(v8_str("x"), v8::True(isolate));
13953   Local<v8::Object> instance = templ->NewInstance();
13954   context->Global()->Set(v8_str("obj"), instance);
13955   Local<Value> value = CompileRun("obj.x");
13956   CHECK(value->BooleanValue());
13957 }
13958
13959
13960 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
13961                                   Local<Value> name,
13962                                   v8::AccessType type,
13963                                   Local<Value> data) {
13964   return false;
13965 }
13966
13967
13968 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
13969                                     uint32_t key,
13970                                     v8::AccessType type,
13971                                     Local<Value> data) {
13972   return false;
13973 }
13974
13975
13976
13977 THREADED_TEST(AccessChecksReenabledCorrectly) {
13978   LocalContext context;
13979   v8::HandleScope scope(context->GetIsolate());
13980   Local<ObjectTemplate> templ = ObjectTemplate::New();
13981   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13982                                  IndexedGetAccessBlocker);
13983   templ->Set(v8_str("a"), v8_str("a"));
13984   // Add more than 8 (see kMaxFastProperties) properties
13985   // so that the constructor will force copying map.
13986   // Cannot sprintf, gcc complains unsafety.
13987   char buf[4];
13988   for (char i = '0'; i <= '9' ; i++) {
13989     buf[0] = i;
13990     for (char j = '0'; j <= '9'; j++) {
13991       buf[1] = j;
13992       for (char k = '0'; k <= '9'; k++) {
13993         buf[2] = k;
13994         buf[3] = 0;
13995         templ->Set(v8_str(buf), v8::Number::New(k));
13996       }
13997     }
13998   }
13999
14000   Local<v8::Object> instance_1 = templ->NewInstance();
14001   context->Global()->Set(v8_str("obj_1"), instance_1);
14002
14003   Local<Value> value_1 = CompileRun("obj_1.a");
14004   CHECK(value_1->IsUndefined());
14005
14006   Local<v8::Object> instance_2 = templ->NewInstance();
14007   context->Global()->Set(v8_str("obj_2"), instance_2);
14008
14009   Local<Value> value_2 = CompileRun("obj_2.a");
14010   CHECK(value_2->IsUndefined());
14011 }
14012
14013
14014 // This tests that access check information remains on the global
14015 // object template when creating contexts.
14016 THREADED_TEST(AccessControlRepeatedContextCreation) {
14017   v8::Isolate* isolate = CcTest::isolate();
14018   v8::HandleScope handle_scope(isolate);
14019   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14020   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14021                                            IndexedSetAccessBlocker);
14022   i::Handle<i::ObjectTemplateInfo> internal_template =
14023       v8::Utils::OpenHandle(*global_template);
14024   CHECK(!internal_template->constructor()->IsUndefined());
14025   i::Handle<i::FunctionTemplateInfo> constructor(
14026       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14027   CHECK(!constructor->access_check_info()->IsUndefined());
14028   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14029   CHECK(!context0.IsEmpty());
14030   CHECK(!constructor->access_check_info()->IsUndefined());
14031 }
14032
14033
14034 THREADED_TEST(TurnOnAccessCheck) {
14035   v8::Isolate* isolate = CcTest::isolate();
14036   v8::HandleScope handle_scope(isolate);
14037
14038   // Create an environment with access check to the global object disabled by
14039   // default.
14040   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14041   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14042                                            IndexedGetAccessBlocker,
14043                                            v8::Handle<v8::Value>(),
14044                                            false);
14045   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14046   Context::Scope context_scope(context);
14047
14048   // Set up a property and a number of functions.
14049   context->Global()->Set(v8_str("a"), v8_num(1));
14050   CompileRun("function f1() {return a;}"
14051              "function f2() {return a;}"
14052              "function g1() {return h();}"
14053              "function g2() {return h();}"
14054              "function h() {return 1;}");
14055   Local<Function> f1 =
14056       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14057   Local<Function> f2 =
14058       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14059   Local<Function> g1 =
14060       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14061   Local<Function> g2 =
14062       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14063   Local<Function> h =
14064       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14065
14066   // Get the global object.
14067   v8::Handle<v8::Object> global = context->Global();
14068
14069   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14070   // uses the runtime system to retreive property a whereas f2 uses global load
14071   // inline cache.
14072   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14073   for (int i = 0; i < 4; i++) {
14074     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14075   }
14076
14077   // Same for g1 and g2.
14078   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14079   for (int i = 0; i < 4; i++) {
14080     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14081   }
14082
14083   // Detach the global and turn on access check.
14084   context->DetachGlobal();
14085   context->Global()->TurnOnAccessCheck();
14086
14087   // Failing access check to property get results in undefined.
14088   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14089   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14090
14091   // Failing access check to function call results in exception.
14092   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14093   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14094
14095   // No failing access check when just returning a constant.
14096   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14097 }
14098
14099
14100 static const char* kPropertyA = "a";
14101 static const char* kPropertyH = "h";
14102
14103 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14104                                        Local<Value> name,
14105                                        v8::AccessType type,
14106                                        Local<Value> data) {
14107   if (!name->IsString()) return false;
14108   i::Handle<i::String> name_handle =
14109       v8::Utils::OpenHandle(String::Cast(*name));
14110   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14111       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14112 }
14113
14114
14115 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14116   v8::Isolate* isolate = CcTest::isolate();
14117   v8::HandleScope handle_scope(isolate);
14118
14119   // Create an environment with access check to the global object disabled by
14120   // default. When the registered access checker will block access to properties
14121   // a and h.
14122   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
14123   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14124                                            IndexedGetAccessBlocker,
14125                                            v8::Handle<v8::Value>(),
14126                                            false);
14127   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14128   Context::Scope context_scope(context);
14129
14130   // Set up a property and a number of functions.
14131   context->Global()->Set(v8_str("a"), v8_num(1));
14132   static const char* source = "function f1() {return a;}"
14133                               "function f2() {return a;}"
14134                               "function g1() {return h();}"
14135                               "function g2() {return h();}"
14136                               "function h() {return 1;}";
14137
14138   CompileRun(source);
14139   Local<Function> f1;
14140   Local<Function> f2;
14141   Local<Function> g1;
14142   Local<Function> g2;
14143   Local<Function> h;
14144   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14145   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14146   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14147   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14148   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14149
14150   // Get the global object.
14151   v8::Handle<v8::Object> global = context->Global();
14152
14153   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14154   // uses the runtime system to retreive property a whereas f2 uses global load
14155   // inline cache.
14156   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14157   for (int i = 0; i < 4; i++) {
14158     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14159   }
14160
14161   // Same for g1 and g2.
14162   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14163   for (int i = 0; i < 4; i++) {
14164     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14165   }
14166
14167   // Detach the global and turn on access check now blocking access to property
14168   // a and function h.
14169   context->DetachGlobal();
14170   context->Global()->TurnOnAccessCheck();
14171
14172   // Failing access check to property get results in undefined.
14173   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14174   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14175
14176   // Failing access check to function call results in exception.
14177   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14178   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14179
14180   // No failing access check when just returning a constant.
14181   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14182
14183   // Now compile the source again. And get the newly compiled functions, except
14184   // for h for which access is blocked.
14185   CompileRun(source);
14186   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14187   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14188   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14189   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14190   CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
14191
14192   // Failing access check to property get results in undefined.
14193   CHECK(f1->Call(global, 0, NULL)->IsUndefined());
14194   CHECK(f2->Call(global, 0, NULL)->IsUndefined());
14195
14196   // Failing access check to function call results in exception.
14197   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14198   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14199 }
14200
14201
14202 // This test verifies that pre-compilation (aka preparsing) can be called
14203 // without initializing the whole VM. Thus we cannot run this test in a
14204 // multi-threaded setup.
14205 TEST(PreCompile) {
14206   // TODO(155): This test would break without the initialization of V8. This is
14207   // a workaround for now to make this test not fail.
14208   v8::V8::Initialize();
14209   v8::Isolate* isolate = CcTest::isolate();
14210   const char* script = "function foo(a) { return a+1; }";
14211   v8::ScriptData* sd =
14212       v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14213   CHECK_NE(sd->Length(), 0);
14214   CHECK_NE(sd->Data(), NULL);
14215   CHECK(!sd->HasError());
14216   delete sd;
14217 }
14218
14219
14220 TEST(PreCompileWithError) {
14221   v8::V8::Initialize();
14222   v8::Isolate* isolate = CcTest::isolate();
14223   const char* script = "function foo(a) { return 1 * * 2; }";
14224   v8::ScriptData* sd =
14225       v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14226   CHECK(sd->HasError());
14227   delete sd;
14228 }
14229
14230
14231 TEST(Regress31661) {
14232   v8::V8::Initialize();
14233   v8::Isolate* isolate = CcTest::isolate();
14234   const char* script = " The Definintive Guide";
14235   v8::ScriptData* sd =
14236       v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14237   CHECK(sd->HasError());
14238   delete sd;
14239 }
14240
14241
14242 // Tests that ScriptData can be serialized and deserialized.
14243 TEST(PreCompileSerialization) {
14244   v8::V8::Initialize();
14245   v8::Isolate* isolate = CcTest::isolate();
14246   const char* script = "function foo(a) { return a+1; }";
14247   v8::ScriptData* sd =
14248       v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14249
14250   // Serialize.
14251   int serialized_data_length = sd->Length();
14252   char* serialized_data = i::NewArray<char>(serialized_data_length);
14253   i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
14254
14255   // Deserialize.
14256   v8::ScriptData* deserialized_sd =
14257       v8::ScriptData::New(serialized_data, serialized_data_length);
14258
14259   // Verify that the original is the same as the deserialized.
14260   CHECK_EQ(sd->Length(), deserialized_sd->Length());
14261   CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
14262   CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
14263
14264   delete sd;
14265   delete deserialized_sd;
14266 }
14267
14268
14269 // Attempts to deserialize bad data.
14270 TEST(PreCompileDeserializationError) {
14271   v8::V8::Initialize();
14272   const char* data = "DONT CARE";
14273   int invalid_size = 3;
14274   v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
14275
14276   CHECK_EQ(0, sd->Length());
14277
14278   delete sd;
14279 }
14280
14281
14282 // Attempts to deserialize bad data.
14283 TEST(PreCompileInvalidPreparseDataError) {
14284   v8::V8::Initialize();
14285   v8::Isolate* isolate = CcTest::isolate();
14286   LocalContext context;
14287   v8::HandleScope scope(context->GetIsolate());
14288
14289   const char* script = "function foo(){ return 5;}\n"
14290       "function bar(){ return 6 + 7;}  foo();";
14291   v8::ScriptData* sd =
14292       v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14293   CHECK(!sd->HasError());
14294   // ScriptDataImpl private implementation details
14295   const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
14296   const int kFunctionEntrySize = i::FunctionEntry::kSize;
14297   const int kFunctionEntryStartOffset = 0;
14298   const int kFunctionEntryEndOffset = 1;
14299   unsigned* sd_data =
14300       reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14301
14302   // Overwrite function bar's end position with 0.
14303   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
14304   v8::TryCatch try_catch;
14305
14306   Local<String> source = String::New(script);
14307   Local<Script> compiled_script = Script::New(source, NULL, sd);
14308   CHECK(try_catch.HasCaught());
14309   String::Utf8Value exception_value(try_catch.Message()->Get());
14310   CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
14311            *exception_value);
14312
14313   try_catch.Reset();
14314
14315   // Overwrite function bar's start position with 200.  The function entry
14316   // will not be found when searching for it by position and we should fall
14317   // back on eager compilation.
14318   sd = v8::ScriptData::PreCompile(isolate, script, i::StrLength(script));
14319   sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
14320   sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
14321       200;
14322   compiled_script = Script::New(source, NULL, sd);
14323   CHECK(!try_catch.HasCaught());
14324
14325   delete sd;
14326 }
14327
14328
14329 // Verifies that the Handle<String> and const char* versions of the API produce
14330 // the same results (at least for one trivial case).
14331 TEST(PreCompileAPIVariationsAreSame) {
14332   v8::V8::Initialize();
14333   v8::Isolate* isolate = CcTest::isolate();
14334   v8::HandleScope scope(isolate);
14335
14336   const char* cstring = "function foo(a) { return a+1; }";
14337
14338   v8::ScriptData* sd_from_cstring =
14339       v8::ScriptData::PreCompile(isolate, cstring, i::StrLength(cstring));
14340
14341   TestAsciiResource* resource = new TestAsciiResource(cstring);
14342   v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
14343       v8::String::NewExternal(resource));
14344
14345   v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
14346       v8::String::New(cstring));
14347
14348   CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
14349   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
14350                      sd_from_external_string->Data(),
14351                      sd_from_cstring->Length()));
14352
14353   CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
14354   CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
14355                      sd_from_string->Data(),
14356                      sd_from_cstring->Length()));
14357
14358
14359   delete sd_from_cstring;
14360   delete sd_from_external_string;
14361   delete sd_from_string;
14362 }
14363
14364
14365 // This tests that we do not allow dictionary load/call inline caches
14366 // to use functions that have not yet been compiled.  The potential
14367 // problem of loading a function that has not yet been compiled can
14368 // arise because we share code between contexts via the compilation
14369 // cache.
14370 THREADED_TEST(DictionaryICLoadedFunction) {
14371   v8::HandleScope scope(CcTest::isolate());
14372   // Test LoadIC.
14373   for (int i = 0; i < 2; i++) {
14374     LocalContext context;
14375     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14376     context->Global()->Delete(v8_str("tmp"));
14377     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14378   }
14379   // Test CallIC.
14380   for (int i = 0; i < 2; i++) {
14381     LocalContext context;
14382     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14383     context->Global()->Delete(v8_str("tmp"));
14384     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14385   }
14386 }
14387
14388
14389 // Test that cross-context new calls use the context of the callee to
14390 // create the new JavaScript object.
14391 THREADED_TEST(CrossContextNew) {
14392   v8::Isolate* isolate = CcTest::isolate();
14393   v8::HandleScope scope(isolate);
14394   v8::Local<Context> context0 = Context::New(isolate);
14395   v8::Local<Context> context1 = Context::New(isolate);
14396
14397   // Allow cross-domain access.
14398   Local<String> token = v8_str("<security token>");
14399   context0->SetSecurityToken(token);
14400   context1->SetSecurityToken(token);
14401
14402   // Set an 'x' property on the Object prototype and define a
14403   // constructor function in context0.
14404   context0->Enter();
14405   CompileRun("Object.prototype.x = 42; function C() {};");
14406   context0->Exit();
14407
14408   // Call the constructor function from context0 and check that the
14409   // result has the 'x' property.
14410   context1->Enter();
14411   context1->Global()->Set(v8_str("other"), context0->Global());
14412   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14413   CHECK(value->IsInt32());
14414   CHECK_EQ(42, value->Int32Value());
14415   context1->Exit();
14416 }
14417
14418
14419 class ApplyInterruptTest {
14420  public:
14421   ApplyInterruptTest() : block_(0) {}
14422   ~ApplyInterruptTest() {}
14423   void RunTest() {
14424     gc_count_ = 0;
14425     gc_during_apply_ = 0;
14426     apply_success_ = false;
14427     gc_success_ = false;
14428     GCThread gc_thread(this);
14429     gc_thread.Start();
14430     v8::Isolate* isolate = CcTest::isolate();
14431     v8::Locker::StartPreemption(isolate, 1);
14432
14433     LongRunningApply();
14434     {
14435       v8::Unlocker unlock(isolate);
14436       gc_thread.Join();
14437     }
14438     v8::Locker::StopPreemption(isolate);
14439     CHECK(apply_success_);
14440     CHECK(gc_success_);
14441   }
14442
14443  private:
14444   // Number of garbage collections required.
14445   static const int kRequiredGCs = 2;
14446
14447   class GCThread : public i::Thread {
14448    public:
14449     explicit GCThread(ApplyInterruptTest* test)
14450         : Thread("GCThread"), test_(test) {}
14451     virtual void Run() {
14452       test_->CollectGarbage();
14453     }
14454    private:
14455      ApplyInterruptTest* test_;
14456   };
14457
14458   void CollectGarbage() {
14459     block_.Wait();
14460     while (gc_during_apply_ < kRequiredGCs) {
14461       {
14462         v8::Locker lock(CcTest::isolate());
14463         v8::Isolate::Scope isolate_scope(CcTest::isolate());
14464         CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14465         gc_count_++;
14466       }
14467       i::OS::Sleep(1);
14468     }
14469     gc_success_ = true;
14470   }
14471
14472   void LongRunningApply() {
14473     block_.Signal();
14474     int rounds = 0;
14475     while (gc_during_apply_ < kRequiredGCs) {
14476       int gc_before = gc_count_;
14477       {
14478         const char* c_source =
14479             "function do_very_little(bar) {"
14480             "  this.foo = bar;"
14481             "}"
14482             "for (var i = 0; i < 100000; i++) {"
14483             "  do_very_little.apply(this, ['bar']);"
14484             "}";
14485         Local<String> source = String::New(c_source);
14486         Local<Script> script = Script::Compile(source);
14487         Local<Value> result = script->Run();
14488         // Check that no exception was thrown.
14489         CHECK(!result.IsEmpty());
14490       }
14491       int gc_after = gc_count_;
14492       gc_during_apply_ += gc_after - gc_before;
14493       rounds++;
14494     }
14495     apply_success_ = true;
14496   }
14497
14498   i::Semaphore block_;
14499   int gc_count_;
14500   int gc_during_apply_;
14501   bool apply_success_;
14502   bool gc_success_;
14503 };
14504
14505
14506 // Test that nothing bad happens if we get a preemption just when we were
14507 // about to do an apply().
14508 TEST(ApplyInterruption) {
14509   v8::Locker lock(CcTest::isolate());
14510   v8::V8::Initialize();
14511   v8::HandleScope scope(CcTest::isolate());
14512   Local<Context> local_env;
14513   {
14514     LocalContext env;
14515     local_env = env.local();
14516   }
14517
14518   // Local context should still be live.
14519   CHECK(!local_env.IsEmpty());
14520   local_env->Enter();
14521
14522   // Should complete without problems.
14523   ApplyInterruptTest().RunTest();
14524
14525   local_env->Exit();
14526 }
14527
14528
14529 // Verify that we can clone an object
14530 TEST(ObjectClone) {
14531   LocalContext env;
14532   v8::HandleScope scope(env->GetIsolate());
14533
14534   const char* sample =
14535     "var rv = {};"      \
14536     "rv.alpha = 'hello';" \
14537     "rv.beta = 123;"     \
14538     "rv;";
14539
14540   // Create an object, verify basics.
14541   Local<Value> val = CompileRun(sample);
14542   CHECK(val->IsObject());
14543   Local<v8::Object> obj = val.As<v8::Object>();
14544   obj->Set(v8_str("gamma"), v8_str("cloneme"));
14545
14546   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14547   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14548   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14549
14550   // Clone it.
14551   Local<v8::Object> clone = obj->Clone();
14552   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14553   CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
14554   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14555
14556   // Set a property on the clone, verify each object.
14557   clone->Set(v8_str("beta"), v8::Integer::New(456));
14558   CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14559   CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
14560 }
14561
14562
14563 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14564  public:
14565   explicit AsciiVectorResource(i::Vector<const char> vector)
14566       : data_(vector) {}
14567   virtual ~AsciiVectorResource() {}
14568   virtual size_t length() const { return data_.length(); }
14569   virtual const char* data() const { return data_.start(); }
14570  private:
14571   i::Vector<const char> data_;
14572 };
14573
14574
14575 class UC16VectorResource : public v8::String::ExternalStringResource {
14576  public:
14577   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14578       : data_(vector) {}
14579   virtual ~UC16VectorResource() {}
14580   virtual size_t length() const { return data_.length(); }
14581   virtual const i::uc16* data() const { return data_.start(); }
14582  private:
14583   i::Vector<const i::uc16> data_;
14584 };
14585
14586
14587 static void MorphAString(i::String* string,
14588                          AsciiVectorResource* ascii_resource,
14589                          UC16VectorResource* uc16_resource) {
14590   CHECK(i::StringShape(string).IsExternal());
14591   if (string->IsOneByteRepresentation()) {
14592     // Check old map is not internalized or long.
14593     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
14594     // Morph external string to be TwoByte string.
14595     string->set_map(CcTest::heap()->external_string_map());
14596     i::ExternalTwoByteString* morphed =
14597          i::ExternalTwoByteString::cast(string);
14598     morphed->set_resource(uc16_resource);
14599   } else {
14600     // Check old map is not internalized or long.
14601     CHECK(string->map() == CcTest::heap()->external_string_map());
14602     // Morph external string to be ASCII string.
14603     string->set_map(CcTest::heap()->external_ascii_string_map());
14604     i::ExternalAsciiString* morphed =
14605          i::ExternalAsciiString::cast(string);
14606     morphed->set_resource(ascii_resource);
14607   }
14608 }
14609
14610
14611 // Test that we can still flatten a string if the components it is built up
14612 // from have been turned into 16 bit strings in the mean time.
14613 THREADED_TEST(MorphCompositeStringTest) {
14614   char utf_buffer[129];
14615   const char* c_string = "Now is the time for all good men"
14616                          " to come to the aid of the party";
14617   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14618   {
14619     LocalContext env;
14620     i::Factory* factory = CcTest::i_isolate()->factory();
14621     v8::HandleScope scope(env->GetIsolate());
14622     AsciiVectorResource ascii_resource(
14623         i::Vector<const char>(c_string, i::StrLength(c_string)));
14624     UC16VectorResource uc16_resource(
14625         i::Vector<const uint16_t>(two_byte_string,
14626                                   i::StrLength(c_string)));
14627
14628     Local<String> lhs(v8::Utils::ToLocal(
14629         factory->NewExternalStringFromAscii(&ascii_resource)));
14630     Local<String> rhs(v8::Utils::ToLocal(
14631         factory->NewExternalStringFromAscii(&ascii_resource)));
14632
14633     env->Global()->Set(v8_str("lhs"), lhs);
14634     env->Global()->Set(v8_str("rhs"), rhs);
14635
14636     CompileRun(
14637         "var cons = lhs + rhs;"
14638         "var slice = lhs.substring(1, lhs.length - 1);"
14639         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
14640
14641     CHECK(lhs->IsOneByte());
14642     CHECK(rhs->IsOneByte());
14643
14644     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
14645     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
14646
14647     // This should UTF-8 without flattening, since everything is ASCII.
14648     Handle<String> cons = v8_compile("cons")->Run().As<String>();
14649     CHECK_EQ(128, cons->Utf8Length());
14650     int nchars = -1;
14651     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
14652     CHECK_EQ(128, nchars);
14653     CHECK_EQ(0, strcmp(
14654         utf_buffer,
14655         "Now is the time for all good men to come to the aid of the party"
14656         "Now is the time for all good men to come to the aid of the party"));
14657
14658     // Now do some stuff to make sure the strings are flattened, etc.
14659     CompileRun(
14660         "/[^a-z]/.test(cons);"
14661         "/[^a-z]/.test(slice);"
14662         "/[^a-z]/.test(slice_on_cons);");
14663     const char* expected_cons =
14664         "Now is the time for all good men to come to the aid of the party"
14665         "Now is the time for all good men to come to the aid of the party";
14666     const char* expected_slice =
14667         "ow is the time for all good men to come to the aid of the part";
14668     const char* expected_slice_on_cons =
14669         "ow is the time for all good men to come to the aid of the party"
14670         "Now is the time for all good men to come to the aid of the part";
14671     CHECK_EQ(String::New(expected_cons),
14672              env->Global()->Get(v8_str("cons")));
14673     CHECK_EQ(String::New(expected_slice),
14674              env->Global()->Get(v8_str("slice")));
14675     CHECK_EQ(String::New(expected_slice_on_cons),
14676              env->Global()->Get(v8_str("slice_on_cons")));
14677   }
14678   i::DeleteArray(two_byte_string);
14679 }
14680
14681
14682 TEST(CompileExternalTwoByteSource) {
14683   LocalContext context;
14684   v8::HandleScope scope(context->GetIsolate());
14685
14686   // This is a very short list of sources, which currently is to check for a
14687   // regression caused by r2703.
14688   const char* ascii_sources[] = {
14689     "0.5",
14690     "-0.5",   // This mainly testes PushBack in the Scanner.
14691     "--0.5",  // This mainly testes PushBack in the Scanner.
14692     NULL
14693   };
14694
14695   // Compile the sources as external two byte strings.
14696   for (int i = 0; ascii_sources[i] != NULL; i++) {
14697     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
14698     UC16VectorResource uc16_resource(
14699         i::Vector<const uint16_t>(two_byte_string,
14700                                   i::StrLength(ascii_sources[i])));
14701     v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
14702     v8::Script::Compile(source);
14703     i::DeleteArray(two_byte_string);
14704   }
14705 }
14706
14707
14708 #ifndef V8_INTERPRETED_REGEXP
14709
14710 struct RegExpInterruptionData {
14711   int loop_count;
14712   UC16VectorResource* string_resource;
14713   v8::Persistent<v8::String> string;
14714 } regexp_interruption_data;
14715
14716
14717 class RegExpInterruptionThread : public i::Thread {
14718  public:
14719   explicit RegExpInterruptionThread(v8::Isolate* isolate)
14720       : Thread("TimeoutThread"), isolate_(isolate) {}
14721
14722   virtual void Run() {
14723     for (regexp_interruption_data.loop_count = 0;
14724          regexp_interruption_data.loop_count < 7;
14725          regexp_interruption_data.loop_count++) {
14726       i::OS::Sleep(50);  // Wait a bit before requesting GC.
14727       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
14728     }
14729     i::OS::Sleep(50);  // Wait a bit before terminating.
14730     v8::V8::TerminateExecution(isolate_);
14731   }
14732
14733  private:
14734   v8::Isolate* isolate_;
14735 };
14736
14737
14738 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
14739   if (regexp_interruption_data.loop_count != 2) return;
14740   v8::HandleScope scope(CcTest::isolate());
14741   v8::Local<v8::String> string = v8::Local<v8::String>::New(
14742       CcTest::isolate(), regexp_interruption_data.string);
14743   string->MakeExternal(regexp_interruption_data.string_resource);
14744 }
14745
14746
14747 // Test that RegExp execution can be interrupted.  Specifically, we test
14748 // * interrupting with GC
14749 // * turn the subject string from one-byte internal to two-byte external string
14750 // * force termination
14751 TEST(RegExpInterruption) {
14752   v8::HandleScope scope(CcTest::isolate());
14753   LocalContext env;
14754
14755   RegExpInterruptionThread timeout_thread(CcTest::isolate());
14756
14757   v8::V8::AddGCPrologueCallback(RunBeforeGC);
14758   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
14759   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
14760   v8::Local<v8::String> string = v8_str(ascii_content);
14761
14762   CcTest::global()->Set(v8_str("a"), string);
14763   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
14764   regexp_interruption_data.string_resource = new UC16VectorResource(
14765       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
14766
14767   v8::TryCatch try_catch;
14768   timeout_thread.Start();
14769
14770   CompileRun("/((a*)*)*b/.exec(a)");
14771   CHECK(try_catch.HasTerminated());
14772
14773   timeout_thread.Join();
14774
14775   delete regexp_interruption_data.string_resource;
14776   regexp_interruption_data.string.Dispose();
14777 }
14778
14779 #endif  // V8_INTERPRETED_REGEXP
14780
14781
14782 // Test that we cannot set a property on the global object if there
14783 // is a read-only property in the prototype chain.
14784 TEST(ReadOnlyPropertyInGlobalProto) {
14785   i::FLAG_es5_readonly = true;
14786   v8::HandleScope scope(CcTest::isolate());
14787   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14788   LocalContext context(0, templ);
14789   v8::Handle<v8::Object> global = context->Global();
14790   v8::Handle<v8::Object> global_proto =
14791       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
14792   global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
14793   global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
14794   // Check without 'eval' or 'with'.
14795   v8::Handle<v8::Value> res =
14796       CompileRun("function f() { x = 42; return x; }; f()");
14797   CHECK_EQ(v8::Integer::New(0), res);
14798   // Check with 'eval'.
14799   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
14800   CHECK_EQ(v8::Integer::New(0), res);
14801   // Check with 'with'.
14802   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
14803   CHECK_EQ(v8::Integer::New(0), res);
14804 }
14805
14806 static int force_set_set_count = 0;
14807 static int force_set_get_count = 0;
14808 bool pass_on_get = false;
14809
14810 static void ForceSetGetter(v8::Local<v8::String> name,
14811                            const v8::PropertyCallbackInfo<v8::Value>& info) {
14812   force_set_get_count++;
14813   if (pass_on_get) {
14814     return;
14815   }
14816   info.GetReturnValue().Set(3);
14817 }
14818
14819 static void ForceSetSetter(v8::Local<v8::String> name,
14820                            v8::Local<v8::Value> value,
14821                            const v8::PropertyCallbackInfo<void>& info) {
14822   force_set_set_count++;
14823 }
14824
14825 static void ForceSetInterceptSetter(
14826     v8::Local<v8::String> name,
14827     v8::Local<v8::Value> value,
14828     const v8::PropertyCallbackInfo<v8::Value>& info) {
14829   force_set_set_count++;
14830   info.GetReturnValue().SetUndefined();
14831 }
14832
14833
14834 TEST(ForceSet) {
14835   force_set_get_count = 0;
14836   force_set_set_count = 0;
14837   pass_on_get = false;
14838
14839   v8::HandleScope scope(CcTest::isolate());
14840   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14841   v8::Handle<v8::String> access_property = v8::String::New("a");
14842   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
14843   LocalContext context(NULL, templ);
14844   v8::Handle<v8::Object> global = context->Global();
14845
14846   // Ordinary properties
14847   v8::Handle<v8::String> simple_property = v8::String::New("p");
14848   global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
14849   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14850   // This should fail because the property is read-only
14851   global->Set(simple_property, v8::Int32::New(5));
14852   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14853   // This should succeed even though the property is read-only
14854   global->ForceSet(simple_property, v8::Int32::New(6));
14855   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
14856
14857   // Accessors
14858   CHECK_EQ(0, force_set_set_count);
14859   CHECK_EQ(0, force_set_get_count);
14860   CHECK_EQ(3, global->Get(access_property)->Int32Value());
14861   // CHECK_EQ the property shouldn't override it, just call the setter
14862   // which in this case does nothing.
14863   global->Set(access_property, v8::Int32::New(7));
14864   CHECK_EQ(3, global->Get(access_property)->Int32Value());
14865   CHECK_EQ(1, force_set_set_count);
14866   CHECK_EQ(2, force_set_get_count);
14867   // Forcing the property to be set should override the accessor without
14868   // calling it
14869   global->ForceSet(access_property, v8::Int32::New(8));
14870   CHECK_EQ(8, global->Get(access_property)->Int32Value());
14871   CHECK_EQ(1, force_set_set_count);
14872   CHECK_EQ(2, force_set_get_count);
14873 }
14874
14875
14876 TEST(ForceSetWithInterceptor) {
14877   force_set_get_count = 0;
14878   force_set_set_count = 0;
14879   pass_on_get = false;
14880
14881   v8::HandleScope scope(CcTest::isolate());
14882   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14883   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
14884   LocalContext context(NULL, templ);
14885   v8::Handle<v8::Object> global = context->Global();
14886
14887   v8::Handle<v8::String> some_property = v8::String::New("a");
14888   CHECK_EQ(0, force_set_set_count);
14889   CHECK_EQ(0, force_set_get_count);
14890   CHECK_EQ(3, global->Get(some_property)->Int32Value());
14891   // Setting the property shouldn't override it, just call the setter
14892   // which in this case does nothing.
14893   global->Set(some_property, v8::Int32::New(7));
14894   CHECK_EQ(3, global->Get(some_property)->Int32Value());
14895   CHECK_EQ(1, force_set_set_count);
14896   CHECK_EQ(2, force_set_get_count);
14897   // Getting the property when the interceptor returns an empty handle
14898   // should yield undefined, since the property isn't present on the
14899   // object itself yet.
14900   pass_on_get = true;
14901   CHECK(global->Get(some_property)->IsUndefined());
14902   CHECK_EQ(1, force_set_set_count);
14903   CHECK_EQ(3, force_set_get_count);
14904   // Forcing the property to be set should cause the value to be
14905   // set locally without calling the interceptor.
14906   global->ForceSet(some_property, v8::Int32::New(8));
14907   CHECK_EQ(8, global->Get(some_property)->Int32Value());
14908   CHECK_EQ(1, force_set_set_count);
14909   CHECK_EQ(4, force_set_get_count);
14910   // Reenabling the interceptor should cause it to take precedence over
14911   // the property
14912   pass_on_get = false;
14913   CHECK_EQ(3, global->Get(some_property)->Int32Value());
14914   CHECK_EQ(1, force_set_set_count);
14915   CHECK_EQ(5, force_set_get_count);
14916   // The interceptor should also work for other properties
14917   CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
14918   CHECK_EQ(1, force_set_set_count);
14919   CHECK_EQ(6, force_set_get_count);
14920 }
14921
14922
14923 THREADED_TEST(ForceDelete) {
14924   v8::HandleScope scope(CcTest::isolate());
14925   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14926   LocalContext context(NULL, templ);
14927   v8::Handle<v8::Object> global = context->Global();
14928
14929   // Ordinary properties
14930   v8::Handle<v8::String> simple_property = v8::String::New("p");
14931   global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
14932   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14933   // This should fail because the property is dont-delete.
14934   CHECK(!global->Delete(simple_property));
14935   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14936   // This should succeed even though the property is dont-delete.
14937   CHECK(global->ForceDelete(simple_property));
14938   CHECK(global->Get(simple_property)->IsUndefined());
14939 }
14940
14941
14942 static int force_delete_interceptor_count = 0;
14943 static bool pass_on_delete = false;
14944
14945
14946 static void ForceDeleteDeleter(
14947     v8::Local<v8::String> name,
14948     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
14949   force_delete_interceptor_count++;
14950   if (pass_on_delete) return;
14951   info.GetReturnValue().Set(true);
14952 }
14953
14954
14955 THREADED_TEST(ForceDeleteWithInterceptor) {
14956   force_delete_interceptor_count = 0;
14957   pass_on_delete = false;
14958
14959   v8::HandleScope scope(CcTest::isolate());
14960   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14961   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
14962   LocalContext context(NULL, templ);
14963   v8::Handle<v8::Object> global = context->Global();
14964
14965   v8::Handle<v8::String> some_property = v8::String::New("a");
14966   global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
14967
14968   // Deleting a property should get intercepted and nothing should
14969   // happen.
14970   CHECK_EQ(0, force_delete_interceptor_count);
14971   CHECK(global->Delete(some_property));
14972   CHECK_EQ(1, force_delete_interceptor_count);
14973   CHECK_EQ(42, global->Get(some_property)->Int32Value());
14974   // Deleting the property when the interceptor returns an empty
14975   // handle should not delete the property since it is DontDelete.
14976   pass_on_delete = true;
14977   CHECK(!global->Delete(some_property));
14978   CHECK_EQ(2, force_delete_interceptor_count);
14979   CHECK_EQ(42, global->Get(some_property)->Int32Value());
14980   // Forcing the property to be deleted should delete the value
14981   // without calling the interceptor.
14982   CHECK(global->ForceDelete(some_property));
14983   CHECK(global->Get(some_property)->IsUndefined());
14984   CHECK_EQ(2, force_delete_interceptor_count);
14985 }
14986
14987
14988 // Make sure that forcing a delete invalidates any IC stubs, so we
14989 // don't read the hole value.
14990 THREADED_TEST(ForceDeleteIC) {
14991   LocalContext context;
14992   v8::HandleScope scope(context->GetIsolate());
14993   // Create a DontDelete variable on the global object.
14994   CompileRun("this.__proto__ = { foo: 'horse' };"
14995              "var foo = 'fish';"
14996              "function f() { return foo.length; }");
14997   // Initialize the IC for foo in f.
14998   CompileRun("for (var i = 0; i < 4; i++) f();");
14999   // Make sure the value of foo is correct before the deletion.
15000   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15001   // Force the deletion of foo.
15002   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15003   // Make sure the value for foo is read from the prototype, and that
15004   // we don't get in trouble with reading the deleted cell value
15005   // sentinel.
15006   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15007 }
15008
15009
15010 TEST(InlinedFunctionAcrossContexts) {
15011   i::FLAG_allow_natives_syntax = true;
15012   v8::Isolate* isolate = CcTest::isolate();
15013   v8::HandleScope outer_scope(isolate);
15014   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15015   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15016   ctx1->Enter();
15017
15018   {
15019     v8::HandleScope inner_scope(CcTest::isolate());
15020     CompileRun("var G = 42; function foo() { return G; }");
15021     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15022     ctx2->Enter();
15023     ctx2->Global()->Set(v8_str("o"), foo);
15024     v8::Local<v8::Value> res = CompileRun(
15025         "function f() { return o(); }"
15026         "for (var i = 0; i < 10; ++i) f();"
15027         "%OptimizeFunctionOnNextCall(f);"
15028         "f();");
15029     CHECK_EQ(42, res->Int32Value());
15030     ctx2->Exit();
15031     v8::Handle<v8::String> G_property = v8::String::New("G");
15032     CHECK(ctx1->Global()->ForceDelete(G_property));
15033     ctx2->Enter();
15034     ExpectString(
15035         "(function() {"
15036         "  try {"
15037         "    return f();"
15038         "  } catch(e) {"
15039         "    return e.toString();"
15040         "  }"
15041         " })()",
15042         "ReferenceError: G is not defined");
15043     ctx2->Exit();
15044     ctx1->Exit();
15045   }
15046 }
15047
15048
15049 static v8::Local<Context> calling_context0;
15050 static v8::Local<Context> calling_context1;
15051 static v8::Local<Context> calling_context2;
15052
15053
15054 // Check that the call to the callback is initiated in
15055 // calling_context2, the directly calling context is calling_context1
15056 // and the callback itself is in calling_context0.
15057 static void GetCallingContextCallback(
15058     const v8::FunctionCallbackInfo<v8::Value>& args) {
15059   ApiTestFuzzer::Fuzz();
15060   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15061   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15062   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15063   args.GetReturnValue().Set(42);
15064 }
15065
15066
15067 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15068   i::Isolate* isolate = CcTest::i_isolate();
15069   CHECK(isolate != NULL);
15070   CHECK(isolate->context() == NULL);
15071   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15072   v8::HandleScope scope(v8_isolate);
15073   // The following should not crash, but return an empty handle.
15074   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15075   CHECK(current.IsEmpty());
15076 }
15077
15078
15079 THREADED_TEST(GetCallingContext) {
15080   v8::Isolate* isolate = CcTest::isolate();
15081   v8::HandleScope scope(isolate);
15082
15083   Local<Context> calling_context0(Context::New(isolate));
15084   Local<Context> calling_context1(Context::New(isolate));
15085   Local<Context> calling_context2(Context::New(isolate));
15086   ::calling_context0 = calling_context0;
15087   ::calling_context1 = calling_context1;
15088   ::calling_context2 = calling_context2;
15089
15090   // Allow cross-domain access.
15091   Local<String> token = v8_str("<security token>");
15092   calling_context0->SetSecurityToken(token);
15093   calling_context1->SetSecurityToken(token);
15094   calling_context2->SetSecurityToken(token);
15095
15096   // Create an object with a C++ callback in context0.
15097   calling_context0->Enter();
15098   Local<v8::FunctionTemplate> callback_templ =
15099       v8::FunctionTemplate::New(GetCallingContextCallback);
15100   calling_context0->Global()->Set(v8_str("callback"),
15101                                   callback_templ->GetFunction());
15102   calling_context0->Exit();
15103
15104   // Expose context0 in context1 and set up a function that calls the
15105   // callback function.
15106   calling_context1->Enter();
15107   calling_context1->Global()->Set(v8_str("context0"),
15108                                   calling_context0->Global());
15109   CompileRun("function f() { context0.callback() }");
15110   calling_context1->Exit();
15111
15112   // Expose context1 in context2 and call the callback function in
15113   // context0 indirectly through f in context1.
15114   calling_context2->Enter();
15115   calling_context2->Global()->Set(v8_str("context1"),
15116                                   calling_context1->Global());
15117   CompileRun("context1.f()");
15118   calling_context2->Exit();
15119   ::calling_context0.Clear();
15120   ::calling_context1.Clear();
15121   ::calling_context2.Clear();
15122 }
15123
15124
15125 // Check that a variable declaration with no explicit initialization
15126 // value does shadow an existing property in the prototype chain.
15127 THREADED_TEST(InitGlobalVarInProtoChain) {
15128   i::FLAG_es52_globals = true;
15129   LocalContext context;
15130   v8::HandleScope scope(context->GetIsolate());
15131   // Introduce a variable in the prototype chain.
15132   CompileRun("__proto__.x = 42");
15133   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15134   CHECK(!result->IsUndefined());
15135   CHECK_EQ(43, result->Int32Value());
15136 }
15137
15138
15139 // Regression test for issue 398.
15140 // If a function is added to an object, creating a constant function
15141 // field, and the result is cloned, replacing the constant function on the
15142 // original should not affect the clone.
15143 // See http://code.google.com/p/v8/issues/detail?id=398
15144 THREADED_TEST(ReplaceConstantFunction) {
15145   LocalContext context;
15146   v8::HandleScope scope(context->GetIsolate());
15147   v8::Handle<v8::Object> obj = v8::Object::New();
15148   v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
15149   v8::Handle<v8::String> foo_string = v8::String::New("foo");
15150   obj->Set(foo_string, func_templ->GetFunction());
15151   v8::Handle<v8::Object> obj_clone = obj->Clone();
15152   obj_clone->Set(foo_string, v8::String::New("Hello"));
15153   CHECK(!obj->Get(foo_string)->IsUndefined());
15154 }
15155
15156
15157 // Regression test for http://crbug.com/16276.
15158 THREADED_TEST(Regress16276) {
15159   LocalContext context;
15160   v8::HandleScope scope(context->GetIsolate());
15161   // Force the IC in f to be a dictionary load IC.
15162   CompileRun("function f(obj) { return obj.x; }\n"
15163              "var obj = { x: { foo: 42 }, y: 87 };\n"
15164              "var x = obj.x;\n"
15165              "delete obj.y;\n"
15166              "for (var i = 0; i < 5; i++) f(obj);");
15167   // Detach the global object to make 'this' refer directly to the
15168   // global object (not the proxy), and make sure that the dictionary
15169   // load IC doesn't mess up loading directly from the global object.
15170   context->DetachGlobal();
15171   CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
15172 }
15173
15174 static void CheckElementValue(i::Isolate* isolate,
15175                               int expected,
15176                               i::Handle<i::Object> obj,
15177                               int offset) {
15178   i::Object* element = obj->GetElement(isolate, offset)->ToObjectChecked();
15179   CHECK_EQ(expected, i::Smi::cast(element)->value());
15180 }
15181
15182
15183 THREADED_TEST(PixelArray) {
15184   LocalContext context;
15185   i::Isolate* isolate = CcTest::i_isolate();
15186   i::Factory* factory = isolate->factory();
15187   v8::HandleScope scope(context->GetIsolate());
15188   const int kElementCount = 260;
15189   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15190   i::Handle<i::ExternalPixelArray> pixels =
15191       i::Handle<i::ExternalPixelArray>::cast(
15192           factory->NewExternalArray(kElementCount,
15193                                     v8::kExternalPixelArray,
15194                                     pixel_data));
15195   // Force GC to trigger verification.
15196   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15197   for (int i = 0; i < kElementCount; i++) {
15198     pixels->set(i, i % 256);
15199   }
15200   // Force GC to trigger verification.
15201   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15202   for (int i = 0; i < kElementCount; i++) {
15203     CHECK_EQ(i % 256, pixels->get_scalar(i));
15204     CHECK_EQ(i % 256, pixel_data[i]);
15205   }
15206
15207   v8::Handle<v8::Object> obj = v8::Object::New();
15208   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15209   // Set the elements to be the pixels.
15210   // jsobj->set_elements(*pixels);
15211   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15212   CheckElementValue(isolate, 1, jsobj, 1);
15213   obj->Set(v8_str("field"), v8::Int32::New(1503));
15214   context->Global()->Set(v8_str("pixels"), obj);
15215   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15216   CHECK_EQ(1503, result->Int32Value());
15217   result = CompileRun("pixels[1]");
15218   CHECK_EQ(1, result->Int32Value());
15219
15220   result = CompileRun("var sum = 0;"
15221                       "for (var i = 0; i < 8; i++) {"
15222                       "  sum += pixels[i] = pixels[i] = -i;"
15223                       "}"
15224                       "sum;");
15225   CHECK_EQ(-28, result->Int32Value());
15226
15227   result = CompileRun("var sum = 0;"
15228                       "for (var i = 0; i < 8; i++) {"
15229                       "  sum += pixels[i] = pixels[i] = 0;"
15230                       "}"
15231                       "sum;");
15232   CHECK_EQ(0, result->Int32Value());
15233
15234   result = CompileRun("var sum = 0;"
15235                       "for (var i = 0; i < 8; i++) {"
15236                       "  sum += pixels[i] = pixels[i] = 255;"
15237                       "}"
15238                       "sum;");
15239   CHECK_EQ(8 * 255, result->Int32Value());
15240
15241   result = CompileRun("var sum = 0;"
15242                       "for (var i = 0; i < 8; i++) {"
15243                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15244                       "}"
15245                       "sum;");
15246   CHECK_EQ(2076, result->Int32Value());
15247
15248   result = CompileRun("var sum = 0;"
15249                       "for (var i = 0; i < 8; i++) {"
15250                       "  sum += pixels[i] = pixels[i] = i;"
15251                       "}"
15252                       "sum;");
15253   CHECK_EQ(28, result->Int32Value());
15254
15255   result = CompileRun("var sum = 0;"
15256                       "for (var i = 0; i < 8; i++) {"
15257                       "  sum += pixels[i];"
15258                       "}"
15259                       "sum;");
15260   CHECK_EQ(28, result->Int32Value());
15261
15262   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15263                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15264   i::Handle<i::Object> no_failure;
15265   no_failure =
15266       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15267   ASSERT(!no_failure.is_null());
15268   i::USE(no_failure);
15269   CheckElementValue(isolate, 2, jsobj, 1);
15270   *value.location() = i::Smi::FromInt(256);
15271   no_failure =
15272       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15273   ASSERT(!no_failure.is_null());
15274   i::USE(no_failure);
15275   CheckElementValue(isolate, 255, jsobj, 1);
15276   *value.location() = i::Smi::FromInt(-1);
15277   no_failure =
15278       i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
15279   ASSERT(!no_failure.is_null());
15280   i::USE(no_failure);
15281   CheckElementValue(isolate, 0, jsobj, 1);
15282
15283   result = CompileRun("for (var i = 0; i < 8; i++) {"
15284                       "  pixels[i] = (i * 65) - 109;"
15285                       "}"
15286                       "pixels[1] + pixels[6];");
15287   CHECK_EQ(255, result->Int32Value());
15288   CheckElementValue(isolate, 0, jsobj, 0);
15289   CheckElementValue(isolate, 0, jsobj, 1);
15290   CheckElementValue(isolate, 21, jsobj, 2);
15291   CheckElementValue(isolate, 86, jsobj, 3);
15292   CheckElementValue(isolate, 151, jsobj, 4);
15293   CheckElementValue(isolate, 216, jsobj, 5);
15294   CheckElementValue(isolate, 255, jsobj, 6);
15295   CheckElementValue(isolate, 255, jsobj, 7);
15296   result = CompileRun("var sum = 0;"
15297                       "for (var i = 0; i < 8; i++) {"
15298                       "  sum += pixels[i];"
15299                       "}"
15300                       "sum;");
15301   CHECK_EQ(984, result->Int32Value());
15302
15303   result = CompileRun("for (var i = 0; i < 8; i++) {"
15304                       "  pixels[i] = (i * 1.1);"
15305                       "}"
15306                       "pixels[1] + pixels[6];");
15307   CHECK_EQ(8, result->Int32Value());
15308   CheckElementValue(isolate, 0, jsobj, 0);
15309   CheckElementValue(isolate, 1, jsobj, 1);
15310   CheckElementValue(isolate, 2, jsobj, 2);
15311   CheckElementValue(isolate, 3, jsobj, 3);
15312   CheckElementValue(isolate, 4, jsobj, 4);
15313   CheckElementValue(isolate, 6, jsobj, 5);
15314   CheckElementValue(isolate, 7, jsobj, 6);
15315   CheckElementValue(isolate, 8, jsobj, 7);
15316
15317   result = CompileRun("for (var i = 0; i < 8; i++) {"
15318                       "  pixels[7] = undefined;"
15319                       "}"
15320                       "pixels[7];");
15321   CHECK_EQ(0, result->Int32Value());
15322   CheckElementValue(isolate, 0, jsobj, 7);
15323
15324   result = CompileRun("for (var i = 0; i < 8; i++) {"
15325                       "  pixels[6] = '2.3';"
15326                       "}"
15327                       "pixels[6];");
15328   CHECK_EQ(2, result->Int32Value());
15329   CheckElementValue(isolate, 2, jsobj, 6);
15330
15331   result = CompileRun("for (var i = 0; i < 8; i++) {"
15332                       "  pixels[5] = NaN;"
15333                       "}"
15334                       "pixels[5];");
15335   CHECK_EQ(0, result->Int32Value());
15336   CheckElementValue(isolate, 0, jsobj, 5);
15337
15338   result = CompileRun("for (var i = 0; i < 8; i++) {"
15339                       "  pixels[8] = Infinity;"
15340                       "}"
15341                       "pixels[8];");
15342   CHECK_EQ(255, result->Int32Value());
15343   CheckElementValue(isolate, 255, jsobj, 8);
15344
15345   result = CompileRun("for (var i = 0; i < 8; i++) {"
15346                       "  pixels[9] = -Infinity;"
15347                       "}"
15348                       "pixels[9];");
15349   CHECK_EQ(0, result->Int32Value());
15350   CheckElementValue(isolate, 0, jsobj, 9);
15351
15352   result = CompileRun("pixels[3] = 33;"
15353                       "delete pixels[3];"
15354                       "pixels[3];");
15355   CHECK_EQ(33, result->Int32Value());
15356
15357   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15358                       "pixels[2] = 12; pixels[3] = 13;"
15359                       "pixels.__defineGetter__('2',"
15360                       "function() { return 120; });"
15361                       "pixels[2];");
15362   CHECK_EQ(12, result->Int32Value());
15363
15364   result = CompileRun("var js_array = new Array(40);"
15365                       "js_array[0] = 77;"
15366                       "js_array;");
15367   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15368
15369   result = CompileRun("pixels[1] = 23;"
15370                       "pixels.__proto__ = [];"
15371                       "js_array.__proto__ = pixels;"
15372                       "js_array.concat(pixels);");
15373   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15374   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15375
15376   result = CompileRun("pixels[1] = 23;");
15377   CHECK_EQ(23, result->Int32Value());
15378
15379   // Test for index greater than 255.  Regression test for:
15380   // http://code.google.com/p/chromium/issues/detail?id=26337.
15381   result = CompileRun("pixels[256] = 255;");
15382   CHECK_EQ(255, result->Int32Value());
15383   result = CompileRun("var i = 0;"
15384                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15385                       "i");
15386   CHECK_EQ(255, result->Int32Value());
15387
15388   // Make sure that pixel array ICs recognize when a non-pixel array
15389   // is passed to it.
15390   result = CompileRun("function pa_load(p) {"
15391                       "  var sum = 0;"
15392                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15393                       "  return sum;"
15394                       "}"
15395                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15396                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15397                       "just_ints = new Object();"
15398                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15399                       "for (var i = 0; i < 10; ++i) {"
15400                       "  result = pa_load(just_ints);"
15401                       "}"
15402                       "result");
15403   CHECK_EQ(32640, result->Int32Value());
15404
15405   // Make sure that pixel array ICs recognize out-of-bound accesses.
15406   result = CompileRun("function pa_load(p, start) {"
15407                       "  var sum = 0;"
15408                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15409                       "  return sum;"
15410                       "}"
15411                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15412                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15413                       "for (var i = 0; i < 10; ++i) {"
15414                       "  result = pa_load(pixels,-10);"
15415                       "}"
15416                       "result");
15417   CHECK_EQ(0, result->Int32Value());
15418
15419   // Make sure that generic ICs properly handles a pixel array.
15420   result = CompileRun("function pa_load(p) {"
15421                       "  var sum = 0;"
15422                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15423                       "  return sum;"
15424                       "}"
15425                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15426                       "just_ints = new Object();"
15427                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15428                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15429                       "for (var i = 0; i < 10; ++i) {"
15430                       "  result = pa_load(pixels);"
15431                       "}"
15432                       "result");
15433   CHECK_EQ(32640, result->Int32Value());
15434
15435   // Make sure that generic load ICs recognize out-of-bound accesses in
15436   // pixel arrays.
15437   result = CompileRun("function pa_load(p, start) {"
15438                       "  var sum = 0;"
15439                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15440                       "  return sum;"
15441                       "}"
15442                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15443                       "just_ints = new Object();"
15444                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15445                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15446                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15447                       "for (var i = 0; i < 10; ++i) {"
15448                       "  result = pa_load(pixels,-10);"
15449                       "}"
15450                       "result");
15451   CHECK_EQ(0, result->Int32Value());
15452
15453   // Make sure that generic ICs properly handles other types than pixel
15454   // arrays (that the inlined fast pixel array test leaves the right information
15455   // in the right registers).
15456   result = CompileRun("function pa_load(p) {"
15457                       "  var sum = 0;"
15458                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15459                       "  return sum;"
15460                       "}"
15461                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15462                       "just_ints = new Object();"
15463                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15464                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15465                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15466                       "sparse_array = new Object();"
15467                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15468                       "sparse_array[1000000] = 3;"
15469                       "for (var i = 0; i < 10; ++i) {"
15470                       "  result = pa_load(sparse_array);"
15471                       "}"
15472                       "result");
15473   CHECK_EQ(32640, result->Int32Value());
15474
15475   // Make sure that pixel array store ICs clamp values correctly.
15476   result = CompileRun("function pa_store(p) {"
15477                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15478                       "}"
15479                       "pa_store(pixels);"
15480                       "var sum = 0;"
15481                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15482                       "sum");
15483   CHECK_EQ(48896, result->Int32Value());
15484
15485   // Make sure that pixel array stores correctly handle accesses outside
15486   // of the pixel array..
15487   result = CompileRun("function pa_store(p,start) {"
15488                       "  for (var j = 0; j < 256; j++) {"
15489                       "    p[j+start] = j * 2;"
15490                       "  }"
15491                       "}"
15492                       "pa_store(pixels,0);"
15493                       "pa_store(pixels,-128);"
15494                       "var sum = 0;"
15495                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15496                       "sum");
15497   CHECK_EQ(65280, result->Int32Value());
15498
15499   // Make sure that the generic store stub correctly handle accesses outside
15500   // of the pixel array..
15501   result = CompileRun("function pa_store(p,start) {"
15502                       "  for (var j = 0; j < 256; j++) {"
15503                       "    p[j+start] = j * 2;"
15504                       "  }"
15505                       "}"
15506                       "pa_store(pixels,0);"
15507                       "just_ints = new Object();"
15508                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15509                       "pa_store(just_ints, 0);"
15510                       "pa_store(pixels,-128);"
15511                       "var sum = 0;"
15512                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15513                       "sum");
15514   CHECK_EQ(65280, result->Int32Value());
15515
15516   // Make sure that the generic keyed store stub clamps pixel array values
15517   // correctly.
15518   result = CompileRun("function pa_store(p) {"
15519                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15520                       "}"
15521                       "pa_store(pixels);"
15522                       "just_ints = new Object();"
15523                       "pa_store(just_ints);"
15524                       "pa_store(pixels);"
15525                       "var sum = 0;"
15526                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15527                       "sum");
15528   CHECK_EQ(48896, result->Int32Value());
15529
15530   // Make sure that pixel array loads are optimized by crankshaft.
15531   result = CompileRun("function pa_load(p) {"
15532                       "  var sum = 0;"
15533                       "  for (var i=0; i<256; ++i) {"
15534                       "    sum += p[i];"
15535                       "  }"
15536                       "  return sum; "
15537                       "}"
15538                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15539                       "for (var i = 0; i < 5000; ++i) {"
15540                       "  result = pa_load(pixels);"
15541                       "}"
15542                       "result");
15543   CHECK_EQ(32640, result->Int32Value());
15544
15545   // Make sure that pixel array stores are optimized by crankshaft.
15546   result = CompileRun("function pa_init(p) {"
15547                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15548                       "}"
15549                       "function pa_load(p) {"
15550                       "  var sum = 0;"
15551                       "  for (var i=0; i<256; ++i) {"
15552                       "    sum += p[i];"
15553                       "  }"
15554                       "  return sum; "
15555                       "}"
15556                       "for (var i = 0; i < 5000; ++i) {"
15557                       "  pa_init(pixels);"
15558                       "}"
15559                       "result = pa_load(pixels);"
15560                       "result");
15561   CHECK_EQ(32640, result->Int32Value());
15562
15563   free(pixel_data);
15564 }
15565
15566
15567 THREADED_TEST(PixelArrayInfo) {
15568   LocalContext context;
15569   v8::HandleScope scope(context->GetIsolate());
15570   for (int size = 0; size < 100; size += 10) {
15571     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15572     v8::Handle<v8::Object> obj = v8::Object::New();
15573     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15574     CHECK(obj->HasIndexedPropertiesInPixelData());
15575     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15576     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15577     free(pixel_data);
15578   }
15579 }
15580
15581
15582 static void NotHandledIndexedPropertyGetter(
15583     uint32_t index,
15584     const v8::PropertyCallbackInfo<v8::Value>& info) {
15585   ApiTestFuzzer::Fuzz();
15586 }
15587
15588
15589 static void NotHandledIndexedPropertySetter(
15590     uint32_t index,
15591     Local<Value> value,
15592     const v8::PropertyCallbackInfo<v8::Value>& info) {
15593   ApiTestFuzzer::Fuzz();
15594 }
15595
15596
15597 THREADED_TEST(PixelArrayWithInterceptor) {
15598   LocalContext context;
15599   i::Factory* factory = CcTest::i_isolate()->factory();
15600   v8::HandleScope scope(context->GetIsolate());
15601   const int kElementCount = 260;
15602   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15603   i::Handle<i::ExternalPixelArray> pixels =
15604       i::Handle<i::ExternalPixelArray>::cast(
15605           factory->NewExternalArray(kElementCount,
15606                                     v8::kExternalPixelArray,
15607                                     pixel_data));
15608   for (int i = 0; i < kElementCount; i++) {
15609     pixels->set(i, i % 256);
15610   }
15611   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
15612   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
15613                                    NotHandledIndexedPropertySetter);
15614   v8::Handle<v8::Object> obj = templ->NewInstance();
15615   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15616   context->Global()->Set(v8_str("pixels"), obj);
15617   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
15618   CHECK_EQ(1, result->Int32Value());
15619   result = CompileRun("var sum = 0;"
15620                       "for (var i = 0; i < 8; i++) {"
15621                       "  sum += pixels[i] = pixels[i] = -i;"
15622                       "}"
15623                       "sum;");
15624   CHECK_EQ(-28, result->Int32Value());
15625   result = CompileRun("pixels.hasOwnProperty('1')");
15626   CHECK(result->BooleanValue());
15627   free(pixel_data);
15628 }
15629
15630
15631 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
15632   switch (array_type) {
15633     case v8::kExternalByteArray:
15634     case v8::kExternalUnsignedByteArray:
15635     case v8::kExternalPixelArray:
15636       return 1;
15637       break;
15638     case v8::kExternalShortArray:
15639     case v8::kExternalUnsignedShortArray:
15640       return 2;
15641       break;
15642     case v8::kExternalIntArray:
15643     case v8::kExternalUnsignedIntArray:
15644     case v8::kExternalFloatArray:
15645       return 4;
15646       break;
15647     case v8::kExternalDoubleArray:
15648       return 8;
15649       break;
15650     default:
15651       UNREACHABLE();
15652       return -1;
15653   }
15654   UNREACHABLE();
15655   return -1;
15656 }
15657
15658
15659 template <class ExternalArrayClass, class ElementType>
15660 static void ObjectWithExternalArrayTestHelper(
15661     Handle<Context> context,
15662     v8::Handle<Object> obj,
15663     int element_count,
15664     v8::ExternalArrayType array_type,
15665     int64_t low, int64_t high) {
15666   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15667   i::Isolate* isolate = jsobj->GetIsolate();
15668   obj->Set(v8_str("field"), v8::Int32::New(1503));
15669   context->Global()->Set(v8_str("ext_array"), obj);
15670   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
15671   CHECK_EQ(1503, result->Int32Value());
15672   result = CompileRun("ext_array[1]");
15673   CHECK_EQ(1, result->Int32Value());
15674
15675   // Check pass through of assigned smis
15676   result = CompileRun("var sum = 0;"
15677                       "for (var i = 0; i < 8; i++) {"
15678                       "  sum += ext_array[i] = ext_array[i] = -i;"
15679                       "}"
15680                       "sum;");
15681   CHECK_EQ(-28, result->Int32Value());
15682
15683   // Check assigned smis
15684   result = CompileRun("for (var i = 0; i < 8; i++) {"
15685                       "  ext_array[i] = i;"
15686                       "}"
15687                       "var sum = 0;"
15688                       "for (var i = 0; i < 8; i++) {"
15689                       "  sum += ext_array[i];"
15690                       "}"
15691                       "sum;");
15692   CHECK_EQ(28, result->Int32Value());
15693
15694   // Check assigned smis in reverse order
15695   result = CompileRun("for (var i = 8; --i >= 0; ) {"
15696                       "  ext_array[i] = i;"
15697                       "}"
15698                       "var sum = 0;"
15699                       "for (var i = 0; i < 8; i++) {"
15700                       "  sum += ext_array[i];"
15701                       "}"
15702                       "sum;");
15703   CHECK_EQ(28, result->Int32Value());
15704
15705   // Check pass through of assigned HeapNumbers
15706   result = CompileRun("var sum = 0;"
15707                       "for (var i = 0; i < 16; i+=2) {"
15708                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15709                       "}"
15710                       "sum;");
15711   CHECK_EQ(-28, result->Int32Value());
15712
15713   // Check assigned HeapNumbers
15714   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15715                       "  ext_array[i] = (i * 0.5);"
15716                       "}"
15717                       "var sum = 0;"
15718                       "for (var i = 0; i < 16; i+=2) {"
15719                       "  sum += ext_array[i];"
15720                       "}"
15721                       "sum;");
15722   CHECK_EQ(28, result->Int32Value());
15723
15724   // Check assigned HeapNumbers in reverse order
15725   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15726                       "  ext_array[i] = (i * 0.5);"
15727                       "}"
15728                       "var sum = 0;"
15729                       "for (var i = 0; i < 16; i+=2) {"
15730                       "  sum += ext_array[i];"
15731                       "}"
15732                       "sum;");
15733   CHECK_EQ(28, result->Int32Value());
15734
15735   i::ScopedVector<char> test_buf(1024);
15736
15737   // Check legal boundary conditions.
15738   // The repeated loads and stores ensure the ICs are exercised.
15739   const char* boundary_program =
15740       "var res = 0;"
15741       "for (var i = 0; i < 16; i++) {"
15742       "  ext_array[i] = %lld;"
15743       "  if (i > 8) {"
15744       "    res = ext_array[i];"
15745       "  }"
15746       "}"
15747       "res;";
15748   i::OS::SNPrintF(test_buf,
15749                   boundary_program,
15750                   low);
15751   result = CompileRun(test_buf.start());
15752   CHECK_EQ(low, result->IntegerValue());
15753
15754   i::OS::SNPrintF(test_buf,
15755                   boundary_program,
15756                   high);
15757   result = CompileRun(test_buf.start());
15758   CHECK_EQ(high, result->IntegerValue());
15759
15760   // Check misprediction of type in IC.
15761   result = CompileRun("var tmp_array = ext_array;"
15762                       "var sum = 0;"
15763                       "for (var i = 0; i < 8; i++) {"
15764                       "  tmp_array[i] = i;"
15765                       "  sum += tmp_array[i];"
15766                       "  if (i == 4) {"
15767                       "    tmp_array = {};"
15768                       "  }"
15769                       "}"
15770                       "sum;");
15771   // Force GC to trigger verification.
15772   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15773   CHECK_EQ(28, result->Int32Value());
15774
15775   // Make sure out-of-range loads do not throw.
15776   i::OS::SNPrintF(test_buf,
15777                   "var caught_exception = false;"
15778                   "try {"
15779                   "  ext_array[%d];"
15780                   "} catch (e) {"
15781                   "  caught_exception = true;"
15782                   "}"
15783                   "caught_exception;",
15784                   element_count);
15785   result = CompileRun(test_buf.start());
15786   CHECK_EQ(false, result->BooleanValue());
15787
15788   // Make sure out-of-range stores do not throw.
15789   i::OS::SNPrintF(test_buf,
15790                   "var caught_exception = false;"
15791                   "try {"
15792                   "  ext_array[%d] = 1;"
15793                   "} catch (e) {"
15794                   "  caught_exception = true;"
15795                   "}"
15796                   "caught_exception;",
15797                   element_count);
15798   result = CompileRun(test_buf.start());
15799   CHECK_EQ(false, result->BooleanValue());
15800
15801   // Check other boundary conditions, values and operations.
15802   result = CompileRun("for (var i = 0; i < 8; i++) {"
15803                       "  ext_array[7] = undefined;"
15804                       "}"
15805                       "ext_array[7];");
15806   CHECK_EQ(0, result->Int32Value());
15807   if (array_type == v8::kExternalDoubleArray ||
15808       array_type == v8::kExternalFloatArray) {
15809     CHECK_EQ(static_cast<int>(i::OS::nan_value()),
15810              static_cast<int>(
15811                  jsobj->GetElement(isolate, 7)->ToObjectChecked()->Number()));
15812   } else {
15813     CheckElementValue(isolate, 0, jsobj, 7);
15814   }
15815
15816   result = CompileRun("for (var i = 0; i < 8; i++) {"
15817                       "  ext_array[6] = '2.3';"
15818                       "}"
15819                       "ext_array[6];");
15820   CHECK_EQ(2, result->Int32Value());
15821   CHECK_EQ(2,
15822            static_cast<int>(
15823                jsobj->GetElement(isolate, 6)->ToObjectChecked()->Number()));
15824
15825   if (array_type != v8::kExternalFloatArray &&
15826       array_type != v8::kExternalDoubleArray) {
15827     // Though the specification doesn't state it, be explicit about
15828     // converting NaNs and +/-Infinity to zero.
15829     result = CompileRun("for (var i = 0; i < 8; i++) {"
15830                         "  ext_array[i] = 5;"
15831                         "}"
15832                         "for (var i = 0; i < 8; i++) {"
15833                         "  ext_array[i] = NaN;"
15834                         "}"
15835                         "ext_array[5];");
15836     CHECK_EQ(0, result->Int32Value());
15837     CheckElementValue(isolate, 0, jsobj, 5);
15838
15839     result = CompileRun("for (var i = 0; i < 8; i++) {"
15840                         "  ext_array[i] = 5;"
15841                         "}"
15842                         "for (var i = 0; i < 8; i++) {"
15843                         "  ext_array[i] = Infinity;"
15844                         "}"
15845                         "ext_array[5];");
15846     int expected_value =
15847         (array_type == v8::kExternalPixelArray) ? 255 : 0;
15848     CHECK_EQ(expected_value, result->Int32Value());
15849     CheckElementValue(isolate, expected_value, jsobj, 5);
15850
15851     result = CompileRun("for (var i = 0; i < 8; i++) {"
15852                         "  ext_array[i] = 5;"
15853                         "}"
15854                         "for (var i = 0; i < 8; i++) {"
15855                         "  ext_array[i] = -Infinity;"
15856                         "}"
15857                         "ext_array[5];");
15858     CHECK_EQ(0, result->Int32Value());
15859     CheckElementValue(isolate, 0, jsobj, 5);
15860
15861     // Check truncation behavior of integral arrays.
15862     const char* unsigned_data =
15863         "var source_data = [0.6, 10.6];"
15864         "var expected_results = [0, 10];";
15865     const char* signed_data =
15866         "var source_data = [0.6, 10.6, -0.6, -10.6];"
15867         "var expected_results = [0, 10, 0, -10];";
15868     const char* pixel_data =
15869         "var source_data = [0.6, 10.6];"
15870         "var expected_results = [1, 11];";
15871     bool is_unsigned =
15872         (array_type == v8::kExternalUnsignedByteArray ||
15873          array_type == v8::kExternalUnsignedShortArray ||
15874          array_type == v8::kExternalUnsignedIntArray);
15875     bool is_pixel_data = array_type == v8::kExternalPixelArray;
15876
15877     i::OS::SNPrintF(test_buf,
15878                     "%s"
15879                     "var all_passed = true;"
15880                     "for (var i = 0; i < source_data.length; i++) {"
15881                     "  for (var j = 0; j < 8; j++) {"
15882                     "    ext_array[j] = source_data[i];"
15883                     "  }"
15884                     "  all_passed = all_passed &&"
15885                     "               (ext_array[5] == expected_results[i]);"
15886                     "}"
15887                     "all_passed;",
15888                     (is_unsigned ?
15889                          unsigned_data :
15890                          (is_pixel_data ? pixel_data : signed_data)));
15891     result = CompileRun(test_buf.start());
15892     CHECK_EQ(true, result->BooleanValue());
15893   }
15894
15895   i::Handle<ExternalArrayClass> array(
15896       ExternalArrayClass::cast(jsobj->elements()));
15897   for (int i = 0; i < element_count; i++) {
15898     array->set(i, static_cast<ElementType>(i));
15899   }
15900
15901   // Test complex assignments
15902   result = CompileRun("function ee_op_test_complex_func(sum) {"
15903                       " for (var i = 0; i < 40; ++i) {"
15904                       "   sum += (ext_array[i] += 1);"
15905                       "   sum += (ext_array[i] -= 1);"
15906                       " } "
15907                       " return sum;"
15908                       "}"
15909                       "sum=0;"
15910                       "for (var i=0;i<10000;++i) {"
15911                       "  sum=ee_op_test_complex_func(sum);"
15912                       "}"
15913                       "sum;");
15914   CHECK_EQ(16000000, result->Int32Value());
15915
15916   // Test count operations
15917   result = CompileRun("function ee_op_test_count_func(sum) {"
15918                       " for (var i = 0; i < 40; ++i) {"
15919                       "   sum += (++ext_array[i]);"
15920                       "   sum += (--ext_array[i]);"
15921                       " } "
15922                       " return sum;"
15923                       "}"
15924                       "sum=0;"
15925                       "for (var i=0;i<10000;++i) {"
15926                       "  sum=ee_op_test_count_func(sum);"
15927                       "}"
15928                       "sum;");
15929   CHECK_EQ(16000000, result->Int32Value());
15930
15931   result = CompileRun("ext_array[3] = 33;"
15932                       "delete ext_array[3];"
15933                       "ext_array[3];");
15934   CHECK_EQ(33, result->Int32Value());
15935
15936   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
15937                       "ext_array[2] = 12; ext_array[3] = 13;"
15938                       "ext_array.__defineGetter__('2',"
15939                       "function() { return 120; });"
15940                       "ext_array[2];");
15941   CHECK_EQ(12, result->Int32Value());
15942
15943   result = CompileRun("var js_array = new Array(40);"
15944                       "js_array[0] = 77;"
15945                       "js_array;");
15946   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15947
15948   result = CompileRun("ext_array[1] = 23;"
15949                       "ext_array.__proto__ = [];"
15950                       "js_array.__proto__ = ext_array;"
15951                       "js_array.concat(ext_array);");
15952   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15953   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15954
15955   result = CompileRun("ext_array[1] = 23;");
15956   CHECK_EQ(23, result->Int32Value());
15957 }
15958
15959
15960 template <class ExternalArrayClass, class ElementType>
15961 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
15962                                     int64_t low,
15963                                     int64_t high) {
15964   LocalContext context;
15965   i::Isolate* isolate = CcTest::i_isolate();
15966   i::Factory* factory = isolate->factory();
15967   v8::HandleScope scope(context->GetIsolate());
15968   const int kElementCount = 40;
15969   int element_size = ExternalArrayElementSize(array_type);
15970   ElementType* array_data =
15971       static_cast<ElementType*>(malloc(kElementCount * element_size));
15972   i::Handle<ExternalArrayClass> array =
15973       i::Handle<ExternalArrayClass>::cast(
15974           factory->NewExternalArray(kElementCount, array_type, array_data));
15975   // Force GC to trigger verification.
15976   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15977   for (int i = 0; i < kElementCount; i++) {
15978     array->set(i, static_cast<ElementType>(i));
15979   }
15980   // Force GC to trigger verification.
15981   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15982   for (int i = 0; i < kElementCount; i++) {
15983     CHECK_EQ(static_cast<int64_t>(i),
15984              static_cast<int64_t>(array->get_scalar(i)));
15985     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
15986   }
15987
15988   v8::Handle<v8::Object> obj = v8::Object::New();
15989   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15990   // Set the elements to be the external array.
15991   obj->SetIndexedPropertiesToExternalArrayData(array_data,
15992                                                array_type,
15993                                                kElementCount);
15994   CHECK_EQ(1,
15995            static_cast<int>(
15996                jsobj->GetElement(isolate, 1)->ToObjectChecked()->Number()));
15997
15998   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15999       context.local(), obj, kElementCount, array_type, low, high);
16000
16001   v8::Handle<v8::Value> result;
16002
16003   // Test more complex manipulations which cause eax to contain values
16004   // that won't be completely overwritten by loads from the arrays.
16005   // This catches bugs in the instructions used for the KeyedLoadIC
16006   // for byte and word types.
16007   {
16008     const int kXSize = 300;
16009     const int kYSize = 300;
16010     const int kLargeElementCount = kXSize * kYSize * 4;
16011     ElementType* large_array_data =
16012         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16013     v8::Handle<v8::Object> large_obj = v8::Object::New();
16014     // Set the elements to be the external array.
16015     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16016                                                        array_type,
16017                                                        kLargeElementCount);
16018     context->Global()->Set(v8_str("large_array"), large_obj);
16019     // Initialize contents of a few rows.
16020     for (int x = 0; x < 300; x++) {
16021       int row = 0;
16022       int offset = row * 300 * 4;
16023       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16024       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16025       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16026       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16027       row = 150;
16028       offset = row * 300 * 4;
16029       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16030       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16031       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16032       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16033       row = 298;
16034       offset = row * 300 * 4;
16035       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16036       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16037       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16038       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16039     }
16040     // The goal of the code below is to make "offset" large enough
16041     // that the computation of the index (which goes into eax) has
16042     // high bits set which will not be overwritten by a byte or short
16043     // load.
16044     result = CompileRun("var failed = false;"
16045                         "var offset = 0;"
16046                         "for (var i = 0; i < 300; i++) {"
16047                         "  if (large_array[4 * i] != 127 ||"
16048                         "      large_array[4 * i + 1] != 0 ||"
16049                         "      large_array[4 * i + 2] != 0 ||"
16050                         "      large_array[4 * i + 3] != 127) {"
16051                         "    failed = true;"
16052                         "  }"
16053                         "}"
16054                         "offset = 150 * 300 * 4;"
16055                         "for (var i = 0; i < 300; i++) {"
16056                         "  if (large_array[offset + 4 * i] != 127 ||"
16057                         "      large_array[offset + 4 * i + 1] != 0 ||"
16058                         "      large_array[offset + 4 * i + 2] != 0 ||"
16059                         "      large_array[offset + 4 * i + 3] != 127) {"
16060                         "    failed = true;"
16061                         "  }"
16062                         "}"
16063                         "offset = 298 * 300 * 4;"
16064                         "for (var i = 0; i < 300; i++) {"
16065                         "  if (large_array[offset + 4 * i] != 127 ||"
16066                         "      large_array[offset + 4 * i + 1] != 0 ||"
16067                         "      large_array[offset + 4 * i + 2] != 0 ||"
16068                         "      large_array[offset + 4 * i + 3] != 127) {"
16069                         "    failed = true;"
16070                         "  }"
16071                         "}"
16072                         "!failed;");
16073     CHECK_EQ(true, result->BooleanValue());
16074     free(large_array_data);
16075   }
16076
16077   // The "" property descriptor is overloaded to store information about
16078   // the external array. Ensure that setting and accessing the "" property
16079   // works (it should overwrite the information cached about the external
16080   // array in the DescriptorArray) in various situations.
16081   result = CompileRun("ext_array[''] = 23; ext_array['']");
16082   CHECK_EQ(23, result->Int32Value());
16083
16084   // Property "" set after the external array is associated with the object.
16085   {
16086     v8::Handle<v8::Object> obj2 = v8::Object::New();
16087     obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
16088     obj2->Set(v8_str(""), v8::Int32::New(1503));
16089     // Set the elements to be the external array.
16090     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16091                                                   array_type,
16092                                                   kElementCount);
16093     context->Global()->Set(v8_str("ext_array"), obj2);
16094     result = CompileRun("ext_array['']");
16095     CHECK_EQ(1503, result->Int32Value());
16096   }
16097
16098   // Property "" set after the external array is associated with the object.
16099   {
16100     v8::Handle<v8::Object> obj2 = v8::Object::New();
16101     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
16102     // Set the elements to be the external array.
16103     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16104                                                   array_type,
16105                                                   kElementCount);
16106     obj2->Set(v8_str(""), v8::Int32::New(1503));
16107     context->Global()->Set(v8_str("ext_array"), obj2);
16108     result = CompileRun("ext_array['']");
16109     CHECK_EQ(1503, result->Int32Value());
16110   }
16111
16112   // Should reuse the map from previous test.
16113   {
16114     v8::Handle<v8::Object> obj2 = v8::Object::New();
16115     obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
16116     // Set the elements to be the external array. Should re-use the map
16117     // from previous test.
16118     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16119                                                   array_type,
16120                                                   kElementCount);
16121     context->Global()->Set(v8_str("ext_array"), obj2);
16122     result = CompileRun("ext_array['']");
16123   }
16124
16125   // Property "" is a constant function that shouldn't not be interfered with
16126   // when an external array is set.
16127   {
16128     v8::Handle<v8::Object> obj2 = v8::Object::New();
16129     // Start
16130     obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
16131
16132     // Add a constant function to an object.
16133     context->Global()->Set(v8_str("ext_array"), obj2);
16134     result = CompileRun("ext_array[''] = function() {return 1503;};"
16135                         "ext_array['']();");
16136
16137     // Add an external array transition to the same map that
16138     // has the constant transition.
16139     v8::Handle<v8::Object> obj3 = v8::Object::New();
16140     obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
16141     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16142                                                   array_type,
16143                                                   kElementCount);
16144     context->Global()->Set(v8_str("ext_array"), obj3);
16145   }
16146
16147   // If a external array transition is in the map, it should get clobbered
16148   // by a constant function.
16149   {
16150     // Add an external array transition.
16151     v8::Handle<v8::Object> obj3 = v8::Object::New();
16152     obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
16153     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16154                                                   array_type,
16155                                                   kElementCount);
16156
16157     // Add a constant function to the same map that just got an external array
16158     // transition.
16159     v8::Handle<v8::Object> obj2 = v8::Object::New();
16160     obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
16161     context->Global()->Set(v8_str("ext_array"), obj2);
16162     result = CompileRun("ext_array[''] = function() {return 1503;};"
16163                         "ext_array['']();");
16164   }
16165
16166   free(array_data);
16167 }
16168
16169
16170 THREADED_TEST(ExternalByteArray) {
16171   ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
16172       v8::kExternalByteArray,
16173       -128,
16174       127);
16175 }
16176
16177
16178 THREADED_TEST(ExternalUnsignedByteArray) {
16179   ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
16180       v8::kExternalUnsignedByteArray,
16181       0,
16182       255);
16183 }
16184
16185
16186 THREADED_TEST(ExternalPixelArray) {
16187   ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
16188       v8::kExternalPixelArray,
16189       0,
16190       255);
16191 }
16192
16193
16194 THREADED_TEST(ExternalShortArray) {
16195   ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
16196       v8::kExternalShortArray,
16197       -32768,
16198       32767);
16199 }
16200
16201
16202 THREADED_TEST(ExternalUnsignedShortArray) {
16203   ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
16204       v8::kExternalUnsignedShortArray,
16205       0,
16206       65535);
16207 }
16208
16209
16210 THREADED_TEST(ExternalIntArray) {
16211   ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
16212       v8::kExternalIntArray,
16213       INT_MIN,   // -2147483648
16214       INT_MAX);  //  2147483647
16215 }
16216
16217
16218 THREADED_TEST(ExternalUnsignedIntArray) {
16219   ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
16220       v8::kExternalUnsignedIntArray,
16221       0,
16222       UINT_MAX);  // 4294967295
16223 }
16224
16225
16226 THREADED_TEST(ExternalFloatArray) {
16227   ExternalArrayTestHelper<i::ExternalFloatArray, float>(
16228       v8::kExternalFloatArray,
16229       -500,
16230       500);
16231 }
16232
16233
16234 THREADED_TEST(ExternalDoubleArray) {
16235   ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
16236       v8::kExternalDoubleArray,
16237       -500,
16238       500);
16239 }
16240
16241
16242 THREADED_TEST(ExternalArrays) {
16243   TestExternalByteArray();
16244   TestExternalUnsignedByteArray();
16245   TestExternalShortArray();
16246   TestExternalUnsignedShortArray();
16247   TestExternalIntArray();
16248   TestExternalUnsignedIntArray();
16249   TestExternalFloatArray();
16250 }
16251
16252
16253 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16254   LocalContext context;
16255   v8::HandleScope scope(context->GetIsolate());
16256   for (int size = 0; size < 100; size += 10) {
16257     int element_size = ExternalArrayElementSize(array_type);
16258     void* external_data = malloc(size * element_size);
16259     v8::Handle<v8::Object> obj = v8::Object::New();
16260     obj->SetIndexedPropertiesToExternalArrayData(
16261         external_data, array_type, size);
16262     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16263     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16264     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16265     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16266     free(external_data);
16267   }
16268 }
16269
16270
16271 THREADED_TEST(ExternalArrayInfo) {
16272   ExternalArrayInfoTestHelper(v8::kExternalByteArray);
16273   ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
16274   ExternalArrayInfoTestHelper(v8::kExternalShortArray);
16275   ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
16276   ExternalArrayInfoTestHelper(v8::kExternalIntArray);
16277   ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
16278   ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
16279   ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
16280   ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
16281 }
16282
16283
16284 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
16285   v8::Handle<v8::Object> obj = v8::Object::New();
16286   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16287   last_location = last_message = NULL;
16288   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16289   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16290   CHECK_NE(NULL, last_location);
16291   CHECK_NE(NULL, last_message);
16292 }
16293
16294
16295 TEST(ExternalArrayLimits) {
16296   LocalContext context;
16297   v8::HandleScope scope(context->GetIsolate());
16298   ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
16299   ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
16300   ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
16301   ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
16302   ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
16303   ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
16304   ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
16305   ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
16306   ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
16307   ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
16308   ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
16309   ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
16310   ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
16311   ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
16312   ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
16313   ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
16314   ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
16315   ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
16316 }
16317
16318
16319 template <typename ElementType, typename TypedArray,
16320           class ExternalArrayClass>
16321 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16322                           int64_t low, int64_t high) {
16323   const int kElementCount = 50;
16324
16325   i::ScopedVector<ElementType> backing_store(kElementCount+2);
16326
16327   LocalContext env;
16328   v8::Isolate* isolate = env->GetIsolate();
16329   v8::HandleScope handle_scope(isolate);
16330
16331   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
16332       backing_store.start(), (kElementCount+2)*sizeof(ElementType));
16333   Local<TypedArray> ta =
16334       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16335   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16336   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16337   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16338   CHECK_EQ(kElementCount*sizeof(ElementType),
16339            static_cast<int>(ta->ByteLength()));
16340   CHECK_EQ(ab, ta->Buffer());
16341
16342   ElementType* data = backing_store.start() + 2;
16343   for (int i = 0; i < kElementCount; i++) {
16344     data[i] = static_cast<ElementType>(i);
16345   }
16346
16347   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16348       env.local(), ta, kElementCount, array_type, low, high);
16349 }
16350
16351
16352 THREADED_TEST(Uint8Array) {
16353   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>(
16354       v8::kExternalUnsignedByteArray, 0, 0xFF);
16355 }
16356
16357
16358 THREADED_TEST(Int8Array) {
16359   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>(
16360       v8::kExternalByteArray, -0x80, 0x7F);
16361 }
16362
16363
16364 THREADED_TEST(Uint16Array) {
16365   TypedArrayTestHelper<uint16_t,
16366                        v8::Uint16Array,
16367                        i::ExternalUnsignedShortArray>(
16368       v8::kExternalUnsignedShortArray, 0, 0xFFFF);
16369 }
16370
16371
16372 THREADED_TEST(Int16Array) {
16373   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>(
16374       v8::kExternalShortArray, -0x8000, 0x7FFF);
16375 }
16376
16377
16378 THREADED_TEST(Uint32Array) {
16379   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>(
16380       v8::kExternalUnsignedIntArray, 0, UINT_MAX);
16381 }
16382
16383
16384 THREADED_TEST(Int32Array) {
16385   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>(
16386       v8::kExternalIntArray, INT_MIN, INT_MAX);
16387 }
16388
16389
16390 THREADED_TEST(Float32Array) {
16391   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>(
16392       v8::kExternalFloatArray, -500, 500);
16393 }
16394
16395
16396 THREADED_TEST(Float64Array) {
16397   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>(
16398       v8::kExternalDoubleArray, -500, 500);
16399 }
16400
16401
16402 THREADED_TEST(Uint8ClampedArray) {
16403   TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>(
16404       v8::kExternalPixelArray, 0, 0xFF);
16405 }
16406
16407
16408 THREADED_TEST(DataView) {
16409   const int kSize = 50;
16410
16411   i::ScopedVector<uint8_t> backing_store(kSize+2);
16412
16413   LocalContext env;
16414   v8::Isolate* isolate = env->GetIsolate();
16415   v8::HandleScope handle_scope(isolate);
16416
16417   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
16418       backing_store.start(), 2 + kSize);
16419   Local<v8::DataView> dv =
16420       v8::DataView::New(ab, 2, kSize);
16421   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16422   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16423   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16424   CHECK_EQ(ab, dv->Buffer());
16425 }
16426
16427
16428 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
16429   THREADED_TEST(Is##View) {                                                   \
16430     LocalContext env;                                                         \
16431     v8::Isolate* isolate = env->GetIsolate();                                 \
16432     v8::HandleScope handle_scope(isolate);                                    \
16433                                                                               \
16434     Handle<Value> result = CompileRun(                                        \
16435         "var ab = new ArrayBuffer(128);"                                      \
16436         "new " #View "(ab)");                                                 \
16437     CHECK(result->IsArrayBufferView());                                       \
16438     CHECK(result->Is##View());                                                \
16439     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
16440   }
16441
16442 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16443 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16444 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16445 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16446 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16447 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16448 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16449 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16450 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16451 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16452
16453 #undef IS_ARRAY_BUFFER_VIEW_TEST
16454
16455
16456
16457 THREADED_TEST(ScriptContextDependence) {
16458   LocalContext c1;
16459   v8::HandleScope scope(c1->GetIsolate());
16460   const char *source = "foo";
16461   v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
16462   v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
16463   c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
16464   CHECK_EQ(dep->Run()->Int32Value(), 100);
16465   CHECK_EQ(indep->Run()->Int32Value(), 100);
16466   LocalContext c2;
16467   c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
16468   CHECK_EQ(dep->Run()->Int32Value(), 100);
16469   CHECK_EQ(indep->Run()->Int32Value(), 101);
16470 }
16471
16472
16473 THREADED_TEST(StackTrace) {
16474   LocalContext context;
16475   v8::HandleScope scope(context->GetIsolate());
16476   v8::TryCatch try_catch;
16477   const char *source = "function foo() { FAIL.FAIL; }; foo();";
16478   v8::Handle<v8::String> src = v8::String::New(source);
16479   v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
16480   v8::Script::New(src, origin)->Run();
16481   CHECK(try_catch.HasCaught());
16482   v8::String::Utf8Value stack(try_catch.StackTrace());
16483   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
16484 }
16485
16486
16487 // Checks that a StackFrame has certain expected values.
16488 void checkStackFrame(const char* expected_script_name,
16489     const char* expected_func_name, int expected_line_number,
16490     int expected_column, bool is_eval, bool is_constructor,
16491     v8::Handle<v8::StackFrame> frame) {
16492   v8::HandleScope scope(CcTest::isolate());
16493   v8::String::Utf8Value func_name(frame->GetFunctionName());
16494   v8::String::Utf8Value script_name(frame->GetScriptName());
16495   if (*script_name == NULL) {
16496     // The situation where there is no associated script, like for evals.
16497     CHECK(expected_script_name == NULL);
16498   } else {
16499     CHECK(strstr(*script_name, expected_script_name) != NULL);
16500   }
16501   CHECK(strstr(*func_name, expected_func_name) != NULL);
16502   CHECK_EQ(expected_line_number, frame->GetLineNumber());
16503   CHECK_EQ(expected_column, frame->GetColumn());
16504   CHECK_EQ(is_eval, frame->IsEval());
16505   CHECK_EQ(is_constructor, frame->IsConstructor());
16506 }
16507
16508
16509 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16510   v8::HandleScope scope(args.GetIsolate());
16511   const char* origin = "capture-stack-trace-test";
16512   const int kOverviewTest = 1;
16513   const int kDetailedTest = 2;
16514
16515   ASSERT(args.Length() == 1);
16516
16517   int testGroup = args[0]->Int32Value();
16518   if (testGroup == kOverviewTest) {
16519     v8::Handle<v8::StackTrace> stackTrace =
16520         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
16521     CHECK_EQ(4, stackTrace->GetFrameCount());
16522     checkStackFrame(origin, "bar", 2, 10, false, false,
16523                     stackTrace->GetFrame(0));
16524     checkStackFrame(origin, "foo", 6, 3, false, false,
16525                     stackTrace->GetFrame(1));
16526     // This is the source string inside the eval which has the call to foo.
16527     checkStackFrame(NULL, "", 1, 5, false, false,
16528                     stackTrace->GetFrame(2));
16529     // The last frame is an anonymous function which has the initial eval call.
16530     checkStackFrame(origin, "", 8, 7, false, false,
16531                     stackTrace->GetFrame(3));
16532
16533     CHECK(stackTrace->AsArray()->IsArray());
16534   } else if (testGroup == kDetailedTest) {
16535     v8::Handle<v8::StackTrace> stackTrace =
16536         v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16537     CHECK_EQ(4, stackTrace->GetFrameCount());
16538     checkStackFrame(origin, "bat", 4, 22, false, false,
16539                     stackTrace->GetFrame(0));
16540     checkStackFrame(origin, "baz", 8, 3, false, true,
16541                     stackTrace->GetFrame(1));
16542 #ifdef ENABLE_DEBUGGER_SUPPORT
16543     bool is_eval = true;
16544 #else  // ENABLE_DEBUGGER_SUPPORT
16545     bool is_eval = false;
16546 #endif  // ENABLE_DEBUGGER_SUPPORT
16547
16548     // This is the source string inside the eval which has the call to baz.
16549     checkStackFrame(NULL, "", 1, 5, is_eval, false,
16550                     stackTrace->GetFrame(2));
16551     // The last frame is an anonymous function which has the initial eval call.
16552     checkStackFrame(origin, "", 10, 1, false, false,
16553                     stackTrace->GetFrame(3));
16554
16555     CHECK(stackTrace->AsArray()->IsArray());
16556   }
16557 }
16558
16559
16560 // Tests the C++ StackTrace API.
16561 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16562 // THREADED_TEST(CaptureStackTrace) {
16563 TEST(CaptureStackTrace) {
16564   v8::HandleScope scope(CcTest::isolate());
16565   v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
16566   Local<ObjectTemplate> templ = ObjectTemplate::New();
16567   templ->Set(v8_str("AnalyzeStackInNativeCode"),
16568              v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
16569   LocalContext context(0, templ);
16570
16571   // Test getting OVERVIEW information. Should ignore information that is not
16572   // script name, function name, line number, and column offset.
16573   const char *overview_source =
16574     "function bar() {\n"
16575     "  var y; AnalyzeStackInNativeCode(1);\n"
16576     "}\n"
16577     "function foo() {\n"
16578     "\n"
16579     "  bar();\n"
16580     "}\n"
16581     "var x;eval('new foo();');";
16582   v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
16583   v8::Handle<Value> overview_result(
16584       v8::Script::New(overview_src, origin)->Run());
16585   CHECK(!overview_result.IsEmpty());
16586   CHECK(overview_result->IsObject());
16587
16588   // Test getting DETAILED information.
16589   const char *detailed_source =
16590     "function bat() {AnalyzeStackInNativeCode(2);\n"
16591     "}\n"
16592     "\n"
16593     "function baz() {\n"
16594     "  bat();\n"
16595     "}\n"
16596     "eval('new baz();');";
16597   v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
16598   // Make the script using a non-zero line and column offset.
16599   v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
16600   v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
16601   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16602   v8::Handle<v8::Script> detailed_script(
16603       v8::Script::New(detailed_src, &detailed_origin));
16604   v8::Handle<Value> detailed_result(detailed_script->Run());
16605   CHECK(!detailed_result.IsEmpty());
16606   CHECK(detailed_result->IsObject());
16607 }
16608
16609
16610 static void StackTraceForUncaughtExceptionListener(
16611     v8::Handle<v8::Message> message,
16612     v8::Handle<Value>) {
16613   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16614   CHECK_EQ(2, stack_trace->GetFrameCount());
16615   checkStackFrame("origin", "foo", 2, 3, false, false,
16616                   stack_trace->GetFrame(0));
16617   checkStackFrame("origin", "bar", 5, 3, false, false,
16618                   stack_trace->GetFrame(1));
16619 }
16620
16621
16622 TEST(CaptureStackTraceForUncaughtException) {
16623   report_count = 0;
16624   LocalContext env;
16625   v8::HandleScope scope(env->GetIsolate());
16626   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
16627   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16628
16629   Script::Compile(v8_str("function foo() {\n"
16630                          "  throw 1;\n"
16631                          "};\n"
16632                          "function bar() {\n"
16633                          "  foo();\n"
16634                          "};"),
16635                   v8_str("origin"))->Run();
16636   v8::Local<v8::Object> global = env->Global();
16637   Local<Value> trouble = global->Get(v8_str("bar"));
16638   CHECK(trouble->IsFunction());
16639   Function::Cast(*trouble)->Call(global, 0, NULL);
16640   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16641   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16642 }
16643
16644
16645 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16646   LocalContext env;
16647   v8::HandleScope scope(env->GetIsolate());
16648   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
16649                                                     1024,
16650                                                     v8::StackTrace::kDetailed);
16651
16652   CompileRun(
16653       "var setters = ['column', 'lineNumber', 'scriptName',\n"
16654       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16655       "    'isConstructor'];\n"
16656       "for (var i = 0; i < setters.length; i++) {\n"
16657       "  var prop = setters[i];\n"
16658       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16659       "}\n");
16660   CompileRun("throw 'exception';");
16661   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16662 }
16663
16664
16665 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
16666                                      v8::Handle<v8::Value> data) {
16667   // Use the frame where JavaScript is called from.
16668   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16669   CHECK(!stack_trace.IsEmpty());
16670   int frame_count = stack_trace->GetFrameCount();
16671   CHECK_EQ(3, frame_count);
16672   int line_number[] = {1, 2, 5};
16673   for (int i = 0; i < frame_count; i++) {
16674     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16675   }
16676 }
16677
16678
16679 // Test that we only return the stack trace at the site where the exception
16680 // is first thrown (not where it is rethrown).
16681 TEST(RethrowStackTrace) {
16682   LocalContext env;
16683   v8::HandleScope scope(env->GetIsolate());
16684   // We make sure that
16685   // - the stack trace of the ReferenceError in g() is reported.
16686   // - the stack trace is not overwritten when e1 is rethrown by t().
16687   // - the stack trace of e2 does not overwrite that of e1.
16688   const char* source =
16689       "function g() { error; }          \n"
16690       "function f() { g(); }            \n"
16691       "function t(e) { throw e; }       \n"
16692       "try {                            \n"
16693       "  f();                           \n"
16694       "} catch (e1) {                   \n"
16695       "  try {                          \n"
16696       "    error;                       \n"
16697       "  } catch (e2) {                 \n"
16698       "    t(e1);                       \n"
16699       "  }                              \n"
16700       "}                                \n";
16701   v8::V8::AddMessageListener(RethrowStackTraceHandler);
16702   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16703   CompileRun(source);
16704   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16705   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
16706 }
16707
16708
16709 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
16710                                               v8::Handle<v8::Value> data) {
16711   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16712   CHECK(!stack_trace.IsEmpty());
16713   int frame_count = stack_trace->GetFrameCount();
16714   CHECK_EQ(2, frame_count);
16715   int line_number[] = {3, 7};
16716   for (int i = 0; i < frame_count; i++) {
16717     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16718   }
16719 }
16720
16721
16722 // Test that we do not recognize identity for primitive exceptions.
16723 TEST(RethrowPrimitiveStackTrace) {
16724   LocalContext env;
16725   v8::HandleScope scope(env->GetIsolate());
16726   // We do not capture stack trace for non Error objects on creation time.
16727   // Instead, we capture the stack trace on last throw.
16728   const char* source =
16729       "function g() { throw 404; }      \n"
16730       "function f() { g(); }            \n"
16731       "function t(e) { throw e; }       \n"
16732       "try {                            \n"
16733       "  f();                           \n"
16734       "} catch (e1) {                   \n"
16735       "  t(e1)                          \n"
16736       "}                                \n";
16737   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
16738   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16739   CompileRun(source);
16740   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16741   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16742 }
16743
16744
16745 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
16746                                               v8::Handle<v8::Value> data) {
16747   // Use the frame where JavaScript is called from.
16748   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16749   CHECK(!stack_trace.IsEmpty());
16750   CHECK_EQ(1, stack_trace->GetFrameCount());
16751   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
16752 }
16753
16754
16755 // Test that the stack trace is captured when the error object is created and
16756 // not where it is thrown.
16757 TEST(RethrowExistingStackTrace) {
16758   LocalContext env;
16759   v8::HandleScope scope(env->GetIsolate());
16760   const char* source =
16761       "var e = new Error();           \n"
16762       "throw e;                       \n";
16763   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
16764   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16765   CompileRun(source);
16766   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16767   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
16768 }
16769
16770
16771 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
16772                                                v8::Handle<v8::Value> data) {
16773   // Use the frame where JavaScript is called from.
16774   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16775   CHECK(!stack_trace.IsEmpty());
16776   CHECK_EQ(1, stack_trace->GetFrameCount());
16777   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
16778 }
16779
16780
16781 // Test that the stack trace is captured where the bogus Error object is thrown.
16782 TEST(RethrowBogusErrorStackTrace) {
16783   LocalContext env;
16784   v8::HandleScope scope(env->GetIsolate());
16785   const char* source =
16786       "var e = {__proto__: new Error()} \n"
16787       "throw e;                         \n";
16788   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
16789   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16790   CompileRun(source);
16791   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16792   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16793 }
16794
16795
16796 void AnalyzeStackOfEvalWithSourceURL(
16797     const v8::FunctionCallbackInfo<v8::Value>& args) {
16798   v8::HandleScope scope(args.GetIsolate());
16799   v8::Handle<v8::StackTrace> stackTrace =
16800       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16801   CHECK_EQ(5, stackTrace->GetFrameCount());
16802   v8::Handle<v8::String> url = v8_str("eval_url");
16803   for (int i = 0; i < 3; i++) {
16804     v8::Handle<v8::String> name =
16805         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16806     CHECK(!name.IsEmpty());
16807     CHECK_EQ(url, name);
16808   }
16809 }
16810
16811
16812 TEST(SourceURLInStackTrace) {
16813   v8::HandleScope scope(CcTest::isolate());
16814   Local<ObjectTemplate> templ = ObjectTemplate::New();
16815   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
16816              v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
16817   LocalContext context(0, templ);
16818
16819   const char *source =
16820     "function outer() {\n"
16821     "function bar() {\n"
16822     "  AnalyzeStackOfEvalWithSourceURL();\n"
16823     "}\n"
16824     "function foo() {\n"
16825     "\n"
16826     "  bar();\n"
16827     "}\n"
16828     "foo();\n"
16829     "}\n"
16830     "eval('(' + outer +')()%s');";
16831
16832   i::ScopedVector<char> code(1024);
16833   i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
16834   CHECK(CompileRun(code.start())->IsUndefined());
16835   i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
16836   CHECK(CompileRun(code.start())->IsUndefined());
16837 }
16838
16839
16840 static int scriptIdInStack[2];
16841
16842 void AnalyzeScriptIdInStack(
16843     const v8::FunctionCallbackInfo<v8::Value>& args) {
16844   v8::HandleScope scope(args.GetIsolate());
16845   v8::Handle<v8::StackTrace> stackTrace =
16846       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kScriptId);
16847   CHECK_EQ(2, stackTrace->GetFrameCount());
16848   for (int i = 0; i < 2; i++) {
16849     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
16850   }
16851 }
16852
16853
16854 TEST(ScriptIdInStackTrace) {
16855   v8::HandleScope scope(CcTest::isolate());
16856   Local<ObjectTemplate> templ = ObjectTemplate::New();
16857   templ->Set(v8_str("AnalyzeScriptIdInStack"),
16858              v8::FunctionTemplate::New(AnalyzeScriptIdInStack));
16859   LocalContext context(0, templ);
16860
16861   v8::Handle<v8::String> scriptSource = v8::String::New(
16862     "function foo() {\n"
16863     "  AnalyzeScriptIdInStack();"
16864     "}\n"
16865     "foo();\n");
16866   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
16867   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16868   script->Run();
16869   for (int i = 0; i < 2; i++) {
16870     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
16871     CHECK_EQ(scriptIdInStack[i], script->GetId());
16872   }
16873 }
16874
16875
16876 void AnalyzeStackOfInlineScriptWithSourceURL(
16877     const v8::FunctionCallbackInfo<v8::Value>& args) {
16878   v8::HandleScope scope(args.GetIsolate());
16879   v8::Handle<v8::StackTrace> stackTrace =
16880       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16881   CHECK_EQ(4, stackTrace->GetFrameCount());
16882   v8::Handle<v8::String> url = v8_str("url");
16883   for (int i = 0; i < 3; i++) {
16884     v8::Handle<v8::String> name =
16885         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16886     CHECK(!name.IsEmpty());
16887     CHECK_EQ(url, name);
16888   }
16889 }
16890
16891
16892 TEST(InlineScriptWithSourceURLInStackTrace) {
16893   v8::HandleScope scope(CcTest::isolate());
16894   Local<ObjectTemplate> templ = ObjectTemplate::New();
16895   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
16896              v8::FunctionTemplate::New(
16897                  AnalyzeStackOfInlineScriptWithSourceURL));
16898   LocalContext context(0, templ);
16899
16900   const char *source =
16901     "function outer() {\n"
16902     "function bar() {\n"
16903     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
16904     "}\n"
16905     "function foo() {\n"
16906     "\n"
16907     "  bar();\n"
16908     "}\n"
16909     "foo();\n"
16910     "}\n"
16911     "outer()\n%s";
16912
16913   i::ScopedVector<char> code(1024);
16914   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16915   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16916   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16917   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16918 }
16919
16920
16921 void AnalyzeStackOfDynamicScriptWithSourceURL(
16922     const v8::FunctionCallbackInfo<v8::Value>& args) {
16923   v8::HandleScope scope(args.GetIsolate());
16924   v8::Handle<v8::StackTrace> stackTrace =
16925       v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16926   CHECK_EQ(4, stackTrace->GetFrameCount());
16927   v8::Handle<v8::String> url = v8_str("source_url");
16928   for (int i = 0; i < 3; i++) {
16929     v8::Handle<v8::String> name =
16930         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16931     CHECK(!name.IsEmpty());
16932     CHECK_EQ(url, name);
16933   }
16934 }
16935
16936
16937 TEST(DynamicWithSourceURLInStackTrace) {
16938   v8::HandleScope scope(CcTest::isolate());
16939   Local<ObjectTemplate> templ = ObjectTemplate::New();
16940   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
16941              v8::FunctionTemplate::New(
16942                  AnalyzeStackOfDynamicScriptWithSourceURL));
16943   LocalContext context(0, templ);
16944
16945   const char *source =
16946     "function outer() {\n"
16947     "function bar() {\n"
16948     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
16949     "}\n"
16950     "function foo() {\n"
16951     "\n"
16952     "  bar();\n"
16953     "}\n"
16954     "foo();\n"
16955     "}\n"
16956     "outer()\n%s";
16957
16958   i::ScopedVector<char> code(1024);
16959   i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16960   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16961   i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16962   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16963 }
16964
16965
16966 static void CreateGarbageInOldSpace() {
16967   i::Factory* factory = CcTest::i_isolate()->factory();
16968   v8::HandleScope scope(CcTest::isolate());
16969   i::AlwaysAllocateScope always_allocate;
16970   for (int i = 0; i < 1000; i++) {
16971     factory->NewFixedArray(1000, i::TENURED);
16972   }
16973 }
16974
16975
16976 // Test that idle notification can be handled and eventually returns true.
16977 TEST(IdleNotification) {
16978   const intptr_t MB = 1024 * 1024;
16979   LocalContext env;
16980   v8::HandleScope scope(env->GetIsolate());
16981   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
16982   CreateGarbageInOldSpace();
16983   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
16984   CHECK_GT(size_with_garbage, initial_size + MB);
16985   bool finished = false;
16986   for (int i = 0; i < 200 && !finished; i++) {
16987     finished = v8::V8::IdleNotification();
16988   }
16989   intptr_t final_size = CcTest::heap()->SizeOfObjects();
16990   CHECK(finished);
16991   CHECK_LT(final_size, initial_size + 1);
16992 }
16993
16994
16995 // Test that idle notification can be handled and eventually collects garbage.
16996 TEST(IdleNotificationWithSmallHint) {
16997   const intptr_t MB = 1024 * 1024;
16998   const int IdlePauseInMs = 900;
16999   LocalContext env;
17000   v8::HandleScope scope(env->GetIsolate());
17001   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17002   CreateGarbageInOldSpace();
17003   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17004   CHECK_GT(size_with_garbage, initial_size + MB);
17005   bool finished = false;
17006   for (int i = 0; i < 200 && !finished; i++) {
17007     finished = v8::V8::IdleNotification(IdlePauseInMs);
17008   }
17009   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17010   CHECK(finished);
17011   CHECK_LT(final_size, initial_size + 1);
17012 }
17013
17014
17015 // Test that idle notification can be handled and eventually collects garbage.
17016 TEST(IdleNotificationWithLargeHint) {
17017   const intptr_t MB = 1024 * 1024;
17018   const int IdlePauseInMs = 900;
17019   LocalContext env;
17020   v8::HandleScope scope(env->GetIsolate());
17021   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17022   CreateGarbageInOldSpace();
17023   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17024   CHECK_GT(size_with_garbage, initial_size + MB);
17025   bool finished = false;
17026   for (int i = 0; i < 200 && !finished; i++) {
17027     finished = v8::V8::IdleNotification(IdlePauseInMs);
17028   }
17029   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17030   CHECK(finished);
17031   CHECK_LT(final_size, initial_size + 1);
17032 }
17033
17034
17035 TEST(Regress2107) {
17036   const intptr_t MB = 1024 * 1024;
17037   const int kShortIdlePauseInMs = 100;
17038   const int kLongIdlePauseInMs = 1000;
17039   LocalContext env;
17040   v8::Isolate* isolate = env->GetIsolate();
17041   v8::HandleScope scope(env->GetIsolate());
17042   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17043   // Send idle notification to start a round of incremental GCs.
17044   v8::V8::IdleNotification(kShortIdlePauseInMs);
17045   // Emulate 7 page reloads.
17046   for (int i = 0; i < 7; i++) {
17047     {
17048       v8::HandleScope inner_scope(env->GetIsolate());
17049       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17050       ctx->Enter();
17051       CreateGarbageInOldSpace();
17052       ctx->Exit();
17053     }
17054     v8::V8::ContextDisposedNotification();
17055     v8::V8::IdleNotification(kLongIdlePauseInMs);
17056   }
17057   // Create garbage and check that idle notification still collects it.
17058   CreateGarbageInOldSpace();
17059   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17060   CHECK_GT(size_with_garbage, initial_size + MB);
17061   bool finished = false;
17062   for (int i = 0; i < 200 && !finished; i++) {
17063     finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
17064   }
17065   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17066   CHECK_LT(final_size, initial_size + 1);
17067 }
17068
17069 static uint32_t* stack_limit;
17070
17071 static void GetStackLimitCallback(
17072     const v8::FunctionCallbackInfo<v8::Value>& args) {
17073   stack_limit = reinterpret_cast<uint32_t*>(
17074       CcTest::i_isolate()->stack_guard()->real_climit());
17075 }
17076
17077
17078 // Uses the address of a local variable to determine the stack top now.
17079 // Given a size, returns an address that is that far from the current
17080 // top of stack.
17081 static uint32_t* ComputeStackLimit(uint32_t size) {
17082   uint32_t* answer = &size - (size / sizeof(size));
17083   // If the size is very large and the stack is very near the bottom of
17084   // memory then the calculation above may wrap around and give an address
17085   // that is above the (downwards-growing) stack.  In that case we return
17086   // a very low address.
17087   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17088   return answer;
17089 }
17090
17091
17092 // We need at least 165kB for an x64 debug build with clang and ASAN.
17093 static const int stack_breathing_room = 256 * i::KB;
17094
17095
17096 TEST(SetResourceConstraints) {
17097   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17098
17099   // Set stack limit.
17100   v8::ResourceConstraints constraints;
17101   constraints.set_stack_limit(set_limit);
17102   CHECK(v8::SetResourceConstraints(&constraints));
17103
17104   // Execute a script.
17105   LocalContext env;
17106   v8::HandleScope scope(env->GetIsolate());
17107   Local<v8::FunctionTemplate> fun_templ =
17108       v8::FunctionTemplate::New(GetStackLimitCallback);
17109   Local<Function> fun = fun_templ->GetFunction();
17110   env->Global()->Set(v8_str("get_stack_limit"), fun);
17111   CompileRun("get_stack_limit();");
17112
17113   CHECK(stack_limit == set_limit);
17114 }
17115
17116
17117 TEST(SetResourceConstraintsInThread) {
17118   uint32_t* set_limit;
17119   {
17120     v8::Locker locker(CcTest::isolate());
17121     set_limit = ComputeStackLimit(stack_breathing_room);
17122
17123     // Set stack limit.
17124     v8::ResourceConstraints constraints;
17125     constraints.set_stack_limit(set_limit);
17126     CHECK(v8::SetResourceConstraints(&constraints));
17127
17128     // Execute a script.
17129     v8::HandleScope scope(CcTest::isolate());
17130     LocalContext env;
17131     Local<v8::FunctionTemplate> fun_templ =
17132         v8::FunctionTemplate::New(GetStackLimitCallback);
17133     Local<Function> fun = fun_templ->GetFunction();
17134     env->Global()->Set(v8_str("get_stack_limit"), fun);
17135     CompileRun("get_stack_limit();");
17136
17137     CHECK(stack_limit == set_limit);
17138   }
17139   {
17140     v8::Locker locker(CcTest::isolate());
17141     CHECK(stack_limit == set_limit);
17142   }
17143 }
17144
17145
17146 THREADED_TEST(GetHeapStatistics) {
17147   LocalContext c1;
17148   v8::HandleScope scope(c1->GetIsolate());
17149   v8::HeapStatistics heap_statistics;
17150   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17151   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17152   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17153   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17154   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17155 }
17156
17157
17158 class VisitorImpl : public v8::ExternalResourceVisitor {
17159  public:
17160   explicit VisitorImpl(TestResource** resource) {
17161     for (int i = 0; i < 4; i++) {
17162       resource_[i] = resource[i];
17163       found_resource_[i] = false;
17164     }
17165   }
17166   virtual ~VisitorImpl() {}
17167   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17168     if (!string->IsExternal()) {
17169       CHECK(string->IsExternalAscii());
17170       return;
17171     }
17172     v8::String::ExternalStringResource* resource =
17173         string->GetExternalStringResource();
17174     CHECK(resource);
17175     for (int i = 0; i < 4; i++) {
17176       if (resource_[i] == resource) {
17177         CHECK(!found_resource_[i]);
17178         found_resource_[i] = true;
17179       }
17180     }
17181   }
17182   void CheckVisitedResources() {
17183     for (int i = 0; i < 4; i++) {
17184       CHECK(found_resource_[i]);
17185     }
17186   }
17187
17188  private:
17189   v8::String::ExternalStringResource* resource_[4];
17190   bool found_resource_[4];
17191 };
17192
17193
17194 TEST(VisitExternalStrings) {
17195   LocalContext env;
17196   v8::HandleScope scope(env->GetIsolate());
17197   const char* string = "Some string";
17198   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17199   TestResource* resource[4];
17200   resource[0] = new TestResource(two_byte_string);
17201   v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
17202   resource[1] = new TestResource(two_byte_string);
17203   v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
17204
17205   // Externalized symbol.
17206   resource[2] = new TestResource(two_byte_string);
17207   v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
17208   CHECK(string2->MakeExternal(resource[2]));
17209
17210   // Symbolized External.
17211   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17212   v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
17213   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
17214   // Turn into a symbol.
17215   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17216   CHECK(!CcTest::heap()->InternalizeString(*string3_i)->IsFailure());
17217   CHECK(string3_i->IsInternalizedString());
17218
17219   // We need to add usages for string* to avoid warnings in GCC 4.7
17220   CHECK(string0->IsExternal());
17221   CHECK(string1->IsExternal());
17222   CHECK(string2->IsExternal());
17223   CHECK(string3->IsExternal());
17224
17225   VisitorImpl visitor(resource);
17226   v8::V8::VisitExternalResources(&visitor);
17227   visitor.CheckVisitedResources();
17228 }
17229
17230
17231 static double DoubleFromBits(uint64_t value) {
17232   double target;
17233   i::OS::MemCopy(&target, &value, sizeof(target));
17234   return target;
17235 }
17236
17237
17238 static uint64_t DoubleToBits(double value) {
17239   uint64_t target;
17240   i::OS::MemCopy(&target, &value, sizeof(target));
17241   return target;
17242 }
17243
17244
17245 static double DoubleToDateTime(double input) {
17246   double date_limit = 864e13;
17247   if (std::isnan(input) || input < -date_limit || input > date_limit) {
17248     return i::OS::nan_value();
17249   }
17250   return (input < 0) ? -(floor(-input)) : floor(input);
17251 }
17252
17253
17254 // We don't have a consistent way to write 64-bit constants syntactically, so we
17255 // split them into two 32-bit constants and combine them programmatically.
17256 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
17257   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
17258 }
17259
17260
17261 THREADED_TEST(QuietSignalingNaNs) {
17262   LocalContext context;
17263   v8::HandleScope scope(context->GetIsolate());
17264   v8::TryCatch try_catch;
17265
17266   // Special double values.
17267   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
17268   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
17269   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
17270   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
17271   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
17272   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
17273   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
17274
17275   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
17276   // on either side of the epoch.
17277   double date_limit = 864e13;
17278
17279   double test_values[] = {
17280       snan,
17281       qnan,
17282       infinity,
17283       max_normal,
17284       date_limit + 1,
17285       date_limit,
17286       min_normal,
17287       max_denormal,
17288       min_denormal,
17289       0,
17290       -0,
17291       -min_denormal,
17292       -max_denormal,
17293       -min_normal,
17294       -date_limit,
17295       -date_limit - 1,
17296       -max_normal,
17297       -infinity,
17298       -qnan,
17299       -snan
17300   };
17301   int num_test_values = 20;
17302
17303   for (int i = 0; i < num_test_values; i++) {
17304     double test_value = test_values[i];
17305
17306     // Check that Number::New preserves non-NaNs and quiets SNaNs.
17307     v8::Handle<v8::Value> number = v8::Number::New(test_value);
17308     double stored_number = number->NumberValue();
17309     if (!std::isnan(test_value)) {
17310       CHECK_EQ(test_value, stored_number);
17311     } else {
17312       uint64_t stored_bits = DoubleToBits(stored_number);
17313       // Check if quiet nan (bits 51..62 all set).
17314 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17315       // Most significant fraction bit for quiet nan is set to 0
17316       // on MIPS architecture. Allowed by IEEE-754.
17317       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
17318 #else
17319       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
17320 #endif
17321     }
17322
17323     // Check that Date::New preserves non-NaNs in the date range and
17324     // quiets SNaNs.
17325     v8::Handle<v8::Value> date = v8::Date::New(test_value);
17326     double expected_stored_date = DoubleToDateTime(test_value);
17327     double stored_date = date->NumberValue();
17328     if (!std::isnan(expected_stored_date)) {
17329       CHECK_EQ(expected_stored_date, stored_date);
17330     } else {
17331       uint64_t stored_bits = DoubleToBits(stored_date);
17332       // Check if quiet nan (bits 51..62 all set).
17333 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
17334       // Most significant fraction bit for quiet nan is set to 0
17335       // on MIPS architecture. Allowed by IEEE-754.
17336       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
17337 #else
17338       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
17339 #endif
17340     }
17341   }
17342 }
17343
17344
17345 static void SpaghettiIncident(
17346     const v8::FunctionCallbackInfo<v8::Value>& args) {
17347   v8::HandleScope scope(args.GetIsolate());
17348   v8::TryCatch tc;
17349   v8::Handle<v8::String> str(args[0]->ToString());
17350   USE(str);
17351   if (tc.HasCaught())
17352     tc.ReThrow();
17353 }
17354
17355
17356 // Test that an exception can be propagated down through a spaghetti
17357 // stack using ReThrow.
17358 THREADED_TEST(SpaghettiStackReThrow) {
17359   v8::HandleScope scope(CcTest::isolate());
17360   LocalContext context;
17361   context->Global()->Set(
17362       v8::String::New("s"),
17363       v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
17364   v8::TryCatch try_catch;
17365   CompileRun(
17366       "var i = 0;"
17367       "var o = {"
17368       "  toString: function () {"
17369       "    if (i == 10) {"
17370       "      throw 'Hey!';"
17371       "    } else {"
17372       "      i++;"
17373       "      return s(o);"
17374       "    }"
17375       "  }"
17376       "};"
17377       "s(o);");
17378   CHECK(try_catch.HasCaught());
17379   v8::String::Utf8Value value(try_catch.Exception());
17380   CHECK_EQ(0, strcmp(*value, "Hey!"));
17381 }
17382
17383
17384 TEST(Regress528) {
17385   v8::V8::Initialize();
17386   v8::Isolate* isolate = CcTest::isolate();
17387   v8::HandleScope scope(isolate);
17388   v8::Local<Context> other_context;
17389   int gc_count;
17390
17391   // Create a context used to keep the code from aging in the compilation
17392   // cache.
17393   other_context = Context::New(isolate);
17394
17395   // Context-dependent context data creates reference from the compilation
17396   // cache to the global object.
17397   const char* source_simple = "1";
17398   {
17399     v8::HandleScope scope(isolate);
17400     v8::Local<Context> context = Context::New(isolate);
17401
17402     context->Enter();
17403     Local<v8::String> obj = v8::String::New("");
17404     context->SetEmbedderData(0, obj);
17405     CompileRun(source_simple);
17406     context->Exit();
17407   }
17408   v8::V8::ContextDisposedNotification();
17409   for (gc_count = 1; gc_count < 10; gc_count++) {
17410     other_context->Enter();
17411     CompileRun(source_simple);
17412     other_context->Exit();
17413     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17414     if (GetGlobalObjectsCount() == 1) break;
17415   }
17416   CHECK_GE(2, gc_count);
17417   CHECK_EQ(1, GetGlobalObjectsCount());
17418
17419   // Eval in a function creates reference from the compilation cache to the
17420   // global object.
17421   const char* source_eval = "function f(){eval('1')}; f()";
17422   {
17423     v8::HandleScope scope(isolate);
17424     v8::Local<Context> context = Context::New(isolate);
17425
17426     context->Enter();
17427     CompileRun(source_eval);
17428     context->Exit();
17429   }
17430   v8::V8::ContextDisposedNotification();
17431   for (gc_count = 1; gc_count < 10; gc_count++) {
17432     other_context->Enter();
17433     CompileRun(source_eval);
17434     other_context->Exit();
17435     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17436     if (GetGlobalObjectsCount() == 1) break;
17437   }
17438   CHECK_GE(2, gc_count);
17439   CHECK_EQ(1, GetGlobalObjectsCount());
17440
17441   // Looking up the line number for an exception creates reference from the
17442   // compilation cache to the global object.
17443   const char* source_exception = "function f(){throw 1;} f()";
17444   {
17445     v8::HandleScope scope(isolate);
17446     v8::Local<Context> context = Context::New(isolate);
17447
17448     context->Enter();
17449     v8::TryCatch try_catch;
17450     CompileRun(source_exception);
17451     CHECK(try_catch.HasCaught());
17452     v8::Handle<v8::Message> message = try_catch.Message();
17453     CHECK(!message.IsEmpty());
17454     CHECK_EQ(1, message->GetLineNumber());
17455     context->Exit();
17456   }
17457   v8::V8::ContextDisposedNotification();
17458   for (gc_count = 1; gc_count < 10; gc_count++) {
17459     other_context->Enter();
17460     CompileRun(source_exception);
17461     other_context->Exit();
17462     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17463     if (GetGlobalObjectsCount() == 1) break;
17464   }
17465   CHECK_GE(2, gc_count);
17466   CHECK_EQ(1, GetGlobalObjectsCount());
17467
17468   v8::V8::ContextDisposedNotification();
17469 }
17470
17471
17472 THREADED_TEST(ScriptOrigin) {
17473   LocalContext env;
17474   v8::HandleScope scope(env->GetIsolate());
17475   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17476   v8::Handle<v8::String> script = v8::String::New(
17477       "function f() {}\n\nfunction g() {}");
17478   v8::Script::Compile(script, &origin)->Run();
17479   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17480       env->Global()->Get(v8::String::New("f")));
17481   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17482       env->Global()->Get(v8::String::New("g")));
17483
17484   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
17485   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
17486   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
17487
17488   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
17489   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
17490   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
17491 }
17492
17493
17494 THREADED_TEST(FunctionGetInferredName) {
17495   LocalContext env;
17496   v8::HandleScope scope(env->GetIsolate());
17497   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17498   v8::Handle<v8::String> script = v8::String::New(
17499       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
17500   v8::Script::Compile(script, &origin)->Run();
17501   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17502       env->Global()->Get(v8::String::New("f")));
17503   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
17504 }
17505
17506
17507 THREADED_TEST(FunctionGetDisplayName) {
17508   LocalContext env;
17509   v8::HandleScope scope(env->GetIsolate());
17510   const char* code = "var error = false;"
17511                      "function a() { this.x = 1; };"
17512                      "a.displayName = 'display_a';"
17513                      "var b = (function() {"
17514                      "  var f = function() { this.x = 2; };"
17515                      "  f.displayName = 'display_b';"
17516                      "  return f;"
17517                      "})();"
17518                      "var c = function() {};"
17519                      "c.__defineGetter__('displayName', function() {"
17520                      "  error = true;"
17521                      "  throw new Error();"
17522                      "});"
17523                      "function d() {};"
17524                      "d.__defineGetter__('displayName', function() {"
17525                      "  error = true;"
17526                      "  return 'wrong_display_name';"
17527                      "});"
17528                      "function e() {};"
17529                      "e.displayName = 'wrong_display_name';"
17530                      "e.__defineSetter__('displayName', function() {"
17531                      "  error = true;"
17532                      "  throw new Error();"
17533                      "});"
17534                      "function f() {};"
17535                      "f.displayName = { 'foo': 6, toString: function() {"
17536                      "  error = true;"
17537                      "  return 'wrong_display_name';"
17538                      "}};"
17539                      "var g = function() {"
17540                      "  arguments.callee.displayName = 'set_in_runtime';"
17541                      "}; g();"
17542                      ;
17543   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17544   v8::Script::Compile(v8::String::New(code), &origin)->Run();
17545   v8::Local<v8::Value> error = env->Global()->Get(v8::String::New("error"));
17546   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
17547       env->Global()->Get(v8::String::New("a")));
17548   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
17549       env->Global()->Get(v8::String::New("b")));
17550   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
17551       env->Global()->Get(v8::String::New("c")));
17552   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
17553       env->Global()->Get(v8::String::New("d")));
17554   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
17555       env->Global()->Get(v8::String::New("e")));
17556   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17557       env->Global()->Get(v8::String::New("f")));
17558   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17559       env->Global()->Get(v8::String::New("g")));
17560   CHECK_EQ(false, error->BooleanValue());
17561   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
17562   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
17563   CHECK(c->GetDisplayName()->IsUndefined());
17564   CHECK(d->GetDisplayName()->IsUndefined());
17565   CHECK(e->GetDisplayName()->IsUndefined());
17566   CHECK(f->GetDisplayName()->IsUndefined());
17567   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
17568 }
17569
17570
17571 THREADED_TEST(ScriptLineNumber) {
17572   LocalContext env;
17573   v8::HandleScope scope(env->GetIsolate());
17574   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17575   v8::Handle<v8::String> script = v8::String::New(
17576       "function f() {}\n\nfunction g() {}");
17577   v8::Script::Compile(script, &origin)->Run();
17578   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17579       env->Global()->Get(v8::String::New("f")));
17580   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17581       env->Global()->Get(v8::String::New("g")));
17582   CHECK_EQ(0, f->GetScriptLineNumber());
17583   CHECK_EQ(2, g->GetScriptLineNumber());
17584 }
17585
17586
17587 THREADED_TEST(ScriptColumnNumber) {
17588   LocalContext env;
17589   v8::HandleScope scope(env->GetIsolate());
17590   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17591       v8::Integer::New(3), v8::Integer::New(2));
17592   v8::Handle<v8::String> script = v8::String::New(
17593       "function foo() {}\n\n     function bar() {}");
17594   v8::Script::Compile(script, &origin)->Run();
17595   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17596       env->Global()->Get(v8::String::New("foo")));
17597   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17598       env->Global()->Get(v8::String::New("bar")));
17599   CHECK_EQ(14, foo->GetScriptColumnNumber());
17600   CHECK_EQ(17, bar->GetScriptColumnNumber());
17601 }
17602
17603
17604 THREADED_TEST(FunctionIsBuiltin) {
17605   LocalContext env;
17606   v8::HandleScope scope(env->GetIsolate());
17607   v8::Local<v8::Function> f;
17608   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
17609   CHECK(f->IsBuiltin());
17610   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
17611   CHECK(f->IsBuiltin());
17612   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
17613   CHECK(f->IsBuiltin());
17614   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
17615   CHECK(f->IsBuiltin());
17616   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
17617   CHECK(!f->IsBuiltin());
17618 }
17619
17620
17621 THREADED_TEST(FunctionGetScriptId) {
17622   LocalContext env;
17623   v8::HandleScope scope(env->GetIsolate());
17624   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17625       v8::Integer::New(3), v8::Integer::New(2));
17626   v8::Handle<v8::String> scriptSource = v8::String::New(
17627       "function foo() {}\n\n     function bar() {}");
17628   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17629   script->Run();
17630   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17631       env->Global()->Get(v8::String::New("foo")));
17632   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17633       env->Global()->Get(v8::String::New("bar")));
17634   CHECK_EQ(script->Id(), foo->GetScriptId());
17635   CHECK_EQ(script->Id(), bar->GetScriptId());
17636 }
17637
17638
17639 static void GetterWhichReturns42(
17640     Local<String> name,
17641     const v8::PropertyCallbackInfo<v8::Value>& info) {
17642   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17643   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17644   info.GetReturnValue().Set(v8_num(42));
17645 }
17646
17647
17648 static void SetterWhichSetsYOnThisTo23(
17649     Local<String> name,
17650     Local<Value> value,
17651     const v8::PropertyCallbackInfo<void>& info) {
17652   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17653   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17654   info.This()->Set(v8_str("y"), v8_num(23));
17655 }
17656
17657
17658 void FooGetInterceptor(Local<String> name,
17659                        const v8::PropertyCallbackInfo<v8::Value>& info) {
17660   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17661   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17662   if (!name->Equals(v8_str("foo"))) return;
17663   info.GetReturnValue().Set(v8_num(42));
17664 }
17665
17666
17667 void FooSetInterceptor(Local<String> name,
17668                        Local<Value> value,
17669                        const v8::PropertyCallbackInfo<v8::Value>& info) {
17670   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17671   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17672   if (!name->Equals(v8_str("foo"))) return;
17673   info.This()->Set(v8_str("y"), v8_num(23));
17674   info.GetReturnValue().Set(v8_num(23));
17675 }
17676
17677
17678 TEST(SetterOnConstructorPrototype) {
17679   v8::HandleScope scope(CcTest::isolate());
17680   Local<ObjectTemplate> templ = ObjectTemplate::New();
17681   templ->SetAccessor(v8_str("x"),
17682                      GetterWhichReturns42,
17683                      SetterWhichSetsYOnThisTo23);
17684   LocalContext context;
17685   context->Global()->Set(v8_str("P"), templ->NewInstance());
17686   CompileRun("function C1() {"
17687              "  this.x = 23;"
17688              "};"
17689              "C1.prototype = P;"
17690              "function C2() {"
17691              "  this.x = 23"
17692              "};"
17693              "C2.prototype = { };"
17694              "C2.prototype.__proto__ = P;");
17695
17696   v8::Local<v8::Script> script;
17697   script = v8::Script::Compile(v8_str("new C1();"));
17698   for (int i = 0; i < 10; i++) {
17699     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17700     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17701     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17702   }
17703
17704   script = v8::Script::Compile(v8_str("new C2();"));
17705   for (int i = 0; i < 10; i++) {
17706     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17707     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
17708     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
17709   }
17710 }
17711
17712
17713 static void NamedPropertyGetterWhichReturns42(
17714     Local<String> name,
17715     const v8::PropertyCallbackInfo<v8::Value>& info) {
17716   info.GetReturnValue().Set(v8_num(42));
17717 }
17718
17719
17720 static void NamedPropertySetterWhichSetsYOnThisTo23(
17721     Local<String> name,
17722     Local<Value> value,
17723     const v8::PropertyCallbackInfo<v8::Value>& info) {
17724   if (name->Equals(v8_str("x"))) {
17725     info.This()->Set(v8_str("y"), v8_num(23));
17726   }
17727 }
17728
17729
17730 THREADED_TEST(InterceptorOnConstructorPrototype) {
17731   v8::HandleScope scope(CcTest::isolate());
17732   Local<ObjectTemplate> templ = ObjectTemplate::New();
17733   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
17734                                  NamedPropertySetterWhichSetsYOnThisTo23);
17735   LocalContext context;
17736   context->Global()->Set(v8_str("P"), templ->NewInstance());
17737   CompileRun("function C1() {"
17738              "  this.x = 23;"
17739              "};"
17740              "C1.prototype = P;"
17741              "function C2() {"
17742              "  this.x = 23"
17743              "};"
17744              "C2.prototype = { };"
17745              "C2.prototype.__proto__ = P;");
17746
17747   v8::Local<v8::Script> script;
17748   script = v8::Script::Compile(v8_str("new C1();"));
17749   for (int i = 0; i < 10; i++) {
17750     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17751     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17752     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17753   }
17754
17755   script = v8::Script::Compile(v8_str("new C2();"));
17756   for (int i = 0; i < 10; i++) {
17757     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17758     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
17759     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
17760   }
17761 }
17762
17763
17764 TEST(Regress618) {
17765   const char* source = "function C1() {"
17766                        "  this.x = 23;"
17767                        "};"
17768                        "C1.prototype = P;";
17769
17770   LocalContext context;
17771   v8::HandleScope scope(context->GetIsolate());
17772   v8::Local<v8::Script> script;
17773
17774   // Use a simple object as prototype.
17775   v8::Local<v8::Object> prototype = v8::Object::New();
17776   prototype->Set(v8_str("y"), v8_num(42));
17777   context->Global()->Set(v8_str("P"), prototype);
17778
17779   // This compile will add the code to the compilation cache.
17780   CompileRun(source);
17781
17782   script = v8::Script::Compile(v8_str("new C1();"));
17783   // Allow enough iterations for the inobject slack tracking logic
17784   // to finalize instance size and install the fast construct stub.
17785   for (int i = 0; i < 256; i++) {
17786     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17787     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17788     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17789   }
17790
17791   // Use an API object with accessors as prototype.
17792   Local<ObjectTemplate> templ = ObjectTemplate::New();
17793   templ->SetAccessor(v8_str("x"),
17794                      GetterWhichReturns42,
17795                      SetterWhichSetsYOnThisTo23);
17796   context->Global()->Set(v8_str("P"), templ->NewInstance());
17797
17798   // This compile will get the code from the compilation cache.
17799   CompileRun(source);
17800
17801   script = v8::Script::Compile(v8_str("new C1();"));
17802   for (int i = 0; i < 10; i++) {
17803     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17804     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17805     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17806   }
17807 }
17808
17809 v8::Isolate* gc_callbacks_isolate = NULL;
17810 int prologue_call_count = 0;
17811 int epilogue_call_count = 0;
17812 int prologue_call_count_second = 0;
17813 int epilogue_call_count_second = 0;
17814
17815 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
17816   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17817   ++prologue_call_count;
17818 }
17819
17820
17821 void PrologueCallback(v8::Isolate* isolate,
17822                       v8::GCType,
17823                       v8::GCCallbackFlags flags) {
17824   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17825   CHECK_EQ(gc_callbacks_isolate, isolate);
17826   ++prologue_call_count;
17827 }
17828
17829
17830 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
17831   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17832   ++epilogue_call_count;
17833 }
17834
17835
17836 void EpilogueCallback(v8::Isolate* isolate,
17837                       v8::GCType,
17838                       v8::GCCallbackFlags flags) {
17839   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17840   CHECK_EQ(gc_callbacks_isolate, isolate);
17841   ++epilogue_call_count;
17842 }
17843
17844
17845 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
17846   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17847   ++prologue_call_count_second;
17848 }
17849
17850
17851 void PrologueCallbackSecond(v8::Isolate* isolate,
17852                             v8::GCType,
17853                             v8::GCCallbackFlags flags) {
17854   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17855   CHECK_EQ(gc_callbacks_isolate, isolate);
17856   ++prologue_call_count_second;
17857 }
17858
17859
17860 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
17861   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17862   ++epilogue_call_count_second;
17863 }
17864
17865
17866 void EpilogueCallbackSecond(v8::Isolate* isolate,
17867                             v8::GCType,
17868                             v8::GCCallbackFlags flags) {
17869   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17870   CHECK_EQ(gc_callbacks_isolate, isolate);
17871   ++epilogue_call_count_second;
17872 }
17873
17874
17875 TEST(GCCallbacksOld) {
17876   LocalContext context;
17877
17878   v8::V8::AddGCPrologueCallback(PrologueCallback);
17879   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17880   CHECK_EQ(0, prologue_call_count);
17881   CHECK_EQ(0, epilogue_call_count);
17882   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17883   CHECK_EQ(1, prologue_call_count);
17884   CHECK_EQ(1, epilogue_call_count);
17885   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17886   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17887   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17888   CHECK_EQ(2, prologue_call_count);
17889   CHECK_EQ(2, epilogue_call_count);
17890   CHECK_EQ(1, prologue_call_count_second);
17891   CHECK_EQ(1, epilogue_call_count_second);
17892   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17893   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17894   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17895   CHECK_EQ(2, prologue_call_count);
17896   CHECK_EQ(2, epilogue_call_count);
17897   CHECK_EQ(2, prologue_call_count_second);
17898   CHECK_EQ(2, epilogue_call_count_second);
17899   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17900   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17901   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17902   CHECK_EQ(2, prologue_call_count);
17903   CHECK_EQ(2, epilogue_call_count);
17904   CHECK_EQ(2, prologue_call_count_second);
17905   CHECK_EQ(2, epilogue_call_count_second);
17906 }
17907
17908
17909 TEST(GCCallbacks) {
17910   LocalContext context;
17911   v8::Isolate* isolate = context->GetIsolate();
17912   gc_callbacks_isolate = isolate;
17913   isolate->AddGCPrologueCallback(PrologueCallback);
17914   isolate->AddGCEpilogueCallback(EpilogueCallback);
17915   CHECK_EQ(0, prologue_call_count);
17916   CHECK_EQ(0, epilogue_call_count);
17917   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17918   CHECK_EQ(1, prologue_call_count);
17919   CHECK_EQ(1, epilogue_call_count);
17920   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
17921   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
17922   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17923   CHECK_EQ(2, prologue_call_count);
17924   CHECK_EQ(2, epilogue_call_count);
17925   CHECK_EQ(1, prologue_call_count_second);
17926   CHECK_EQ(1, epilogue_call_count_second);
17927   isolate->RemoveGCPrologueCallback(PrologueCallback);
17928   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
17929   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17930   CHECK_EQ(2, prologue_call_count);
17931   CHECK_EQ(2, epilogue_call_count);
17932   CHECK_EQ(2, prologue_call_count_second);
17933   CHECK_EQ(2, epilogue_call_count_second);
17934   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
17935   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17936   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17937   CHECK_EQ(2, prologue_call_count);
17938   CHECK_EQ(2, epilogue_call_count);
17939   CHECK_EQ(2, prologue_call_count_second);
17940   CHECK_EQ(2, epilogue_call_count_second);
17941 }
17942
17943
17944 THREADED_TEST(AddToJSFunctionResultCache) {
17945   i::FLAG_stress_compaction = false;
17946   i::FLAG_allow_natives_syntax = true;
17947   v8::HandleScope scope(CcTest::isolate());
17948
17949   LocalContext context;
17950
17951   const char* code =
17952       "(function() {"
17953       "  var key0 = 'a';"
17954       "  var key1 = 'b';"
17955       "  var r0 = %_GetFromCache(0, key0);"
17956       "  var r1 = %_GetFromCache(0, key1);"
17957       "  var r0_ = %_GetFromCache(0, key0);"
17958       "  if (r0 !== r0_)"
17959       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17960       "  var r1_ = %_GetFromCache(0, key1);"
17961       "  if (r1 !== r1_)"
17962       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17963       "  return 'PASSED';"
17964       "})()";
17965   CcTest::heap()->ClearJSFunctionResultCaches();
17966   ExpectString(code, "PASSED");
17967 }
17968
17969
17970 static const int k0CacheSize = 16;
17971
17972 THREADED_TEST(FillJSFunctionResultCache) {
17973   i::FLAG_allow_natives_syntax = true;
17974   LocalContext context;
17975   v8::HandleScope scope(context->GetIsolate());
17976
17977   const char* code =
17978       "(function() {"
17979       "  var k = 'a';"
17980       "  var r = %_GetFromCache(0, k);"
17981       "  for (var i = 0; i < 16; i++) {"
17982       "    %_GetFromCache(0, 'a' + i);"
17983       "  };"
17984       "  if (r === %_GetFromCache(0, k))"
17985       "    return 'FAILED: k0CacheSize is too small';"
17986       "  return 'PASSED';"
17987       "})()";
17988   CcTest::heap()->ClearJSFunctionResultCaches();
17989   ExpectString(code, "PASSED");
17990 }
17991
17992
17993 THREADED_TEST(RoundRobinGetFromCache) {
17994   i::FLAG_allow_natives_syntax = true;
17995   LocalContext context;
17996   v8::HandleScope scope(context->GetIsolate());
17997
17998   const char* code =
17999       "(function() {"
18000       "  var keys = [];"
18001       "  for (var i = 0; i < 16; i++) keys.push(i);"
18002       "  var values = [];"
18003       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18004       "  for (var i = 0; i < 16; i++) {"
18005       "    var v = %_GetFromCache(0, keys[i]);"
18006       "    if (v.toString() !== values[i].toString())"
18007       "      return 'Wrong value for ' + "
18008       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18009       "  };"
18010       "  return 'PASSED';"
18011       "})()";
18012   CcTest::heap()->ClearJSFunctionResultCaches();
18013   ExpectString(code, "PASSED");
18014 }
18015
18016
18017 THREADED_TEST(ReverseGetFromCache) {
18018   i::FLAG_allow_natives_syntax = true;
18019   LocalContext context;
18020   v8::HandleScope scope(context->GetIsolate());
18021
18022   const char* code =
18023       "(function() {"
18024       "  var keys = [];"
18025       "  for (var i = 0; i < 16; i++) keys.push(i);"
18026       "  var values = [];"
18027       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18028       "  for (var i = 15; i >= 16; i--) {"
18029       "    var v = %_GetFromCache(0, keys[i]);"
18030       "    if (v !== values[i])"
18031       "      return 'Wrong value for ' + "
18032       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18033       "  };"
18034       "  return 'PASSED';"
18035       "})()";
18036   CcTest::heap()->ClearJSFunctionResultCaches();
18037   ExpectString(code, "PASSED");
18038 }
18039
18040
18041 THREADED_TEST(TestEviction) {
18042   i::FLAG_allow_natives_syntax = true;
18043   LocalContext context;
18044   v8::HandleScope scope(context->GetIsolate());
18045
18046   const char* code =
18047       "(function() {"
18048       "  for (var i = 0; i < 2*16; i++) {"
18049       "    %_GetFromCache(0, 'a' + i);"
18050       "  };"
18051       "  return 'PASSED';"
18052       "})()";
18053   CcTest::heap()->ClearJSFunctionResultCaches();
18054   ExpectString(code, "PASSED");
18055 }
18056
18057
18058 THREADED_TEST(TwoByteStringInAsciiCons) {
18059   // See Chromium issue 47824.
18060   LocalContext context;
18061   v8::HandleScope scope(context->GetIsolate());
18062
18063   const char* init_code =
18064       "var str1 = 'abelspendabel';"
18065       "var str2 = str1 + str1 + str1;"
18066       "str2;";
18067   Local<Value> result = CompileRun(init_code);
18068
18069   Local<Value> indexof = CompileRun("str2.indexOf('els')");
18070   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18071
18072   CHECK(result->IsString());
18073   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18074   int length = string->length();
18075   CHECK(string->IsOneByteRepresentation());
18076
18077   FlattenString(string);
18078   i::Handle<i::String> flat_string = FlattenGetString(string);
18079
18080   CHECK(string->IsOneByteRepresentation());
18081   CHECK(flat_string->IsOneByteRepresentation());
18082
18083   // Create external resource.
18084   uint16_t* uc16_buffer = new uint16_t[length + 1];
18085
18086   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18087   uc16_buffer[length] = 0;
18088
18089   TestResource resource(uc16_buffer);
18090
18091   flat_string->MakeExternal(&resource);
18092
18093   CHECK(flat_string->IsTwoByteRepresentation());
18094
18095   // If the cons string has been short-circuited, skip the following checks.
18096   if (!string.is_identical_to(flat_string)) {
18097     // At this point, we should have a Cons string which is flat and ASCII,
18098     // with a first half that is a two-byte string (although it only contains
18099     // ASCII characters). This is a valid sequence of steps, and it can happen
18100     // in real pages.
18101     CHECK(string->IsOneByteRepresentation());
18102     i::ConsString* cons = i::ConsString::cast(*string);
18103     CHECK_EQ(0, cons->second()->length());
18104     CHECK(cons->first()->IsTwoByteRepresentation());
18105   }
18106
18107   // Check that some string operations work.
18108
18109   // Atom RegExp.
18110   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18111   CHECK_EQ(6, reresult->Int32Value());
18112
18113   // Nonatom RegExp.
18114   reresult = CompileRun("str2.match(/abe./g).length;");
18115   CHECK_EQ(6, reresult->Int32Value());
18116
18117   reresult = CompileRun("str2.search(/bel/g);");
18118   CHECK_EQ(1, reresult->Int32Value());
18119
18120   reresult = CompileRun("str2.search(/be./g);");
18121   CHECK_EQ(1, reresult->Int32Value());
18122
18123   ExpectTrue("/bel/g.test(str2);");
18124
18125   ExpectTrue("/be./g.test(str2);");
18126
18127   reresult = CompileRun("/bel/g.exec(str2);");
18128   CHECK(!reresult->IsNull());
18129
18130   reresult = CompileRun("/be./g.exec(str2);");
18131   CHECK(!reresult->IsNull());
18132
18133   ExpectString("str2.substring(2, 10);", "elspenda");
18134
18135   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
18136
18137   ExpectString("str2.charAt(2);", "e");
18138
18139   ExpectObject("str2.indexOf('els');", indexof);
18140
18141   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
18142
18143   reresult = CompileRun("str2.charCodeAt(2);");
18144   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
18145 }
18146
18147
18148 TEST(ContainsOnlyOneByte) {
18149   v8::V8::Initialize();
18150   v8::Isolate* isolate = CcTest::isolate();
18151   v8::HandleScope scope(isolate);
18152   // Make a buffer long enough that it won't automatically be converted.
18153   const int length = 512;
18154   // Ensure word aligned assignment.
18155   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
18156   i::SmartArrayPointer<uintptr_t>
18157   aligned_contents(new uintptr_t[aligned_length]);
18158   uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents);
18159   // Set to contain only one byte.
18160   for (int i = 0; i < length-1; i++) {
18161     string_contents[i] = 0x41;
18162   }
18163   string_contents[length-1] = 0;
18164   // Simple case.
18165   Handle<String> string;
18166   string = String::NewExternal(new TestResource(string_contents));
18167   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18168   // Counter example.
18169   string = String::NewFromTwoByte(isolate, string_contents);
18170   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18171   // Test left right and balanced cons strings.
18172   Handle<String> base = String::NewFromUtf8(isolate, "a");
18173   Handle<String> left = base;
18174   Handle<String> right = base;
18175   for (int i = 0; i < 1000; i++) {
18176     left = String::Concat(base, left);
18177     right = String::Concat(right, base);
18178   }
18179   Handle<String> balanced = String::Concat(left, base);
18180   balanced = String::Concat(balanced, right);
18181   Handle<String> cons_strings[] = {left, balanced, right};
18182   Handle<String> two_byte =
18183       String::NewExternal(new TestResource(string_contents));
18184   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
18185     // Base assumptions.
18186     string = cons_strings[i];
18187     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
18188     // Test left and right concatentation.
18189     string = String::Concat(two_byte, cons_strings[i]);
18190     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18191     string = String::Concat(cons_strings[i], two_byte);
18192     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
18193   }
18194   // Set bits in different positions
18195   // for strings of different lengths and alignments.
18196   for (int alignment = 0; alignment < 7; alignment++) {
18197     for (int size = 2; alignment + size < length; size *= 2) {
18198       int zero_offset = size + alignment;
18199       string_contents[zero_offset] = 0;
18200       for (int i = 0; i < size; i++) {
18201         int shift = 8 + (i % 7);
18202         string_contents[alignment + i] = 1 << shift;
18203         string =
18204             String::NewExternal(new TestResource(string_contents + alignment));
18205         CHECK_EQ(size, string->Length());
18206         CHECK(!string->ContainsOnlyOneByte());
18207         string_contents[alignment + i] = 0x41;
18208       }
18209       string_contents[zero_offset] = 0x41;
18210     }
18211   }
18212 }
18213
18214
18215 // Failed access check callback that performs a GC on each invocation.
18216 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
18217                                  v8::AccessType type,
18218                                  Local<v8::Value> data) {
18219   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18220 }
18221
18222
18223 TEST(GCInFailedAccessCheckCallback) {
18224   // Install a failed access check callback that performs a GC on each
18225   // invocation. Then force the callback to be called from va
18226
18227   v8::V8::Initialize();
18228   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
18229
18230   v8::HandleScope scope(CcTest::isolate());
18231
18232   // Create an ObjectTemplate for global objects and install access
18233   // check callbacks that will block access.
18234   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
18235   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
18236                                            IndexedGetAccessBlocker,
18237                                            v8::Handle<v8::Value>(),
18238                                            false);
18239
18240   // Create a context and set an x property on it's global object.
18241   LocalContext context0(NULL, global_template);
18242   context0->Global()->Set(v8_str("x"), v8_num(42));
18243   v8::Handle<v8::Object> global0 = context0->Global();
18244
18245   // Create a context with a different security token so that the
18246   // failed access check callback will be called on each access.
18247   LocalContext context1(NULL, global_template);
18248   context1->Global()->Set(v8_str("other"), global0);
18249
18250   // Get property with failed access check.
18251   ExpectUndefined("other.x");
18252
18253   // Get element with failed access check.
18254   ExpectUndefined("other[0]");
18255
18256   // Set property with failed access check.
18257   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
18258   CHECK(result->IsObject());
18259
18260   // Set element with failed access check.
18261   result = CompileRun("other[0] = new Object()");
18262   CHECK(result->IsObject());
18263
18264   // Get property attribute with failed access check.
18265   ExpectFalse("\'x\' in other");
18266
18267   // Get property attribute for element with failed access check.
18268   ExpectFalse("0 in other");
18269
18270   // Delete property.
18271   ExpectFalse("delete other.x");
18272
18273   // Delete element.
18274   CHECK_EQ(false, global0->Delete(0));
18275
18276   // DefineAccessor.
18277   CHECK_EQ(false,
18278            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
18279
18280   // Define JavaScript accessor.
18281   ExpectUndefined("Object.prototype.__defineGetter__.call("
18282                   "    other, \'x\', function() { return 42; })");
18283
18284   // LookupAccessor.
18285   ExpectUndefined("Object.prototype.__lookupGetter__.call("
18286                   "    other, \'x\')");
18287
18288   // HasLocalElement.
18289   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
18290
18291   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
18292   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
18293   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
18294
18295   // Reset the failed access check callback so it does not influence
18296   // the other tests.
18297   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
18298 }
18299
18300
18301 TEST(IsolateNewDispose) {
18302   v8::Isolate* current_isolate = CcTest::isolate();
18303   v8::Isolate* isolate = v8::Isolate::New();
18304   CHECK(isolate != NULL);
18305   CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
18306   CHECK(current_isolate != isolate);
18307   CHECK(current_isolate == CcTest::isolate());
18308
18309   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18310   last_location = last_message = NULL;
18311   isolate->Dispose();
18312   CHECK_EQ(last_location, NULL);
18313   CHECK_EQ(last_message, NULL);
18314 }
18315
18316
18317 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
18318   v8::Isolate* isolate = v8::Isolate::New();
18319   CHECK(isolate);
18320   isolate->Enter();
18321   v8::HandleScope scope(isolate);
18322   LocalContext context(isolate);
18323   // Run something in this isolate.
18324   ExpectTrue("true");
18325   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18326   last_location = last_message = NULL;
18327   // Still entered, should fail.
18328   isolate->Dispose();
18329   CHECK_NE(last_location, NULL);
18330   CHECK_NE(last_message, NULL);
18331 }
18332
18333
18334 TEST(RunTwoIsolatesOnSingleThread) {
18335   // Run isolate 1.
18336   v8::Isolate* isolate1 = v8::Isolate::New();
18337   isolate1->Enter();
18338   v8::Persistent<v8::Context> context1;
18339   {
18340     v8::HandleScope scope(isolate1);
18341     context1.Reset(isolate1, Context::New(isolate1));
18342   }
18343
18344   {
18345     v8::HandleScope scope(isolate1);
18346     v8::Local<v8::Context> context =
18347         v8::Local<v8::Context>::New(isolate1, context1);
18348     v8::Context::Scope context_scope(context);
18349     // Run something in new isolate.
18350     CompileRun("var foo = 'isolate 1';");
18351     ExpectString("function f() { return foo; }; f()", "isolate 1");
18352   }
18353
18354   // Run isolate 2.
18355   v8::Isolate* isolate2 = v8::Isolate::New();
18356   v8::Persistent<v8::Context> context2;
18357
18358   {
18359     v8::Isolate::Scope iscope(isolate2);
18360     v8::HandleScope scope(isolate2);
18361     context2.Reset(isolate2, Context::New(isolate2));
18362     v8::Local<v8::Context> context =
18363         v8::Local<v8::Context>::New(isolate2, context2);
18364     v8::Context::Scope context_scope(context);
18365
18366     // Run something in new isolate.
18367     CompileRun("var foo = 'isolate 2';");
18368     ExpectString("function f() { return foo; }; f()", "isolate 2");
18369   }
18370
18371   {
18372     v8::HandleScope scope(isolate1);
18373     v8::Local<v8::Context> context =
18374         v8::Local<v8::Context>::New(isolate1, context1);
18375     v8::Context::Scope context_scope(context);
18376     // Now again in isolate 1
18377     ExpectString("function f() { return foo; }; f()", "isolate 1");
18378   }
18379
18380   isolate1->Exit();
18381
18382   // Run some stuff in default isolate.
18383   v8::Persistent<v8::Context> context_default;
18384   {
18385     v8::Isolate* isolate = CcTest::isolate();
18386     v8::Isolate::Scope iscope(isolate);
18387     v8::HandleScope scope(isolate);
18388     context_default.Reset(isolate, Context::New(isolate));
18389   }
18390
18391   {
18392     v8::HandleScope scope(CcTest::isolate());
18393     v8::Local<v8::Context> context =
18394         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
18395     v8::Context::Scope context_scope(context);
18396     // Variables in other isolates should be not available, verify there
18397     // is an exception.
18398     ExpectTrue("function f() {"
18399                "  try {"
18400                "    foo;"
18401                "    return false;"
18402                "  } catch(e) {"
18403                "    return true;"
18404                "  }"
18405                "};"
18406                "var isDefaultIsolate = true;"
18407                "f()");
18408   }
18409
18410   isolate1->Enter();
18411
18412   {
18413     v8::Isolate::Scope iscope(isolate2);
18414     v8::HandleScope scope(isolate2);
18415     v8::Local<v8::Context> context =
18416         v8::Local<v8::Context>::New(isolate2, context2);
18417     v8::Context::Scope context_scope(context);
18418     ExpectString("function f() { return foo; }; f()", "isolate 2");
18419   }
18420
18421   {
18422     v8::HandleScope scope(v8::Isolate::GetCurrent());
18423     v8::Local<v8::Context> context =
18424         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
18425     v8::Context::Scope context_scope(context);
18426     ExpectString("function f() { return foo; }; f()", "isolate 1");
18427   }
18428
18429   {
18430     v8::Isolate::Scope iscope(isolate2);
18431     context2.Dispose();
18432   }
18433
18434   context1.Dispose();
18435   isolate1->Exit();
18436
18437   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
18438   last_location = last_message = NULL;
18439
18440   isolate1->Dispose();
18441   CHECK_EQ(last_location, NULL);
18442   CHECK_EQ(last_message, NULL);
18443
18444   isolate2->Dispose();
18445   CHECK_EQ(last_location, NULL);
18446   CHECK_EQ(last_message, NULL);
18447
18448   // Check that default isolate still runs.
18449   {
18450     v8::HandleScope scope(CcTest::isolate());
18451     v8::Local<v8::Context> context =
18452         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
18453     v8::Context::Scope context_scope(context);
18454     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
18455   }
18456 }
18457
18458
18459 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
18460   v8::Isolate::Scope isolate_scope(isolate);
18461   v8::HandleScope scope(isolate);
18462   LocalContext context(isolate);
18463   i::ScopedVector<char> code(1024);
18464   i::OS::SNPrintF(code, "function fib(n) {"
18465                         "  if (n <= 2) return 1;"
18466                         "  return fib(n-1) + fib(n-2);"
18467                         "}"
18468                         "fib(%d)", limit);
18469   Local<Value> value = CompileRun(code.start());
18470   CHECK(value->IsNumber());
18471   return static_cast<int>(value->NumberValue());
18472 }
18473
18474 class IsolateThread : public v8::internal::Thread {
18475  public:
18476   IsolateThread(v8::Isolate* isolate, int fib_limit)
18477       : Thread("IsolateThread"),
18478         isolate_(isolate),
18479         fib_limit_(fib_limit),
18480         result_(0) { }
18481
18482   void Run() {
18483     result_ = CalcFibonacci(isolate_, fib_limit_);
18484   }
18485
18486   int result() { return result_; }
18487
18488  private:
18489   v8::Isolate* isolate_;
18490   int fib_limit_;
18491   int result_;
18492 };
18493
18494
18495 TEST(MultipleIsolatesOnIndividualThreads) {
18496   v8::Isolate* isolate1 = v8::Isolate::New();
18497   v8::Isolate* isolate2 = v8::Isolate::New();
18498
18499   IsolateThread thread1(isolate1, 21);
18500   IsolateThread thread2(isolate2, 12);
18501
18502   // Compute some fibonacci numbers on 3 threads in 3 isolates.
18503   thread1.Start();
18504   thread2.Start();
18505
18506   int result1 = CalcFibonacci(CcTest::isolate(), 21);
18507   int result2 = CalcFibonacci(CcTest::isolate(), 12);
18508
18509   thread1.Join();
18510   thread2.Join();
18511
18512   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
18513   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
18514   CHECK_EQ(result1, 10946);
18515   CHECK_EQ(result2, 144);
18516   CHECK_EQ(result1, thread1.result());
18517   CHECK_EQ(result2, thread2.result());
18518
18519   isolate1->Dispose();
18520   isolate2->Dispose();
18521 }
18522
18523
18524 TEST(IsolateDifferentContexts) {
18525   v8::Isolate* isolate = v8::Isolate::New();
18526   Local<v8::Context> context;
18527   {
18528     v8::Isolate::Scope isolate_scope(isolate);
18529     v8::HandleScope handle_scope(isolate);
18530     context = v8::Context::New(isolate);
18531     v8::Context::Scope context_scope(context);
18532     Local<Value> v = CompileRun("2");
18533     CHECK(v->IsNumber());
18534     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
18535   }
18536   {
18537     v8::Isolate::Scope isolate_scope(isolate);
18538     v8::HandleScope handle_scope(isolate);
18539     context = v8::Context::New(isolate);
18540     v8::Context::Scope context_scope(context);
18541     Local<Value> v = CompileRun("22");
18542     CHECK(v->IsNumber());
18543     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
18544   }
18545 }
18546
18547 class InitDefaultIsolateThread : public v8::internal::Thread {
18548  public:
18549   enum TestCase {
18550     IgnoreOOM,
18551     SetResourceConstraints,
18552     SetFatalHandler,
18553     SetCounterFunction,
18554     SetCreateHistogramFunction,
18555     SetAddHistogramSampleFunction
18556   };
18557
18558   explicit InitDefaultIsolateThread(TestCase testCase)
18559       : Thread("InitDefaultIsolateThread"),
18560         testCase_(testCase),
18561         result_(false) { }
18562
18563   void Run() {
18564     v8::Isolate* isolate = v8::Isolate::New();
18565     isolate->Enter();
18566     switch (testCase_) {
18567     case IgnoreOOM:
18568       v8::V8::IgnoreOutOfMemoryException();
18569       break;
18570
18571     case SetResourceConstraints: {
18572       static const int K = 1024;
18573       v8::ResourceConstraints constraints;
18574       constraints.set_max_young_space_size(256 * K);
18575       constraints.set_max_old_space_size(4 * K * K);
18576       v8::SetResourceConstraints(&constraints);
18577       break;
18578     }
18579
18580     case SetFatalHandler:
18581       v8::V8::SetFatalErrorHandler(NULL);
18582       break;
18583
18584     case SetCounterFunction:
18585       v8::V8::SetCounterFunction(NULL);
18586       break;
18587
18588     case SetCreateHistogramFunction:
18589       v8::V8::SetCreateHistogramFunction(NULL);
18590       break;
18591
18592     case SetAddHistogramSampleFunction:
18593       v8::V8::SetAddHistogramSampleFunction(NULL);
18594       break;
18595     }
18596     isolate->Exit();
18597     isolate->Dispose();
18598     result_ = true;
18599   }
18600
18601   bool result() { return result_; }
18602
18603  private:
18604   TestCase testCase_;
18605   bool result_;
18606 };
18607
18608
18609 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
18610   InitDefaultIsolateThread thread(testCase);
18611   thread.Start();
18612   thread.Join();
18613   CHECK_EQ(thread.result(), true);
18614 }
18615
18616
18617 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
18618   InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
18619 }
18620
18621
18622 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
18623   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
18624 }
18625
18626
18627 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
18628   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
18629 }
18630
18631
18632 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
18633   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
18634 }
18635
18636
18637 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
18638   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
18639 }
18640
18641
18642 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
18643   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
18644 }
18645
18646
18647 TEST(StringCheckMultipleContexts) {
18648   const char* code =
18649       "(function() { return \"a\".charAt(0); })()";
18650
18651   {
18652     // Run the code twice in the first context to initialize the call IC.
18653     LocalContext context1;
18654     v8::HandleScope scope(context1->GetIsolate());
18655     ExpectString(code, "a");
18656     ExpectString(code, "a");
18657   }
18658
18659   {
18660     // Change the String.prototype in the second context and check
18661     // that the right function gets called.
18662     LocalContext context2;
18663     v8::HandleScope scope(context2->GetIsolate());
18664     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
18665     ExpectString(code, "not a");
18666   }
18667 }
18668
18669
18670 TEST(NumberCheckMultipleContexts) {
18671   const char* code =
18672       "(function() { return (42).toString(); })()";
18673
18674   {
18675     // Run the code twice in the first context to initialize the call IC.
18676     LocalContext context1;
18677     v8::HandleScope scope(context1->GetIsolate());
18678     ExpectString(code, "42");
18679     ExpectString(code, "42");
18680   }
18681
18682   {
18683     // Change the Number.prototype in the second context and check
18684     // that the right function gets called.
18685     LocalContext context2;
18686     v8::HandleScope scope(context2->GetIsolate());
18687     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
18688     ExpectString(code, "not 42");
18689   }
18690 }
18691
18692
18693 TEST(BooleanCheckMultipleContexts) {
18694   const char* code =
18695       "(function() { return true.toString(); })()";
18696
18697   {
18698     // Run the code twice in the first context to initialize the call IC.
18699     LocalContext context1;
18700     v8::HandleScope scope(context1->GetIsolate());
18701     ExpectString(code, "true");
18702     ExpectString(code, "true");
18703   }
18704
18705   {
18706     // Change the Boolean.prototype in the second context and check
18707     // that the right function gets called.
18708     LocalContext context2;
18709     v8::HandleScope scope(context2->GetIsolate());
18710     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
18711     ExpectString(code, "");
18712   }
18713 }
18714
18715
18716 TEST(DontDeleteCellLoadIC) {
18717   const char* function_code =
18718       "function readCell() { while (true) { return cell; } }";
18719
18720   {
18721     // Run the code twice in the first context to initialize the load
18722     // IC for a don't delete cell.
18723     LocalContext context1;
18724     v8::HandleScope scope(context1->GetIsolate());
18725     CompileRun("var cell = \"first\";");
18726     ExpectBoolean("delete cell", false);
18727     CompileRun(function_code);
18728     ExpectString("readCell()", "first");
18729     ExpectString("readCell()", "first");
18730   }
18731
18732   {
18733     // Use a deletable cell in the second context.
18734     LocalContext context2;
18735     v8::HandleScope scope(context2->GetIsolate());
18736     CompileRun("cell = \"second\";");
18737     CompileRun(function_code);
18738     ExpectString("readCell()", "second");
18739     ExpectBoolean("delete cell", true);
18740     ExpectString("(function() {"
18741                  "  try {"
18742                  "    return readCell();"
18743                  "  } catch(e) {"
18744                  "    return e.toString();"
18745                  "  }"
18746                  "})()",
18747                  "ReferenceError: cell is not defined");
18748     CompileRun("cell = \"new_second\";");
18749     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18750     ExpectString("readCell()", "new_second");
18751     ExpectString("readCell()", "new_second");
18752   }
18753 }
18754
18755
18756 TEST(DontDeleteCellLoadICForceDelete) {
18757   const char* function_code =
18758       "function readCell() { while (true) { return cell; } }";
18759
18760   // Run the code twice to initialize the load IC for a don't delete
18761   // cell.
18762   LocalContext context;
18763   v8::HandleScope scope(context->GetIsolate());
18764   CompileRun("var cell = \"value\";");
18765   ExpectBoolean("delete cell", false);
18766   CompileRun(function_code);
18767   ExpectString("readCell()", "value");
18768   ExpectString("readCell()", "value");
18769
18770   // Delete the cell using the API and check the inlined code works
18771   // correctly.
18772   CHECK(context->Global()->ForceDelete(v8_str("cell")));
18773   ExpectString("(function() {"
18774                "  try {"
18775                "    return readCell();"
18776                "  } catch(e) {"
18777                "    return e.toString();"
18778                "  }"
18779                "})()",
18780                "ReferenceError: cell is not defined");
18781 }
18782
18783
18784 TEST(DontDeleteCellLoadICAPI) {
18785   const char* function_code =
18786       "function readCell() { while (true) { return cell; } }";
18787
18788   // Run the code twice to initialize the load IC for a don't delete
18789   // cell created using the API.
18790   LocalContext context;
18791   v8::HandleScope scope(context->GetIsolate());
18792   context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
18793   ExpectBoolean("delete cell", false);
18794   CompileRun(function_code);
18795   ExpectString("readCell()", "value");
18796   ExpectString("readCell()", "value");
18797
18798   // Delete the cell using the API and check the inlined code works
18799   // correctly.
18800   CHECK(context->Global()->ForceDelete(v8_str("cell")));
18801   ExpectString("(function() {"
18802                "  try {"
18803                "    return readCell();"
18804                "  } catch(e) {"
18805                "    return e.toString();"
18806                "  }"
18807                "})()",
18808                "ReferenceError: cell is not defined");
18809 }
18810
18811
18812 class Visitor42 : public v8::PersistentHandleVisitor {
18813  public:
18814   explicit Visitor42(v8::Persistent<v8::Object>* object)
18815       : counter_(0), object_(object) { }
18816
18817   virtual void VisitPersistentHandle(Persistent<Value>* value,
18818                                      uint16_t class_id) {
18819     if (class_id != 42) return;
18820     CHECK_EQ(42, value->WrapperClassId());
18821     v8::Isolate* isolate = CcTest::isolate();
18822     v8::HandleScope handle_scope(isolate);
18823     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
18824     v8::Handle<v8::Value> object =
18825         v8::Local<v8::Object>::New(isolate, *object_);
18826     CHECK(handle->IsObject());
18827     CHECK_EQ(Handle<Object>::Cast(handle), object);
18828     ++counter_;
18829   }
18830
18831   int counter_;
18832   v8::Persistent<v8::Object>* object_;
18833 };
18834
18835
18836 TEST(PersistentHandleVisitor) {
18837   LocalContext context;
18838   v8::Isolate* isolate = context->GetIsolate();
18839   v8::HandleScope scope(isolate);
18840   v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18841   CHECK_EQ(0, object.WrapperClassId());
18842   object.SetWrapperClassId(42);
18843   CHECK_EQ(42, object.WrapperClassId());
18844
18845   Visitor42 visitor(&object);
18846   v8::V8::VisitHandlesWithClassIds(&visitor);
18847   CHECK_EQ(1, visitor.counter_);
18848
18849   object.Dispose();
18850 }
18851
18852
18853 TEST(WrapperClassId) {
18854   LocalContext context;
18855   v8::Isolate* isolate = context->GetIsolate();
18856   v8::HandleScope scope(isolate);
18857   v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18858   CHECK_EQ(0, object.WrapperClassId());
18859   object.SetWrapperClassId(65535);
18860   CHECK_EQ(65535, object.WrapperClassId());
18861   object.Dispose();
18862 }
18863
18864
18865 TEST(PersistentHandleInNewSpaceVisitor) {
18866   LocalContext context;
18867   v8::Isolate* isolate = context->GetIsolate();
18868   v8::HandleScope scope(isolate);
18869   v8::Persistent<v8::Object> object1(isolate, v8::Object::New());
18870   CHECK_EQ(0, object1.WrapperClassId());
18871   object1.SetWrapperClassId(42);
18872   CHECK_EQ(42, object1.WrapperClassId());
18873
18874   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18875
18876   v8::Persistent<v8::Object> object2(isolate, v8::Object::New());
18877   CHECK_EQ(0, object2.WrapperClassId());
18878   object2.SetWrapperClassId(42);
18879   CHECK_EQ(42, object2.WrapperClassId());
18880
18881   Visitor42 visitor(&object2);
18882   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18883   CHECK_EQ(1, visitor.counter_);
18884
18885   object1.Dispose();
18886   object2.Dispose();
18887 }
18888
18889
18890 TEST(RegExp) {
18891   LocalContext context;
18892   v8::HandleScope scope(context->GetIsolate());
18893
18894   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18895   CHECK(re->IsRegExp());
18896   CHECK(re->GetSource()->Equals(v8_str("foo")));
18897   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18898
18899   re = v8::RegExp::New(v8_str("bar"),
18900                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18901                                                       v8::RegExp::kGlobal));
18902   CHECK(re->IsRegExp());
18903   CHECK(re->GetSource()->Equals(v8_str("bar")));
18904   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18905            static_cast<int>(re->GetFlags()));
18906
18907   re = v8::RegExp::New(v8_str("baz"),
18908                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18909                                                       v8::RegExp::kMultiline));
18910   CHECK(re->IsRegExp());
18911   CHECK(re->GetSource()->Equals(v8_str("baz")));
18912   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18913            static_cast<int>(re->GetFlags()));
18914
18915   re = CompileRun("/quux/").As<v8::RegExp>();
18916   CHECK(re->IsRegExp());
18917   CHECK(re->GetSource()->Equals(v8_str("quux")));
18918   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18919
18920   re = CompileRun("/quux/gm").As<v8::RegExp>();
18921   CHECK(re->IsRegExp());
18922   CHECK(re->GetSource()->Equals(v8_str("quux")));
18923   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18924            static_cast<int>(re->GetFlags()));
18925
18926   // Override the RegExp constructor and check the API constructor
18927   // still works.
18928   CompileRun("RegExp = function() {}");
18929
18930   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18931   CHECK(re->IsRegExp());
18932   CHECK(re->GetSource()->Equals(v8_str("foobar")));
18933   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18934
18935   re = v8::RegExp::New(v8_str("foobarbaz"),
18936                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18937                                                       v8::RegExp::kMultiline));
18938   CHECK(re->IsRegExp());
18939   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18940   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18941            static_cast<int>(re->GetFlags()));
18942
18943   context->Global()->Set(v8_str("re"), re);
18944   ExpectTrue("re.test('FoobarbaZ')");
18945
18946   // RegExps are objects on which you can set properties.
18947   re->Set(v8_str("property"), v8::Integer::New(32));
18948   v8::Handle<v8::Value> value(CompileRun("re.property"));
18949   CHECK_EQ(32, value->Int32Value());
18950
18951   v8::TryCatch try_catch;
18952   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18953   CHECK(re.IsEmpty());
18954   CHECK(try_catch.HasCaught());
18955   context->Global()->Set(v8_str("ex"), try_catch.Exception());
18956   ExpectTrue("ex instanceof SyntaxError");
18957 }
18958
18959
18960 THREADED_TEST(Equals) {
18961   LocalContext localContext;
18962   v8::HandleScope handleScope(localContext->GetIsolate());
18963
18964   v8::Handle<v8::Object> globalProxy = localContext->Global();
18965   v8::Handle<Value> global = globalProxy->GetPrototype();
18966
18967   CHECK(global->StrictEquals(global));
18968   CHECK(!global->StrictEquals(globalProxy));
18969   CHECK(!globalProxy->StrictEquals(global));
18970   CHECK(globalProxy->StrictEquals(globalProxy));
18971
18972   CHECK(global->Equals(global));
18973   CHECK(!global->Equals(globalProxy));
18974   CHECK(!globalProxy->Equals(global));
18975   CHECK(globalProxy->Equals(globalProxy));
18976 }
18977
18978
18979 static void Getter(v8::Local<v8::String> property,
18980                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
18981   info.GetReturnValue().Set(v8_str("42!"));
18982 }
18983
18984
18985 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18986   v8::Handle<v8::Array> result = v8::Array::New();
18987   result->Set(0, v8_str("universalAnswer"));
18988   info.GetReturnValue().Set(result);
18989 }
18990
18991
18992 TEST(NamedEnumeratorAndForIn) {
18993   LocalContext context;
18994   v8::HandleScope handle_scope(context->GetIsolate());
18995   v8::Context::Scope context_scope(context.local());
18996
18997   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
18998   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
18999   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19000   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19001         "var result = []; for (var k in o) result.push(k); result"));
19002   CHECK_EQ(1, result->Length());
19003   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19004 }
19005
19006
19007 TEST(DefinePropertyPostDetach) {
19008   LocalContext context;
19009   v8::HandleScope scope(context->GetIsolate());
19010   v8::Handle<v8::Object> proxy = context->Global();
19011   v8::Handle<v8::Function> define_property =
19012       CompileRun("(function() {"
19013                  "  Object.defineProperty("
19014                  "    this,"
19015                  "    1,"
19016                  "    { configurable: true, enumerable: true, value: 3 });"
19017                  "})").As<Function>();
19018   context->DetachGlobal();
19019   define_property->Call(proxy, 0, NULL);
19020 }
19021
19022
19023 static void InstallContextId(v8::Handle<Context> context, int id) {
19024   Context::Scope scope(context);
19025   CompileRun("Object.prototype").As<Object>()->
19026       Set(v8_str("context_id"), v8::Integer::New(id));
19027 }
19028
19029
19030 static void CheckContextId(v8::Handle<Object> object, int expected) {
19031   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19032 }
19033
19034
19035 THREADED_TEST(CreationContext) {
19036   HandleScope handle_scope(CcTest::isolate());
19037   Handle<Context> context1 = Context::New(CcTest::isolate());
19038   InstallContextId(context1, 1);
19039   Handle<Context> context2 = Context::New(CcTest::isolate());
19040   InstallContextId(context2, 2);
19041   Handle<Context> context3 = Context::New(CcTest::isolate());
19042   InstallContextId(context3, 3);
19043
19044   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
19045
19046   Local<Object> object1;
19047   Local<Function> func1;
19048   {
19049     Context::Scope scope(context1);
19050     object1 = Object::New();
19051     func1 = tmpl->GetFunction();
19052   }
19053
19054   Local<Object> object2;
19055   Local<Function> func2;
19056   {
19057     Context::Scope scope(context2);
19058     object2 = Object::New();
19059     func2 = tmpl->GetFunction();
19060   }
19061
19062   Local<Object> instance1;
19063   Local<Object> instance2;
19064
19065   {
19066     Context::Scope scope(context3);
19067     instance1 = func1->NewInstance();
19068     instance2 = func2->NewInstance();
19069   }
19070
19071   CHECK(object1->CreationContext() == context1);
19072   CheckContextId(object1, 1);
19073   CHECK(func1->CreationContext() == context1);
19074   CheckContextId(func1, 1);
19075   CHECK(instance1->CreationContext() == context1);
19076   CheckContextId(instance1, 1);
19077   CHECK(object2->CreationContext() == context2);
19078   CheckContextId(object2, 2);
19079   CHECK(func2->CreationContext() == context2);
19080   CheckContextId(func2, 2);
19081   CHECK(instance2->CreationContext() == context2);
19082   CheckContextId(instance2, 2);
19083
19084   {
19085     Context::Scope scope(context1);
19086     CHECK(object1->CreationContext() == context1);
19087     CheckContextId(object1, 1);
19088     CHECK(func1->CreationContext() == context1);
19089     CheckContextId(func1, 1);
19090     CHECK(instance1->CreationContext() == context1);
19091     CheckContextId(instance1, 1);
19092     CHECK(object2->CreationContext() == context2);
19093     CheckContextId(object2, 2);
19094     CHECK(func2->CreationContext() == context2);
19095     CheckContextId(func2, 2);
19096     CHECK(instance2->CreationContext() == context2);
19097     CheckContextId(instance2, 2);
19098   }
19099
19100   {
19101     Context::Scope scope(context2);
19102     CHECK(object1->CreationContext() == context1);
19103     CheckContextId(object1, 1);
19104     CHECK(func1->CreationContext() == context1);
19105     CheckContextId(func1, 1);
19106     CHECK(instance1->CreationContext() == context1);
19107     CheckContextId(instance1, 1);
19108     CHECK(object2->CreationContext() == context2);
19109     CheckContextId(object2, 2);
19110     CHECK(func2->CreationContext() == context2);
19111     CheckContextId(func2, 2);
19112     CHECK(instance2->CreationContext() == context2);
19113     CheckContextId(instance2, 2);
19114   }
19115 }
19116
19117
19118 THREADED_TEST(CreationContextOfJsFunction) {
19119   HandleScope handle_scope(CcTest::isolate());
19120   Handle<Context> context = Context::New(CcTest::isolate());
19121   InstallContextId(context, 1);
19122
19123   Local<Object> function;
19124   {
19125     Context::Scope scope(context);
19126     function = CompileRun("function foo() {}; foo").As<Object>();
19127   }
19128
19129   CHECK(function->CreationContext() == context);
19130   CheckContextId(function, 1);
19131 }
19132
19133
19134 void HasOwnPropertyIndexedPropertyGetter(
19135     uint32_t index,
19136     const v8::PropertyCallbackInfo<v8::Value>& info) {
19137   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
19138 }
19139
19140
19141 void HasOwnPropertyNamedPropertyGetter(
19142     Local<String> property,
19143     const v8::PropertyCallbackInfo<v8::Value>& info) {
19144   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
19145 }
19146
19147
19148 void HasOwnPropertyIndexedPropertyQuery(
19149     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
19150   if (index == 42) info.GetReturnValue().Set(1);
19151 }
19152
19153
19154 void HasOwnPropertyNamedPropertyQuery(
19155     Local<String> property,
19156     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19157   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
19158 }
19159
19160
19161 void HasOwnPropertyNamedPropertyQuery2(
19162     Local<String> property,
19163     const v8::PropertyCallbackInfo<v8::Integer>& info) {
19164   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
19165 }
19166
19167
19168 void HasOwnPropertyAccessorGetter(
19169     Local<String> property,
19170     const v8::PropertyCallbackInfo<v8::Value>& info) {
19171   info.GetReturnValue().Set(v8_str("yes"));
19172 }
19173
19174
19175 TEST(HasOwnProperty) {
19176   LocalContext env;
19177   v8::HandleScope scope(env->GetIsolate());
19178   { // Check normal properties and defined getters.
19179     Handle<Value> value = CompileRun(
19180         "function Foo() {"
19181         "    this.foo = 11;"
19182         "    this.__defineGetter__('baz', function() { return 1; });"
19183         "};"
19184         "function Bar() { "
19185         "    this.bar = 13;"
19186         "    this.__defineGetter__('bla', function() { return 2; });"
19187         "};"
19188         "Bar.prototype = new Foo();"
19189         "new Bar();");
19190     CHECK(value->IsObject());
19191     Handle<Object> object = value->ToObject();
19192     CHECK(object->Has(v8_str("foo")));
19193     CHECK(!object->HasOwnProperty(v8_str("foo")));
19194     CHECK(object->HasOwnProperty(v8_str("bar")));
19195     CHECK(object->Has(v8_str("baz")));
19196     CHECK(!object->HasOwnProperty(v8_str("baz")));
19197     CHECK(object->HasOwnProperty(v8_str("bla")));
19198   }
19199   { // Check named getter interceptors.
19200     Handle<ObjectTemplate> templ = ObjectTemplate::New();
19201     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
19202     Handle<Object> instance = templ->NewInstance();
19203     CHECK(!instance->HasOwnProperty(v8_str("42")));
19204     CHECK(instance->HasOwnProperty(v8_str("foo")));
19205     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19206   }
19207   { // Check indexed getter interceptors.
19208     Handle<ObjectTemplate> templ = ObjectTemplate::New();
19209     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
19210     Handle<Object> instance = templ->NewInstance();
19211     CHECK(instance->HasOwnProperty(v8_str("42")));
19212     CHECK(!instance->HasOwnProperty(v8_str("43")));
19213     CHECK(!instance->HasOwnProperty(v8_str("foo")));
19214   }
19215   { // Check named query interceptors.
19216     Handle<ObjectTemplate> templ = ObjectTemplate::New();
19217     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
19218     Handle<Object> instance = templ->NewInstance();
19219     CHECK(instance->HasOwnProperty(v8_str("foo")));
19220     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19221   }
19222   { // Check indexed query interceptors.
19223     Handle<ObjectTemplate> templ = ObjectTemplate::New();
19224     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
19225     Handle<Object> instance = templ->NewInstance();
19226     CHECK(instance->HasOwnProperty(v8_str("42")));
19227     CHECK(!instance->HasOwnProperty(v8_str("41")));
19228   }
19229   { // Check callbacks.
19230     Handle<ObjectTemplate> templ = ObjectTemplate::New();
19231     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
19232     Handle<Object> instance = templ->NewInstance();
19233     CHECK(instance->HasOwnProperty(v8_str("foo")));
19234     CHECK(!instance->HasOwnProperty(v8_str("bar")));
19235   }
19236   { // Check that query wins on disagreement.
19237     Handle<ObjectTemplate> templ = ObjectTemplate::New();
19238     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
19239                                    0,
19240                                    HasOwnPropertyNamedPropertyQuery2);
19241     Handle<Object> instance = templ->NewInstance();
19242     CHECK(!instance->HasOwnProperty(v8_str("foo")));
19243     CHECK(instance->HasOwnProperty(v8_str("bar")));
19244   }
19245 }
19246
19247
19248 TEST(IndexedInterceptorWithStringProto) {
19249   v8::HandleScope scope(CcTest::isolate());
19250   Handle<ObjectTemplate> templ = ObjectTemplate::New();
19251   templ->SetIndexedPropertyHandler(NULL,
19252                                    NULL,
19253                                    HasOwnPropertyIndexedPropertyQuery);
19254   LocalContext context;
19255   context->Global()->Set(v8_str("obj"), templ->NewInstance());
19256   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
19257   // These should be intercepted.
19258   CHECK(CompileRun("42 in obj")->BooleanValue());
19259   CHECK(CompileRun("'42' in obj")->BooleanValue());
19260   // These should fall through to the String prototype.
19261   CHECK(CompileRun("0 in obj")->BooleanValue());
19262   CHECK(CompileRun("'0' in obj")->BooleanValue());
19263   // And these should both fail.
19264   CHECK(!CompileRun("32 in obj")->BooleanValue());
19265   CHECK(!CompileRun("'32' in obj")->BooleanValue());
19266 }
19267
19268
19269 void CheckCodeGenerationAllowed() {
19270   Handle<Value> result = CompileRun("eval('42')");
19271   CHECK_EQ(42, result->Int32Value());
19272   result = CompileRun("(function(e) { return e('42'); })(eval)");
19273   CHECK_EQ(42, result->Int32Value());
19274   result = CompileRun("var f = new Function('return 42'); f()");
19275   CHECK_EQ(42, result->Int32Value());
19276 }
19277
19278
19279 void CheckCodeGenerationDisallowed() {
19280   TryCatch try_catch;
19281
19282   Handle<Value> result = CompileRun("eval('42')");
19283   CHECK(result.IsEmpty());
19284   CHECK(try_catch.HasCaught());
19285   try_catch.Reset();
19286
19287   result = CompileRun("(function(e) { return e('42'); })(eval)");
19288   CHECK(result.IsEmpty());
19289   CHECK(try_catch.HasCaught());
19290   try_catch.Reset();
19291
19292   result = CompileRun("var f = new Function('return 42'); f()");
19293   CHECK(result.IsEmpty());
19294   CHECK(try_catch.HasCaught());
19295 }
19296
19297
19298 bool CodeGenerationAllowed(Local<Context> context) {
19299   ApiTestFuzzer::Fuzz();
19300   return true;
19301 }
19302
19303
19304 bool CodeGenerationDisallowed(Local<Context> context) {
19305   ApiTestFuzzer::Fuzz();
19306   return false;
19307 }
19308
19309
19310 THREADED_TEST(AllowCodeGenFromStrings) {
19311   LocalContext context;
19312   v8::HandleScope scope(context->GetIsolate());
19313
19314   // eval and the Function constructor allowed by default.
19315   CHECK(context->IsCodeGenerationFromStringsAllowed());
19316   CheckCodeGenerationAllowed();
19317
19318   // Disallow eval and the Function constructor.
19319   context->AllowCodeGenerationFromStrings(false);
19320   CHECK(!context->IsCodeGenerationFromStringsAllowed());
19321   CheckCodeGenerationDisallowed();
19322
19323   // Allow again.
19324   context->AllowCodeGenerationFromStrings(true);
19325   CheckCodeGenerationAllowed();
19326
19327   // Disallow but setting a global callback that will allow the calls.
19328   context->AllowCodeGenerationFromStrings(false);
19329   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
19330   CHECK(!context->IsCodeGenerationFromStringsAllowed());
19331   CheckCodeGenerationAllowed();
19332
19333   // Set a callback that disallows the code generation.
19334   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
19335   CHECK(!context->IsCodeGenerationFromStringsAllowed());
19336   CheckCodeGenerationDisallowed();
19337 }
19338
19339
19340 TEST(SetErrorMessageForCodeGenFromStrings) {
19341   LocalContext context;
19342   v8::HandleScope scope(context->GetIsolate());
19343   TryCatch try_catch;
19344
19345   Handle<String> message = v8_str("Message") ;
19346   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
19347   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
19348   context->AllowCodeGenerationFromStrings(false);
19349   context->SetErrorMessageForCodeGenerationFromStrings(message);
19350   Handle<Value> result = CompileRun("eval('42')");
19351   CHECK(result.IsEmpty());
19352   CHECK(try_catch.HasCaught());
19353   Handle<String> actual_message = try_catch.Message()->Get();
19354   CHECK(expected_message->Equals(actual_message));
19355 }
19356
19357
19358 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
19359 }
19360
19361
19362 THREADED_TEST(CallAPIFunctionOnNonObject) {
19363   LocalContext context;
19364   v8::HandleScope scope(context->GetIsolate());
19365   Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
19366   Handle<Function> function = templ->GetFunction();
19367   context->Global()->Set(v8_str("f"), function);
19368   TryCatch try_catch;
19369   CompileRun("f.call(2)");
19370 }
19371
19372
19373 // Regression test for issue 1470.
19374 THREADED_TEST(ReadOnlyIndexedProperties) {
19375   v8::HandleScope scope(CcTest::isolate());
19376   Local<ObjectTemplate> templ = ObjectTemplate::New();
19377
19378   LocalContext context;
19379   Local<v8::Object> obj = templ->NewInstance();
19380   context->Global()->Set(v8_str("obj"), obj);
19381   obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
19382   obj->Set(v8_str("1"), v8_str("foobar"));
19383   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
19384   obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
19385   obj->Set(v8_num(2), v8_str("foobar"));
19386   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
19387
19388   // Test non-smi case.
19389   obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
19390   obj->Set(v8_str("2000000000"), v8_str("foobar"));
19391   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
19392 }
19393
19394
19395 THREADED_TEST(Regress1516) {
19396   LocalContext context;
19397   v8::HandleScope scope(context->GetIsolate());
19398
19399   { v8::HandleScope temp_scope(context->GetIsolate());
19400     CompileRun("({'a': 0})");
19401   }
19402
19403   int elements;
19404   { i::MapCache* map_cache =
19405         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
19406     elements = map_cache->NumberOfElements();
19407     CHECK_LE(1, elements);
19408   }
19409
19410   CcTest::heap()->CollectAllGarbage(
19411       i::Heap::kAbortIncrementalMarkingMask);
19412   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
19413     if (raw_map_cache != CcTest::heap()->undefined_value()) {
19414       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
19415       CHECK_GT(elements, map_cache->NumberOfElements());
19416     }
19417   }
19418 }
19419
19420
19421 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
19422                                                 Local<Value> name,
19423                                                 v8::AccessType type,
19424                                                 Local<Value> data) {
19425   // Only block read access to __proto__.
19426   if (type == v8::ACCESS_GET &&
19427       name->IsString() &&
19428       name->ToString()->Length() == 9 &&
19429       name->ToString()->Utf8Length() == 9) {
19430     char buffer[10];
19431     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
19432     return strncmp(buffer, "__proto__", 9) != 0;
19433   }
19434
19435   return true;
19436 }
19437
19438
19439 THREADED_TEST(Regress93759) {
19440   v8::Isolate* isolate = CcTest::isolate();
19441   HandleScope scope(isolate);
19442
19443   // Template for object with security check.
19444   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
19445   // We don't do indexing, so any callback can be used for that.
19446   no_proto_template->SetAccessCheckCallbacks(
19447       BlockProtoNamedSecurityTestCallback,
19448       IndexedSecurityTestCallback);
19449
19450   // Templates for objects with hidden prototypes and possibly security check.
19451   Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
19452   hidden_proto_template->SetHiddenPrototype(true);
19453
19454   Local<FunctionTemplate> protected_hidden_proto_template =
19455       v8::FunctionTemplate::New();
19456   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
19457       BlockProtoNamedSecurityTestCallback,
19458       IndexedSecurityTestCallback);
19459   protected_hidden_proto_template->SetHiddenPrototype(true);
19460
19461   // Context for "foreign" objects used in test.
19462   Local<Context> context = v8::Context::New(isolate);
19463   context->Enter();
19464
19465   // Plain object, no security check.
19466   Local<Object> simple_object = Object::New();
19467
19468   // Object with explicit security check.
19469   Local<Object> protected_object =
19470       no_proto_template->NewInstance();
19471
19472   // JSGlobalProxy object, always have security check.
19473   Local<Object> proxy_object =
19474       context->Global();
19475
19476   // Global object, the  prototype of proxy_object. No security checks.
19477   Local<Object> global_object =
19478       proxy_object->GetPrototype()->ToObject();
19479
19480   // Hidden prototype without security check.
19481   Local<Object> hidden_prototype =
19482       hidden_proto_template->GetFunction()->NewInstance();
19483   Local<Object> object_with_hidden =
19484     Object::New();
19485   object_with_hidden->SetPrototype(hidden_prototype);
19486
19487   // Hidden prototype with security check on the hidden prototype.
19488   Local<Object> protected_hidden_prototype =
19489       protected_hidden_proto_template->GetFunction()->NewInstance();
19490   Local<Object> object_with_protected_hidden =
19491     Object::New();
19492   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
19493
19494   context->Exit();
19495
19496   // Template for object for second context. Values to test are put on it as
19497   // properties.
19498   Local<ObjectTemplate> global_template = ObjectTemplate::New();
19499   global_template->Set(v8_str("simple"), simple_object);
19500   global_template->Set(v8_str("protected"), protected_object);
19501   global_template->Set(v8_str("global"), global_object);
19502   global_template->Set(v8_str("proxy"), proxy_object);
19503   global_template->Set(v8_str("hidden"), object_with_hidden);
19504   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
19505
19506   LocalContext context2(NULL, global_template);
19507
19508   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
19509   CHECK(result1->Equals(simple_object->GetPrototype()));
19510
19511   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
19512   CHECK(result2->Equals(Undefined(isolate)));
19513
19514   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
19515   CHECK(result3->Equals(global_object->GetPrototype()));
19516
19517   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
19518   CHECK(result4->Equals(Undefined(isolate)));
19519
19520   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
19521   CHECK(result5->Equals(
19522       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
19523
19524   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
19525   CHECK(result6->Equals(Undefined(isolate)));
19526 }
19527
19528
19529 THREADED_TEST(Regress125988) {
19530   v8::HandleScope scope(CcTest::isolate());
19531   Handle<FunctionTemplate> intercept = FunctionTemplate::New();
19532   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
19533   LocalContext env;
19534   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
19535   CompileRun("var a = new Object();"
19536              "var b = new Intercept();"
19537              "var c = new Object();"
19538              "c.__proto__ = b;"
19539              "b.__proto__ = a;"
19540              "a.x = 23;"
19541              "for (var i = 0; i < 3; i++) c.x;");
19542   ExpectBoolean("c.hasOwnProperty('x')", false);
19543   ExpectInt32("c.x", 23);
19544   CompileRun("a.y = 42;"
19545              "for (var i = 0; i < 3; i++) c.x;");
19546   ExpectBoolean("c.hasOwnProperty('x')", false);
19547   ExpectInt32("c.x", 23);
19548   ExpectBoolean("c.hasOwnProperty('y')", false);
19549   ExpectInt32("c.y", 42);
19550 }
19551
19552
19553 static void TestReceiver(Local<Value> expected_result,
19554                          Local<Value> expected_receiver,
19555                          const char* code) {
19556   Local<Value> result = CompileRun(code);
19557   CHECK(result->IsObject());
19558   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
19559   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
19560 }
19561
19562
19563 THREADED_TEST(ForeignFunctionReceiver) {
19564   v8::Isolate* isolate = CcTest::isolate();
19565   HandleScope scope(isolate);
19566
19567   // Create two contexts with different "id" properties ('i' and 'o').
19568   // Call a function both from its own context and from a the foreign
19569   // context, and see what "this" is bound to (returning both "this"
19570   // and "this.id" for comparison).
19571
19572   Local<Context> foreign_context = v8::Context::New(isolate);
19573   foreign_context->Enter();
19574   Local<Value> foreign_function =
19575     CompileRun("function func() { return { 0: this.id, "
19576                "                           1: this, "
19577                "                           toString: function() { "
19578                "                               return this[0];"
19579                "                           }"
19580                "                         };"
19581                "}"
19582                "var id = 'i';"
19583                "func;");
19584   CHECK(foreign_function->IsFunction());
19585   foreign_context->Exit();
19586
19587   LocalContext context;
19588
19589   Local<String> password = v8_str("Password");
19590   // Don't get hit by security checks when accessing foreign_context's
19591   // global receiver (aka. global proxy).
19592   context->SetSecurityToken(password);
19593   foreign_context->SetSecurityToken(password);
19594
19595   Local<String> i = v8_str("i");
19596   Local<String> o = v8_str("o");
19597   Local<String> id = v8_str("id");
19598
19599   CompileRun("function ownfunc() { return { 0: this.id, "
19600              "                              1: this, "
19601              "                              toString: function() { "
19602              "                                  return this[0];"
19603              "                              }"
19604              "                             };"
19605              "}"
19606              "var id = 'o';"
19607              "ownfunc");
19608   context->Global()->Set(v8_str("func"), foreign_function);
19609
19610   // Sanity check the contexts.
19611   CHECK(i->Equals(foreign_context->Global()->Get(id)));
19612   CHECK(o->Equals(context->Global()->Get(id)));
19613
19614   // Checking local function's receiver.
19615   // Calling function using its call/apply methods.
19616   TestReceiver(o, context->Global(), "ownfunc.call()");
19617   TestReceiver(o, context->Global(), "ownfunc.apply()");
19618   // Making calls through built-in functions.
19619   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
19620   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
19621   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
19622   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
19623   // Calling with environment record as base.
19624   TestReceiver(o, context->Global(), "ownfunc()");
19625   // Calling with no base.
19626   TestReceiver(o, context->Global(), "(1,ownfunc)()");
19627
19628   // Checking foreign function return value.
19629   // Calling function using its call/apply methods.
19630   TestReceiver(i, foreign_context->Global(), "func.call()");
19631   TestReceiver(i, foreign_context->Global(), "func.apply()");
19632   // Calling function using another context's call/apply methods.
19633   TestReceiver(i, foreign_context->Global(),
19634                "Function.prototype.call.call(func)");
19635   TestReceiver(i, foreign_context->Global(),
19636                "Function.prototype.call.apply(func)");
19637   TestReceiver(i, foreign_context->Global(),
19638                "Function.prototype.apply.call(func)");
19639   TestReceiver(i, foreign_context->Global(),
19640                "Function.prototype.apply.apply(func)");
19641   // Making calls through built-in functions.
19642   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
19643   // ToString(func()) is func()[0], i.e., the returned this.id.
19644   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
19645   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
19646   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
19647
19648   // TODO(1547): Make the following also return "i".
19649   // Calling with environment record as base.
19650   TestReceiver(o, context->Global(), "func()");
19651   // Calling with no base.
19652   TestReceiver(o, context->Global(), "(1,func)()");
19653 }
19654
19655
19656 uint8_t callback_fired = 0;
19657
19658
19659 void CallCompletedCallback1() {
19660   i::OS::Print("Firing callback 1.\n");
19661   callback_fired ^= 1;  // Toggle first bit.
19662 }
19663
19664
19665 void CallCompletedCallback2() {
19666   i::OS::Print("Firing callback 2.\n");
19667   callback_fired ^= 2;  // Toggle second bit.
19668 }
19669
19670
19671 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
19672   int32_t level = args[0]->Int32Value();
19673   if (level < 3) {
19674     level++;
19675     i::OS::Print("Entering recursion level %d.\n", level);
19676     char script[64];
19677     i::Vector<char> script_vector(script, sizeof(script));
19678     i::OS::SNPrintF(script_vector, "recursion(%d)", level);
19679     CompileRun(script_vector.start());
19680     i::OS::Print("Leaving recursion level %d.\n", level);
19681     CHECK_EQ(0, callback_fired);
19682   } else {
19683     i::OS::Print("Recursion ends.\n");
19684     CHECK_EQ(0, callback_fired);
19685   }
19686 }
19687
19688
19689 TEST(CallCompletedCallback) {
19690   LocalContext env;
19691   v8::HandleScope scope(env->GetIsolate());
19692   v8::Handle<v8::FunctionTemplate> recursive_runtime =
19693       v8::FunctionTemplate::New(RecursiveCall);
19694   env->Global()->Set(v8_str("recursion"),
19695                      recursive_runtime->GetFunction());
19696   // Adding the same callback a second time has no effect.
19697   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19698   v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19699   v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
19700   i::OS::Print("--- Script (1) ---\n");
19701   Local<Script> script =
19702       v8::Script::Compile(v8::String::New("recursion(0)"));
19703   script->Run();
19704   CHECK_EQ(3, callback_fired);
19705
19706   i::OS::Print("\n--- Script (2) ---\n");
19707   callback_fired = 0;
19708   v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
19709   script->Run();
19710   CHECK_EQ(2, callback_fired);
19711
19712   i::OS::Print("\n--- Function ---\n");
19713   callback_fired = 0;
19714   Local<Function> recursive_function =
19715       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
19716   v8::Handle<Value> args[] = { v8_num(0) };
19717   recursive_function->Call(env->Global(), 1, args);
19718   CHECK_EQ(2, callback_fired);
19719 }
19720
19721
19722 void CallCompletedCallbackNoException() {
19723   v8::HandleScope scope(CcTest::isolate());
19724   CompileRun("1+1;");
19725 }
19726
19727
19728 void CallCompletedCallbackException() {
19729   v8::HandleScope scope(CcTest::isolate());
19730   CompileRun("throw 'second exception';");
19731 }
19732
19733
19734 TEST(CallCompletedCallbackOneException) {
19735   LocalContext env;
19736   v8::HandleScope scope(env->GetIsolate());
19737   v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
19738   CompileRun("throw 'exception';");
19739 }
19740
19741
19742 TEST(CallCompletedCallbackTwoExceptions) {
19743   LocalContext env;
19744   v8::HandleScope scope(env->GetIsolate());
19745   v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
19746   CompileRun("throw 'first exception';");
19747 }
19748
19749
19750 static int probes_counter = 0;
19751 static int misses_counter = 0;
19752 static int updates_counter = 0;
19753
19754
19755 static int* LookupCounter(const char* name) {
19756   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19757     return &probes_counter;
19758   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19759     return &misses_counter;
19760   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19761     return &updates_counter;
19762   }
19763   return NULL;
19764 }
19765
19766
19767 static const char* kMegamorphicTestProgram =
19768     "function ClassA() { };"
19769     "function ClassB() { };"
19770     "ClassA.prototype.foo = function() { };"
19771     "ClassB.prototype.foo = function() { };"
19772     "function fooify(obj) { obj.foo(); };"
19773     "var a = new ClassA();"
19774     "var b = new ClassB();"
19775     "for (var i = 0; i < 10000; i++) {"
19776     "  fooify(a);"
19777     "  fooify(b);"
19778     "}";
19779
19780
19781 static void StubCacheHelper(bool primary) {
19782   V8::SetCounterFunction(LookupCounter);
19783   USE(kMegamorphicTestProgram);
19784 #ifdef DEBUG
19785   i::FLAG_native_code_counters = true;
19786   if (primary) {
19787     i::FLAG_test_primary_stub_cache = true;
19788   } else {
19789     i::FLAG_test_secondary_stub_cache = true;
19790   }
19791   i::FLAG_crankshaft = false;
19792   LocalContext env;
19793   v8::HandleScope scope(env->GetIsolate());
19794   int initial_probes = probes_counter;
19795   int initial_misses = misses_counter;
19796   int initial_updates = updates_counter;
19797   CompileRun(kMegamorphicTestProgram);
19798   int probes = probes_counter - initial_probes;
19799   int misses = misses_counter - initial_misses;
19800   int updates = updates_counter - initial_updates;
19801   CHECK_LT(updates, 10);
19802   CHECK_LT(misses, 10);
19803   CHECK_GE(probes, 10000);
19804 #endif
19805 }
19806
19807
19808 TEST(SecondaryStubCache) {
19809   StubCacheHelper(true);
19810 }
19811
19812
19813 TEST(PrimaryStubCache) {
19814   StubCacheHelper(false);
19815 }
19816
19817
19818 TEST(StaticGetters) {
19819   LocalContext context;
19820   i::Factory* factory = CcTest::i_isolate()->factory();
19821   v8::Isolate* isolate = CcTest::isolate();
19822   v8::HandleScope scope(isolate);
19823   i::Handle<i::Object> undefined_value = factory->undefined_value();
19824   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19825   i::Handle<i::Object> null_value = factory->null_value();
19826   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19827   i::Handle<i::Object> true_value = factory->true_value();
19828   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19829   i::Handle<i::Object> false_value = factory->false_value();
19830   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19831 }
19832
19833
19834 UNINITIALIZED_TEST(IsolateEmbedderData) {
19835   CcTest::DisableAutomaticDispose();
19836   v8::Isolate* isolate = v8::Isolate::New();
19837   isolate->Enter();
19838   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19839   CHECK_EQ(NULL, isolate->GetData());
19840   CHECK_EQ(NULL, i_isolate->GetData());
19841   static void* data1 = reinterpret_cast<void*>(0xacce55ed);
19842   isolate->SetData(data1);
19843   CHECK_EQ(data1, isolate->GetData());
19844   CHECK_EQ(data1, i_isolate->GetData());
19845   static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
19846   i_isolate->SetData(data2);
19847   CHECK_EQ(data2, isolate->GetData());
19848   CHECK_EQ(data2, i_isolate->GetData());
19849   isolate->Exit();
19850   isolate->Dispose();
19851 }
19852
19853
19854 TEST(StringEmpty) {
19855   LocalContext context;
19856   i::Factory* factory = CcTest::i_isolate()->factory();
19857   v8::Isolate* isolate = CcTest::isolate();
19858   v8::HandleScope scope(isolate);
19859   i::Handle<i::Object> empty_string = factory->empty_string();
19860   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
19861   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19862 }
19863
19864
19865 static int instance_checked_getter_count = 0;
19866 static void InstanceCheckedGetter(
19867     Local<String> name,
19868     const v8::PropertyCallbackInfo<v8::Value>& info) {
19869   CHECK_EQ(name, v8_str("foo"));
19870   instance_checked_getter_count++;
19871   info.GetReturnValue().Set(v8_num(11));
19872 }
19873
19874
19875 static int instance_checked_setter_count = 0;
19876 static void InstanceCheckedSetter(Local<String> name,
19877                       Local<Value> value,
19878                       const v8::PropertyCallbackInfo<void>& info) {
19879   CHECK_EQ(name, v8_str("foo"));
19880   CHECK_EQ(value, v8_num(23));
19881   instance_checked_setter_count++;
19882 }
19883
19884
19885 static void CheckInstanceCheckedResult(int getters,
19886                                        int setters,
19887                                        bool expects_callbacks,
19888                                        TryCatch* try_catch) {
19889   if (expects_callbacks) {
19890     CHECK(!try_catch->HasCaught());
19891     CHECK_EQ(getters, instance_checked_getter_count);
19892     CHECK_EQ(setters, instance_checked_setter_count);
19893   } else {
19894     CHECK(try_catch->HasCaught());
19895     CHECK_EQ(0, instance_checked_getter_count);
19896     CHECK_EQ(0, instance_checked_setter_count);
19897   }
19898   try_catch->Reset();
19899 }
19900
19901
19902 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19903   instance_checked_getter_count = 0;
19904   instance_checked_setter_count = 0;
19905   TryCatch try_catch;
19906
19907   // Test path through generic runtime code.
19908   CompileRun("obj.foo");
19909   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19910   CompileRun("obj.foo = 23");
19911   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19912
19913   // Test path through generated LoadIC and StoredIC.
19914   CompileRun("function test_get(o) { o.foo; }"
19915              "test_get(obj);");
19916   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19917   CompileRun("test_get(obj);");
19918   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19919   CompileRun("test_get(obj);");
19920   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19921   CompileRun("function test_set(o) { o.foo = 23; }"
19922              "test_set(obj);");
19923   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19924   CompileRun("test_set(obj);");
19925   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19926   CompileRun("test_set(obj);");
19927   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19928
19929   // Test path through optimized code.
19930   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19931              "test_get(obj);");
19932   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19933   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19934              "test_set(obj);");
19935   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19936
19937   // Cleanup so that closures start out fresh in next check.
19938   CompileRun("%DeoptimizeFunction(test_get);"
19939              "%ClearFunctionTypeFeedback(test_get);"
19940              "%DeoptimizeFunction(test_set);"
19941              "%ClearFunctionTypeFeedback(test_set);");
19942 }
19943
19944
19945 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19946   v8::internal::FLAG_allow_natives_syntax = true;
19947   LocalContext context;
19948   v8::HandleScope scope(context->GetIsolate());
19949
19950   Local<FunctionTemplate> templ = FunctionTemplate::New();
19951   Local<ObjectTemplate> inst = templ->InstanceTemplate();
19952   inst->SetAccessor(v8_str("foo"),
19953                     InstanceCheckedGetter, InstanceCheckedSetter,
19954                     Handle<Value>(),
19955                     v8::DEFAULT,
19956                     v8::None,
19957                     v8::AccessorSignature::New(templ));
19958   context->Global()->Set(v8_str("f"), templ->GetFunction());
19959
19960   printf("Testing positive ...\n");
19961   CompileRun("var obj = new f();");
19962   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19963   CheckInstanceCheckedAccessors(true);
19964
19965   printf("Testing negative ...\n");
19966   CompileRun("var obj = {};"
19967              "obj.__proto__ = new f();");
19968   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19969   CheckInstanceCheckedAccessors(false);
19970 }
19971
19972
19973 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19974   v8::internal::FLAG_allow_natives_syntax = true;
19975   LocalContext context;
19976   v8::HandleScope scope(context->GetIsolate());
19977
19978   Local<FunctionTemplate> templ = FunctionTemplate::New();
19979   Local<ObjectTemplate> inst = templ->InstanceTemplate();
19980   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19981   inst->SetAccessor(v8_str("foo"),
19982                     InstanceCheckedGetter, InstanceCheckedSetter,
19983                     Handle<Value>(),
19984                     v8::DEFAULT,
19985                     v8::None,
19986                     v8::AccessorSignature::New(templ));
19987   context->Global()->Set(v8_str("f"), templ->GetFunction());
19988
19989   printf("Testing positive ...\n");
19990   CompileRun("var obj = new f();");
19991   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19992   CheckInstanceCheckedAccessors(true);
19993
19994   printf("Testing negative ...\n");
19995   CompileRun("var obj = {};"
19996              "obj.__proto__ = new f();");
19997   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19998   CheckInstanceCheckedAccessors(false);
19999 }
20000
20001
20002 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
20003   v8::internal::FLAG_allow_natives_syntax = true;
20004   LocalContext context;
20005   v8::HandleScope scope(context->GetIsolate());
20006
20007   Local<FunctionTemplate> templ = FunctionTemplate::New();
20008   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
20009   proto->SetAccessor(v8_str("foo"),
20010                      InstanceCheckedGetter, InstanceCheckedSetter,
20011                      Handle<Value>(),
20012                      v8::DEFAULT,
20013                      v8::None,
20014                      v8::AccessorSignature::New(templ));
20015   context->Global()->Set(v8_str("f"), templ->GetFunction());
20016
20017   printf("Testing positive ...\n");
20018   CompileRun("var obj = new f();");
20019   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20020   CheckInstanceCheckedAccessors(true);
20021
20022   printf("Testing negative ...\n");
20023   CompileRun("var obj = {};"
20024              "obj.__proto__ = new f();");
20025   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20026   CheckInstanceCheckedAccessors(false);
20027
20028   printf("Testing positive with modified prototype chain ...\n");
20029   CompileRun("var obj = new f();"
20030              "var pro = {};"
20031              "pro.__proto__ = obj.__proto__;"
20032              "obj.__proto__ = pro;");
20033   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
20034   CheckInstanceCheckedAccessors(true);
20035 }
20036
20037
20038 TEST(TryFinallyMessage) {
20039   LocalContext context;
20040   v8::HandleScope scope(context->GetIsolate());
20041   {
20042     // Test that the original error message is not lost if there is a
20043     // recursive call into Javascript is done in the finally block, e.g. to
20044     // initialize an IC. (crbug.com/129171)
20045     TryCatch try_catch;
20046     const char* trigger_ic =
20047         "try {                      \n"
20048         "  throw new Error('test'); \n"
20049         "} finally {                \n"
20050         "  var x = 0;               \n"
20051         "  x++;                     \n"  // Trigger an IC initialization here.
20052         "}                          \n";
20053     CompileRun(trigger_ic);
20054     CHECK(try_catch.HasCaught());
20055     Local<Message> message = try_catch.Message();
20056     CHECK(!message.IsEmpty());
20057     CHECK_EQ(2, message->GetLineNumber());
20058   }
20059
20060   {
20061     // Test that the original exception message is indeed overwritten if
20062     // a new error is thrown in the finally block.
20063     TryCatch try_catch;
20064     const char* throw_again =
20065         "try {                       \n"
20066         "  throw new Error('test');  \n"
20067         "} finally {                 \n"
20068         "  var x = 0;                \n"
20069         "  x++;                      \n"
20070         "  throw new Error('again'); \n"  // This is the new uncaught error.
20071         "}                           \n";
20072     CompileRun(throw_again);
20073     CHECK(try_catch.HasCaught());
20074     Local<Message> message = try_catch.Message();
20075     CHECK(!message.IsEmpty());
20076     CHECK_EQ(6, message->GetLineNumber());
20077   }
20078 }
20079
20080
20081 static void Helper137002(bool do_store,
20082                          bool polymorphic,
20083                          bool remove_accessor,
20084                          bool interceptor) {
20085   LocalContext context;
20086   Local<ObjectTemplate> templ = ObjectTemplate::New();
20087   if (interceptor) {
20088     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
20089   } else {
20090     templ->SetAccessor(v8_str("foo"),
20091                        GetterWhichReturns42,
20092                        SetterWhichSetsYOnThisTo23);
20093   }
20094   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20095
20096   // Turn monomorphic on slow object with native accessor, then turn
20097   // polymorphic, finally optimize to create negative lookup and fail.
20098   CompileRun(do_store ?
20099              "function f(x) { x.foo = void 0; }" :
20100              "function f(x) { return x.foo; }");
20101   CompileRun("obj.y = void 0;");
20102   if (!interceptor) {
20103     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
20104   }
20105   CompileRun("obj.__proto__ = null;"
20106              "f(obj); f(obj); f(obj);");
20107   if (polymorphic) {
20108     CompileRun("f({});");
20109   }
20110   CompileRun("obj.y = void 0;"
20111              "%OptimizeFunctionOnNextCall(f);");
20112   if (remove_accessor) {
20113     CompileRun("delete obj.foo;");
20114   }
20115   CompileRun("var result = f(obj);");
20116   if (do_store) {
20117     CompileRun("result = obj.y;");
20118   }
20119   if (remove_accessor && !interceptor) {
20120     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
20121   } else {
20122     CHECK_EQ(do_store ? 23 : 42,
20123              context->Global()->Get(v8_str("result"))->Int32Value());
20124   }
20125 }
20126
20127
20128 THREADED_TEST(Regress137002a) {
20129   i::FLAG_allow_natives_syntax = true;
20130   i::FLAG_compilation_cache = false;
20131   v8::HandleScope scope(CcTest::isolate());
20132   for (int i = 0; i < 16; i++) {
20133     Helper137002(i & 8, i & 4, i & 2, i & 1);
20134   }
20135 }
20136
20137
20138 THREADED_TEST(Regress137002b) {
20139   i::FLAG_allow_natives_syntax = true;
20140   LocalContext context;
20141   v8::HandleScope scope(context->GetIsolate());
20142   Local<ObjectTemplate> templ = ObjectTemplate::New();
20143   templ->SetAccessor(v8_str("foo"),
20144                      GetterWhichReturns42,
20145                      SetterWhichSetsYOnThisTo23);
20146   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20147
20148   // Turn monomorphic on slow object with native accessor, then just
20149   // delete the property and fail.
20150   CompileRun("function load(x) { return x.foo; }"
20151              "function store(x) { x.foo = void 0; }"
20152              "function keyed_load(x, key) { return x[key]; }"
20153              // Second version of function has a different source (add void 0)
20154              // so that it does not share code with the first version.  This
20155              // ensures that the ICs are monomorphic.
20156              "function load2(x) { void 0; return x.foo; }"
20157              "function store2(x) { void 0; x.foo = void 0; }"
20158              "function keyed_load2(x, key) { void 0; return x[key]; }"
20159
20160              "obj.y = void 0;"
20161              "obj.__proto__ = null;"
20162              "var subobj = {};"
20163              "subobj.y = void 0;"
20164              "subobj.__proto__ = obj;"
20165              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20166
20167              // Make the ICs monomorphic.
20168              "load(obj); load(obj);"
20169              "load2(subobj); load2(subobj);"
20170              "store(obj); store(obj);"
20171              "store2(subobj); store2(subobj);"
20172              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
20173              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
20174
20175              // Actually test the shiny new ICs and better not crash. This
20176              // serves as a regression test for issue 142088 as well.
20177              "load(obj);"
20178              "load2(subobj);"
20179              "store(obj);"
20180              "store2(subobj);"
20181              "keyed_load(obj, 'foo');"
20182              "keyed_load2(subobj, 'foo');"
20183
20184              // Delete the accessor.  It better not be called any more now.
20185              "delete obj.foo;"
20186              "obj.y = void 0;"
20187              "subobj.y = void 0;"
20188
20189              "var load_result = load(obj);"
20190              "var load_result2 = load2(subobj);"
20191              "var keyed_load_result = keyed_load(obj, 'foo');"
20192              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
20193              "store(obj);"
20194              "store2(subobj);"
20195              "var y_from_obj = obj.y;"
20196              "var y_from_subobj = subobj.y;");
20197   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
20198   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
20199   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
20200   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
20201   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
20202   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
20203 }
20204
20205
20206 THREADED_TEST(Regress142088) {
20207   i::FLAG_allow_natives_syntax = true;
20208   LocalContext context;
20209   v8::HandleScope scope(context->GetIsolate());
20210   Local<ObjectTemplate> templ = ObjectTemplate::New();
20211   templ->SetAccessor(v8_str("foo"),
20212                      GetterWhichReturns42,
20213                      SetterWhichSetsYOnThisTo23);
20214   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20215
20216   CompileRun("function load(x) { return x.foo; }"
20217              "var o = Object.create(obj);"
20218              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
20219              "load(o); load(o); load(o); load(o);");
20220 }
20221
20222
20223 THREADED_TEST(Regress137496) {
20224   i::FLAG_expose_gc = true;
20225   LocalContext context;
20226   v8::HandleScope scope(context->GetIsolate());
20227
20228   // Compile a try-finally clause where the finally block causes a GC
20229   // while there still is a message pending for external reporting.
20230   TryCatch try_catch;
20231   try_catch.SetVerbose(true);
20232   CompileRun("try { throw new Error(); } finally { gc(); }");
20233   CHECK(try_catch.HasCaught());
20234 }
20235
20236
20237 THREADED_TEST(Regress149912) {
20238   LocalContext context;
20239   v8::HandleScope scope(context->GetIsolate());
20240   Handle<FunctionTemplate> templ = FunctionTemplate::New();
20241   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20242   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
20243   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
20244 }
20245
20246
20247 THREADED_TEST(Regress157124) {
20248   LocalContext context;
20249   v8::HandleScope scope(context->GetIsolate());
20250   Local<ObjectTemplate> templ = ObjectTemplate::New();
20251   Local<Object> obj = templ->NewInstance();
20252   obj->GetIdentityHash();
20253   obj->DeleteHiddenValue(v8_str("Bug"));
20254 }
20255
20256
20257 THREADED_TEST(Regress2535) {
20258   i::FLAG_harmony_collections = true;
20259   LocalContext context;
20260   v8::HandleScope scope(context->GetIsolate());
20261   Local<Value> set_value = CompileRun("new Set();");
20262   Local<Object> set_object(Local<Object>::Cast(set_value));
20263   CHECK_EQ(0, set_object->InternalFieldCount());
20264   Local<Value> map_value = CompileRun("new Map();");
20265   Local<Object> map_object(Local<Object>::Cast(map_value));
20266   CHECK_EQ(0, map_object->InternalFieldCount());
20267 }
20268
20269
20270 THREADED_TEST(Regress2746) {
20271   LocalContext context;
20272   v8::Isolate* isolate = context->GetIsolate();
20273   v8::HandleScope scope(isolate);
20274   Local<Object> obj = Object::New();
20275   Local<String> key = String::New("key");
20276   obj->SetHiddenValue(key, v8::Undefined(isolate));
20277   Local<Value> value = obj->GetHiddenValue(key);
20278   CHECK(!value.IsEmpty());
20279   CHECK(value->IsUndefined());
20280 }
20281
20282
20283 THREADED_TEST(Regress260106) {
20284   LocalContext context;
20285   v8::HandleScope scope(context->GetIsolate());
20286   Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler);
20287   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
20288   Local<Function> function = templ->GetFunction();
20289   CHECK(!function.IsEmpty());
20290   CHECK(function->IsFunction());
20291 }
20292
20293
20294 THREADED_TEST(JSONParseObject) {
20295   LocalContext context;
20296   HandleScope scope(context->GetIsolate());
20297   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
20298   Handle<Object> global = context->Global();
20299   global->Set(v8_str("obj"), obj);
20300   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
20301 }
20302
20303
20304 THREADED_TEST(JSONParseNumber) {
20305   LocalContext context;
20306   HandleScope scope(context->GetIsolate());
20307   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
20308   Handle<Object> global = context->Global();
20309   global->Set(v8_str("obj"), obj);
20310   ExpectString("JSON.stringify(obj)", "42");
20311 }
20312
20313
20314 #if V8_OS_POSIX
20315 class ThreadInterruptTest {
20316  public:
20317   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
20318   ~ThreadInterruptTest() {}
20319
20320   void RunTest() {
20321     InterruptThread i_thread(this);
20322     i_thread.Start();
20323
20324     sem_.Wait();
20325     CHECK_EQ(kExpectedValue, sem_value_);
20326   }
20327
20328  private:
20329   static const int kExpectedValue = 1;
20330
20331   class InterruptThread : public i::Thread {
20332    public:
20333     explicit InterruptThread(ThreadInterruptTest* test)
20334         : Thread("InterruptThread"), test_(test) {}
20335
20336     virtual void Run() {
20337       struct sigaction action;
20338
20339       // Ensure that we'll enter waiting condition
20340       i::OS::Sleep(100);
20341
20342       // Setup signal handler
20343       memset(&action, 0, sizeof(action));
20344       action.sa_handler = SignalHandler;
20345       sigaction(SIGCHLD, &action, NULL);
20346
20347       // Send signal
20348       kill(getpid(), SIGCHLD);
20349
20350       // Ensure that if wait has returned because of error
20351       i::OS::Sleep(100);
20352
20353       // Set value and signal semaphore
20354       test_->sem_value_ = 1;
20355       test_->sem_.Signal();
20356     }
20357
20358     static void SignalHandler(int signal) {
20359     }
20360
20361    private:
20362      ThreadInterruptTest* test_;
20363   };
20364
20365   i::Semaphore sem_;
20366   volatile int sem_value_;
20367 };
20368
20369
20370 THREADED_TEST(SemaphoreInterruption) {
20371   ThreadInterruptTest().RunTest();
20372 }
20373
20374
20375 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
20376                                      Local<Value> name,
20377                                      v8::AccessType type,
20378                                      Local<Value> data) {
20379   i::PrintF("Named access blocked.\n");
20380   return false;
20381 }
20382
20383
20384 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
20385                                      uint32_t key,
20386                                      v8::AccessType type,
20387                                      Local<Value> data) {
20388   i::PrintF("Indexed access blocked.\n");
20389   return false;
20390 }
20391
20392
20393 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20394   CHECK(false);
20395 }
20396
20397
20398 TEST(JSONStringifyAccessCheck) {
20399   v8::V8::Initialize();
20400   v8::HandleScope scope(CcTest::isolate());
20401
20402   // Create an ObjectTemplate for global objects and install access
20403   // check callbacks that will block access.
20404   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
20405   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
20406                                            IndexAccessAlwaysBlocked);
20407
20408   // Create a context and set an x property on it's global object.
20409   LocalContext context0(NULL, global_template);
20410   v8::Handle<v8::Object> global0 = context0->Global();
20411   global0->Set(v8_str("x"), v8_num(42));
20412   ExpectString("JSON.stringify(this)", "{\"x\":42}");
20413
20414   for (int i = 0; i < 2; i++) {
20415     if (i == 1) {
20416       // Install a toJSON function on the second run.
20417       v8::Handle<v8::FunctionTemplate> toJSON =
20418           v8::FunctionTemplate::New(UnreachableCallback);
20419
20420       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
20421     }
20422     // Create a context with a different security token so that the
20423     // failed access check callback will be called on each access.
20424     LocalContext context1(NULL, global_template);
20425     context1->Global()->Set(v8_str("other"), global0);
20426
20427     ExpectString("JSON.stringify(other)", "{}");
20428     ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
20429                  "{\"a\":{},\"b\":[\"c\"]}");
20430     ExpectString("JSON.stringify([other, 'b', 'c'])",
20431                  "[{},\"b\",\"c\"]");
20432
20433     v8::Handle<v8::Array> array = v8::Array::New(2);
20434     array->Set(0, v8_str("a"));
20435     array->Set(1, v8_str("b"));
20436     context1->Global()->Set(v8_str("array"), array);
20437     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
20438     array->TurnOnAccessCheck();
20439     ExpectString("JSON.stringify(array)", "[]");
20440     ExpectString("JSON.stringify([array])", "[[]]");
20441     ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
20442   }
20443 }
20444
20445
20446 bool access_check_fail_thrown = false;
20447 bool catch_callback_called = false;
20448
20449
20450 // Failed access check callback that performs a GC on each invocation.
20451 void FailedAccessCheckThrows(Local<v8::Object> target,
20452                              v8::AccessType type,
20453                              Local<v8::Value> data) {
20454   access_check_fail_thrown = true;
20455   i::PrintF("Access check failed. Error thrown.\n");
20456   CcTest::isolate()->ThrowException(
20457       v8::Exception::Error(v8_str("cross context")));
20458 }
20459
20460
20461 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20462   for (int i = 0; i < args.Length(); i++) {
20463     i::PrintF("%s\n", *String::Utf8Value(args[i]));
20464   }
20465   catch_callback_called = true;
20466 }
20467
20468
20469 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
20470   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
20471 }
20472
20473
20474 void CheckCorrectThrow(const char* script) {
20475   // Test that the script, when wrapped into a try-catch, triggers the catch
20476   // clause due to failed access check throwing an exception.
20477   // The subsequent try-catch should run without any exception.
20478   access_check_fail_thrown = false;
20479   catch_callback_called = false;
20480   i::ScopedVector<char> source(1024);
20481   i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
20482   CompileRun(source.start());
20483   CHECK(access_check_fail_thrown);
20484   CHECK(catch_callback_called);
20485
20486   access_check_fail_thrown = false;
20487   catch_callback_called = false;
20488   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
20489   CHECK(!access_check_fail_thrown);
20490   CHECK(!catch_callback_called);
20491 }
20492
20493
20494 TEST(AccessCheckThrows) {
20495   i::FLAG_allow_natives_syntax = true;
20496   v8::V8::Initialize();
20497   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
20498   v8::HandleScope scope(CcTest::isolate());
20499
20500   // Create an ObjectTemplate for global objects and install access
20501   // check callbacks that will block access.
20502   v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
20503   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
20504                                            IndexAccessAlwaysBlocked);
20505
20506   // Create a context and set an x property on it's global object.
20507   LocalContext context0(NULL, global_template);
20508   context0->Global()->Set(v8_str("x"), v8_num(42));
20509   v8::Handle<v8::Object> global0 = context0->Global();
20510
20511   // Create a context with a different security token so that the
20512   // failed access check callback will be called on each access.
20513   LocalContext context1(NULL, global_template);
20514   context1->Global()->Set(v8_str("other"), global0);
20515
20516   v8::Handle<v8::FunctionTemplate> catcher_fun =
20517       v8::FunctionTemplate::New(CatcherCallback);
20518   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
20519
20520   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
20521       v8::FunctionTemplate::New(HasOwnPropertyCallback);
20522   context1->Global()->Set(v8_str("has_own_property"),
20523                           has_own_property_fun->GetFunction());
20524
20525   { v8::TryCatch try_catch;
20526     access_check_fail_thrown = false;
20527     CompileRun("other.x;");
20528     CHECK(access_check_fail_thrown);
20529     CHECK(try_catch.HasCaught());
20530   }
20531
20532   CheckCorrectThrow("other.x");
20533   CheckCorrectThrow("other[1]");
20534   CheckCorrectThrow("JSON.stringify(other)");
20535   CheckCorrectThrow("has_own_property(other, 'x')");
20536   CheckCorrectThrow("%GetProperty(other, 'x')");
20537   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
20538   CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
20539   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
20540   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
20541   CheckCorrectThrow("%HasLocalProperty(other, 'x')");
20542   CheckCorrectThrow("%HasProperty(other, 'x')");
20543   CheckCorrectThrow("%HasElement(other, 1)");
20544   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
20545   CheckCorrectThrow("%GetPropertyNames(other)");
20546   CheckCorrectThrow("%GetLocalPropertyNames(other, true)");
20547   CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
20548                         "other, 'x', null, null, 1)");
20549
20550   // Reset the failed access check callback so it does not influence
20551   // the other tests.
20552   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20553 }
20554
20555
20556 THREADED_TEST(Regress256330) {
20557   i::FLAG_allow_natives_syntax = true;
20558   LocalContext context;
20559   v8::HandleScope scope(context->GetIsolate());
20560   Handle<FunctionTemplate> templ = FunctionTemplate::New();
20561   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
20562   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
20563   CompileRun("\"use strict\"; var o = new Bug;"
20564              "function f(o) { o.x = 10; };"
20565              "f(o); f(o); f(o);"
20566              "%OptimizeFunctionOnNextCall(f);"
20567              "f(o);");
20568   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
20569 }
20570
20571
20572 THREADED_TEST(CrankshaftInterceptorSetter) {
20573   i::FLAG_allow_natives_syntax = true;
20574   v8::HandleScope scope(CcTest::isolate());
20575   Handle<FunctionTemplate> templ = FunctionTemplate::New();
20576   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20577   LocalContext env;
20578   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20579   CompileRun("var obj = new Obj;"
20580              // Initialize fields to avoid transitions later.
20581              "obj.age = 0;"
20582              "obj.accessor_age = 42;"
20583              "function setter(i) { this.accessor_age = i; };"
20584              "function getter() { return this.accessor_age; };"
20585              "function setAge(i) { obj.age = i; };"
20586              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
20587              "setAge(1);"
20588              "setAge(2);"
20589              "setAge(3);"
20590              "%OptimizeFunctionOnNextCall(setAge);"
20591              "setAge(4);");
20592   // All stores went through the interceptor.
20593   ExpectInt32("obj.interceptor_age", 4);
20594   ExpectInt32("obj.accessor_age", 42);
20595 }
20596
20597
20598 THREADED_TEST(CrankshaftInterceptorGetter) {
20599   i::FLAG_allow_natives_syntax = true;
20600   v8::HandleScope scope(CcTest::isolate());
20601   Handle<FunctionTemplate> templ = FunctionTemplate::New();
20602   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20603   LocalContext env;
20604   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20605   CompileRun("var obj = new Obj;"
20606              // Initialize fields to avoid transitions later.
20607              "obj.age = 1;"
20608              "obj.accessor_age = 42;"
20609              "function getter() { return this.accessor_age; };"
20610              "function getAge() { return obj.interceptor_age; };"
20611              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
20612              "getAge();"
20613              "getAge();"
20614              "getAge();"
20615              "%OptimizeFunctionOnNextCall(getAge);");
20616   // Access through interceptor.
20617   ExpectInt32("getAge()", 1);
20618 }
20619
20620
20621 THREADED_TEST(CrankshaftInterceptorFieldRead) {
20622   i::FLAG_allow_natives_syntax = true;
20623   v8::HandleScope scope(CcTest::isolate());
20624   Handle<FunctionTemplate> templ = FunctionTemplate::New();
20625   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20626   LocalContext env;
20627   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20628   CompileRun("var obj = new Obj;"
20629              "obj.__proto__.interceptor_age = 42;"
20630              "obj.age = 100;"
20631              "function getAge() { return obj.interceptor_age; };");
20632   ExpectInt32("getAge();", 100);
20633   ExpectInt32("getAge();", 100);
20634   ExpectInt32("getAge();", 100);
20635   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
20636   // Access through interceptor.
20637   ExpectInt32("getAge();", 100);
20638 }
20639
20640
20641 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
20642   i::FLAG_allow_natives_syntax = true;
20643   v8::HandleScope scope(CcTest::isolate());
20644   Handle<FunctionTemplate> templ = FunctionTemplate::New();
20645   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
20646   LocalContext env;
20647   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
20648   CompileRun("var obj = new Obj;"
20649              "obj.age = 100000;"
20650              "function setAge(i) { obj.age = i };"
20651              "setAge(100);"
20652              "setAge(101);"
20653              "setAge(102);"
20654              "%OptimizeFunctionOnNextCall(setAge);"
20655              "setAge(103);");
20656   ExpectInt32("obj.age", 100000);
20657   ExpectInt32("obj.interceptor_age", 103);
20658 }
20659
20660
20661 #endif  // V8_OS_POSIX
20662
20663
20664 static Local<Value> function_new_expected_env;
20665 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
20666   CHECK_EQ(function_new_expected_env, info.Data());
20667   info.GetReturnValue().Set(17);
20668 }
20669
20670
20671 THREADED_TEST(FunctionNew) {
20672   LocalContext env;
20673   v8::Isolate* isolate = env->GetIsolate();
20674   v8::HandleScope scope(isolate);
20675   Local<Object> data = v8::Object::New();
20676   function_new_expected_env = data;
20677   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
20678   env->Global()->Set(v8_str("func"), func);
20679   Local<Value> result = CompileRun("func();");
20680   CHECK_EQ(v8::Integer::New(17, isolate), result);
20681   // Verify function not cached
20682   int serial_number =
20683       i::Smi::cast(v8::Utils::OpenHandle(*func)
20684           ->shared()->get_api_func_data()->serial_number())->value();
20685   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20686   i::Object* elm = i_isolate->native_context()->function_cache()
20687       ->GetElementNoExceptionThrown(i_isolate, serial_number);
20688   CHECK(elm->IsUndefined());
20689   // Verify that each Function::New creates a new function instance
20690   Local<Object> data2 = v8::Object::New();
20691   function_new_expected_env = data2;
20692   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
20693   CHECK(!func2->IsNull());
20694   CHECK_NE(func, func2);
20695   env->Global()->Set(v8_str("func2"), func2);
20696   Local<Value> result2 = CompileRun("func2();");
20697   CHECK_EQ(v8::Integer::New(17, isolate), result2);
20698 }
20699
20700
20701 TEST(EscapeableHandleScope) {
20702   HandleScope outer_scope(CcTest::isolate());
20703   LocalContext context;
20704   const int runs = 10;
20705   Local<String> values[runs];
20706   for (int i = 0; i < runs; i++) {
20707     v8::EscapableHandleScope inner_scope(CcTest::isolate());
20708     Local<String> value;
20709     if (i != 0) value = v8_str("escape value");
20710     values[i] = inner_scope.Escape(value);
20711   }
20712   for (int i = 0; i < runs; i++) {
20713     Local<String> expected;
20714     if (i != 0) {
20715       CHECK_EQ(v8_str("escape value"), values[i]);
20716     } else {
20717       CHECK(values[i].IsEmpty());
20718     }
20719   }
20720 }