deps: upgrade v8 to 3.31.74.1
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <map>
31 #include <string>
32
33 #include "src/v8.h"
34
35 #if V8_OS_POSIX
36 #include <unistd.h>  // NOLINT
37 #endif
38
39 #include "include/v8-util.h"
40 #include "src/api.h"
41 #include "src/arguments.h"
42 #include "src/base/platform/platform.h"
43 #include "src/compilation-cache.h"
44 #include "src/cpu-profiler.h"
45 #include "src/execution.h"
46 #include "src/isolate.h"
47 #include "src/objects.h"
48 #include "src/parser.h"
49 #include "src/snapshot.h"
50 #include "src/unicode-inl.h"
51 #include "src/utils.h"
52 #include "src/vm-state.h"
53 #include "test/cctest/cctest.h"
54
55 static const bool kLogThreading = false;
56
57 using ::v8::Boolean;
58 using ::v8::BooleanObject;
59 using ::v8::Context;
60 using ::v8::Extension;
61 using ::v8::Function;
62 using ::v8::FunctionTemplate;
63 using ::v8::Handle;
64 using ::v8::HandleScope;
65 using ::v8::Local;
66 using ::v8::Name;
67 using ::v8::Message;
68 using ::v8::MessageCallback;
69 using ::v8::Object;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::Script;
73 using ::v8::StackTrace;
74 using ::v8::String;
75 using ::v8::Symbol;
76 using ::v8::TryCatch;
77 using ::v8::Undefined;
78 using ::v8::UniqueId;
79 using ::v8::V8;
80 using ::v8::Value;
81
82
83 #define THREADED_PROFILED_TEST(Name)                                 \
84   static void Test##Name();                                          \
85   TEST(Name##WithProfiler) {                                         \
86     RunWithProfiler(&Test##Name);                                    \
87   }                                                                  \
88   THREADED_TEST(Name)
89
90
91 void RunWithProfiler(void (*test)()) {
92   LocalContext env;
93   v8::HandleScope scope(env->GetIsolate());
94   v8::Local<v8::String> profile_name =
95       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
97
98   cpu_profiler->StartProfiling(profile_name);
99   (*test)();
100   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
101 }
102
103
104 static int signature_callback_count;
105 static Local<Value> signature_expected_receiver;
106 static void IncrementingSignatureCallback(
107     const v8::FunctionCallbackInfo<v8::Value>& args) {
108   ApiTestFuzzer::Fuzz();
109   signature_callback_count++;
110   CHECK_EQ(signature_expected_receiver, args.Holder());
111   CHECK_EQ(signature_expected_receiver, args.This());
112   v8::Handle<v8::Array> result =
113       v8::Array::New(args.GetIsolate(), args.Length());
114   for (int i = 0; i < args.Length(); i++)
115     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116   args.GetReturnValue().Set(result);
117 }
118
119
120 static void SignatureCallback(
121     const v8::FunctionCallbackInfo<v8::Value>& args) {
122   ApiTestFuzzer::Fuzz();
123   v8::Handle<v8::Array> result =
124       v8::Array::New(args.GetIsolate(), args.Length());
125   for (int i = 0; i < args.Length(); i++) {
126     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
127   }
128   args.GetReturnValue().Set(result);
129 }
130
131
132 // Tests that call v8::V8::Dispose() cannot be threaded.
133 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
134   CHECK(v8::V8::Initialize());
135   CHECK(v8::V8::Dispose());
136 }
137
138
139 // Tests that call v8::V8::Dispose() cannot be threaded.
140 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
143   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
145   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
146 }
147
148
149 THREADED_TEST(Handles) {
150   v8::HandleScope scope(CcTest::isolate());
151   Local<Context> local_env;
152   {
153     LocalContext env;
154     local_env = env.local();
155   }
156
157   // Local context should still be live.
158   CHECK(!local_env.IsEmpty());
159   local_env->Enter();
160
161   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
162   CHECK(!undef.IsEmpty());
163   CHECK(undef->IsUndefined());
164
165   const char* source = "1 + 2 + 3";
166   Local<Script> script = v8_compile(source);
167   CHECK_EQ(6, script->Run()->Int32Value());
168
169   local_env->Exit();
170 }
171
172
173 THREADED_TEST(IsolateOfContext) {
174   v8::HandleScope scope(CcTest::isolate());
175   v8::Handle<Context> env = Context::New(CcTest::isolate());
176
177   CHECK(!env->GetIsolate()->InContext());
178   CHECK(env->GetIsolate() == CcTest::isolate());
179   env->Enter();
180   CHECK(env->GetIsolate()->InContext());
181   CHECK(env->GetIsolate() == CcTest::isolate());
182   env->Exit();
183   CHECK(!env->GetIsolate()->InContext());
184   CHECK(env->GetIsolate() == CcTest::isolate());
185 }
186
187
188 static void TestSignature(const char* loop_js, Local<Value> receiver,
189                           v8::Isolate* isolate) {
190   i::ScopedVector<char> source(200);
191   i::SNPrintF(source,
192               "for (var i = 0; i < 10; i++) {"
193               "  %s"
194               "}",
195               loop_js);
196   signature_callback_count = 0;
197   signature_expected_receiver = receiver;
198   bool expected_to_throw = receiver.IsEmpty();
199   v8::TryCatch try_catch;
200   CompileRun(source.start());
201   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
202   if (!expected_to_throw) {
203     CHECK_EQ(10, signature_callback_count);
204   } else {
205     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
206              try_catch.Exception()->ToString(isolate));
207   }
208 }
209
210
211 THREADED_TEST(ReceiverSignature) {
212   LocalContext env;
213   v8::Isolate* isolate = env->GetIsolate();
214   v8::HandleScope scope(isolate);
215   // Setup templates.
216   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
217   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
218   v8::Handle<v8::FunctionTemplate> callback_sig =
219       v8::FunctionTemplate::New(
220           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
221   v8::Handle<v8::FunctionTemplate> callback =
222       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
223   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
224   sub_fun->Inherit(fun);
225   v8::Handle<v8::FunctionTemplate> unrel_fun =
226       v8::FunctionTemplate::New(isolate);
227   // Install properties.
228   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
229   fun_proto->Set(v8_str("prop_sig"), callback_sig);
230   fun_proto->Set(v8_str("prop"), callback);
231   fun_proto->SetAccessorProperty(
232       v8_str("accessor_sig"), callback_sig, callback_sig);
233   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
234   // Instantiate templates.
235   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
236   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
237   // Setup global variables.
238   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
239   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
240   env->Global()->Set(v8_str("fun_instance"), fun_instance);
241   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
242   CompileRun(
243       "var accessor_sig_key = 'accessor_sig';"
244       "var accessor_key = 'accessor';"
245       "var prop_sig_key = 'prop_sig';"
246       "var prop_key = 'prop';"
247       ""
248       "function copy_props(obj) {"
249       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
250       "  var source = Fun.prototype;"
251       "  for (var i in keys) {"
252       "    var key = keys[i];"
253       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
254       "    Object.defineProperty(obj, key, desc);"
255       "  }"
256       "}"
257       ""
258       "var obj = {};"
259       "copy_props(obj);"
260       "var unrel = new UnrelFun();"
261       "copy_props(unrel);");
262   // Test with and without ICs
263   const char* test_objects[] = {
264       "fun_instance", "sub_fun_instance", "obj", "unrel" };
265   unsigned bad_signature_start_offset = 2;
266   for (unsigned i = 0; i < arraysize(test_objects); i++) {
267     i::ScopedVector<char> source(200);
268     i::SNPrintF(
269         source, "var test_object = %s; test_object", test_objects[i]);
270     Local<Value> test_object = CompileRun(source.start());
271     TestSignature("test_object.prop();", test_object, isolate);
272     TestSignature("test_object.accessor;", test_object, isolate);
273     TestSignature("test_object[accessor_key];", test_object, isolate);
274     TestSignature("test_object.accessor = 1;", test_object, isolate);
275     TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
276     if (i >= bad_signature_start_offset) test_object = Local<Value>();
277     TestSignature("test_object.prop_sig();", test_object, isolate);
278     TestSignature("test_object.accessor_sig;", test_object, isolate);
279     TestSignature("test_object[accessor_sig_key];", test_object, isolate);
280     TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
281     TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
282   }
283 }
284
285
286 THREADED_TEST(ArgumentSignature) {
287   LocalContext env;
288   v8::Isolate* isolate = env->GetIsolate();
289   v8::HandleScope scope(isolate);
290   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
291   cons->SetClassName(v8_str("Cons"));
292   v8::Handle<v8::Signature> sig = v8::Signature::New(
293       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
294   v8::Handle<v8::FunctionTemplate> fun =
295       v8::FunctionTemplate::New(isolate,
296                                 SignatureCallback,
297                                 v8::Handle<Value>(),
298                                 sig);
299   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
300   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
301
302   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
303   CHECK(value1->IsTrue());
304
305   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
306   CHECK(value2->IsTrue());
307
308   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
309   CHECK(value3->IsTrue());
310
311   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
312   cons1->SetClassName(v8_str("Cons1"));
313   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
314   cons2->SetClassName(v8_str("Cons2"));
315   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
316   cons3->SetClassName(v8_str("Cons3"));
317
318   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
319   v8::Handle<v8::Signature> wsig = v8::Signature::New(
320       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
321   v8::Handle<v8::FunctionTemplate> fun2 =
322       v8::FunctionTemplate::New(isolate,
323                                 SignatureCallback,
324                                 v8::Handle<Value>(),
325                                 wsig);
326
327   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
328   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
329   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
330   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
331   v8::Handle<Value> value4 = CompileRun(
332       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
333       "'[object Cons1],[object Cons2],[object Cons3]'");
334   CHECK(value4->IsTrue());
335
336   v8::Handle<Value> value5 = CompileRun(
337       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
338   CHECK(value5->IsTrue());
339
340   v8::Handle<Value> value6 = CompileRun(
341       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
342   CHECK(value6->IsTrue());
343
344   v8::Handle<Value> value7 = CompileRun(
345       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
346       "'[object Cons1],[object Cons2],[object Cons3],d';");
347   CHECK(value7->IsTrue());
348
349   v8::Handle<Value> value8 = CompileRun(
350       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
351   CHECK(value8->IsTrue());
352 }
353
354
355 THREADED_TEST(HulIgennem) {
356   LocalContext env;
357   v8::Isolate* isolate = env->GetIsolate();
358   v8::HandleScope scope(isolate);
359   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
360   Local<String> undef_str = undef->ToString(isolate);
361   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
362   undef_str->WriteUtf8(value);
363   CHECK_EQ(0, strcmp(value, "undefined"));
364   i::DeleteArray(value);
365 }
366
367
368 THREADED_TEST(Access) {
369   LocalContext env;
370   v8::Isolate* isolate = env->GetIsolate();
371   v8::HandleScope scope(isolate);
372   Local<v8::Object> obj = v8::Object::New(isolate);
373   Local<Value> foo_before = obj->Get(v8_str("foo"));
374   CHECK(foo_before->IsUndefined());
375   Local<String> bar_str = v8_str("bar");
376   obj->Set(v8_str("foo"), bar_str);
377   Local<Value> foo_after = obj->Get(v8_str("foo"));
378   CHECK(!foo_after->IsUndefined());
379   CHECK(foo_after->IsString());
380   CHECK_EQ(bar_str, foo_after);
381 }
382
383
384 THREADED_TEST(AccessElement) {
385   LocalContext env;
386   v8::HandleScope scope(env->GetIsolate());
387   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
388   Local<Value> before = obj->Get(1);
389   CHECK(before->IsUndefined());
390   Local<String> bar_str = v8_str("bar");
391   obj->Set(1, bar_str);
392   Local<Value> after = obj->Get(1);
393   CHECK(!after->IsUndefined());
394   CHECK(after->IsString());
395   CHECK_EQ(bar_str, after);
396
397   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
398   CHECK_EQ(v8_str("a"), value->Get(0));
399   CHECK_EQ(v8_str("b"), value->Get(1));
400 }
401
402
403 THREADED_TEST(Script) {
404   LocalContext env;
405   v8::HandleScope scope(env->GetIsolate());
406   const char* source = "1 + 2 + 3";
407   Local<Script> script = v8_compile(source);
408   CHECK_EQ(6, script->Run()->Int32Value());
409 }
410
411
412 class TestResource: public String::ExternalStringResource {
413  public:
414   explicit TestResource(uint16_t* data, int* counter = NULL,
415                         bool owning_data = true)
416       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
417     while (data[length_]) ++length_;
418   }
419
420   ~TestResource() {
421     if (owning_data_) i::DeleteArray(data_);
422     if (counter_ != NULL) ++*counter_;
423   }
424
425   const uint16_t* data() const {
426     return data_;
427   }
428
429   size_t length() const {
430     return length_;
431   }
432
433  private:
434   uint16_t* data_;
435   size_t length_;
436   int* counter_;
437   bool owning_data_;
438 };
439
440
441 class TestOneByteResource : public String::ExternalOneByteStringResource {
442  public:
443   explicit TestOneByteResource(const char* data, int* counter = NULL,
444                                size_t offset = 0)
445       : orig_data_(data),
446         data_(data + offset),
447         length_(strlen(data) - offset),
448         counter_(counter) {}
449
450   ~TestOneByteResource() {
451     i::DeleteArray(orig_data_);
452     if (counter_ != NULL) ++*counter_;
453   }
454
455   const char* data() const {
456     return data_;
457   }
458
459   size_t length() const {
460     return length_;
461   }
462
463  private:
464   const char* orig_data_;
465   const char* data_;
466   size_t length_;
467   int* counter_;
468 };
469
470
471 THREADED_TEST(ScriptUsingStringResource) {
472   int dispose_count = 0;
473   const char* c_source = "1 + 2 * 3";
474   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
475   {
476     LocalContext env;
477     v8::HandleScope scope(env->GetIsolate());
478     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
479     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
480     Local<Script> script = v8_compile(source);
481     Local<Value> value = script->Run();
482     CHECK(value->IsNumber());
483     CHECK_EQ(7, value->Int32Value());
484     CHECK(source->IsExternal());
485     CHECK_EQ(resource,
486              static_cast<TestResource*>(source->GetExternalStringResource()));
487     String::Encoding encoding = String::UNKNOWN_ENCODING;
488     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
489              source->GetExternalStringResourceBase(&encoding));
490     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
491     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
492     CHECK_EQ(0, dispose_count);
493   }
494   CcTest::i_isolate()->compilation_cache()->Clear();
495   CcTest::heap()->CollectAllAvailableGarbage();
496   CHECK_EQ(1, dispose_count);
497 }
498
499
500 THREADED_TEST(ScriptUsingOneByteStringResource) {
501   int dispose_count = 0;
502   const char* c_source = "1 + 2 * 3";
503   {
504     LocalContext env;
505     v8::HandleScope scope(env->GetIsolate());
506     TestOneByteResource* resource =
507         new TestOneByteResource(i::StrDup(c_source), &dispose_count);
508     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
509     CHECK(source->IsExternalOneByte());
510     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
511              source->GetExternalOneByteStringResource());
512     String::Encoding encoding = String::UNKNOWN_ENCODING;
513     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
514              source->GetExternalStringResourceBase(&encoding));
515     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
516     Local<Script> script = v8_compile(source);
517     Local<Value> value = script->Run();
518     CHECK(value->IsNumber());
519     CHECK_EQ(7, value->Int32Value());
520     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
521     CHECK_EQ(0, dispose_count);
522   }
523   CcTest::i_isolate()->compilation_cache()->Clear();
524   CcTest::heap()->CollectAllAvailableGarbage();
525   CHECK_EQ(1, dispose_count);
526 }
527
528
529 THREADED_TEST(ScriptMakingExternalString) {
530   int dispose_count = 0;
531   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
532   {
533     LocalContext env;
534     v8::HandleScope scope(env->GetIsolate());
535     Local<String> source =
536         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
537     // Trigger GCs so that the newly allocated string moves to old gen.
538     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
539     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
540     CHECK_EQ(source->IsExternal(), false);
541     CHECK_EQ(source->IsExternalOneByte(), false);
542     String::Encoding encoding = String::UNKNOWN_ENCODING;
543     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
544     CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
545     bool success = source->MakeExternal(new TestResource(two_byte_source,
546                                                          &dispose_count));
547     CHECK(success);
548     Local<Script> script = v8_compile(source);
549     Local<Value> value = script->Run();
550     CHECK(value->IsNumber());
551     CHECK_EQ(7, value->Int32Value());
552     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
553     CHECK_EQ(0, dispose_count);
554   }
555   CcTest::i_isolate()->compilation_cache()->Clear();
556   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
557   CHECK_EQ(1, dispose_count);
558 }
559
560
561 THREADED_TEST(ScriptMakingExternalOneByteString) {
562   int dispose_count = 0;
563   const char* c_source = "1 + 2 * 3";
564   {
565     LocalContext env;
566     v8::HandleScope scope(env->GetIsolate());
567     Local<String> source = v8_str(c_source);
568     // Trigger GCs so that the newly allocated string moves to old gen.
569     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
570     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
571     bool success = source->MakeExternal(
572         new TestOneByteResource(i::StrDup(c_source), &dispose_count));
573     CHECK(success);
574     Local<Script> script = v8_compile(source);
575     Local<Value> value = script->Run();
576     CHECK(value->IsNumber());
577     CHECK_EQ(7, value->Int32Value());
578     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
579     CHECK_EQ(0, dispose_count);
580   }
581   CcTest::i_isolate()->compilation_cache()->Clear();
582   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
583   CHECK_EQ(1, dispose_count);
584 }
585
586
587 TEST(MakingExternalStringConditions) {
588   LocalContext env;
589   v8::HandleScope scope(env->GetIsolate());
590
591   // Free some space in the new space so that we can check freshness.
592   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
594
595   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
596   Local<String> small_string =
597       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
598   i::DeleteArray(two_byte_string);
599
600   // We should refuse to externalize newly created small string.
601   CHECK(!small_string->CanMakeExternal());
602   // Trigger GCs so that the newly allocated string moves to old gen.
603   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
604   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
605   // Old space strings should be accepted.
606   CHECK(small_string->CanMakeExternal());
607
608   two_byte_string = AsciiToTwoByteString("small string 2");
609   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
610   i::DeleteArray(two_byte_string);
611
612   // We should refuse externalizing newly created small string.
613   CHECK(!small_string->CanMakeExternal());
614   for (int i = 0; i < 100; i++) {
615     String::Value value(small_string);
616   }
617   // Frequently used strings should be accepted.
618   CHECK(small_string->CanMakeExternal());
619
620   const int buf_size = 10 * 1024;
621   char* buf = i::NewArray<char>(buf_size);
622   memset(buf, 'a', buf_size);
623   buf[buf_size - 1] = '\0';
624
625   two_byte_string = AsciiToTwoByteString(buf);
626   Local<String> large_string =
627       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
628   i::DeleteArray(buf);
629   i::DeleteArray(two_byte_string);
630   // Large strings should be immediately accepted.
631   CHECK(large_string->CanMakeExternal());
632 }
633
634
635 TEST(MakingExternalOneByteStringConditions) {
636   LocalContext env;
637   v8::HandleScope scope(env->GetIsolate());
638
639   // Free some space in the new space so that we can check freshness.
640   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642
643   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
644   // We should refuse to externalize newly created small string.
645   CHECK(!small_string->CanMakeExternal());
646   // Trigger GCs so that the newly allocated string moves to old gen.
647   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
648   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
649   // Old space strings should be accepted.
650   CHECK(small_string->CanMakeExternal());
651
652   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
653   // We should refuse externalizing newly created small string.
654   CHECK(!small_string->CanMakeExternal());
655   for (int i = 0; i < 100; i++) {
656     String::Value value(small_string);
657   }
658   // Frequently used strings should be accepted.
659   CHECK(small_string->CanMakeExternal());
660
661   const int buf_size = 10 * 1024;
662   char* buf = i::NewArray<char>(buf_size);
663   memset(buf, 'a', buf_size);
664   buf[buf_size - 1] = '\0';
665   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
666   i::DeleteArray(buf);
667   // Large strings should be immediately accepted.
668   CHECK(large_string->CanMakeExternal());
669 }
670
671
672 TEST(MakingExternalUnalignedOneByteString) {
673   LocalContext env;
674   v8::HandleScope scope(env->GetIsolate());
675
676   CompileRun("function cons(a, b) { return a + b; }"
677              "function slice(a) { return a.substring(1); }");
678   // Create a cons string that will land in old pointer space.
679   Local<String> cons = Local<String>::Cast(CompileRun(
680       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
681   // Create a sliced string that will land in old pointer space.
682   Local<String> slice = Local<String>::Cast(CompileRun(
683       "slice('abcdefghijklmnopqrstuvwxyz');"));
684
685   // Trigger GCs so that the newly allocated string moves to old gen.
686   SimulateFullSpace(CcTest::heap()->old_pointer_space());
687   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
688   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
689
690   // Turn into external string with unaligned resource data.
691   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
692   bool success =
693       cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
694   CHECK(success);
695   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
696   success =
697       slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
698   CHECK(success);
699
700   // Trigger GCs and force evacuation.
701   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
702   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
703 }
704
705
706 THREADED_TEST(UsingExternalString) {
707   i::Factory* factory = CcTest::i_isolate()->factory();
708   {
709     v8::HandleScope scope(CcTest::isolate());
710     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
711     Local<String> string = String::NewExternal(
712         CcTest::isolate(), new TestResource(two_byte_string));
713     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
714     // Trigger GCs so that the newly allocated string moves to old gen.
715     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
716     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
717     i::Handle<i::String> isymbol =
718         factory->InternalizeString(istring);
719     CHECK(isymbol->IsInternalizedString());
720   }
721   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
723 }
724
725
726 THREADED_TEST(UsingExternalOneByteString) {
727   i::Factory* factory = CcTest::i_isolate()->factory();
728   {
729     v8::HandleScope scope(CcTest::isolate());
730     const char* one_byte_string = "test string";
731     Local<String> string = String::NewExternal(
732         CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
733     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
734     // Trigger GCs so that the newly allocated string moves to old gen.
735     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
736     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
737     i::Handle<i::String> isymbol =
738         factory->InternalizeString(istring);
739     CHECK(isymbol->IsInternalizedString());
740   }
741   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
743 }
744
745
746 class RandomLengthResource : public v8::String::ExternalStringResource {
747  public:
748   explicit RandomLengthResource(int length) : length_(length) {}
749   virtual const uint16_t* data() const { return string_; }
750   virtual size_t length() const { return length_; }
751
752  private:
753   uint16_t string_[10];
754   int length_;
755 };
756
757
758 class RandomLengthOneByteResource
759     : public v8::String::ExternalOneByteStringResource {
760  public:
761   explicit RandomLengthOneByteResource(int length) : length_(length) {}
762   virtual const char* data() const { return string_; }
763   virtual size_t length() const { return length_; }
764
765  private:
766   char string_[10];
767   int length_;
768 };
769
770
771 THREADED_TEST(NewExternalForVeryLongString) {
772   {
773     LocalContext env;
774     v8::HandleScope scope(env->GetIsolate());
775     v8::TryCatch try_catch;
776     RandomLengthOneByteResource r(1 << 30);
777     v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
778     CHECK(str.IsEmpty());
779     CHECK(try_catch.HasCaught());
780     String::Utf8Value exception_value(try_catch.Exception());
781     CHECK_EQ("RangeError: Invalid string length", *exception_value);
782   }
783
784   {
785     LocalContext env;
786     v8::HandleScope scope(env->GetIsolate());
787     v8::TryCatch try_catch;
788     RandomLengthResource r(1 << 30);
789     v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
790     CHECK(str.IsEmpty());
791     CHECK(try_catch.HasCaught());
792     String::Utf8Value exception_value(try_catch.Exception());
793     CHECK_EQ("RangeError: Invalid string length", *exception_value);
794   }
795 }
796
797
798 THREADED_TEST(ScavengeExternalString) {
799   i::FLAG_stress_compaction = false;
800   i::FLAG_gc_global = false;
801   int dispose_count = 0;
802   bool in_new_space = false;
803   {
804     v8::HandleScope scope(CcTest::isolate());
805     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
806     Local<String> string = String::NewExternal(
807         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
808     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
809     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
810     in_new_space = CcTest::heap()->InNewSpace(*istring);
811     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
812     CHECK_EQ(0, dispose_count);
813   }
814   CcTest::heap()->CollectGarbage(
815       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
816   CHECK_EQ(1, dispose_count);
817 }
818
819
820 THREADED_TEST(ScavengeExternalOneByteString) {
821   i::FLAG_stress_compaction = false;
822   i::FLAG_gc_global = false;
823   int dispose_count = 0;
824   bool in_new_space = false;
825   {
826     v8::HandleScope scope(CcTest::isolate());
827     const char* one_byte_string = "test string";
828     Local<String> string = String::NewExternal(
829         CcTest::isolate(),
830         new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
831     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
832     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
833     in_new_space = CcTest::heap()->InNewSpace(*istring);
834     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
835     CHECK_EQ(0, dispose_count);
836   }
837   CcTest::heap()->CollectGarbage(
838       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
839   CHECK_EQ(1, dispose_count);
840 }
841
842
843 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
844  public:
845   // Only used by non-threaded tests, so it can use static fields.
846   static int dispose_calls;
847   static int dispose_count;
848
849   TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
850       : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
851
852   void Dispose() {
853     ++dispose_calls;
854     if (dispose_) delete this;
855   }
856  private:
857   bool dispose_;
858 };
859
860
861 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
862 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
863
864
865 TEST(ExternalStringWithDisposeHandling) {
866   const char* c_source = "1 + 2 * 3";
867
868   // Use a stack allocated external string resource allocated object.
869   TestOneByteResourceWithDisposeControl::dispose_count = 0;
870   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
871   TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
872   {
873     LocalContext env;
874     v8::HandleScope scope(env->GetIsolate());
875     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
876     Local<Script> script = v8_compile(source);
877     Local<Value> value = script->Run();
878     CHECK(value->IsNumber());
879     CHECK_EQ(7, value->Int32Value());
880     CcTest::heap()->CollectAllAvailableGarbage();
881     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
882   }
883   CcTest::i_isolate()->compilation_cache()->Clear();
884   CcTest::heap()->CollectAllAvailableGarbage();
885   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
886   CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
887
888   // Use a heap allocated external string resource allocated object.
889   TestOneByteResourceWithDisposeControl::dispose_count = 0;
890   TestOneByteResourceWithDisposeControl::dispose_calls = 0;
891   TestOneByteResource* res_heap =
892       new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
893   {
894     LocalContext env;
895     v8::HandleScope scope(env->GetIsolate());
896     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
897     Local<Script> script = v8_compile(source);
898     Local<Value> value = script->Run();
899     CHECK(value->IsNumber());
900     CHECK_EQ(7, value->Int32Value());
901     CcTest::heap()->CollectAllAvailableGarbage();
902     CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
903   }
904   CcTest::i_isolate()->compilation_cache()->Clear();
905   CcTest::heap()->CollectAllAvailableGarbage();
906   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
907   CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
908 }
909
910
911 THREADED_TEST(StringConcat) {
912   {
913     LocalContext env;
914     v8::HandleScope scope(env->GetIsolate());
915     const char* one_byte_string_1 = "function a_times_t";
916     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
917     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
918     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
919     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
920     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
921     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
922     Local<String> left = v8_str(one_byte_string_1);
923
924     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
925     Local<String> right =
926         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
927     i::DeleteArray(two_byte_source);
928
929     Local<String> source = String::Concat(left, right);
930     right = String::NewExternal(
931         env->GetIsolate(),
932         new TestOneByteResource(i::StrDup(one_byte_extern_1)));
933     source = String::Concat(source, right);
934     right = String::NewExternal(
935         env->GetIsolate(),
936         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
937     source = String::Concat(source, right);
938     right = v8_str(one_byte_string_2);
939     source = String::Concat(source, right);
940
941     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
942     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
943     i::DeleteArray(two_byte_source);
944
945     source = String::Concat(source, right);
946     right = String::NewExternal(
947         env->GetIsolate(),
948         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
949     source = String::Concat(source, right);
950     Local<Script> script = v8_compile(source);
951     Local<Value> value = script->Run();
952     CHECK(value->IsNumber());
953     CHECK_EQ(68, value->Int32Value());
954   }
955   CcTest::i_isolate()->compilation_cache()->Clear();
956   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
957   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
958 }
959
960
961 THREADED_TEST(GlobalProperties) {
962   LocalContext env;
963   v8::HandleScope scope(env->GetIsolate());
964   v8::Handle<v8::Object> global = env->Global();
965   global->Set(v8_str("pi"), v8_num(3.1415926));
966   Local<Value> pi = global->Get(v8_str("pi"));
967   CHECK_EQ(3.1415926, pi->NumberValue());
968 }
969
970
971 template<typename T>
972 static void CheckReturnValue(const T& t, i::Address callback) {
973   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
974   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
975   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
976   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
977   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
978   // Verify reset
979   bool is_runtime = (*o)->IsTheHole();
980   rv.Set(true);
981   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
982   rv.Set(v8::Handle<v8::Object>());
983   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
984   CHECK_EQ(is_runtime, (*o)->IsTheHole());
985
986   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
987   // If CPU profiler is active check that when API callback is invoked
988   // VMState is set to EXTERNAL.
989   if (isolate->cpu_profiler()->is_profiling()) {
990     CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
991     CHECK(isolate->external_callback_scope());
992     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
993   }
994 }
995
996
997 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
998                                  i::Address callback) {
999   ApiTestFuzzer::Fuzz();
1000   CheckReturnValue(info, callback);
1001   info.GetReturnValue().Set(v8_str("bad value"));
1002   info.GetReturnValue().Set(v8_num(102));
1003 }
1004
1005
1006 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1007   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1008 }
1009
1010
1011 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1012   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1013 }
1014
1015 static void construct_callback(
1016     const v8::FunctionCallbackInfo<Value>& info) {
1017   ApiTestFuzzer::Fuzz();
1018   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1019   info.This()->Set(v8_str("x"), v8_num(1));
1020   info.This()->Set(v8_str("y"), v8_num(2));
1021   info.GetReturnValue().Set(v8_str("bad value"));
1022   info.GetReturnValue().Set(info.This());
1023 }
1024
1025
1026 static void Return239Callback(
1027     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1028   ApiTestFuzzer::Fuzz();
1029   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1030   info.GetReturnValue().Set(v8_str("bad value"));
1031   info.GetReturnValue().Set(v8_num(239));
1032 }
1033
1034
1035 template<typename Handler>
1036 static void TestFunctionTemplateInitializer(Handler handler,
1037                                             Handler handler_2) {
1038   // Test constructor calls.
1039   {
1040     LocalContext env;
1041     v8::Isolate* isolate = env->GetIsolate();
1042     v8::HandleScope scope(isolate);
1043
1044     Local<v8::FunctionTemplate> fun_templ =
1045         v8::FunctionTemplate::New(isolate, handler);
1046     Local<Function> fun = fun_templ->GetFunction();
1047     env->Global()->Set(v8_str("obj"), fun);
1048     Local<Script> script = v8_compile("obj()");
1049     for (int i = 0; i < 30; i++) {
1050       CHECK_EQ(102, script->Run()->Int32Value());
1051     }
1052   }
1053   // Use SetCallHandler to initialize a function template, should work like
1054   // the previous one.
1055   {
1056     LocalContext env;
1057     v8::Isolate* isolate = env->GetIsolate();
1058     v8::HandleScope scope(isolate);
1059
1060     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1061     fun_templ->SetCallHandler(handler_2);
1062     Local<Function> fun = fun_templ->GetFunction();
1063     env->Global()->Set(v8_str("obj"), fun);
1064     Local<Script> script = v8_compile("obj()");
1065     for (int i = 0; i < 30; i++) {
1066       CHECK_EQ(102, script->Run()->Int32Value());
1067     }
1068   }
1069 }
1070
1071
1072 template<typename Constructor, typename Accessor>
1073 static void TestFunctionTemplateAccessor(Constructor constructor,
1074                                          Accessor accessor) {
1075   LocalContext env;
1076   v8::HandleScope scope(env->GetIsolate());
1077
1078   Local<v8::FunctionTemplate> fun_templ =
1079       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1080   fun_templ->SetClassName(v8_str("funky"));
1081   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1082   Local<Function> fun = fun_templ->GetFunction();
1083   env->Global()->Set(v8_str("obj"), fun);
1084   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1085   CHECK_EQ(v8_str("[object funky]"), result);
1086   CompileRun("var obj_instance = new obj();");
1087   Local<Script> script;
1088   script = v8_compile("obj_instance.x");
1089   for (int i = 0; i < 30; i++) {
1090     CHECK_EQ(1, script->Run()->Int32Value());
1091   }
1092   script = v8_compile("obj_instance.m");
1093   for (int i = 0; i < 30; i++) {
1094     CHECK_EQ(239, script->Run()->Int32Value());
1095   }
1096 }
1097
1098
1099 THREADED_PROFILED_TEST(FunctionTemplate) {
1100   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1101   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1102 }
1103
1104
1105 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1106   ApiTestFuzzer::Fuzz();
1107   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1108   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1109 }
1110
1111
1112 template<typename Callback>
1113 static void TestSimpleCallback(Callback callback) {
1114   LocalContext env;
1115   v8::Isolate* isolate = env->GetIsolate();
1116   v8::HandleScope scope(isolate);
1117
1118   v8::Handle<v8::ObjectTemplate> object_template =
1119       v8::ObjectTemplate::New(isolate);
1120   object_template->Set(isolate, "callback",
1121                        v8::FunctionTemplate::New(isolate, callback));
1122   v8::Local<v8::Object> object = object_template->NewInstance();
1123   (*env)->Global()->Set(v8_str("callback_object"), object);
1124   v8::Handle<v8::Script> script;
1125   script = v8_compile("callback_object.callback(17)");
1126   for (int i = 0; i < 30; i++) {
1127     CHECK_EQ(51424, script->Run()->Int32Value());
1128   }
1129   script = v8_compile("callback_object.callback(17, 24)");
1130   for (int i = 0; i < 30; i++) {
1131     CHECK_EQ(51425, script->Run()->Int32Value());
1132   }
1133 }
1134
1135
1136 THREADED_PROFILED_TEST(SimpleCallback) {
1137   TestSimpleCallback(SimpleCallback);
1138 }
1139
1140
1141 template<typename T>
1142 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1143
1144 // constant return values
1145 static int32_t fast_return_value_int32 = 471;
1146 static uint32_t fast_return_value_uint32 = 571;
1147 static const double kFastReturnValueDouble = 2.7;
1148 // variable return values
1149 static bool fast_return_value_bool = false;
1150 enum ReturnValueOddball {
1151   kNullReturnValue,
1152   kUndefinedReturnValue,
1153   kEmptyStringReturnValue
1154 };
1155 static ReturnValueOddball fast_return_value_void;
1156 static bool fast_return_value_object_is_empty = false;
1157
1158 // Helper function to avoid compiler error: insufficient contextual information
1159 // to determine type when applying FUNCTION_ADDR to a template function.
1160 static i::Address address_of(v8::FunctionCallback callback) {
1161   return FUNCTION_ADDR(callback);
1162 }
1163
1164 template<>
1165 void FastReturnValueCallback<int32_t>(
1166     const v8::FunctionCallbackInfo<v8::Value>& info) {
1167   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1168   info.GetReturnValue().Set(fast_return_value_int32);
1169 }
1170
1171 template<>
1172 void FastReturnValueCallback<uint32_t>(
1173     const v8::FunctionCallbackInfo<v8::Value>& info) {
1174   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1175   info.GetReturnValue().Set(fast_return_value_uint32);
1176 }
1177
1178 template<>
1179 void FastReturnValueCallback<double>(
1180     const v8::FunctionCallbackInfo<v8::Value>& info) {
1181   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1182   info.GetReturnValue().Set(kFastReturnValueDouble);
1183 }
1184
1185 template<>
1186 void FastReturnValueCallback<bool>(
1187     const v8::FunctionCallbackInfo<v8::Value>& info) {
1188   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1189   info.GetReturnValue().Set(fast_return_value_bool);
1190 }
1191
1192 template<>
1193 void FastReturnValueCallback<void>(
1194     const v8::FunctionCallbackInfo<v8::Value>& info) {
1195   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1196   switch (fast_return_value_void) {
1197     case kNullReturnValue:
1198       info.GetReturnValue().SetNull();
1199       break;
1200     case kUndefinedReturnValue:
1201       info.GetReturnValue().SetUndefined();
1202       break;
1203     case kEmptyStringReturnValue:
1204       info.GetReturnValue().SetEmptyString();
1205       break;
1206   }
1207 }
1208
1209 template<>
1210 void FastReturnValueCallback<Object>(
1211     const v8::FunctionCallbackInfo<v8::Value>& info) {
1212   v8::Handle<v8::Object> object;
1213   if (!fast_return_value_object_is_empty) {
1214     object = Object::New(info.GetIsolate());
1215   }
1216   info.GetReturnValue().Set(object);
1217 }
1218
1219 template<typename T>
1220 Handle<Value> TestFastReturnValues() {
1221   LocalContext env;
1222   v8::Isolate* isolate = env->GetIsolate();
1223   v8::EscapableHandleScope scope(isolate);
1224   v8::Handle<v8::ObjectTemplate> object_template =
1225       v8::ObjectTemplate::New(isolate);
1226   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1227   object_template->Set(isolate, "callback",
1228                        v8::FunctionTemplate::New(isolate, callback));
1229   v8::Local<v8::Object> object = object_template->NewInstance();
1230   (*env)->Global()->Set(v8_str("callback_object"), object);
1231   return scope.Escape(CompileRun("callback_object.callback()"));
1232 }
1233
1234
1235 THREADED_PROFILED_TEST(FastReturnValues) {
1236   LocalContext env;
1237   v8::Isolate* isolate = env->GetIsolate();
1238   v8::HandleScope scope(isolate);
1239   v8::Handle<v8::Value> value;
1240   // check int32_t and uint32_t
1241   int32_t int_values[] = {
1242       0, 234, -723,
1243       i::Smi::kMinValue, i::Smi::kMaxValue
1244   };
1245   for (size_t i = 0; i < arraysize(int_values); i++) {
1246     for (int modifier = -1; modifier <= 1; modifier++) {
1247       int int_value = int_values[i] + modifier;
1248       // check int32_t
1249       fast_return_value_int32 = int_value;
1250       value = TestFastReturnValues<int32_t>();
1251       CHECK(value->IsInt32());
1252       CHECK(fast_return_value_int32 == value->Int32Value());
1253       // check uint32_t
1254       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1255       value = TestFastReturnValues<uint32_t>();
1256       CHECK(value->IsUint32());
1257       CHECK(fast_return_value_uint32 == value->Uint32Value());
1258     }
1259   }
1260   // check double
1261   value = TestFastReturnValues<double>();
1262   CHECK(value->IsNumber());
1263   CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1264   // check bool values
1265   for (int i = 0; i < 2; i++) {
1266     fast_return_value_bool = i == 0;
1267     value = TestFastReturnValues<bool>();
1268     CHECK(value->IsBoolean());
1269     CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1270   }
1271   // check oddballs
1272   ReturnValueOddball oddballs[] = {
1273       kNullReturnValue,
1274       kUndefinedReturnValue,
1275       kEmptyStringReturnValue
1276   };
1277   for (size_t i = 0; i < arraysize(oddballs); i++) {
1278     fast_return_value_void = oddballs[i];
1279     value = TestFastReturnValues<void>();
1280     switch (fast_return_value_void) {
1281       case kNullReturnValue:
1282         CHECK(value->IsNull());
1283         break;
1284       case kUndefinedReturnValue:
1285         CHECK(value->IsUndefined());
1286         break;
1287       case kEmptyStringReturnValue:
1288         CHECK(value->IsString());
1289         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1290         break;
1291     }
1292   }
1293   // check handles
1294   fast_return_value_object_is_empty = false;
1295   value = TestFastReturnValues<Object>();
1296   CHECK(value->IsObject());
1297   fast_return_value_object_is_empty = true;
1298   value = TestFastReturnValues<Object>();
1299   CHECK(value->IsUndefined());
1300 }
1301
1302
1303 THREADED_TEST(FunctionTemplateSetLength) {
1304   LocalContext env;
1305   v8::Isolate* isolate = env->GetIsolate();
1306   v8::HandleScope scope(isolate);
1307   {
1308     Local<v8::FunctionTemplate> fun_templ =
1309         v8::FunctionTemplate::New(isolate,
1310                                   handle_callback,
1311                                   Handle<v8::Value>(),
1312                                   Handle<v8::Signature>(),
1313                                   23);
1314     Local<Function> fun = fun_templ->GetFunction();
1315     env->Global()->Set(v8_str("obj"), fun);
1316     Local<Script> script = v8_compile("obj.length");
1317     CHECK_EQ(23, script->Run()->Int32Value());
1318   }
1319   {
1320     Local<v8::FunctionTemplate> fun_templ =
1321         v8::FunctionTemplate::New(isolate, handle_callback);
1322     fun_templ->SetLength(22);
1323     Local<Function> fun = fun_templ->GetFunction();
1324     env->Global()->Set(v8_str("obj"), fun);
1325     Local<Script> script = v8_compile("obj.length");
1326     CHECK_EQ(22, script->Run()->Int32Value());
1327   }
1328   {
1329     // Without setting length it defaults to 0.
1330     Local<v8::FunctionTemplate> fun_templ =
1331         v8::FunctionTemplate::New(isolate, handle_callback);
1332     Local<Function> fun = fun_templ->GetFunction();
1333     env->Global()->Set(v8_str("obj"), fun);
1334     Local<Script> script = v8_compile("obj.length");
1335     CHECK_EQ(0, script->Run()->Int32Value());
1336   }
1337 }
1338
1339
1340 static void* expected_ptr;
1341 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1342   void* ptr = v8::External::Cast(*args.Data())->Value();
1343   CHECK_EQ(expected_ptr, ptr);
1344   args.GetReturnValue().Set(true);
1345 }
1346
1347
1348 static void TestExternalPointerWrapping() {
1349   LocalContext env;
1350   v8::Isolate* isolate = env->GetIsolate();
1351   v8::HandleScope scope(isolate);
1352
1353   v8::Handle<v8::Value> data =
1354       v8::External::New(isolate, expected_ptr);
1355
1356   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1357   obj->Set(v8_str("func"),
1358            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1359   env->Global()->Set(v8_str("obj"), obj);
1360
1361   CHECK(CompileRun(
1362         "function foo() {\n"
1363         "  for (var i = 0; i < 13; i++) obj.func();\n"
1364         "}\n"
1365         "foo(), true")->BooleanValue());
1366 }
1367
1368
1369 THREADED_TEST(ExternalWrap) {
1370   // Check heap allocated object.
1371   int* ptr = new int;
1372   expected_ptr = ptr;
1373   TestExternalPointerWrapping();
1374   delete ptr;
1375
1376   // Check stack allocated object.
1377   int foo;
1378   expected_ptr = &foo;
1379   TestExternalPointerWrapping();
1380
1381   // Check not aligned addresses.
1382   const int n = 100;
1383   char* s = new char[n];
1384   for (int i = 0; i < n; i++) {
1385     expected_ptr = s + i;
1386     TestExternalPointerWrapping();
1387   }
1388
1389   delete[] s;
1390
1391   // Check several invalid addresses.
1392   expected_ptr = reinterpret_cast<void*>(1);
1393   TestExternalPointerWrapping();
1394
1395   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1396   TestExternalPointerWrapping();
1397
1398   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1399   TestExternalPointerWrapping();
1400
1401 #if defined(V8_HOST_ARCH_X64)
1402   // Check a value with a leading 1 bit in x64 Smi encoding.
1403   expected_ptr = reinterpret_cast<void*>(0x400000000);
1404   TestExternalPointerWrapping();
1405
1406   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1407   TestExternalPointerWrapping();
1408
1409   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1410   TestExternalPointerWrapping();
1411 #endif
1412 }
1413
1414
1415 THREADED_TEST(FindInstanceInPrototypeChain) {
1416   LocalContext env;
1417   v8::Isolate* isolate = env->GetIsolate();
1418   v8::HandleScope scope(isolate);
1419
1420   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1421   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1422   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1423   derived->Inherit(base);
1424
1425   Local<v8::Function> base_function = base->GetFunction();
1426   Local<v8::Function> derived_function = derived->GetFunction();
1427   Local<v8::Function> other_function = other->GetFunction();
1428
1429   Local<v8::Object> base_instance = base_function->NewInstance();
1430   Local<v8::Object> derived_instance = derived_function->NewInstance();
1431   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1432   Local<v8::Object> other_instance = other_function->NewInstance();
1433   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1434   other_instance->Set(v8_str("__proto__"), derived_instance2);
1435
1436   // base_instance is only an instance of base.
1437   CHECK_EQ(base_instance,
1438            base_instance->FindInstanceInPrototypeChain(base));
1439   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1440   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1441
1442   // derived_instance is an instance of base and derived.
1443   CHECK_EQ(derived_instance,
1444            derived_instance->FindInstanceInPrototypeChain(base));
1445   CHECK_EQ(derived_instance,
1446            derived_instance->FindInstanceInPrototypeChain(derived));
1447   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1448
1449   // other_instance is an instance of other and its immediate
1450   // prototype derived_instance2 is an instance of base and derived.
1451   // Note, derived_instance is an instance of base and derived too,
1452   // but it comes after derived_instance2 in the prototype chain of
1453   // other_instance.
1454   CHECK_EQ(derived_instance2,
1455            other_instance->FindInstanceInPrototypeChain(base));
1456   CHECK_EQ(derived_instance2,
1457            other_instance->FindInstanceInPrototypeChain(derived));
1458   CHECK_EQ(other_instance,
1459            other_instance->FindInstanceInPrototypeChain(other));
1460 }
1461
1462
1463 THREADED_TEST(TinyInteger) {
1464   LocalContext env;
1465   v8::Isolate* isolate = env->GetIsolate();
1466   v8::HandleScope scope(isolate);
1467
1468   int32_t value = 239;
1469   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1470   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1471
1472   value_obj = v8::Integer::New(isolate, value);
1473   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1474 }
1475
1476
1477 THREADED_TEST(BigSmiInteger) {
1478   LocalContext env;
1479   v8::HandleScope scope(env->GetIsolate());
1480   v8::Isolate* isolate = CcTest::isolate();
1481
1482   int32_t value = i::Smi::kMaxValue;
1483   // We cannot add one to a Smi::kMaxValue without wrapping.
1484   if (i::SmiValuesAre31Bits()) {
1485     CHECK(i::Smi::IsValid(value));
1486     CHECK(!i::Smi::IsValid(value + 1));
1487
1488     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1489     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1490
1491     value_obj = v8::Integer::New(isolate, value);
1492     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1493   }
1494 }
1495
1496
1497 THREADED_TEST(BigInteger) {
1498   LocalContext env;
1499   v8::HandleScope scope(env->GetIsolate());
1500   v8::Isolate* isolate = CcTest::isolate();
1501
1502   // We cannot add one to a Smi::kMaxValue without wrapping.
1503   if (i::SmiValuesAre31Bits()) {
1504     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1505     // The code will not be run in that case, due to the "if" guard.
1506     int32_t value =
1507         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1508     CHECK(value > i::Smi::kMaxValue);
1509     CHECK(!i::Smi::IsValid(value));
1510
1511     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1512     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1513
1514     value_obj = v8::Integer::New(isolate, value);
1515     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1516   }
1517 }
1518
1519
1520 THREADED_TEST(TinyUnsignedInteger) {
1521   LocalContext env;
1522   v8::HandleScope scope(env->GetIsolate());
1523   v8::Isolate* isolate = CcTest::isolate();
1524
1525   uint32_t value = 239;
1526
1527   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1528   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1529
1530   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1531   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1532 }
1533
1534
1535 THREADED_TEST(BigUnsignedSmiInteger) {
1536   LocalContext env;
1537   v8::HandleScope scope(env->GetIsolate());
1538   v8::Isolate* isolate = CcTest::isolate();
1539
1540   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1541   CHECK(i::Smi::IsValid(value));
1542   CHECK(!i::Smi::IsValid(value + 1));
1543
1544   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1545   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1546
1547   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1548   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1549 }
1550
1551
1552 THREADED_TEST(BigUnsignedInteger) {
1553   LocalContext env;
1554   v8::HandleScope scope(env->GetIsolate());
1555   v8::Isolate* isolate = CcTest::isolate();
1556
1557   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1558   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1559   CHECK(!i::Smi::IsValid(value));
1560
1561   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1562   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1563
1564   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1565   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1566 }
1567
1568
1569 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1570   LocalContext env;
1571   v8::HandleScope scope(env->GetIsolate());
1572   v8::Isolate* isolate = CcTest::isolate();
1573
1574   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1575   uint32_t value = INT32_MAX_AS_UINT + 1;
1576   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1577
1578   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1579   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1580
1581   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1582   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1583 }
1584
1585
1586 THREADED_TEST(IsNativeError) {
1587   LocalContext env;
1588   v8::HandleScope scope(env->GetIsolate());
1589   v8::Handle<Value> syntax_error = CompileRun(
1590       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1591   CHECK(syntax_error->IsNativeError());
1592   v8::Handle<Value> not_error = CompileRun("{a:42}");
1593   CHECK(!not_error->IsNativeError());
1594   v8::Handle<Value> not_object = CompileRun("42");
1595   CHECK(!not_object->IsNativeError());
1596 }
1597
1598
1599 THREADED_TEST(IsGeneratorFunctionOrObject) {
1600   LocalContext env;
1601   v8::HandleScope scope(env->GetIsolate());
1602
1603   CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1604   v8::Handle<Value> gen = CompileRun("gen");
1605   v8::Handle<Value> genObj = CompileRun("gen()");
1606   v8::Handle<Value> object = CompileRun("{a:42}");
1607   v8::Handle<Value> func = CompileRun("func");
1608
1609   CHECK(gen->IsGeneratorFunction());
1610   CHECK(gen->IsFunction());
1611   CHECK(!gen->IsGeneratorObject());
1612
1613   CHECK(!genObj->IsGeneratorFunction());
1614   CHECK(!genObj->IsFunction());
1615   CHECK(genObj->IsGeneratorObject());
1616
1617   CHECK(!object->IsGeneratorFunction());
1618   CHECK(!object->IsFunction());
1619   CHECK(!object->IsGeneratorObject());
1620
1621   CHECK(!func->IsGeneratorFunction());
1622   CHECK(func->IsFunction());
1623   CHECK(!func->IsGeneratorObject());
1624 }
1625
1626
1627 THREADED_TEST(ArgumentsObject) {
1628   LocalContext env;
1629   v8::HandleScope scope(env->GetIsolate());
1630   v8::Handle<Value> arguments_object =
1631       CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1632   CHECK(arguments_object->IsArgumentsObject());
1633   v8::Handle<Value> array = CompileRun("[1,2,3]");
1634   CHECK(!array->IsArgumentsObject());
1635   v8::Handle<Value> object = CompileRun("{a:42}");
1636   CHECK(!object->IsArgumentsObject());
1637 }
1638
1639
1640 THREADED_TEST(IsMapOrSet) {
1641   LocalContext env;
1642   v8::HandleScope scope(env->GetIsolate());
1643   v8::Handle<Value> map = CompileRun("new Map()");
1644   v8::Handle<Value> set = CompileRun("new Set()");
1645   v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1646   v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1647   CHECK(map->IsMap());
1648   CHECK(set->IsSet());
1649   CHECK(weak_map->IsWeakMap());
1650   CHECK(weak_set->IsWeakSet());
1651
1652   CHECK(!map->IsSet());
1653   CHECK(!map->IsWeakMap());
1654   CHECK(!map->IsWeakSet());
1655
1656   CHECK(!set->IsMap());
1657   CHECK(!set->IsWeakMap());
1658   CHECK(!set->IsWeakSet());
1659
1660   CHECK(!weak_map->IsMap());
1661   CHECK(!weak_map->IsSet());
1662   CHECK(!weak_map->IsWeakSet());
1663
1664   CHECK(!weak_set->IsMap());
1665   CHECK(!weak_set->IsSet());
1666   CHECK(!weak_set->IsWeakMap());
1667
1668   v8::Handle<Value> object = CompileRun("{a:42}");
1669   CHECK(!object->IsMap());
1670   CHECK(!object->IsSet());
1671   CHECK(!object->IsWeakMap());
1672   CHECK(!object->IsWeakSet());
1673 }
1674
1675
1676 THREADED_TEST(StringObject) {
1677   LocalContext env;
1678   v8::HandleScope scope(env->GetIsolate());
1679   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1680   CHECK(boxed_string->IsStringObject());
1681   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1682   CHECK(!unboxed_string->IsStringObject());
1683   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1684   CHECK(!boxed_not_string->IsStringObject());
1685   v8::Handle<Value> not_object = CompileRun("0");
1686   CHECK(!not_object->IsStringObject());
1687   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1688   CHECK(!as_boxed.IsEmpty());
1689   Local<v8::String> the_string = as_boxed->ValueOf();
1690   CHECK(!the_string.IsEmpty());
1691   ExpectObject("\"test\"", the_string);
1692   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1693   CHECK(new_boxed_string->IsStringObject());
1694   as_boxed = new_boxed_string.As<v8::StringObject>();
1695   the_string = as_boxed->ValueOf();
1696   CHECK(!the_string.IsEmpty());
1697   ExpectObject("\"test\"", the_string);
1698 }
1699
1700
1701 THREADED_TEST(NumberObject) {
1702   LocalContext env;
1703   v8::HandleScope scope(env->GetIsolate());
1704   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1705   CHECK(boxed_number->IsNumberObject());
1706   v8::Handle<Value> unboxed_number = CompileRun("42");
1707   CHECK(!unboxed_number->IsNumberObject());
1708   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1709   CHECK(!boxed_not_number->IsNumberObject());
1710   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1711   CHECK(!as_boxed.IsEmpty());
1712   double the_number = as_boxed->ValueOf();
1713   CHECK_EQ(42.0, the_number);
1714   v8::Handle<v8::Value> new_boxed_number =
1715       v8::NumberObject::New(env->GetIsolate(), 43);
1716   CHECK(new_boxed_number->IsNumberObject());
1717   as_boxed = new_boxed_number.As<v8::NumberObject>();
1718   the_number = as_boxed->ValueOf();
1719   CHECK_EQ(43.0, the_number);
1720 }
1721
1722
1723 THREADED_TEST(BooleanObject) {
1724   LocalContext env;
1725   v8::HandleScope scope(env->GetIsolate());
1726   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1727   CHECK(boxed_boolean->IsBooleanObject());
1728   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1729   CHECK(!unboxed_boolean->IsBooleanObject());
1730   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1731   CHECK(!boxed_not_boolean->IsBooleanObject());
1732   v8::Handle<v8::BooleanObject> as_boxed =
1733       boxed_boolean.As<v8::BooleanObject>();
1734   CHECK(!as_boxed.IsEmpty());
1735   bool the_boolean = as_boxed->ValueOf();
1736   CHECK_EQ(true, the_boolean);
1737   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1738   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1739   CHECK(boxed_true->IsBooleanObject());
1740   CHECK(boxed_false->IsBooleanObject());
1741   as_boxed = boxed_true.As<v8::BooleanObject>();
1742   CHECK_EQ(true, as_boxed->ValueOf());
1743   as_boxed = boxed_false.As<v8::BooleanObject>();
1744   CHECK_EQ(false, as_boxed->ValueOf());
1745 }
1746
1747
1748 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1749   LocalContext env;
1750   v8::HandleScope scope(env->GetIsolate());
1751
1752   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1753   CHECK(primitive_false->IsBoolean());
1754   CHECK(!primitive_false->IsBooleanObject());
1755   CHECK(!primitive_false->BooleanValue());
1756   CHECK(!primitive_false->IsTrue());
1757   CHECK(primitive_false->IsFalse());
1758
1759   Local<Value> false_value = BooleanObject::New(false);
1760   CHECK(!false_value->IsBoolean());
1761   CHECK(false_value->IsBooleanObject());
1762   CHECK(false_value->BooleanValue());
1763   CHECK(!false_value->IsTrue());
1764   CHECK(!false_value->IsFalse());
1765
1766   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1767   CHECK(!false_boolean_object->IsBoolean());
1768   CHECK(false_boolean_object->IsBooleanObject());
1769   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1770   // CHECK(false_boolean_object->BooleanValue());
1771   CHECK(!false_boolean_object->ValueOf());
1772   CHECK(!false_boolean_object->IsTrue());
1773   CHECK(!false_boolean_object->IsFalse());
1774
1775   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1776   CHECK(primitive_true->IsBoolean());
1777   CHECK(!primitive_true->IsBooleanObject());
1778   CHECK(primitive_true->BooleanValue());
1779   CHECK(primitive_true->IsTrue());
1780   CHECK(!primitive_true->IsFalse());
1781
1782   Local<Value> true_value = BooleanObject::New(true);
1783   CHECK(!true_value->IsBoolean());
1784   CHECK(true_value->IsBooleanObject());
1785   CHECK(true_value->BooleanValue());
1786   CHECK(!true_value->IsTrue());
1787   CHECK(!true_value->IsFalse());
1788
1789   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1790   CHECK(!true_boolean_object->IsBoolean());
1791   CHECK(true_boolean_object->IsBooleanObject());
1792   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1793   // CHECK(true_boolean_object->BooleanValue());
1794   CHECK(true_boolean_object->ValueOf());
1795   CHECK(!true_boolean_object->IsTrue());
1796   CHECK(!true_boolean_object->IsFalse());
1797 }
1798
1799
1800 THREADED_TEST(Number) {
1801   LocalContext env;
1802   v8::HandleScope scope(env->GetIsolate());
1803   double PI = 3.1415926;
1804   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1805   CHECK_EQ(PI, pi_obj->NumberValue());
1806 }
1807
1808
1809 THREADED_TEST(ToNumber) {
1810   LocalContext env;
1811   v8::Isolate* isolate = CcTest::isolate();
1812   v8::HandleScope scope(isolate);
1813   Local<String> str = v8_str("3.1415926");
1814   CHECK_EQ(3.1415926, str->NumberValue());
1815   v8::Handle<v8::Boolean> t = v8::True(isolate);
1816   CHECK_EQ(1.0, t->NumberValue());
1817   v8::Handle<v8::Boolean> f = v8::False(isolate);
1818   CHECK_EQ(0.0, f->NumberValue());
1819 }
1820
1821
1822 THREADED_TEST(Date) {
1823   LocalContext env;
1824   v8::HandleScope scope(env->GetIsolate());
1825   double PI = 3.1415926;
1826   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1827   CHECK_EQ(3.0, date->NumberValue());
1828   date.As<v8::Date>()->Set(v8_str("property"),
1829                            v8::Integer::New(env->GetIsolate(), 42));
1830   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1831 }
1832
1833
1834 THREADED_TEST(Boolean) {
1835   LocalContext env;
1836   v8::Isolate* isolate = env->GetIsolate();
1837   v8::HandleScope scope(isolate);
1838   v8::Handle<v8::Boolean> t = v8::True(isolate);
1839   CHECK(t->Value());
1840   v8::Handle<v8::Boolean> f = v8::False(isolate);
1841   CHECK(!f->Value());
1842   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1843   CHECK(!u->BooleanValue());
1844   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1845   CHECK(!n->BooleanValue());
1846   v8::Handle<String> str1 = v8_str("");
1847   CHECK(!str1->BooleanValue());
1848   v8::Handle<String> str2 = v8_str("x");
1849   CHECK(str2->BooleanValue());
1850   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1851   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1852   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1853   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1854   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1855 }
1856
1857
1858 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1859   ApiTestFuzzer::Fuzz();
1860   args.GetReturnValue().Set(v8_num(13.4));
1861 }
1862
1863
1864 static void GetM(Local<String> name,
1865                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1866   ApiTestFuzzer::Fuzz();
1867   info.GetReturnValue().Set(v8_num(876));
1868 }
1869
1870
1871 THREADED_TEST(GlobalPrototype) {
1872   v8::Isolate* isolate = CcTest::isolate();
1873   v8::HandleScope scope(isolate);
1874   v8::Handle<v8::FunctionTemplate> func_templ =
1875       v8::FunctionTemplate::New(isolate);
1876   func_templ->PrototypeTemplate()->Set(
1877       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1878   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1879   templ->Set(isolate, "x", v8_num(200));
1880   templ->SetAccessor(v8_str("m"), GetM);
1881   LocalContext env(0, templ);
1882   v8::Handle<Script> script(v8_compile("dummy()"));
1883   v8::Handle<Value> result(script->Run());
1884   CHECK_EQ(13.4, result->NumberValue());
1885   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1886   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1887 }
1888
1889
1890 THREADED_TEST(ObjectTemplate) {
1891   v8::Isolate* isolate = CcTest::isolate();
1892   v8::HandleScope scope(isolate);
1893   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1894   templ1->Set(isolate, "x", v8_num(10));
1895   templ1->Set(isolate, "y", v8_num(13));
1896   LocalContext env;
1897   Local<v8::Object> instance1 = templ1->NewInstance();
1898   env->Global()->Set(v8_str("p"), instance1);
1899   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1900   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1901   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1902   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1903   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1904   templ2->Set(isolate, "a", v8_num(12));
1905   templ2->Set(isolate, "b", templ1);
1906   Local<v8::Object> instance2 = templ2->NewInstance();
1907   env->Global()->Set(v8_str("q"), instance2);
1908   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1909   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1910   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1911   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1912 }
1913
1914
1915 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1916   ApiTestFuzzer::Fuzz();
1917   args.GetReturnValue().Set(v8_num(17.2));
1918 }
1919
1920
1921 static void GetKnurd(Local<String> property,
1922                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1923   ApiTestFuzzer::Fuzz();
1924   info.GetReturnValue().Set(v8_num(15.2));
1925 }
1926
1927
1928 THREADED_TEST(DescriptorInheritance) {
1929   v8::Isolate* isolate = CcTest::isolate();
1930   v8::HandleScope scope(isolate);
1931   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1932   super->PrototypeTemplate()->Set(isolate, "flabby",
1933                                   v8::FunctionTemplate::New(isolate,
1934                                                             GetFlabby));
1935   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1936
1937   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1938
1939   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1940   base1->Inherit(super);
1941   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1942
1943   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1944   base2->Inherit(super);
1945   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1946
1947   LocalContext env;
1948
1949   env->Global()->Set(v8_str("s"), super->GetFunction());
1950   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1951   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1952
1953   // Checks right __proto__ chain.
1954   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1955   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1956
1957   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1958
1959   // Instance accessor should not be visible on function object or its prototype
1960   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1961   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1962   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1963
1964   env->Global()->Set(v8_str("obj"),
1965                      base1->GetFunction()->NewInstance());
1966   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1967   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1968   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1969   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1970   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1971
1972   env->Global()->Set(v8_str("obj2"),
1973                      base2->GetFunction()->NewInstance());
1974   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1975   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1976   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1977   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1978   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1979
1980   // base1 and base2 cannot cross reference to each's prototype
1981   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1982   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1983 }
1984
1985
1986 int echo_named_call_count;
1987
1988
1989 static void EchoNamedProperty(Local<Name> name,
1990                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1991   ApiTestFuzzer::Fuzz();
1992   CHECK_EQ(v8_str("data"), info.Data());
1993   echo_named_call_count++;
1994   info.GetReturnValue().Set(name);
1995 }
1996
1997
1998 // Helper functions for Interceptor/Accessor interaction tests
1999
2000 void SimpleAccessorGetter(Local<String> name,
2001                           const v8::PropertyCallbackInfo<v8::Value>& info) {
2002   Handle<Object> self = Handle<Object>::Cast(info.This());
2003   info.GetReturnValue().Set(
2004       self->Get(String::Concat(v8_str("accessor_"), name)));
2005 }
2006
2007 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2008                           const v8::PropertyCallbackInfo<void>& info) {
2009   Handle<Object> self = Handle<Object>::Cast(info.This());
2010   self->Set(String::Concat(v8_str("accessor_"), name), value);
2011 }
2012
2013 void SymbolAccessorGetter(Local<Name> name,
2014                           const v8::PropertyCallbackInfo<v8::Value>& info) {
2015   CHECK(name->IsSymbol());
2016   Local<Symbol> sym = Local<Symbol>::Cast(name);
2017   if (sym->Name()->IsUndefined())
2018     return;
2019   SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2020 }
2021
2022 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2023                           const v8::PropertyCallbackInfo<void>& info) {
2024   CHECK(name->IsSymbol());
2025   Local<Symbol> sym = Local<Symbol>::Cast(name);
2026   if (sym->Name()->IsUndefined())
2027     return;
2028   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2029 }
2030
2031 void SymbolAccessorGetterReturnsDefault(
2032     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2033   CHECK(name->IsSymbol());
2034   Local<Symbol> sym = Local<Symbol>::Cast(name);
2035   if (sym->Name()->IsUndefined()) return;
2036   info.GetReturnValue().Set(info.Data());
2037 }
2038
2039 static void ThrowingSymbolAccessorGetter(
2040     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2041   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2042 }
2043
2044
2045 void EmptyInterceptorGetter(Local<Name> name,
2046                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
2047
2048
2049 void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
2050                             const v8::PropertyCallbackInfo<v8::Value>& info) {}
2051
2052
2053 void EmptyGenericInterceptorGetter(
2054     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
2055
2056
2057 void EmptyGenericInterceptorSetter(
2058     Local<Name> name, Local<Value> value,
2059     const v8::PropertyCallbackInfo<v8::Value>& info) {}
2060
2061
2062 void StringInterceptorGetter(
2063     Local<String> name,
2064     const v8::PropertyCallbackInfo<v8::Value>&
2065         info) {  // Intercept names that start with 'interceptor_'.
2066   String::Utf8Value utf8(name);
2067   char* name_str = *utf8;
2068   char prefix[] = "interceptor_";
2069   int i;
2070   for (i = 0; name_str[i] && prefix[i]; ++i) {
2071     if (name_str[i] != prefix[i]) return;
2072   }
2073   Handle<Object> self = Handle<Object>::Cast(info.This());
2074   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
2075 }
2076
2077
2078 void StringInterceptorSetter(Local<String> name, Local<Value> value,
2079                              const v8::PropertyCallbackInfo<v8::Value>& info) {
2080   // Intercept accesses that set certain integer values, for which the name does
2081   // not start with 'accessor_'.
2082   String::Utf8Value utf8(name);
2083   char* name_str = *utf8;
2084   char prefix[] = "accessor_";
2085   int i;
2086   for (i = 0; name_str[i] && prefix[i]; ++i) {
2087     if (name_str[i] != prefix[i]) break;
2088   }
2089   if (!prefix[i]) return;
2090
2091   if (value->IsInt32() && value->Int32Value() < 10000) {
2092     Handle<Object> self = Handle<Object>::Cast(info.This());
2093     self->SetHiddenValue(name, value);
2094     info.GetReturnValue().Set(value);
2095   }
2096 }
2097
2098 void InterceptorGetter(Local<Name> generic_name,
2099                        const v8::PropertyCallbackInfo<v8::Value>& info) {
2100   if (generic_name->IsSymbol()) return;
2101   StringInterceptorGetter(Local<String>::Cast(generic_name), info);
2102 }
2103
2104 void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
2105                        const v8::PropertyCallbackInfo<v8::Value>& info) {
2106   if (generic_name->IsSymbol()) return;
2107   StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
2108 }
2109
2110 void GenericInterceptorGetter(Local<Name> generic_name,
2111                               const v8::PropertyCallbackInfo<v8::Value>& info) {
2112   Local<String> str;
2113   if (generic_name->IsSymbol()) {
2114     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
2115     if (name->IsUndefined()) return;
2116     str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
2117   } else {
2118     Local<String> name = Local<String>::Cast(generic_name);
2119     String::Utf8Value utf8(name);
2120     char* name_str = *utf8;
2121     if (*name_str == '_') return;
2122     str = String::Concat(v8_str("_str_"), name);
2123   }
2124
2125   Handle<Object> self = Handle<Object>::Cast(info.This());
2126   info.GetReturnValue().Set(self->Get(str));
2127 }
2128
2129 void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
2130                               const v8::PropertyCallbackInfo<v8::Value>& info) {
2131   Local<String> str;
2132   if (generic_name->IsSymbol()) {
2133     Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
2134     if (name->IsUndefined()) return;
2135     str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
2136   } else {
2137     Local<String> name = Local<String>::Cast(generic_name);
2138     String::Utf8Value utf8(name);
2139     char* name_str = *utf8;
2140     if (*name_str == '_') return;
2141     str = String::Concat(v8_str("_str_"), name);
2142   }
2143
2144   Handle<Object> self = Handle<Object>::Cast(info.This());
2145   self->Set(str, value);
2146   info.GetReturnValue().Set(value);
2147 }
2148
2149 void AddAccessor(Handle<FunctionTemplate> templ,
2150                  Handle<String> name,
2151                  v8::AccessorGetterCallback getter,
2152                  v8::AccessorSetterCallback setter) {
2153   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2154 }
2155
2156 void AddInterceptor(Handle<FunctionTemplate> templ,
2157                     v8::NamedPropertyGetterCallback getter,
2158                     v8::NamedPropertySetterCallback setter) {
2159   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2160 }
2161
2162
2163 void AddAccessor(Handle<FunctionTemplate> templ,
2164                  Handle<Name> name,
2165                  v8::AccessorNameGetterCallback getter,
2166                  v8::AccessorNameSetterCallback setter) {
2167   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2168 }
2169
2170 void AddInterceptor(Handle<FunctionTemplate> templ,
2171                     v8::GenericNamedPropertyGetterCallback getter,
2172                     v8::GenericNamedPropertySetterCallback setter) {
2173   templ->InstanceTemplate()->SetHandler(
2174       v8::NamedPropertyHandlerConfiguration(getter, setter));
2175 }
2176
2177
2178 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2179   v8::HandleScope scope(CcTest::isolate());
2180   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2181   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2182   child->Inherit(parent);
2183   AddAccessor(parent, v8_str("age"),
2184               SimpleAccessorGetter, SimpleAccessorSetter);
2185   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2186   LocalContext env;
2187   env->Global()->Set(v8_str("Child"), child->GetFunction());
2188   CompileRun("var child = new Child;"
2189              "child.age = 10;");
2190   ExpectBoolean("child.hasOwnProperty('age')", false);
2191   ExpectInt32("child.age", 10);
2192   ExpectInt32("child.accessor_age", 10);
2193 }
2194
2195
2196 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
2197   LocalContext env;
2198   v8::Isolate* isolate = CcTest::isolate();
2199   v8::HandleScope scope(isolate);
2200   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2201   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2202   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
2203
2204   child->Inherit(parent);
2205   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
2206   AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
2207
2208   env->Global()->Set(v8_str("Child"), child->GetFunction());
2209   env->Global()->Set(v8_str("age"), age);
2210   CompileRun(
2211       "var child = new Child;"
2212       "child[age] = 10;");
2213   ExpectInt32("child[age]", 10);
2214   ExpectBoolean("child.hasOwnProperty('age')", false);
2215   ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
2216 }
2217
2218
2219 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
2220   LocalContext env;
2221   v8::Isolate* isolate = CcTest::isolate();
2222   v8::HandleScope scope(isolate);
2223   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2224   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2225   v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
2226   v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
2227
2228   child->Inherit(parent);
2229   AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
2230   AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
2231
2232   env->Global()->Set(v8_str("Child"), child->GetFunction());
2233   env->Global()->Set(v8_str("age"), age);
2234   env->Global()->Set(v8_str("anon"), anon);
2235   CompileRun(
2236       "var child = new Child;"
2237       "child[age] = 10;");
2238   ExpectInt32("child[age]", 10);
2239   ExpectInt32("child._sym_age", 10);
2240
2241   // Check that it also sees strings.
2242   CompileRun("child.foo = 47");
2243   ExpectInt32("child.foo", 47);
2244   ExpectInt32("child._str_foo", 47);
2245
2246   // Check that the interceptor can punt (in this case, on anonymous symbols).
2247   CompileRun("child[anon] = 31337");
2248   ExpectInt32("child[anon]", 31337);
2249 }
2250
2251
2252 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2253   v8::Isolate* isolate = CcTest::isolate();
2254   v8::HandleScope scope(isolate);
2255   LocalContext env;
2256   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2257   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2258   CHECK(a->map()->instance_descriptors()->IsFixedArray());
2259   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2260   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2261   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2262   // But we should still have an ExecutableAccessorInfo.
2263   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2264   i::LookupResult lookup(i_isolate);
2265   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2266   i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2267   CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2268   CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2269 }
2270
2271
2272 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2273   v8::HandleScope scope(CcTest::isolate());
2274   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2275   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2276   LocalContext env;
2277   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2278   CompileRun("var o1 = new Constructor;"
2279              "o1.a = 1;"  // Ensure a and x share the descriptor array.
2280              "Object.defineProperty(o1, 'x', {value: 10});");
2281   CompileRun("var o2 = new Constructor;"
2282              "o2.a = 1;"
2283              "Object.defineProperty(o2, 'x', {value: 10});");
2284 }
2285
2286
2287 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2288   v8::Isolate* isolate = CcTest::isolate();
2289   v8::HandleScope scope(isolate);
2290   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2291   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2292   child->Inherit(parent);
2293   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2294   LocalContext env;
2295   env->Global()->Set(v8_str("Child"), child->GetFunction());
2296   CompileRun("var child = new Child;"
2297              "var parent = child.__proto__;"
2298              "Object.defineProperty(parent, 'age', "
2299              "  {get: function(){ return this.accessor_age; }, "
2300              "   set: function(v){ this.accessor_age = v; }, "
2301              "   enumerable: true, configurable: true});"
2302              "child.age = 10;");
2303   ExpectBoolean("child.hasOwnProperty('age')", false);
2304   ExpectInt32("child.age", 10);
2305   ExpectInt32("child.accessor_age", 10);
2306 }
2307
2308
2309 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2310   v8::Isolate* isolate = CcTest::isolate();
2311   v8::HandleScope scope(isolate);
2312   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2313   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2314   child->Inherit(parent);
2315   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2316   LocalContext env;
2317   env->Global()->Set(v8_str("Child"), child->GetFunction());
2318   CompileRun("var child = new Child;"
2319              "var parent = child.__proto__;"
2320              "parent.name = 'Alice';");
2321   ExpectBoolean("child.hasOwnProperty('name')", false);
2322   ExpectString("child.name", "Alice");
2323   CompileRun("child.name = 'Bob';");
2324   ExpectString("child.name", "Bob");
2325   ExpectBoolean("child.hasOwnProperty('name')", true);
2326   ExpectString("parent.name", "Alice");
2327 }
2328
2329
2330 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2331   v8::HandleScope scope(CcTest::isolate());
2332   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2333   AddAccessor(templ, v8_str("age"),
2334               SimpleAccessorGetter, SimpleAccessorSetter);
2335   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2336   LocalContext env;
2337   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2338   CompileRun("var obj = new Obj;"
2339              "function setAge(i){ obj.age = i; };"
2340              "for(var i = 0; i <= 10000; i++) setAge(i);");
2341   // All i < 10000 go to the interceptor.
2342   ExpectInt32("obj.interceptor_age", 9999);
2343   // The last i goes to the accessor.
2344   ExpectInt32("obj.accessor_age", 10000);
2345 }
2346
2347
2348 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2349   v8::HandleScope scope(CcTest::isolate());
2350   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2351   AddAccessor(templ, v8_str("age"),
2352               SimpleAccessorGetter, SimpleAccessorSetter);
2353   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2354   LocalContext env;
2355   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2356   CompileRun("var obj = new Obj;"
2357              "function setAge(i){ obj.age = i; };"
2358              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2359   // All i >= 10000 go to the accessor.
2360   ExpectInt32("obj.accessor_age", 10000);
2361   // The last i goes to the interceptor.
2362   ExpectInt32("obj.interceptor_age", 9999);
2363 }
2364
2365
2366 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2367   v8::HandleScope scope(CcTest::isolate());
2368   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2369   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2370   child->Inherit(parent);
2371   AddAccessor(parent, v8_str("age"),
2372               SimpleAccessorGetter, SimpleAccessorSetter);
2373   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2374   LocalContext env;
2375   env->Global()->Set(v8_str("Child"), child->GetFunction());
2376   CompileRun("var child = new Child;"
2377              "function setAge(i){ child.age = i; };"
2378              "for(var i = 0; i <= 10000; i++) setAge(i);");
2379   // All i < 10000 go to the interceptor.
2380   ExpectInt32("child.interceptor_age", 9999);
2381   // The last i goes to the accessor.
2382   ExpectInt32("child.accessor_age", 10000);
2383 }
2384
2385
2386 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2387   v8::HandleScope scope(CcTest::isolate());
2388   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2389   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2390   child->Inherit(parent);
2391   AddAccessor(parent, v8_str("age"),
2392               SimpleAccessorGetter, SimpleAccessorSetter);
2393   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2394   LocalContext env;
2395   env->Global()->Set(v8_str("Child"), child->GetFunction());
2396   CompileRun("var child = new Child;"
2397              "function setAge(i){ child.age = i; };"
2398              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2399   // All i >= 10000 go to the accessor.
2400   ExpectInt32("child.accessor_age", 10000);
2401   // The last i goes to the interceptor.
2402   ExpectInt32("child.interceptor_age", 9999);
2403 }
2404
2405
2406 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2407   v8::HandleScope scope(CcTest::isolate());
2408   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2409   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2410   LocalContext env;
2411   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2412   CompileRun("var obj = new Obj;"
2413              "function setter(i) { this.accessor_age = i; };"
2414              "function getter() { return this.accessor_age; };"
2415              "function setAge(i) { obj.age = i; };"
2416              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2417              "for(var i = 0; i <= 10000; i++) setAge(i);");
2418   // All i < 10000 go to the interceptor.
2419   ExpectInt32("obj.interceptor_age", 9999);
2420   // The last i goes to the JavaScript accessor.
2421   ExpectInt32("obj.accessor_age", 10000);
2422   // The installed JavaScript getter is still intact.
2423   // This last part is a regression test for issue 1651 and relies on the fact
2424   // that both interceptor and accessor are being installed on the same object.
2425   ExpectInt32("obj.age", 10000);
2426   ExpectBoolean("obj.hasOwnProperty('age')", true);
2427   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2428 }
2429
2430
2431 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2432   v8::HandleScope scope(CcTest::isolate());
2433   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2434   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2435   LocalContext env;
2436   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2437   CompileRun("var obj = new Obj;"
2438              "function setter(i) { this.accessor_age = i; };"
2439              "function getter() { return this.accessor_age; };"
2440              "function setAge(i) { obj.age = i; };"
2441              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2442              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2443   // All i >= 10000 go to the accessor.
2444   ExpectInt32("obj.accessor_age", 10000);
2445   // The last i goes to the interceptor.
2446   ExpectInt32("obj.interceptor_age", 9999);
2447   // The installed JavaScript getter is still intact.
2448   // This last part is a regression test for issue 1651 and relies on the fact
2449   // that both interceptor and accessor are being installed on the same object.
2450   ExpectInt32("obj.age", 10000);
2451   ExpectBoolean("obj.hasOwnProperty('age')", true);
2452   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2453 }
2454
2455
2456 THREADED_TEST(SwitchFromInterceptorToProperty) {
2457   v8::HandleScope scope(CcTest::isolate());
2458   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2459   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2460   child->Inherit(parent);
2461   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2462   LocalContext env;
2463   env->Global()->Set(v8_str("Child"), child->GetFunction());
2464   CompileRun("var child = new Child;"
2465              "function setAge(i){ child.age = i; };"
2466              "for(var i = 0; i <= 10000; i++) setAge(i);");
2467   // All i < 10000 go to the interceptor.
2468   ExpectInt32("child.interceptor_age", 9999);
2469   // The last i goes to child's own property.
2470   ExpectInt32("child.age", 10000);
2471 }
2472
2473
2474 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2475   v8::HandleScope scope(CcTest::isolate());
2476   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2477   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2478   child->Inherit(parent);
2479   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2480   LocalContext env;
2481   env->Global()->Set(v8_str("Child"), child->GetFunction());
2482   CompileRun("var child = new Child;"
2483              "function setAge(i){ child.age = i; };"
2484              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2485   // All i >= 10000 go to child's own property.
2486   ExpectInt32("child.age", 10000);
2487   // The last i goes to the interceptor.
2488   ExpectInt32("child.interceptor_age", 9999);
2489 }
2490
2491
2492 THREADED_TEST(NamedPropertyHandlerGetter) {
2493   echo_named_call_count = 0;
2494   v8::HandleScope scope(CcTest::isolate());
2495   v8::Handle<v8::FunctionTemplate> templ =
2496       v8::FunctionTemplate::New(CcTest::isolate());
2497   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2498       EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
2499   LocalContext env;
2500   env->Global()->Set(v8_str("obj"),
2501                      templ->GetFunction()->NewInstance());
2502   CHECK_EQ(echo_named_call_count, 0);
2503   v8_compile("obj.x")->Run();
2504   CHECK_EQ(echo_named_call_count, 1);
2505   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2506   v8::Handle<Value> str = CompileRun(code);
2507   String::Utf8Value value(str);
2508   CHECK_EQ(*value, "oddlepoddle");
2509   // Check default behavior
2510   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2511   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2512   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2513 }
2514
2515
2516 int echo_indexed_call_count = 0;
2517
2518
2519 static void EchoIndexedProperty(
2520     uint32_t index,
2521     const v8::PropertyCallbackInfo<v8::Value>& info) {
2522   ApiTestFuzzer::Fuzz();
2523   CHECK_EQ(v8_num(637), info.Data());
2524   echo_indexed_call_count++;
2525   info.GetReturnValue().Set(v8_num(index));
2526 }
2527
2528
2529 THREADED_TEST(IndexedPropertyHandlerGetter) {
2530   v8::Isolate* isolate = CcTest::isolate();
2531   v8::HandleScope scope(isolate);
2532   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2533   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2534       EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
2535   LocalContext env;
2536   env->Global()->Set(v8_str("obj"),
2537                      templ->GetFunction()->NewInstance());
2538   Local<Script> script = v8_compile("obj[900]");
2539   CHECK_EQ(script->Run()->Int32Value(), 900);
2540 }
2541
2542
2543 v8::Handle<v8::Object> bottom;
2544
2545 static void CheckThisIndexedPropertyHandler(
2546     uint32_t index,
2547     const v8::PropertyCallbackInfo<v8::Value>& info) {
2548   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2549   ApiTestFuzzer::Fuzz();
2550   CHECK(info.This()->Equals(bottom));
2551 }
2552
2553 static void CheckThisNamedPropertyHandler(
2554     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2555   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2556   ApiTestFuzzer::Fuzz();
2557   CHECK(info.This()->Equals(bottom));
2558 }
2559
2560 void CheckThisIndexedPropertySetter(
2561     uint32_t index,
2562     Local<Value> value,
2563     const v8::PropertyCallbackInfo<v8::Value>& info) {
2564   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2565   ApiTestFuzzer::Fuzz();
2566   CHECK(info.This()->Equals(bottom));
2567 }
2568
2569
2570 void CheckThisNamedPropertySetter(
2571     Local<Name> property, Local<Value> value,
2572     const v8::PropertyCallbackInfo<v8::Value>& info) {
2573   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2574   ApiTestFuzzer::Fuzz();
2575   CHECK(info.This()->Equals(bottom));
2576 }
2577
2578 void CheckThisIndexedPropertyQuery(
2579     uint32_t index,
2580     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2581   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2582   ApiTestFuzzer::Fuzz();
2583   CHECK(info.This()->Equals(bottom));
2584 }
2585
2586
2587 void CheckThisNamedPropertyQuery(
2588     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
2589   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2590   ApiTestFuzzer::Fuzz();
2591   CHECK(info.This()->Equals(bottom));
2592 }
2593
2594
2595 void CheckThisIndexedPropertyDeleter(
2596     uint32_t index,
2597     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2598   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2599   ApiTestFuzzer::Fuzz();
2600   CHECK(info.This()->Equals(bottom));
2601 }
2602
2603
2604 void CheckThisNamedPropertyDeleter(
2605     Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2606   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2607   ApiTestFuzzer::Fuzz();
2608   CHECK(info.This()->Equals(bottom));
2609 }
2610
2611
2612 void CheckThisIndexedPropertyEnumerator(
2613     const v8::PropertyCallbackInfo<v8::Array>& info) {
2614   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2615   ApiTestFuzzer::Fuzz();
2616   CHECK(info.This()->Equals(bottom));
2617 }
2618
2619
2620 void CheckThisNamedPropertyEnumerator(
2621     const v8::PropertyCallbackInfo<v8::Array>& info) {
2622   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2623   ApiTestFuzzer::Fuzz();
2624   CHECK(info.This()->Equals(bottom));
2625 }
2626
2627
2628 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2629   LocalContext env;
2630   v8::Isolate* isolate = env->GetIsolate();
2631   v8::HandleScope scope(isolate);
2632
2633   // Set up a prototype chain with three interceptors.
2634   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2635   templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2636       CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
2637       CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
2638       CheckThisIndexedPropertyEnumerator));
2639
2640   templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2641       CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
2642       CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
2643       CheckThisNamedPropertyEnumerator));
2644
2645   bottom = templ->GetFunction()->NewInstance();
2646   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2647   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2648
2649   bottom->SetPrototype(middle);
2650   middle->SetPrototype(top);
2651   env->Global()->Set(v8_str("obj"), bottom);
2652
2653   // Indexed and named get.
2654   CompileRun("obj[0]");
2655   CompileRun("obj.x");
2656
2657   // Indexed and named set.
2658   CompileRun("obj[1] = 42");
2659   CompileRun("obj.y = 42");
2660
2661   // Indexed and named query.
2662   CompileRun("0 in obj");
2663   CompileRun("'x' in obj");
2664
2665   // Indexed and named deleter.
2666   CompileRun("delete obj[0]");
2667   CompileRun("delete obj.x");
2668
2669   // Enumerators.
2670   CompileRun("for (var p in obj) ;");
2671 }
2672
2673
2674 static void PrePropertyHandlerGet(
2675     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2676   ApiTestFuzzer::Fuzz();
2677   if (v8_str("pre")->Equals(key)) {
2678     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2679   }
2680 }
2681
2682
2683 static void PrePropertyHandlerQuery(
2684     Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
2685   if (v8_str("pre")->Equals(key)) {
2686     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2687   }
2688 }
2689
2690
2691 THREADED_TEST(PrePropertyHandler) {
2692   v8::Isolate* isolate = CcTest::isolate();
2693   v8::HandleScope scope(isolate);
2694   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2695   desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2696       PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
2697   LocalContext env(NULL, desc->InstanceTemplate());
2698   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2699   v8::Handle<Value> result_pre = CompileRun("pre");
2700   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2701   v8::Handle<Value> result_on = CompileRun("on");
2702   CHECK_EQ(v8_str("Object: on"), result_on);
2703   v8::Handle<Value> result_post = CompileRun("post");
2704   CHECK(result_post.IsEmpty());
2705 }
2706
2707
2708 THREADED_TEST(UndefinedIsNotEnumerable) {
2709   LocalContext env;
2710   v8::HandleScope scope(env->GetIsolate());
2711   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2712   CHECK(result->IsFalse());
2713 }
2714
2715
2716 v8::Handle<Script> call_recursively_script;
2717 static const int kTargetRecursionDepth = 200;  // near maximum
2718
2719
2720 static void CallScriptRecursivelyCall(
2721     const v8::FunctionCallbackInfo<v8::Value>& args) {
2722   ApiTestFuzzer::Fuzz();
2723   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2724   if (depth == kTargetRecursionDepth) return;
2725   args.This()->Set(v8_str("depth"),
2726                    v8::Integer::New(args.GetIsolate(), depth + 1));
2727   args.GetReturnValue().Set(call_recursively_script->Run());
2728 }
2729
2730
2731 static void CallFunctionRecursivelyCall(
2732     const v8::FunctionCallbackInfo<v8::Value>& args) {
2733   ApiTestFuzzer::Fuzz();
2734   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2735   if (depth == kTargetRecursionDepth) {
2736     printf("[depth = %d]\n", depth);
2737     return;
2738   }
2739   args.This()->Set(v8_str("depth"),
2740                    v8::Integer::New(args.GetIsolate(), depth + 1));
2741   v8::Handle<Value> function =
2742       args.This()->Get(v8_str("callFunctionRecursively"));
2743   args.GetReturnValue().Set(
2744       function.As<Function>()->Call(args.This(), 0, NULL));
2745 }
2746
2747
2748 THREADED_TEST(DeepCrossLanguageRecursion) {
2749   v8::Isolate* isolate = CcTest::isolate();
2750   v8::HandleScope scope(isolate);
2751   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2752   global->Set(v8_str("callScriptRecursively"),
2753               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2754   global->Set(v8_str("callFunctionRecursively"),
2755               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2756   LocalContext env(NULL, global);
2757
2758   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2759   call_recursively_script = v8_compile("callScriptRecursively()");
2760   call_recursively_script->Run();
2761   call_recursively_script = v8::Handle<Script>();
2762
2763   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2764   CompileRun("callFunctionRecursively()");
2765 }
2766
2767
2768 static void ThrowingPropertyHandlerGet(
2769     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2770   // Since this interceptor is used on "with" objects, the runtime will look up
2771   // @@unscopables.  Punt.
2772   if (key->IsSymbol()) return;
2773   ApiTestFuzzer::Fuzz();
2774   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2775 }
2776
2777
2778 static void ThrowingPropertyHandlerSet(
2779     Local<Name> key, Local<Value>,
2780     const v8::PropertyCallbackInfo<v8::Value>& info) {
2781   info.GetIsolate()->ThrowException(key);
2782   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2783 }
2784
2785
2786 THREADED_TEST(CallbackExceptionRegression) {
2787   v8::Isolate* isolate = CcTest::isolate();
2788   v8::HandleScope scope(isolate);
2789   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2790   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2791       ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2792   LocalContext env;
2793   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2794   v8::Handle<Value> otto = CompileRun(
2795       "try { with (obj) { otto; } } catch (e) { e; }");
2796   CHECK_EQ(v8_str("otto"), otto);
2797   v8::Handle<Value> netto = CompileRun(
2798       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2799   CHECK_EQ(v8_str("netto"), netto);
2800 }
2801
2802
2803 THREADED_TEST(FunctionPrototype) {
2804   v8::Isolate* isolate = CcTest::isolate();
2805   v8::HandleScope scope(isolate);
2806   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2807   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2808   LocalContext env;
2809   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2810   Local<Script> script = v8_compile("Foo.prototype.plak");
2811   CHECK_EQ(script->Run()->Int32Value(), 321);
2812 }
2813
2814
2815 THREADED_TEST(InternalFields) {
2816   LocalContext env;
2817   v8::Isolate* isolate = env->GetIsolate();
2818   v8::HandleScope scope(isolate);
2819
2820   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2821   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2822   instance_templ->SetInternalFieldCount(1);
2823   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2824   CHECK_EQ(1, obj->InternalFieldCount());
2825   CHECK(obj->GetInternalField(0)->IsUndefined());
2826   obj->SetInternalField(0, v8_num(17));
2827   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2828 }
2829
2830
2831 THREADED_TEST(GlobalObjectInternalFields) {
2832   v8::Isolate* isolate = CcTest::isolate();
2833   v8::HandleScope scope(isolate);
2834   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2835   global_template->SetInternalFieldCount(1);
2836   LocalContext env(NULL, global_template);
2837   v8::Handle<v8::Object> global_proxy = env->Global();
2838   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2839   CHECK_EQ(1, global->InternalFieldCount());
2840   CHECK(global->GetInternalField(0)->IsUndefined());
2841   global->SetInternalField(0, v8_num(17));
2842   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2843 }
2844
2845
2846 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2847   LocalContext env;
2848   v8::HandleScope scope(CcTest::isolate());
2849
2850   v8::Local<v8::Object> global = env->Global();
2851   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2852   CHECK(global->HasRealIndexedProperty(0));
2853 }
2854
2855
2856 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2857                                                void* value) {
2858   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2859   obj->SetAlignedPointerInInternalField(0, value);
2860   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2861   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2862 }
2863
2864
2865 THREADED_TEST(InternalFieldsAlignedPointers) {
2866   LocalContext env;
2867   v8::Isolate* isolate = env->GetIsolate();
2868   v8::HandleScope scope(isolate);
2869
2870   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2871   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2872   instance_templ->SetInternalFieldCount(1);
2873   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2874   CHECK_EQ(1, obj->InternalFieldCount());
2875
2876   CheckAlignedPointerInInternalField(obj, NULL);
2877
2878   int* heap_allocated = new int[100];
2879   CheckAlignedPointerInInternalField(obj, heap_allocated);
2880   delete[] heap_allocated;
2881
2882   int stack_allocated[100];
2883   CheckAlignedPointerInInternalField(obj, stack_allocated);
2884
2885   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2886   CheckAlignedPointerInInternalField(obj, huge);
2887
2888   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2889   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2890   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2891 }
2892
2893
2894 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2895                                               int index,
2896                                               void* value) {
2897   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2898   (*env)->SetAlignedPointerInEmbedderData(index, value);
2899   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2900   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2901 }
2902
2903
2904 static void* AlignedTestPointer(int i) {
2905   return reinterpret_cast<void*>(i * 1234);
2906 }
2907
2908
2909 THREADED_TEST(EmbedderDataAlignedPointers) {
2910   LocalContext env;
2911   v8::HandleScope scope(env->GetIsolate());
2912
2913   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2914
2915   int* heap_allocated = new int[100];
2916   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2917   delete[] heap_allocated;
2918
2919   int stack_allocated[100];
2920   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2921
2922   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2923   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2924
2925   // Test growing of the embedder data's backing store.
2926   for (int i = 0; i < 100; i++) {
2927     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2928   }
2929   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2930   for (int i = 0; i < 100; i++) {
2931     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2932   }
2933 }
2934
2935
2936 static void CheckEmbedderData(LocalContext* env,
2937                               int index,
2938                               v8::Handle<Value> data) {
2939   (*env)->SetEmbedderData(index, data);
2940   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2941 }
2942
2943
2944 THREADED_TEST(EmbedderData) {
2945   LocalContext env;
2946   v8::Isolate* isolate = env->GetIsolate();
2947   v8::HandleScope scope(isolate);
2948
2949   CheckEmbedderData(
2950       &env, 3,
2951       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2952   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2953                                                      "over the lazy dog."));
2954   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2955   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2956 }
2957
2958
2959 THREADED_TEST(GetIsolate) {
2960   LocalContext env;
2961   v8::Isolate* isolate = env->GetIsolate();
2962   v8::HandleScope scope(isolate);
2963   Local<v8::Object> obj = v8::Object::New(isolate);
2964   CHECK_EQ(isolate, obj->GetIsolate());
2965   CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2966 }
2967
2968
2969 THREADED_TEST(IdentityHash) {
2970   LocalContext env;
2971   v8::Isolate* isolate = env->GetIsolate();
2972   v8::HandleScope scope(isolate);
2973
2974   // Ensure that the test starts with an fresh heap to test whether the hash
2975   // code is based on the address.
2976   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2977   Local<v8::Object> obj = v8::Object::New(isolate);
2978   int hash = obj->GetIdentityHash();
2979   int hash1 = obj->GetIdentityHash();
2980   CHECK_EQ(hash, hash1);
2981   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2982   // Since the identity hash is essentially a random number two consecutive
2983   // objects should not be assigned the same hash code. If the test below fails
2984   // the random number generator should be evaluated.
2985   CHECK_NE(hash, hash2);
2986   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2987   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2988   // Make sure that the identity hash is not based on the initial address of
2989   // the object alone. If the test below fails the random number generator
2990   // should be evaluated.
2991   CHECK_NE(hash, hash3);
2992   int hash4 = obj->GetIdentityHash();
2993   CHECK_EQ(hash, hash4);
2994
2995   // Check identity hashes behaviour in the presence of JS accessors.
2996   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2997   {
2998     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2999     Local<v8::Object> o1 = v8::Object::New(isolate);
3000     Local<v8::Object> o2 = v8::Object::New(isolate);
3001     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3002   }
3003   {
3004     CompileRun(
3005         "function cnst() { return 42; };\n"
3006         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
3007     Local<v8::Object> o1 = v8::Object::New(isolate);
3008     Local<v8::Object> o2 = v8::Object::New(isolate);
3009     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3010   }
3011 }
3012
3013
3014 THREADED_TEST(GlobalProxyIdentityHash) {
3015   LocalContext env;
3016   v8::Isolate* isolate = env->GetIsolate();
3017   v8::HandleScope scope(isolate);
3018   Handle<Object> global_proxy = env->Global();
3019   int hash1 = global_proxy->GetIdentityHash();
3020   // Hash should be retained after being detached.
3021   env->DetachGlobal();
3022   int hash2 = global_proxy->GetIdentityHash();
3023   CHECK_EQ(hash1, hash2);
3024   {
3025     // Re-attach global proxy to a new context, hash should stay the same.
3026     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
3027     int hash3 = global_proxy->GetIdentityHash();
3028     CHECK_EQ(hash1, hash3);
3029   }
3030 }
3031
3032
3033 TEST(SymbolIdentityHash) {
3034   LocalContext env;
3035   v8::Isolate* isolate = env->GetIsolate();
3036   v8::HandleScope scope(isolate);
3037
3038   {
3039     Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3040     int hash = symbol->GetIdentityHash();
3041     int hash1 = symbol->GetIdentityHash();
3042     CHECK_EQ(hash, hash1);
3043     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3044     int hash3 = symbol->GetIdentityHash();
3045     CHECK_EQ(hash, hash3);
3046   }
3047
3048   {
3049     v8::Handle<v8::Symbol> js_symbol =
3050         CompileRun("Symbol('foo')").As<v8::Symbol>();
3051     int hash = js_symbol->GetIdentityHash();
3052     int hash1 = js_symbol->GetIdentityHash();
3053     CHECK_EQ(hash, hash1);
3054     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3055     int hash3 = js_symbol->GetIdentityHash();
3056     CHECK_EQ(hash, hash3);
3057   }
3058 }
3059
3060
3061 TEST(StringIdentityHash) {
3062   LocalContext env;
3063   v8::Isolate* isolate = env->GetIsolate();
3064   v8::HandleScope scope(isolate);
3065
3066   Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
3067   int hash = str->GetIdentityHash();
3068   int hash1 = str->GetIdentityHash();
3069   CHECK_EQ(hash, hash1);
3070   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3071   int hash3 = str->GetIdentityHash();
3072   CHECK_EQ(hash, hash3);
3073
3074   Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
3075   int hash4 = str2->GetIdentityHash();
3076   CHECK_EQ(hash, hash4);
3077 }
3078
3079
3080 THREADED_TEST(SymbolProperties) {
3081   LocalContext env;
3082   v8::Isolate* isolate = env->GetIsolate();
3083   v8::HandleScope scope(isolate);
3084
3085   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3086   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3087   v8::Local<v8::Symbol> sym2 =
3088       v8::Symbol::New(isolate, v8_str("my-symbol"));
3089   v8::Local<v8::Symbol> sym3 =
3090       v8::Symbol::New(isolate, v8_str("sym3"));
3091
3092   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3093
3094   // Check basic symbol functionality.
3095   CHECK(sym1->IsSymbol());
3096   CHECK(sym2->IsSymbol());
3097   CHECK(!obj->IsSymbol());
3098
3099   CHECK(sym1->Equals(sym1));
3100   CHECK(sym2->Equals(sym2));
3101   CHECK(!sym1->Equals(sym2));
3102   CHECK(!sym2->Equals(sym1));
3103   CHECK(sym1->StrictEquals(sym1));
3104   CHECK(sym2->StrictEquals(sym2));
3105   CHECK(!sym1->StrictEquals(sym2));
3106   CHECK(!sym2->StrictEquals(sym1));
3107
3108   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
3109
3110   v8::Local<v8::Value> sym_val = sym2;
3111   CHECK(sym_val->IsSymbol());
3112   CHECK(sym_val->Equals(sym2));
3113   CHECK(sym_val->StrictEquals(sym2));
3114   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
3115
3116   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3117   CHECK(sym_obj->IsSymbolObject());
3118   CHECK(!sym2->IsSymbolObject());
3119   CHECK(!obj->IsSymbolObject());
3120   CHECK(!sym_obj->Equals(sym2));
3121   CHECK(!sym_obj->StrictEquals(sym2));
3122   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
3123   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
3124
3125   // Make sure delete of a non-existent symbol property works.
3126   CHECK(obj->Delete(sym1));
3127   CHECK(!obj->Has(sym1));
3128
3129   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
3130   CHECK(obj->Has(sym1));
3131   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
3132   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
3133   CHECK(obj->Has(sym1));
3134   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3135   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
3136
3137   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3138   int num_props = obj->GetPropertyNames()->Length();
3139   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3140                  v8::Integer::New(isolate, 20)));
3141   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3142   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3143
3144   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3145
3146   CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
3147   CHECK(obj->Get(sym3)->IsUndefined());
3148   CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
3149   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3150   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3151       v8::Integer::New(isolate, 42)));
3152
3153   // Add another property and delete it afterwards to force the object in
3154   // slow case.
3155   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
3156   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3157   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
3158   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3159   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3160
3161   CHECK(obj->Has(sym1));
3162   CHECK(obj->Has(sym2));
3163   CHECK(obj->Has(sym3));
3164   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3165   CHECK(obj->Delete(sym2));
3166   CHECK(obj->Has(sym1));
3167   CHECK(!obj->Has(sym2));
3168   CHECK(obj->Has(sym3));
3169   CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3170   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3171   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3172   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3173       v8::Integer::New(isolate, 42)));
3174   CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3175
3176   // Symbol properties are inherited.
3177   v8::Local<v8::Object> child = v8::Object::New(isolate);
3178   child->SetPrototype(obj);
3179   CHECK(child->Has(sym1));
3180   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
3181   CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3182   CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3183       v8::Integer::New(isolate, 42)));
3184   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3185 }
3186
3187
3188 THREADED_TEST(SymbolTemplateProperties) {
3189   LocalContext env;
3190   v8::Isolate* isolate = env->GetIsolate();
3191   v8::HandleScope scope(isolate);
3192   v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3193   v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3194   CHECK(!name.IsEmpty());
3195   foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3196   v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3197   CHECK(!new_instance.IsEmpty());
3198   CHECK(new_instance->Has(name));
3199 }
3200
3201
3202 THREADED_TEST(PrivateProperties) {
3203   LocalContext env;
3204   v8::Isolate* isolate = env->GetIsolate();
3205   v8::HandleScope scope(isolate);
3206
3207   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3208   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3209   v8::Local<v8::Private> priv2 =
3210       v8::Private::New(isolate, v8_str("my-private"));
3211
3212   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3213
3214   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3215
3216   // Make sure delete of a non-existent private symbol property works.
3217   CHECK(obj->DeletePrivate(priv1));
3218   CHECK(!obj->HasPrivate(priv1));
3219
3220   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3221   CHECK(obj->HasPrivate(priv1));
3222   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3223   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3224   CHECK(obj->HasPrivate(priv1));
3225   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3226
3227   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3228   int num_props = obj->GetPropertyNames()->Length();
3229   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3230                  v8::Integer::New(isolate, 20)));
3231   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3232   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3233
3234   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3235
3236   // Add another property and delete it afterwards to force the object in
3237   // slow case.
3238   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3239   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3240   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3241   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3242   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3243
3244   CHECK(obj->HasPrivate(priv1));
3245   CHECK(obj->HasPrivate(priv2));
3246   CHECK(obj->DeletePrivate(priv2));
3247   CHECK(obj->HasPrivate(priv1));
3248   CHECK(!obj->HasPrivate(priv2));
3249   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3250   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3251
3252   // Private properties are inherited (for the time being).
3253   v8::Local<v8::Object> child = v8::Object::New(isolate);
3254   child->SetPrototype(obj);
3255   CHECK(child->HasPrivate(priv1));
3256   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3257   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3258 }
3259
3260
3261 THREADED_TEST(GlobalSymbols) {
3262   LocalContext env;
3263   v8::Isolate* isolate = env->GetIsolate();
3264   v8::HandleScope scope(isolate);
3265
3266   v8::Local<String> name = v8_str("my-symbol");
3267   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3268   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3269   CHECK(glob2->SameValue(glob));
3270
3271   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3272   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3273   CHECK(glob_api2->SameValue(glob_api));
3274   CHECK(!glob_api->SameValue(glob));
3275
3276   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3277   CHECK(!sym->SameValue(glob));
3278
3279   CompileRun("var sym2 = Symbol.for('my-symbol')");
3280   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3281   CHECK(sym2->SameValue(glob));
3282   CHECK(!sym2->SameValue(glob_api));
3283 }
3284
3285
3286 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3287                                  const char* name) {
3288   LocalContext env;
3289   v8::Isolate* isolate = env->GetIsolate();
3290   v8::HandleScope scope(isolate);
3291
3292   v8::Local<v8::Symbol> symbol = getter(isolate);
3293   std::string script = std::string("var sym = ") + name;
3294   CompileRun(script.c_str());
3295   v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3296
3297   CHECK(!value.IsEmpty());
3298   CHECK(!symbol.IsEmpty());
3299   CHECK(value->SameValue(symbol));
3300 }
3301
3302
3303 THREADED_TEST(WellKnownSymbols) {
3304   CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3305   CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3306 }
3307
3308
3309 THREADED_TEST(GlobalPrivates) {
3310   LocalContext env;
3311   v8::Isolate* isolate = env->GetIsolate();
3312   v8::HandleScope scope(isolate);
3313
3314   v8::Local<String> name = v8_str("my-private");
3315   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3316   v8::Local<v8::Object> obj = v8::Object::New(isolate);
3317   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3318
3319   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3320   CHECK(obj->HasPrivate(glob2));
3321
3322   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3323   CHECK(!obj->HasPrivate(priv));
3324
3325   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3326   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3327   CHECK(!obj->Has(intern));
3328 }
3329
3330
3331 class ScopedArrayBufferContents {
3332  public:
3333   explicit ScopedArrayBufferContents(
3334       const v8::ArrayBuffer::Contents& contents)
3335     : contents_(contents) {}
3336   ~ScopedArrayBufferContents() { free(contents_.Data()); }
3337   void* Data() const { return contents_.Data(); }
3338   size_t ByteLength() const { return contents_.ByteLength(); }
3339  private:
3340   const v8::ArrayBuffer::Contents contents_;
3341 };
3342
3343 template <typename T>
3344 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3345   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3346   for (int i = 0; i < value->InternalFieldCount(); i++) {
3347     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3348   }
3349 }
3350
3351
3352 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3353   LocalContext env;
3354   v8::Isolate* isolate = env->GetIsolate();
3355   v8::HandleScope handle_scope(isolate);
3356
3357   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3358   CheckInternalFieldsAreZero(ab);
3359   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3360   CHECK(!ab->IsExternal());
3361   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3362
3363   ScopedArrayBufferContents ab_contents(ab->Externalize());
3364   CHECK(ab->IsExternal());
3365
3366   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3367   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3368   DCHECK(data != NULL);
3369   env->Global()->Set(v8_str("ab"), ab);
3370
3371   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3372   CHECK_EQ(1024, result->Int32Value());
3373
3374   result = CompileRun("var u8 = new Uint8Array(ab);"
3375                       "u8[0] = 0xFF;"
3376                       "u8[1] = 0xAA;"
3377                       "u8.length");
3378   CHECK_EQ(1024, result->Int32Value());
3379   CHECK_EQ(0xFF, data[0]);
3380   CHECK_EQ(0xAA, data[1]);
3381   data[0] = 0xCC;
3382   data[1] = 0x11;
3383   result = CompileRun("u8[0] + u8[1]");
3384   CHECK_EQ(0xDD, result->Int32Value());
3385 }
3386
3387
3388 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3389   LocalContext env;
3390   v8::Isolate* isolate = env->GetIsolate();
3391   v8::HandleScope handle_scope(isolate);
3392
3393
3394   v8::Local<v8::Value> result =
3395       CompileRun("var ab1 = new ArrayBuffer(2);"
3396                  "var u8_a = new Uint8Array(ab1);"
3397                  "u8_a[0] = 0xAA;"
3398                  "u8_a[1] = 0xFF; u8_a.buffer");
3399   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3400   CheckInternalFieldsAreZero(ab1);
3401   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3402   CHECK(!ab1->IsExternal());
3403   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3404   CHECK(ab1->IsExternal());
3405
3406   result = CompileRun("ab1.byteLength");
3407   CHECK_EQ(2, result->Int32Value());
3408   result = CompileRun("u8_a[0]");
3409   CHECK_EQ(0xAA, result->Int32Value());
3410   result = CompileRun("u8_a[1]");
3411   CHECK_EQ(0xFF, result->Int32Value());
3412   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3413                       "u8_b[0] = 0xBB;"
3414                       "u8_a[0]");
3415   CHECK_EQ(0xBB, result->Int32Value());
3416   result = CompileRun("u8_b[1]");
3417   CHECK_EQ(0xFF, result->Int32Value());
3418
3419   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3420   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3421   CHECK_EQ(0xBB, ab1_data[0]);
3422   CHECK_EQ(0xFF, ab1_data[1]);
3423   ab1_data[0] = 0xCC;
3424   ab1_data[1] = 0x11;
3425   result = CompileRun("u8_a[0] + u8_a[1]");
3426   CHECK_EQ(0xDD, result->Int32Value());
3427 }
3428
3429
3430 THREADED_TEST(ArrayBuffer_External) {
3431   LocalContext env;
3432   v8::Isolate* isolate = env->GetIsolate();
3433   v8::HandleScope handle_scope(isolate);
3434
3435   i::ScopedVector<uint8_t> my_data(100);
3436   memset(my_data.start(), 0, 100);
3437   Local<v8::ArrayBuffer> ab3 =
3438       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3439   CheckInternalFieldsAreZero(ab3);
3440   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3441   CHECK(ab3->IsExternal());
3442
3443   env->Global()->Set(v8_str("ab3"), ab3);
3444
3445   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3446   CHECK_EQ(100, result->Int32Value());
3447
3448   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3449                       "u8_b[0] = 0xBB;"
3450                       "u8_b[1] = 0xCC;"
3451                       "u8_b.length");
3452   CHECK_EQ(100, result->Int32Value());
3453   CHECK_EQ(0xBB, my_data[0]);
3454   CHECK_EQ(0xCC, my_data[1]);
3455   my_data[0] = 0xCC;
3456   my_data[1] = 0x11;
3457   result = CompileRun("u8_b[0] + u8_b[1]");
3458   CHECK_EQ(0xDD, result->Int32Value());
3459 }
3460
3461
3462 THREADED_TEST(ArrayBuffer_DisableNeuter) {
3463   LocalContext env;
3464   v8::Isolate* isolate = env->GetIsolate();
3465   v8::HandleScope handle_scope(isolate);
3466
3467   i::ScopedVector<uint8_t> my_data(100);
3468   memset(my_data.start(), 0, 100);
3469   Local<v8::ArrayBuffer> ab =
3470       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3471   CHECK(ab->IsNeuterable());
3472
3473   i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3474   buf->set_is_neuterable(false);
3475
3476   CHECK(!ab->IsNeuterable());
3477 }
3478
3479
3480 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3481   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3482   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3483 }
3484
3485
3486 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3487   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3488   CHECK_EQ(0, static_cast<int>(ta->Length()));
3489   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3490 }
3491
3492
3493 static void CheckIsTypedArrayVarNeutered(const char* name) {
3494   i::ScopedVector<char> source(1024);
3495   i::SNPrintF(source,
3496       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3497       name, name, name);
3498   CHECK(CompileRun(source.start())->IsTrue());
3499   v8::Handle<v8::TypedArray> ta =
3500     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3501   CheckIsNeutered(ta);
3502 }
3503
3504
3505 template <typename TypedArray, int kElementSize>
3506 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3507                                          int byteOffset,
3508                                          int length) {
3509   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3510   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3511   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3512   CHECK_EQ(length, static_cast<int>(ta->Length()));
3513   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3514   return ta;
3515 }
3516
3517
3518 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3519   LocalContext env;
3520   v8::Isolate* isolate = env->GetIsolate();
3521   v8::HandleScope handle_scope(isolate);
3522
3523   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3524
3525   v8::Handle<v8::Uint8Array> u8a =
3526     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3527   v8::Handle<v8::Uint8ClampedArray> u8c =
3528     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3529   v8::Handle<v8::Int8Array> i8a =
3530     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3531
3532   v8::Handle<v8::Uint16Array> u16a =
3533     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3534   v8::Handle<v8::Int16Array> i16a =
3535     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3536
3537   v8::Handle<v8::Uint32Array> u32a =
3538     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3539   v8::Handle<v8::Int32Array> i32a =
3540     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3541
3542   v8::Handle<v8::Float32Array> f32a =
3543     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3544   v8::Handle<v8::Float64Array> f64a =
3545     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3546
3547   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3548   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3549   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3550   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3551
3552   ScopedArrayBufferContents contents(buffer->Externalize());
3553   buffer->Neuter();
3554   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3555   CheckIsNeutered(u8a);
3556   CheckIsNeutered(u8c);
3557   CheckIsNeutered(i8a);
3558   CheckIsNeutered(u16a);
3559   CheckIsNeutered(i16a);
3560   CheckIsNeutered(u32a);
3561   CheckIsNeutered(i32a);
3562   CheckIsNeutered(f32a);
3563   CheckIsNeutered(f64a);
3564   CheckDataViewIsNeutered(dv);
3565 }
3566
3567
3568 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3569   LocalContext env;
3570   v8::Isolate* isolate = env->GetIsolate();
3571   v8::HandleScope handle_scope(isolate);
3572
3573   CompileRun(
3574       "var ab = new ArrayBuffer(1024);"
3575       "var u8a = new Uint8Array(ab, 1, 1023);"
3576       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3577       "var i8a = new Int8Array(ab, 1, 1023);"
3578       "var u16a = new Uint16Array(ab, 2, 511);"
3579       "var i16a = new Int16Array(ab, 2, 511);"
3580       "var u32a = new Uint32Array(ab, 4, 255);"
3581       "var i32a = new Int32Array(ab, 4, 255);"
3582       "var f32a = new Float32Array(ab, 4, 255);"
3583       "var f64a = new Float64Array(ab, 8, 127);"
3584       "var dv = new DataView(ab, 1, 1023);");
3585
3586   v8::Handle<v8::ArrayBuffer> ab =
3587       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3588
3589   v8::Handle<v8::DataView> dv =
3590     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3591
3592   ScopedArrayBufferContents contents(ab->Externalize());
3593   ab->Neuter();
3594   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3595   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3596
3597   CheckIsTypedArrayVarNeutered("u8a");
3598   CheckIsTypedArrayVarNeutered("u8c");
3599   CheckIsTypedArrayVarNeutered("i8a");
3600   CheckIsTypedArrayVarNeutered("u16a");
3601   CheckIsTypedArrayVarNeutered("i16a");
3602   CheckIsTypedArrayVarNeutered("u32a");
3603   CheckIsTypedArrayVarNeutered("i32a");
3604   CheckIsTypedArrayVarNeutered("f32a");
3605   CheckIsTypedArrayVarNeutered("f64a");
3606
3607   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3608   CheckDataViewIsNeutered(dv);
3609 }
3610
3611
3612
3613 THREADED_TEST(HiddenProperties) {
3614   LocalContext env;
3615   v8::Isolate* isolate = env->GetIsolate();
3616   v8::HandleScope scope(isolate);
3617
3618   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3619   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3620   v8::Local<v8::String> empty = v8_str("");
3621   v8::Local<v8::String> prop_name = v8_str("prop_name");
3622
3623   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3624
3625   // Make sure delete of a non-existent hidden value works
3626   CHECK(obj->DeleteHiddenValue(key));
3627
3628   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3629   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3630   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3631   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3632
3633   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3634
3635   // Make sure we do not find the hidden property.
3636   CHECK(!obj->Has(empty));
3637   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3638   CHECK(obj->Get(empty)->IsUndefined());
3639   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3640   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3641   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3642   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3643
3644   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3645
3646   // Add another property and delete it afterwards to force the object in
3647   // slow case.
3648   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3649   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3650   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3651   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3652   CHECK(obj->Delete(prop_name));
3653   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3654
3655   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3656
3657   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3658   CHECK(obj->GetHiddenValue(key).IsEmpty());
3659
3660   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3661   CHECK(obj->DeleteHiddenValue(key));
3662   CHECK(obj->GetHiddenValue(key).IsEmpty());
3663 }
3664
3665
3666 THREADED_TEST(Regress97784) {
3667   // Regression test for crbug.com/97784
3668   // Messing with the Object.prototype should not have effect on
3669   // hidden properties.
3670   LocalContext env;
3671   v8::HandleScope scope(env->GetIsolate());
3672
3673   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3674   v8::Local<v8::String> key = v8_str("hidden");
3675
3676   CompileRun(
3677       "set_called = false;"
3678       "Object.defineProperty("
3679       "    Object.prototype,"
3680       "    'hidden',"
3681       "    {get: function() { return 45; },"
3682       "     set: function() { set_called = true; }})");
3683
3684   CHECK(obj->GetHiddenValue(key).IsEmpty());
3685   // Make sure that the getter and setter from Object.prototype is not invoked.
3686   // If it did we would have full access to the hidden properties in
3687   // the accessor.
3688   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3689   ExpectFalse("set_called");
3690   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3691 }
3692
3693
3694 static bool interceptor_for_hidden_properties_called;
3695 static void InterceptorForHiddenProperties(
3696     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3697   interceptor_for_hidden_properties_called = true;
3698 }
3699
3700
3701 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3702   LocalContext context;
3703   v8::Isolate* isolate = context->GetIsolate();
3704   v8::HandleScope scope(isolate);
3705
3706   interceptor_for_hidden_properties_called = false;
3707
3708   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3709
3710   // Associate an interceptor with an object and start setting hidden values.
3711   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3712   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3713   instance_templ->SetHandler(
3714       v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
3715   Local<v8::Function> function = fun_templ->GetFunction();
3716   Local<v8::Object> obj = function->NewInstance();
3717   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3718   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3719   CHECK(!interceptor_for_hidden_properties_called);
3720 }
3721
3722
3723 THREADED_TEST(External) {
3724   v8::HandleScope scope(CcTest::isolate());
3725   int x = 3;
3726   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3727   LocalContext env;
3728   env->Global()->Set(v8_str("ext"), ext);
3729   Local<Value> reext_obj = CompileRun("this.ext");
3730   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3731   int* ptr = static_cast<int*>(reext->Value());
3732   CHECK_EQ(x, 3);
3733   *ptr = 10;
3734   CHECK_EQ(x, 10);
3735
3736   // Make sure unaligned pointers are wrapped properly.
3737   char* data = i::StrDup("0123456789");
3738   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3739   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3740   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3741   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3742
3743   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3744   CHECK_EQ('0', *char_ptr);
3745   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3746   CHECK_EQ('1', *char_ptr);
3747   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3748   CHECK_EQ('2', *char_ptr);
3749   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3750   CHECK_EQ('3', *char_ptr);
3751   i::DeleteArray(data);
3752 }
3753
3754
3755 THREADED_TEST(GlobalHandle) {
3756   v8::Isolate* isolate = CcTest::isolate();
3757   v8::Persistent<String> global;
3758   {
3759     v8::HandleScope scope(isolate);
3760     global.Reset(isolate, v8_str("str"));
3761   }
3762   {
3763     v8::HandleScope scope(isolate);
3764     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3765   }
3766   global.Reset();
3767   {
3768     v8::HandleScope scope(isolate);
3769     global.Reset(isolate, v8_str("str"));
3770   }
3771   {
3772     v8::HandleScope scope(isolate);
3773     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3774   }
3775   global.Reset();
3776 }
3777
3778
3779 THREADED_TEST(ResettingGlobalHandle) {
3780   v8::Isolate* isolate = CcTest::isolate();
3781   v8::Persistent<String> global;
3782   {
3783     v8::HandleScope scope(isolate);
3784     global.Reset(isolate, v8_str("str"));
3785   }
3786   v8::internal::GlobalHandles* global_handles =
3787       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3788   int initial_handle_count = global_handles->global_handles_count();
3789   {
3790     v8::HandleScope scope(isolate);
3791     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3792   }
3793   {
3794     v8::HandleScope scope(isolate);
3795     global.Reset(isolate, v8_str("longer"));
3796   }
3797   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3798   {
3799     v8::HandleScope scope(isolate);
3800     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3801   }
3802   global.Reset();
3803   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3804 }
3805
3806
3807 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3808   v8::Isolate* isolate = CcTest::isolate();
3809   v8::Persistent<String> global;
3810   {
3811     v8::HandleScope scope(isolate);
3812     global.Reset(isolate, v8_str("str"));
3813   }
3814   v8::internal::GlobalHandles* global_handles =
3815       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3816   int initial_handle_count = global_handles->global_handles_count();
3817   {
3818     v8::HandleScope scope(isolate);
3819     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3820   }
3821   {
3822     v8::HandleScope scope(isolate);
3823     Local<String> empty;
3824     global.Reset(isolate, empty);
3825   }
3826   CHECK(global.IsEmpty());
3827   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3828 }
3829
3830
3831 template<class T>
3832 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3833   return unique.Pass();
3834 }
3835
3836
3837 template<class T>
3838 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3839                                             const v8::Persistent<T> & global) {
3840   v8::UniquePersistent<String> unique(isolate, global);
3841   return unique.Pass();
3842 }
3843
3844
3845 THREADED_TEST(UniquePersistent) {
3846   v8::Isolate* isolate = CcTest::isolate();
3847   v8::Persistent<String> global;
3848   {
3849     v8::HandleScope scope(isolate);
3850     global.Reset(isolate, v8_str("str"));
3851   }
3852   v8::internal::GlobalHandles* global_handles =
3853       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3854   int initial_handle_count = global_handles->global_handles_count();
3855   {
3856     v8::UniquePersistent<String> unique(isolate, global);
3857     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3858     // Test assignment via Pass
3859     {
3860       v8::UniquePersistent<String> copy = unique.Pass();
3861       CHECK(unique.IsEmpty());
3862       CHECK(copy == global);
3863       CHECK_EQ(initial_handle_count + 1,
3864                global_handles->global_handles_count());
3865       unique = copy.Pass();
3866     }
3867     // Test ctor via Pass
3868     {
3869       v8::UniquePersistent<String> copy(unique.Pass());
3870       CHECK(unique.IsEmpty());
3871       CHECK(copy == global);
3872       CHECK_EQ(initial_handle_count + 1,
3873                global_handles->global_handles_count());
3874       unique = copy.Pass();
3875     }
3876     // Test pass through function call
3877     {
3878       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3879       CHECK(unique.IsEmpty());
3880       CHECK(copy == global);
3881       CHECK_EQ(initial_handle_count + 1,
3882                global_handles->global_handles_count());
3883       unique = copy.Pass();
3884     }
3885     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3886   }
3887   // Test pass from function call
3888   {
3889     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3890     CHECK(unique == global);
3891     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3892   }
3893   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3894   global.Reset();
3895 }
3896
3897
3898 template<typename K, typename V>
3899 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3900  public:
3901   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3902       MapType;
3903   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3904   struct WeakCallbackDataType {
3905     MapType* map;
3906     K key;
3907   };
3908   static WeakCallbackDataType* WeakCallbackParameter(
3909       MapType* map, const K& key, Local<V> value) {
3910     WeakCallbackDataType* data = new WeakCallbackDataType;
3911     data->map = map;
3912     data->key = key;
3913     return data;
3914   }
3915   static MapType* MapFromWeakCallbackData(
3916       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3917     return data.GetParameter()->map;
3918   }
3919   static K KeyFromWeakCallbackData(
3920       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3921     return data.GetParameter()->key;
3922   }
3923   static void DisposeCallbackData(WeakCallbackDataType* data) {
3924     delete data;
3925   }
3926   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3927       K key) { }
3928 };
3929
3930
3931 template<typename Map>
3932 static void TestPersistentValueMap() {
3933   LocalContext env;
3934   v8::Isolate* isolate = env->GetIsolate();
3935   Map map(isolate);
3936   v8::internal::GlobalHandles* global_handles =
3937       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3938   int initial_handle_count = global_handles->global_handles_count();
3939   CHECK_EQ(0, static_cast<int>(map.Size()));
3940   {
3941     HandleScope scope(isolate);
3942     Local<v8::Object> obj = map.Get(7);
3943     CHECK(obj.IsEmpty());
3944     Local<v8::Object> expected = v8::Object::New(isolate);
3945     map.Set(7, expected);
3946     CHECK_EQ(1, static_cast<int>(map.Size()));
3947     obj = map.Get(7);
3948     CHECK_EQ(expected, obj);
3949     {
3950       typename Map::PersistentValueReference ref = map.GetReference(7);
3951       CHECK_EQ(expected, ref.NewLocal(isolate));
3952     }
3953     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3954     CHECK_EQ(0, static_cast<int>(map.Size()));
3955     CHECK(expected == removed);
3956     removed = map.Remove(7);
3957     CHECK(removed.IsEmpty());
3958     map.Set(8, expected);
3959     CHECK_EQ(1, static_cast<int>(map.Size()));
3960     map.Set(8, expected);
3961     CHECK_EQ(1, static_cast<int>(map.Size()));
3962     {
3963       typename Map::PersistentValueReference ref;
3964       Local<v8::Object> expected2 = v8::Object::New(isolate);
3965       removed = map.Set(8,
3966           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3967       CHECK_EQ(1, static_cast<int>(map.Size()));
3968       CHECK(expected == removed);
3969       CHECK_EQ(expected2, ref.NewLocal(isolate));
3970     }
3971   }
3972   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3973   if (map.IsWeak()) {
3974     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3975         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3976   } else {
3977     map.Clear();
3978   }
3979   CHECK_EQ(0, static_cast<int>(map.Size()));
3980   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3981 }
3982
3983
3984 TEST(PersistentValueMap) {
3985   // Default case, w/o weak callbacks:
3986   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3987
3988   // Custom traits with weak callbacks:
3989   typedef v8::PersistentValueMap<int, v8::Object,
3990       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3991   TestPersistentValueMap<WeakPersistentValueMap>();
3992 }
3993
3994
3995 TEST(PersistentValueVector) {
3996   LocalContext env;
3997   v8::Isolate* isolate = env->GetIsolate();
3998   v8::internal::GlobalHandles* global_handles =
3999       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4000   int handle_count = global_handles->global_handles_count();
4001   HandleScope scope(isolate);
4002
4003   v8::PersistentValueVector<v8::Object> vector(isolate);
4004
4005   Local<v8::Object> obj1 = v8::Object::New(isolate);
4006   Local<v8::Object> obj2 = v8::Object::New(isolate);
4007   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
4008
4009   CHECK(vector.IsEmpty());
4010   CHECK_EQ(0, static_cast<int>(vector.Size()));
4011
4012   vector.ReserveCapacity(3);
4013   CHECK(vector.IsEmpty());
4014
4015   vector.Append(obj1);
4016   vector.Append(obj2);
4017   vector.Append(obj1);
4018   vector.Append(obj3.Pass());
4019   vector.Append(obj1);
4020
4021   CHECK(!vector.IsEmpty());
4022   CHECK_EQ(5, static_cast<int>(vector.Size()));
4023   CHECK(obj3.IsEmpty());
4024   CHECK_EQ(obj1, vector.Get(0));
4025   CHECK_EQ(obj1, vector.Get(2));
4026   CHECK_EQ(obj1, vector.Get(4));
4027   CHECK_EQ(obj2, vector.Get(1));
4028
4029   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
4030
4031   vector.Clear();
4032   CHECK(vector.IsEmpty());
4033   CHECK_EQ(0, static_cast<int>(vector.Size()));
4034   CHECK_EQ(handle_count, global_handles->global_handles_count());
4035 }
4036
4037
4038 THREADED_TEST(GlobalHandleUpcast) {
4039   v8::Isolate* isolate = CcTest::isolate();
4040   v8::HandleScope scope(isolate);
4041   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4042   v8::Persistent<String> global_string(isolate, local);
4043   v8::Persistent<Value>& global_value =
4044       v8::Persistent<Value>::Cast(global_string);
4045   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4046   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4047   global_string.Reset();
4048 }
4049
4050
4051 THREADED_TEST(HandleEquality) {
4052   v8::Isolate* isolate = CcTest::isolate();
4053   v8::Persistent<String> global1;
4054   v8::Persistent<String> global2;
4055   {
4056     v8::HandleScope scope(isolate);
4057     global1.Reset(isolate, v8_str("str"));
4058     global2.Reset(isolate, v8_str("str2"));
4059   }
4060   CHECK_EQ(global1 == global1, true);
4061   CHECK_EQ(global1 != global1, false);
4062   {
4063     v8::HandleScope scope(isolate);
4064     Local<String> local1 = Local<String>::New(isolate, global1);
4065     Local<String> local2 = Local<String>::New(isolate, global2);
4066
4067     CHECK_EQ(global1 == local1, true);
4068     CHECK_EQ(global1 != local1, false);
4069     CHECK_EQ(local1 == global1, true);
4070     CHECK_EQ(local1 != global1, false);
4071
4072     CHECK_EQ(global1 == local2, false);
4073     CHECK_EQ(global1 != local2, true);
4074     CHECK_EQ(local2 == global1, false);
4075     CHECK_EQ(local2 != global1, true);
4076
4077     CHECK_EQ(local1 == local2, false);
4078     CHECK_EQ(local1 != local2, true);
4079
4080     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4081     CHECK_EQ(local1 == anotherLocal1, true);
4082     CHECK_EQ(local1 != anotherLocal1, false);
4083   }
4084   global1.Reset();
4085   global2.Reset();
4086 }
4087
4088
4089 THREADED_TEST(LocalHandle) {
4090   v8::HandleScope scope(CcTest::isolate());
4091   v8::Local<String> local =
4092       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4093   CHECK_EQ(local->Length(), 3);
4094 }
4095
4096
4097 class WeakCallCounter {
4098  public:
4099   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
4100   int id() { return id_; }
4101   void increment() { number_of_weak_calls_++; }
4102   int NumberOfWeakCalls() { return number_of_weak_calls_; }
4103  private:
4104   int id_;
4105   int number_of_weak_calls_;
4106 };
4107
4108
4109 template<typename T>
4110 struct WeakCallCounterAndPersistent {
4111   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4112       : counter(counter) {}
4113   WeakCallCounter* counter;
4114   v8::Persistent<T> handle;
4115 };
4116
4117
4118 template <typename T>
4119 static void WeakPointerCallback(
4120     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
4121   CHECK_EQ(1234, data.GetParameter()->counter->id());
4122   data.GetParameter()->counter->increment();
4123   data.GetParameter()->handle.Reset();
4124 }
4125
4126
4127 template<typename T>
4128 static UniqueId MakeUniqueId(const Persistent<T>& p) {
4129   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
4130 }
4131
4132
4133 THREADED_TEST(ApiObjectGroups) {
4134   LocalContext env;
4135   v8::Isolate* iso = env->GetIsolate();
4136   HandleScope scope(iso);
4137
4138   WeakCallCounter counter(1234);
4139
4140   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4141   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4142   WeakCallCounterAndPersistent<Value> g1c1(&counter);
4143   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4144   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4145   WeakCallCounterAndPersistent<Value> g2c1(&counter);
4146
4147   {
4148     HandleScope scope(iso);
4149     g1s1.handle.Reset(iso, Object::New(iso));
4150     g1s2.handle.Reset(iso, Object::New(iso));
4151     g1c1.handle.Reset(iso, Object::New(iso));
4152     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4153     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4154     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4155
4156     g2s1.handle.Reset(iso, Object::New(iso));
4157     g2s2.handle.Reset(iso, Object::New(iso));
4158     g2c1.handle.Reset(iso, Object::New(iso));
4159     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4160     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4161     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4162   }
4163
4164   WeakCallCounterAndPersistent<Value> root(&counter);
4165   root.handle.Reset(iso, g1s1.handle);  // make a root.
4166
4167   // Connect group 1 and 2, make a cycle.
4168   {
4169     HandleScope scope(iso);
4170     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
4171             Set(0, Local<Value>::New(iso, g2s2.handle)));
4172     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
4173             Set(0, Local<Value>::New(iso, g1s1.handle)));
4174   }
4175
4176   {
4177     UniqueId id1 = MakeUniqueId(g1s1.handle);
4178     UniqueId id2 = MakeUniqueId(g2s2.handle);
4179     iso->SetObjectGroupId(g1s1.handle, id1);
4180     iso->SetObjectGroupId(g1s2.handle, id1);
4181     iso->SetReferenceFromGroup(id1, g1c1.handle);
4182     iso->SetObjectGroupId(g2s1.handle, id2);
4183     iso->SetObjectGroupId(g2s2.handle, id2);
4184     iso->SetReferenceFromGroup(id2, g2c1.handle);
4185   }
4186   // Do a single full GC, ensure incremental marking is stopped.
4187   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4188       iso)->heap();
4189   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4190
4191   // All object should be alive.
4192   CHECK_EQ(0, counter.NumberOfWeakCalls());
4193
4194   // Weaken the root.
4195   root.handle.SetWeak(&root, &WeakPointerCallback);
4196   // But make children strong roots---all the objects (except for children)
4197   // should be collectable now.
4198   g1c1.handle.ClearWeak();
4199   g2c1.handle.ClearWeak();
4200
4201   // Groups are deleted, rebuild groups.
4202   {
4203     UniqueId id1 = MakeUniqueId(g1s1.handle);
4204     UniqueId id2 = MakeUniqueId(g2s2.handle);
4205     iso->SetObjectGroupId(g1s1.handle, id1);
4206     iso->SetObjectGroupId(g1s2.handle, id1);
4207     iso->SetReferenceFromGroup(id1, g1c1.handle);
4208     iso->SetObjectGroupId(g2s1.handle, id2);
4209     iso->SetObjectGroupId(g2s2.handle, id2);
4210     iso->SetReferenceFromGroup(id2, g2c1.handle);
4211   }
4212
4213   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4214
4215   // All objects should be gone. 5 global handles in total.
4216   CHECK_EQ(5, counter.NumberOfWeakCalls());
4217
4218   // And now make children weak again and collect them.
4219   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4220   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4221
4222   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4223   CHECK_EQ(7, counter.NumberOfWeakCalls());
4224 }
4225
4226
4227 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4228   LocalContext env;
4229   v8::Isolate* iso = env->GetIsolate();
4230   HandleScope scope(iso);
4231
4232   WeakCallCounter counter(1234);
4233
4234   WeakCallCounterAndPersistent<Object> g1s1(&counter);
4235   WeakCallCounterAndPersistent<String> g1s2(&counter);
4236   WeakCallCounterAndPersistent<String> g1c1(&counter);
4237   WeakCallCounterAndPersistent<Object> g2s1(&counter);
4238   WeakCallCounterAndPersistent<String> g2s2(&counter);
4239   WeakCallCounterAndPersistent<String> g2c1(&counter);
4240
4241   {
4242     HandleScope scope(iso);
4243     g1s1.handle.Reset(iso, Object::New(iso));
4244     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4245     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4246     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4247     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4248     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4249
4250     g2s1.handle.Reset(iso, Object::New(iso));
4251     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4252     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4253     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4254     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4255     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4256   }
4257
4258   WeakCallCounterAndPersistent<Value> root(&counter);
4259   root.handle.Reset(iso, g1s1.handle);  // make a root.
4260
4261   // Connect group 1 and 2, make a cycle.
4262   {
4263     HandleScope scope(iso);
4264     CHECK(Local<Object>::New(iso, g1s1.handle)
4265               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4266     CHECK(Local<Object>::New(iso, g2s1.handle)
4267               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
4268   }
4269
4270   {
4271     UniqueId id1 = MakeUniqueId(g1s1.handle);
4272     UniqueId id2 = MakeUniqueId(g2s2.handle);
4273     iso->SetObjectGroupId(g1s1.handle, id1);
4274     iso->SetObjectGroupId(g1s2.handle, id1);
4275     iso->SetReference(g1s1.handle, g1c1.handle);
4276     iso->SetObjectGroupId(g2s1.handle, id2);
4277     iso->SetObjectGroupId(g2s2.handle, id2);
4278     iso->SetReferenceFromGroup(id2, g2c1.handle);
4279   }
4280   // Do a single full GC, ensure incremental marking is stopped.
4281   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4282       iso)->heap();
4283   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4284
4285   // All object should be alive.
4286   CHECK_EQ(0, counter.NumberOfWeakCalls());
4287
4288   // Weaken the root.
4289   root.handle.SetWeak(&root, &WeakPointerCallback);
4290   // But make children strong roots---all the objects (except for children)
4291   // should be collectable now.
4292   g1c1.handle.ClearWeak();
4293   g2c1.handle.ClearWeak();
4294
4295   // Groups are deleted, rebuild groups.
4296   {
4297     UniqueId id1 = MakeUniqueId(g1s1.handle);
4298     UniqueId id2 = MakeUniqueId(g2s2.handle);
4299     iso->SetObjectGroupId(g1s1.handle, id1);
4300     iso->SetObjectGroupId(g1s2.handle, id1);
4301     iso->SetReference(g1s1.handle, g1c1.handle);
4302     iso->SetObjectGroupId(g2s1.handle, id2);
4303     iso->SetObjectGroupId(g2s2.handle, id2);
4304     iso->SetReferenceFromGroup(id2, g2c1.handle);
4305   }
4306
4307   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4308
4309   // All objects should be gone. 5 global handles in total.
4310   CHECK_EQ(5, counter.NumberOfWeakCalls());
4311
4312   // And now make children weak again and collect them.
4313   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4314   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4315
4316   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4317   CHECK_EQ(7, counter.NumberOfWeakCalls());
4318 }
4319
4320
4321 THREADED_TEST(ApiObjectGroupsCycle) {
4322   LocalContext env;
4323   v8::Isolate* iso = env->GetIsolate();
4324   HandleScope scope(iso);
4325
4326   WeakCallCounter counter(1234);
4327
4328   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4329   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4330   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4331   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4332   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4333   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4334   WeakCallCounterAndPersistent<Value> g4s1(&counter);
4335   WeakCallCounterAndPersistent<Value> g4s2(&counter);
4336
4337   {
4338     HandleScope scope(iso);
4339     g1s1.handle.Reset(iso, Object::New(iso));
4340     g1s2.handle.Reset(iso, Object::New(iso));
4341     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4342     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4343     CHECK(g1s1.handle.IsWeak());
4344     CHECK(g1s2.handle.IsWeak());
4345
4346     g2s1.handle.Reset(iso, Object::New(iso));
4347     g2s2.handle.Reset(iso, Object::New(iso));
4348     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4349     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4350     CHECK(g2s1.handle.IsWeak());
4351     CHECK(g2s2.handle.IsWeak());
4352
4353     g3s1.handle.Reset(iso, Object::New(iso));
4354     g3s2.handle.Reset(iso, Object::New(iso));
4355     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4356     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4357     CHECK(g3s1.handle.IsWeak());
4358     CHECK(g3s2.handle.IsWeak());
4359
4360     g4s1.handle.Reset(iso, Object::New(iso));
4361     g4s2.handle.Reset(iso, Object::New(iso));
4362     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4363     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4364     CHECK(g4s1.handle.IsWeak());
4365     CHECK(g4s2.handle.IsWeak());
4366   }
4367
4368   WeakCallCounterAndPersistent<Value> root(&counter);
4369   root.handle.Reset(iso, g1s1.handle);  // make a root.
4370
4371   // Connect groups.  We're building the following cycle:
4372   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4373   // groups.
4374   {
4375     UniqueId id1 = MakeUniqueId(g1s1.handle);
4376     UniqueId id2 = MakeUniqueId(g2s1.handle);
4377     UniqueId id3 = MakeUniqueId(g3s1.handle);
4378     UniqueId id4 = MakeUniqueId(g4s1.handle);
4379     iso->SetObjectGroupId(g1s1.handle, id1);
4380     iso->SetObjectGroupId(g1s2.handle, id1);
4381     iso->SetReferenceFromGroup(id1, g2s1.handle);
4382     iso->SetObjectGroupId(g2s1.handle, id2);
4383     iso->SetObjectGroupId(g2s2.handle, id2);
4384     iso->SetReferenceFromGroup(id2, g3s1.handle);
4385     iso->SetObjectGroupId(g3s1.handle, id3);
4386     iso->SetObjectGroupId(g3s2.handle, id3);
4387     iso->SetReferenceFromGroup(id3, g4s1.handle);
4388     iso->SetObjectGroupId(g4s1.handle, id4);
4389     iso->SetObjectGroupId(g4s2.handle, id4);
4390     iso->SetReferenceFromGroup(id4, g1s1.handle);
4391   }
4392   // Do a single full GC
4393   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4394       iso)->heap();
4395   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4396
4397   // All object should be alive.
4398   CHECK_EQ(0, counter.NumberOfWeakCalls());
4399
4400   // Weaken the root.
4401   root.handle.SetWeak(&root, &WeakPointerCallback);
4402
4403   // Groups are deleted, rebuild groups.
4404   {
4405     UniqueId id1 = MakeUniqueId(g1s1.handle);
4406     UniqueId id2 = MakeUniqueId(g2s1.handle);
4407     UniqueId id3 = MakeUniqueId(g3s1.handle);
4408     UniqueId id4 = MakeUniqueId(g4s1.handle);
4409     iso->SetObjectGroupId(g1s1.handle, id1);
4410     iso->SetObjectGroupId(g1s2.handle, id1);
4411     iso->SetReferenceFromGroup(id1, g2s1.handle);
4412     iso->SetObjectGroupId(g2s1.handle, id2);
4413     iso->SetObjectGroupId(g2s2.handle, id2);
4414     iso->SetReferenceFromGroup(id2, g3s1.handle);
4415     iso->SetObjectGroupId(g3s1.handle, id3);
4416     iso->SetObjectGroupId(g3s2.handle, id3);
4417     iso->SetReferenceFromGroup(id3, g4s1.handle);
4418     iso->SetObjectGroupId(g4s1.handle, id4);
4419     iso->SetObjectGroupId(g4s2.handle, id4);
4420     iso->SetReferenceFromGroup(id4, g1s1.handle);
4421   }
4422
4423   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4424
4425   // All objects should be gone. 9 global handles in total.
4426   CHECK_EQ(9, counter.NumberOfWeakCalls());
4427 }
4428
4429
4430 THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
4431   LocalContext env;
4432   v8::Isolate* iso = env->GetIsolate();
4433   HandleScope scope(iso);
4434
4435   WeakCallCounter counter(1234);
4436
4437   WeakCallCounterAndPersistent<Value> weak_obj(&counter);
4438
4439   // Create a weak object that references a internalized string.
4440   {
4441     HandleScope scope(iso);
4442     weak_obj.handle.Reset(iso, Object::New(iso));
4443     weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
4444     CHECK(weak_obj.handle.IsWeak());
4445     Local<Object>::New(iso, weak_obj.handle.As<Object>())->Set(
4446         v8_str("x"),
4447         String::NewFromUtf8(iso, "magic cookie", String::kInternalizedString));
4448   }
4449   // Do a single full GC
4450   i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
4451   i::Heap* heap = i_iso->heap();
4452   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4453
4454   // We should have received the weak callback.
4455   CHECK_EQ(1, counter.NumberOfWeakCalls());
4456
4457   // Check that the string is still alive.
4458   {
4459     HandleScope scope(iso);
4460     i::MaybeHandle<i::String> magic_string =
4461         i::StringTable::LookupStringIfExists(
4462             i_iso,
4463             v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
4464     magic_string.Check();
4465   }
4466 }
4467
4468
4469 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4470 // on the buildbots, so was made non-threaded for the time being.
4471 TEST(ApiObjectGroupsCycleForScavenger) {
4472   i::FLAG_stress_compaction = false;
4473   i::FLAG_gc_global = false;
4474   LocalContext env;
4475   v8::Isolate* iso = env->GetIsolate();
4476   HandleScope scope(iso);
4477
4478   WeakCallCounter counter(1234);
4479
4480   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4481   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4482   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4483   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4484   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4485   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4486
4487   {
4488     HandleScope scope(iso);
4489     g1s1.handle.Reset(iso, Object::New(iso));
4490     g1s2.handle.Reset(iso, Object::New(iso));
4491     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4492     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4493
4494     g2s1.handle.Reset(iso, Object::New(iso));
4495     g2s2.handle.Reset(iso, Object::New(iso));
4496     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4497     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4498
4499     g3s1.handle.Reset(iso, Object::New(iso));
4500     g3s2.handle.Reset(iso, Object::New(iso));
4501     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4502     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4503   }
4504
4505   // Make a root.
4506   WeakCallCounterAndPersistent<Value> root(&counter);
4507   root.handle.Reset(iso, g1s1.handle);
4508   root.handle.MarkPartiallyDependent();
4509
4510   // Connect groups.  We're building the following cycle:
4511   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4512   // groups.
4513   {
4514     HandleScope handle_scope(iso);
4515     g1s1.handle.MarkPartiallyDependent();
4516     g1s2.handle.MarkPartiallyDependent();
4517     g2s1.handle.MarkPartiallyDependent();
4518     g2s2.handle.MarkPartiallyDependent();
4519     g3s1.handle.MarkPartiallyDependent();
4520     g3s2.handle.MarkPartiallyDependent();
4521     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4522     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4523     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4524         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4525     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4526     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4527     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4528         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4529     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4530     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4531     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4532         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4533   }
4534
4535   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4536       iso)->heap();
4537   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4538
4539   // All objects should be alive.
4540   CHECK_EQ(0, counter.NumberOfWeakCalls());
4541
4542   // Weaken the root.
4543   root.handle.SetWeak(&root, &WeakPointerCallback);
4544   root.handle.MarkPartiallyDependent();
4545
4546   // Groups are deleted, rebuild groups.
4547   {
4548     HandleScope handle_scope(iso);
4549     g1s1.handle.MarkPartiallyDependent();
4550     g1s2.handle.MarkPartiallyDependent();
4551     g2s1.handle.MarkPartiallyDependent();
4552     g2s2.handle.MarkPartiallyDependent();
4553     g3s1.handle.MarkPartiallyDependent();
4554     g3s2.handle.MarkPartiallyDependent();
4555     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4556     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4557     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4558         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4559     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4560     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4561     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4562         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4563     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4564     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4565     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4566         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4567   }
4568
4569   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4570
4571   // All objects should be gone. 7 global handles in total.
4572   CHECK_EQ(7, counter.NumberOfWeakCalls());
4573 }
4574
4575
4576 THREADED_TEST(ScriptException) {
4577   LocalContext env;
4578   v8::HandleScope scope(env->GetIsolate());
4579   Local<Script> script = v8_compile("throw 'panama!';");
4580   v8::TryCatch try_catch;
4581   Local<Value> result = script->Run();
4582   CHECK(result.IsEmpty());
4583   CHECK(try_catch.HasCaught());
4584   String::Utf8Value exception_value(try_catch.Exception());
4585   CHECK_EQ(*exception_value, "panama!");
4586 }
4587
4588
4589 TEST(TryCatchCustomException) {
4590   LocalContext env;
4591   v8::Isolate* isolate = env->GetIsolate();
4592   v8::HandleScope scope(isolate);
4593   v8::TryCatch try_catch;
4594   CompileRun("function CustomError() { this.a = 'b'; }"
4595              "(function f() { throw new CustomError(); })();");
4596   CHECK(try_catch.HasCaught());
4597   CHECK(try_catch.Exception()->ToObject(isolate)->Get(v8_str("a"))->Equals(
4598       v8_str("b")));
4599 }
4600
4601
4602 bool message_received;
4603
4604
4605 static void check_message_0(v8::Handle<v8::Message> message,
4606                             v8::Handle<Value> data) {
4607   CHECK_EQ(5.76, data->NumberValue());
4608   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4609   CHECK(!message->IsSharedCrossOrigin());
4610   message_received = true;
4611 }
4612
4613
4614 THREADED_TEST(MessageHandler0) {
4615   message_received = false;
4616   v8::HandleScope scope(CcTest::isolate());
4617   CHECK(!message_received);
4618   LocalContext context;
4619   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4620   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4621   script->Run();
4622   CHECK(message_received);
4623   // clear out the message listener
4624   v8::V8::RemoveMessageListeners(check_message_0);
4625 }
4626
4627
4628 static void check_message_1(v8::Handle<v8::Message> message,
4629                             v8::Handle<Value> data) {
4630   CHECK(data->IsNumber());
4631   CHECK_EQ(1337, data->Int32Value());
4632   CHECK(!message->IsSharedCrossOrigin());
4633   message_received = true;
4634 }
4635
4636
4637 TEST(MessageHandler1) {
4638   message_received = false;
4639   v8::HandleScope scope(CcTest::isolate());
4640   CHECK(!message_received);
4641   v8::V8::AddMessageListener(check_message_1);
4642   LocalContext context;
4643   CompileRun("throw 1337;");
4644   CHECK(message_received);
4645   // clear out the message listener
4646   v8::V8::RemoveMessageListeners(check_message_1);
4647 }
4648
4649
4650 static void check_message_2(v8::Handle<v8::Message> message,
4651                             v8::Handle<Value> data) {
4652   LocalContext context;
4653   CHECK(data->IsObject());
4654   v8::Local<v8::Value> hidden_property =
4655       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4656   CHECK(v8_str("hidden value")->Equals(hidden_property));
4657   CHECK(!message->IsSharedCrossOrigin());
4658   message_received = true;
4659 }
4660
4661
4662 TEST(MessageHandler2) {
4663   message_received = false;
4664   v8::HandleScope scope(CcTest::isolate());
4665   CHECK(!message_received);
4666   v8::V8::AddMessageListener(check_message_2);
4667   LocalContext context;
4668   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4669   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4670                                            v8_str("hidden value"));
4671   context->Global()->Set(v8_str("error"), error);
4672   CompileRun("throw error;");
4673   CHECK(message_received);
4674   // clear out the message listener
4675   v8::V8::RemoveMessageListeners(check_message_2);
4676 }
4677
4678
4679 static void check_message_3(v8::Handle<v8::Message> message,
4680                             v8::Handle<Value> data) {
4681   CHECK(message->IsSharedCrossOrigin());
4682   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4683   message_received = true;
4684 }
4685
4686
4687 TEST(MessageHandler3) {
4688   message_received = false;
4689   v8::Isolate* isolate = CcTest::isolate();
4690   v8::HandleScope scope(isolate);
4691   CHECK(!message_received);
4692   v8::V8::AddMessageListener(check_message_3);
4693   LocalContext context;
4694   v8::ScriptOrigin origin =
4695       v8::ScriptOrigin(v8_str("6.75"),
4696                        v8::Integer::New(isolate, 1),
4697                        v8::Integer::New(isolate, 2),
4698                        v8::True(isolate));
4699   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4700                                                   &origin);
4701   script->Run();
4702   CHECK(message_received);
4703   // clear out the message listener
4704   v8::V8::RemoveMessageListeners(check_message_3);
4705 }
4706
4707
4708 static void check_message_4(v8::Handle<v8::Message> message,
4709                             v8::Handle<Value> data) {
4710   CHECK(!message->IsSharedCrossOrigin());
4711   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4712   message_received = true;
4713 }
4714
4715
4716 TEST(MessageHandler4) {
4717   message_received = false;
4718   v8::Isolate* isolate = CcTest::isolate();
4719   v8::HandleScope scope(isolate);
4720   CHECK(!message_received);
4721   v8::V8::AddMessageListener(check_message_4);
4722   LocalContext context;
4723   v8::ScriptOrigin origin =
4724       v8::ScriptOrigin(v8_str("6.75"),
4725                        v8::Integer::New(isolate, 1),
4726                        v8::Integer::New(isolate, 2),
4727                        v8::False(isolate));
4728   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4729                                                   &origin);
4730   script->Run();
4731   CHECK(message_received);
4732   // clear out the message listener
4733   v8::V8::RemoveMessageListeners(check_message_4);
4734 }
4735
4736
4737 static void check_message_5a(v8::Handle<v8::Message> message,
4738                             v8::Handle<Value> data) {
4739   CHECK(message->IsSharedCrossOrigin());
4740   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4741   message_received = true;
4742 }
4743
4744
4745 static void check_message_5b(v8::Handle<v8::Message> message,
4746                             v8::Handle<Value> data) {
4747   CHECK(!message->IsSharedCrossOrigin());
4748   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4749   message_received = true;
4750 }
4751
4752
4753 TEST(MessageHandler5) {
4754   message_received = false;
4755   v8::Isolate* isolate = CcTest::isolate();
4756   v8::HandleScope scope(isolate);
4757   CHECK(!message_received);
4758   v8::V8::AddMessageListener(check_message_5a);
4759   LocalContext context;
4760   v8::ScriptOrigin origin =
4761       v8::ScriptOrigin(v8_str("6.75"),
4762                        v8::Integer::New(isolate, 1),
4763                        v8::Integer::New(isolate, 2),
4764                        v8::True(isolate));
4765   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4766                                                   &origin);
4767   script->Run();
4768   CHECK(message_received);
4769   // clear out the message listener
4770   v8::V8::RemoveMessageListeners(check_message_5a);
4771
4772   message_received = false;
4773   v8::V8::AddMessageListener(check_message_5b);
4774   origin =
4775       v8::ScriptOrigin(v8_str("6.75"),
4776                        v8::Integer::New(isolate, 1),
4777                        v8::Integer::New(isolate, 2),
4778                        v8::False(isolate));
4779   script = Script::Compile(v8_str("throw 'error'"),
4780                            &origin);
4781   script->Run();
4782   CHECK(message_received);
4783   // clear out the message listener
4784   v8::V8::RemoveMessageListeners(check_message_5b);
4785 }
4786
4787
4788 THREADED_TEST(GetSetProperty) {
4789   LocalContext context;
4790   v8::Isolate* isolate = context->GetIsolate();
4791   v8::HandleScope scope(isolate);
4792   context->Global()->Set(v8_str("foo"), v8_num(14));
4793   context->Global()->Set(v8_str("12"), v8_num(92));
4794   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4795   context->Global()->Set(v8_num(13), v8_num(56));
4796   Local<Value> foo = CompileRun("this.foo");
4797   CHECK_EQ(14, foo->Int32Value());
4798   Local<Value> twelve = CompileRun("this[12]");
4799   CHECK_EQ(92, twelve->Int32Value());
4800   Local<Value> sixteen = CompileRun("this[16]");
4801   CHECK_EQ(32, sixteen->Int32Value());
4802   Local<Value> thirteen = CompileRun("this[13]");
4803   CHECK_EQ(56, thirteen->Int32Value());
4804   CHECK_EQ(92,
4805            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4806   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4807   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4808   CHECK_EQ(32,
4809            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4810   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4811   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4812   CHECK_EQ(56,
4813            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4814   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4815   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4816 }
4817
4818
4819 THREADED_TEST(PropertyAttributes) {
4820   LocalContext context;
4821   v8::HandleScope scope(context->GetIsolate());
4822   // none
4823   Local<String> prop = v8_str("none");
4824   context->Global()->Set(prop, v8_num(7));
4825   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4826   // read-only
4827   prop = v8_str("read_only");
4828   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4829   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4830   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4831   CompileRun("read_only = 9");
4832   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4833   context->Global()->Set(prop, v8_num(10));
4834   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4835   // dont-delete
4836   prop = v8_str("dont_delete");
4837   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4838   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4839   CompileRun("delete dont_delete");
4840   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4841   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4842   // dont-enum
4843   prop = v8_str("dont_enum");
4844   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4845   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4846   // absent
4847   prop = v8_str("absent");
4848   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4849   Local<Value> fake_prop = v8_num(1);
4850   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4851   // exception
4852   TryCatch try_catch;
4853   Local<Value> exception =
4854       CompileRun("({ toString: function() { throw 'exception';} })");
4855   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4856   CHECK(try_catch.HasCaught());
4857   String::Utf8Value exception_value(try_catch.Exception());
4858   CHECK_EQ("exception", *exception_value);
4859   try_catch.Reset();
4860 }
4861
4862
4863 THREADED_TEST(Array) {
4864   LocalContext context;
4865   v8::HandleScope scope(context->GetIsolate());
4866   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4867   CHECK_EQ(0, array->Length());
4868   CHECK(array->Get(0)->IsUndefined());
4869   CHECK(!array->Has(0));
4870   CHECK(array->Get(100)->IsUndefined());
4871   CHECK(!array->Has(100));
4872   array->Set(2, v8_num(7));
4873   CHECK_EQ(3, array->Length());
4874   CHECK(!array->Has(0));
4875   CHECK(!array->Has(1));
4876   CHECK(array->Has(2));
4877   CHECK_EQ(7, array->Get(2)->Int32Value());
4878   Local<Value> obj = CompileRun("[1, 2, 3]");
4879   Local<v8::Array> arr = obj.As<v8::Array>();
4880   CHECK_EQ(3, arr->Length());
4881   CHECK_EQ(1, arr->Get(0)->Int32Value());
4882   CHECK_EQ(2, arr->Get(1)->Int32Value());
4883   CHECK_EQ(3, arr->Get(2)->Int32Value());
4884   array = v8::Array::New(context->GetIsolate(), 27);
4885   CHECK_EQ(27, array->Length());
4886   array = v8::Array::New(context->GetIsolate(), -27);
4887   CHECK_EQ(0, array->Length());
4888 }
4889
4890
4891 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4892   v8::EscapableHandleScope scope(args.GetIsolate());
4893   ApiTestFuzzer::Fuzz();
4894   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4895   for (int i = 0; i < args.Length(); i++)
4896     result->Set(i, args[i]);
4897   args.GetReturnValue().Set(scope.Escape(result));
4898 }
4899
4900
4901 THREADED_TEST(Vector) {
4902   v8::Isolate* isolate = CcTest::isolate();
4903   v8::HandleScope scope(isolate);
4904   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4905   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4906   LocalContext context(0, global);
4907
4908   const char* fun = "f()";
4909   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4910   CHECK_EQ(0, a0->Length());
4911
4912   const char* fun2 = "f(11)";
4913   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4914   CHECK_EQ(1, a1->Length());
4915   CHECK_EQ(11, a1->Get(0)->Int32Value());
4916
4917   const char* fun3 = "f(12, 13)";
4918   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4919   CHECK_EQ(2, a2->Length());
4920   CHECK_EQ(12, a2->Get(0)->Int32Value());
4921   CHECK_EQ(13, a2->Get(1)->Int32Value());
4922
4923   const char* fun4 = "f(14, 15, 16)";
4924   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4925   CHECK_EQ(3, a3->Length());
4926   CHECK_EQ(14, a3->Get(0)->Int32Value());
4927   CHECK_EQ(15, a3->Get(1)->Int32Value());
4928   CHECK_EQ(16, a3->Get(2)->Int32Value());
4929
4930   const char* fun5 = "f(17, 18, 19, 20)";
4931   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4932   CHECK_EQ(4, a4->Length());
4933   CHECK_EQ(17, a4->Get(0)->Int32Value());
4934   CHECK_EQ(18, a4->Get(1)->Int32Value());
4935   CHECK_EQ(19, a4->Get(2)->Int32Value());
4936   CHECK_EQ(20, a4->Get(3)->Int32Value());
4937 }
4938
4939
4940 THREADED_TEST(FunctionCall) {
4941   LocalContext context;
4942   v8::Isolate* isolate = context->GetIsolate();
4943   v8::HandleScope scope(isolate);
4944   CompileRun(
4945     "function Foo() {"
4946     "  var result = [];"
4947     "  for (var i = 0; i < arguments.length; i++) {"
4948     "    result.push(arguments[i]);"
4949     "  }"
4950     "  return result;"
4951     "}"
4952     "function ReturnThisSloppy() {"
4953     "  return this;"
4954     "}"
4955     "function ReturnThisStrict() {"
4956     "  'use strict';"
4957     "  return this;"
4958     "}");
4959   Local<Function> Foo =
4960       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4961   Local<Function> ReturnThisSloppy =
4962       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4963   Local<Function> ReturnThisStrict =
4964       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4965
4966   v8::Handle<Value>* args0 = NULL;
4967   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4968   CHECK_EQ(0, a0->Length());
4969
4970   v8::Handle<Value> args1[] = { v8_num(1.1) };
4971   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4972   CHECK_EQ(1, a1->Length());
4973   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4974
4975   v8::Handle<Value> args2[] = { v8_num(2.2),
4976                                 v8_num(3.3) };
4977   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4978   CHECK_EQ(2, a2->Length());
4979   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4980   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4981
4982   v8::Handle<Value> args3[] = { v8_num(4.4),
4983                                 v8_num(5.5),
4984                                 v8_num(6.6) };
4985   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4986   CHECK_EQ(3, a3->Length());
4987   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4988   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4989   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4990
4991   v8::Handle<Value> args4[] = { v8_num(7.7),
4992                                 v8_num(8.8),
4993                                 v8_num(9.9),
4994                                 v8_num(10.11) };
4995   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4996   CHECK_EQ(4, a4->Length());
4997   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4998   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4999   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
5000   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
5001
5002   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
5003   CHECK(r1->StrictEquals(context->Global()));
5004   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
5005   CHECK(r2->StrictEquals(context->Global()));
5006   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
5007   CHECK(r3->IsNumberObject());
5008   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5009   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
5010   CHECK(r4->IsStringObject());
5011   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5012   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
5013   CHECK(r5->IsBooleanObject());
5014   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5015
5016   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
5017   CHECK(r6->IsUndefined());
5018   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
5019   CHECK(r7->IsNull());
5020   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
5021   CHECK(r8->StrictEquals(v8_num(42)));
5022   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
5023   CHECK(r9->StrictEquals(v8_str("hello")));
5024   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
5025   CHECK(r10->StrictEquals(v8::True(isolate)));
5026 }
5027
5028
5029 THREADED_TEST(ConstructCall) {
5030   LocalContext context;
5031   v8::Isolate* isolate = context->GetIsolate();
5032   v8::HandleScope scope(isolate);
5033   CompileRun(
5034     "function Foo() {"
5035     "  var result = [];"
5036     "  for (var i = 0; i < arguments.length; i++) {"
5037     "    result.push(arguments[i]);"
5038     "  }"
5039     "  return result;"
5040     "}");
5041   Local<Function> Foo =
5042       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
5043
5044   v8::Handle<Value>* args0 = NULL;
5045   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
5046   CHECK_EQ(0, a0->Length());
5047
5048   v8::Handle<Value> args1[] = { v8_num(1.1) };
5049   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
5050   CHECK_EQ(1, a1->Length());
5051   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
5052
5053   v8::Handle<Value> args2[] = { v8_num(2.2),
5054                                 v8_num(3.3) };
5055   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
5056   CHECK_EQ(2, a2->Length());
5057   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
5058   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
5059
5060   v8::Handle<Value> args3[] = { v8_num(4.4),
5061                                 v8_num(5.5),
5062                                 v8_num(6.6) };
5063   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
5064   CHECK_EQ(3, a3->Length());
5065   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
5066   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
5067   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
5068
5069   v8::Handle<Value> args4[] = { v8_num(7.7),
5070                                 v8_num(8.8),
5071                                 v8_num(9.9),
5072                                 v8_num(10.11) };
5073   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
5074   CHECK_EQ(4, a4->Length());
5075   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
5076   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
5077   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
5078   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
5079 }
5080
5081
5082 static void CheckUncle(v8::TryCatch* try_catch) {
5083   CHECK(try_catch->HasCaught());
5084   String::Utf8Value str_value(try_catch->Exception());
5085   CHECK_EQ(*str_value, "uncle?");
5086   try_catch->Reset();
5087 }
5088
5089
5090 THREADED_TEST(ConversionNumber) {
5091   LocalContext env;
5092   v8::Isolate* isolate = env->GetIsolate();
5093   v8::HandleScope scope(isolate);
5094   // Very large number.
5095   CompileRun("var obj = Math.pow(2,32) * 1237;");
5096   Local<Value> obj = env->Global()->Get(v8_str("obj"));
5097   CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
5098   CHECK_EQ(0, obj->ToInt32(isolate)->Value());
5099   CHECK(0u ==
5100         obj->ToUint32(isolate)->Value());  // NOLINT - no CHECK_EQ for unsigned.
5101   // Large number.
5102   CompileRun("var obj = -1234567890123;");
5103   obj = env->Global()->Get(v8_str("obj"));
5104   CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
5105   CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
5106   CHECK(2382691125u == obj->ToUint32(isolate)->Value());  // NOLINT
5107   // Small positive integer.
5108   CompileRun("var obj = 42;");
5109   obj = env->Global()->Get(v8_str("obj"));
5110   CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
5111   CHECK_EQ(42, obj->ToInt32(isolate)->Value());
5112   CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
5113   // Negative integer.
5114   CompileRun("var obj = -37;");
5115   obj = env->Global()->Get(v8_str("obj"));
5116   CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
5117   CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
5118   CHECK(4294967259u == obj->ToUint32(isolate)->Value());  // NOLINT
5119   // Positive non-int32 integer.
5120   CompileRun("var obj = 0x81234567;");
5121   obj = env->Global()->Get(v8_str("obj"));
5122   CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
5123   CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
5124   CHECK(2166572391u == obj->ToUint32(isolate)->Value());  // NOLINT
5125   // Fraction.
5126   CompileRun("var obj = 42.3;");
5127   obj = env->Global()->Get(v8_str("obj"));
5128   CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
5129   CHECK_EQ(42, obj->ToInt32(isolate)->Value());
5130   CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
5131   // Large negative fraction.
5132   CompileRun("var obj = -5726623061.75;");
5133   obj = env->Global()->Get(v8_str("obj"));
5134   CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
5135   CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
5136   CHECK(2863311531u == obj->ToUint32(isolate)->Value());  // NOLINT
5137 }
5138
5139
5140 THREADED_TEST(isNumberType) {
5141   LocalContext env;
5142   v8::HandleScope scope(env->GetIsolate());
5143   // Very large number.
5144   CompileRun("var obj = Math.pow(2,32) * 1237;");
5145   Local<Value> obj = env->Global()->Get(v8_str("obj"));
5146   CHECK(!obj->IsInt32());
5147   CHECK(!obj->IsUint32());
5148   // Large negative number.
5149   CompileRun("var obj = -1234567890123;");
5150   obj = env->Global()->Get(v8_str("obj"));
5151   CHECK(!obj->IsInt32());
5152   CHECK(!obj->IsUint32());
5153   // Small positive integer.
5154   CompileRun("var obj = 42;");
5155   obj = env->Global()->Get(v8_str("obj"));
5156   CHECK(obj->IsInt32());
5157   CHECK(obj->IsUint32());
5158   // Negative integer.
5159   CompileRun("var obj = -37;");
5160   obj = env->Global()->Get(v8_str("obj"));
5161   CHECK(obj->IsInt32());
5162   CHECK(!obj->IsUint32());
5163   // Positive non-int32 integer.
5164   CompileRun("var obj = 0x81234567;");
5165   obj = env->Global()->Get(v8_str("obj"));
5166   CHECK(!obj->IsInt32());
5167   CHECK(obj->IsUint32());
5168   // Fraction.
5169   CompileRun("var obj = 42.3;");
5170   obj = env->Global()->Get(v8_str("obj"));
5171   CHECK(!obj->IsInt32());
5172   CHECK(!obj->IsUint32());
5173   // Large negative fraction.
5174   CompileRun("var obj = -5726623061.75;");
5175   obj = env->Global()->Get(v8_str("obj"));
5176   CHECK(!obj->IsInt32());
5177   CHECK(!obj->IsUint32());
5178   // Positive zero
5179   CompileRun("var obj = 0.0;");
5180   obj = env->Global()->Get(v8_str("obj"));
5181   CHECK(obj->IsInt32());
5182   CHECK(obj->IsUint32());
5183   // Positive zero
5184   CompileRun("var obj = -0.0;");
5185   obj = env->Global()->Get(v8_str("obj"));
5186   CHECK(!obj->IsInt32());
5187   CHECK(!obj->IsUint32());
5188 }
5189
5190
5191 THREADED_TEST(ConversionException) {
5192   LocalContext env;
5193   v8::Isolate* isolate = env->GetIsolate();
5194   v8::HandleScope scope(isolate);
5195   CompileRun(
5196     "function TestClass() { };"
5197     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5198     "var obj = new TestClass();");
5199   Local<Value> obj = env->Global()->Get(v8_str("obj"));
5200
5201   v8::TryCatch try_catch(isolate);
5202
5203   Local<Value> to_string_result = obj->ToString(isolate);
5204   CHECK(to_string_result.IsEmpty());
5205   CheckUncle(&try_catch);
5206
5207   Local<Value> to_number_result = obj->ToNumber(isolate);
5208   CHECK(to_number_result.IsEmpty());
5209   CheckUncle(&try_catch);
5210
5211   Local<Value> to_integer_result = obj->ToInteger(isolate);
5212   CHECK(to_integer_result.IsEmpty());
5213   CheckUncle(&try_catch);
5214
5215   Local<Value> to_uint32_result = obj->ToUint32(isolate);
5216   CHECK(to_uint32_result.IsEmpty());
5217   CheckUncle(&try_catch);
5218
5219   Local<Value> to_int32_result = obj->ToInt32(isolate);
5220   CHECK(to_int32_result.IsEmpty());
5221   CheckUncle(&try_catch);
5222
5223   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
5224   CHECK(to_object_result.IsEmpty());
5225   CHECK(try_catch.HasCaught());
5226   try_catch.Reset();
5227
5228   int32_t int32_value = obj->Int32Value();
5229   CHECK_EQ(0, int32_value);
5230   CheckUncle(&try_catch);
5231
5232   uint32_t uint32_value = obj->Uint32Value();
5233   CHECK_EQ(0, uint32_value);
5234   CheckUncle(&try_catch);
5235
5236   double number_value = obj->NumberValue();
5237   CHECK_NE(0, std::isnan(number_value));
5238   CheckUncle(&try_catch);
5239
5240   int64_t integer_value = obj->IntegerValue();
5241   CHECK_EQ(0.0, static_cast<double>(integer_value));
5242   CheckUncle(&try_catch);
5243 }
5244
5245
5246 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5247   ApiTestFuzzer::Fuzz();
5248   args.GetIsolate()->ThrowException(v8_str("konto"));
5249 }
5250
5251
5252 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5253   if (args.Length() < 1) {
5254     args.GetReturnValue().Set(false);
5255     return;
5256   }
5257   v8::HandleScope scope(args.GetIsolate());
5258   v8::TryCatch try_catch;
5259   Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
5260   CHECK(!try_catch.HasCaught() || result.IsEmpty());
5261   args.GetReturnValue().Set(try_catch.HasCaught());
5262 }
5263
5264
5265 THREADED_TEST(APICatch) {
5266   v8::Isolate* isolate = CcTest::isolate();
5267   v8::HandleScope scope(isolate);
5268   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5269   templ->Set(v8_str("ThrowFromC"),
5270              v8::FunctionTemplate::New(isolate, ThrowFromC));
5271   LocalContext context(0, templ);
5272   CompileRun(
5273     "var thrown = false;"
5274     "try {"
5275     "  ThrowFromC();"
5276     "} catch (e) {"
5277     "  thrown = true;"
5278     "}");
5279   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5280   CHECK(thrown->BooleanValue());
5281 }
5282
5283
5284 THREADED_TEST(APIThrowTryCatch) {
5285   v8::Isolate* isolate = CcTest::isolate();
5286   v8::HandleScope scope(isolate);
5287   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5288   templ->Set(v8_str("ThrowFromC"),
5289              v8::FunctionTemplate::New(isolate, ThrowFromC));
5290   LocalContext context(0, templ);
5291   v8::TryCatch try_catch;
5292   CompileRun("ThrowFromC();");
5293   CHECK(try_catch.HasCaught());
5294 }
5295
5296
5297 // Test that a try-finally block doesn't shadow a try-catch block
5298 // when setting up an external handler.
5299 //
5300 // BUG(271): Some of the exception propagation does not work on the
5301 // ARM simulator because the simulator separates the C++ stack and the
5302 // JS stack.  This test therefore fails on the simulator.  The test is
5303 // not threaded to allow the threading tests to run on the simulator.
5304 TEST(TryCatchInTryFinally) {
5305   v8::Isolate* isolate = CcTest::isolate();
5306   v8::HandleScope scope(isolate);
5307   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5308   templ->Set(v8_str("CCatcher"),
5309              v8::FunctionTemplate::New(isolate, CCatcher));
5310   LocalContext context(0, templ);
5311   Local<Value> result = CompileRun("try {"
5312                                    "  try {"
5313                                    "    CCatcher('throw 7;');"
5314                                    "  } finally {"
5315                                    "  }"
5316                                    "} catch (e) {"
5317                                    "}");
5318   CHECK(result->IsTrue());
5319 }
5320
5321
5322 static void check_reference_error_message(
5323     v8::Handle<v8::Message> message,
5324     v8::Handle<v8::Value> data) {
5325   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5326   CHECK(message->Get()->Equals(v8_str(reference_error)));
5327 }
5328
5329
5330 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5331   ApiTestFuzzer::Fuzz();
5332   CHECK(false);
5333 }
5334
5335
5336 // Test that overwritten methods are not invoked on uncaught exception
5337 // formatting. However, they are invoked when performing normal error
5338 // string conversions.
5339 TEST(APIThrowMessageOverwrittenToString) {
5340   v8::Isolate* isolate = CcTest::isolate();
5341   v8::HandleScope scope(isolate);
5342   v8::V8::AddMessageListener(check_reference_error_message);
5343   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5344   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5345   LocalContext context(NULL, templ);
5346   CompileRun("asdf;");
5347   CompileRun("var limit = {};"
5348              "limit.valueOf = fail;"
5349              "Error.stackTraceLimit = limit;");
5350   CompileRun("asdf");
5351   CompileRun("Array.prototype.pop = fail;");
5352   CompileRun("Object.prototype.hasOwnProperty = fail;");
5353   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5354   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5355   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5356   CompileRun("ReferenceError.prototype.toString ="
5357              "  function() { return 'Whoops' }");
5358   CompileRun("asdf;");
5359   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5360   CompileRun("asdf;");
5361   CompileRun("ReferenceError.prototype.constructor = void 0;");
5362   CompileRun("asdf;");
5363   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5364   CompileRun("asdf;");
5365   CompileRun("ReferenceError.prototype = new Object();");
5366   CompileRun("asdf;");
5367   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5368   CHECK(string->Equals(v8_str("Whoops")));
5369   CompileRun("ReferenceError.prototype.constructor = new Object();"
5370              "ReferenceError.prototype.constructor.name = 1;"
5371              "Number.prototype.toString = function() { return 'Whoops'; };"
5372              "ReferenceError.prototype.toString = Object.prototype.toString;");
5373   CompileRun("asdf;");
5374   v8::V8::RemoveMessageListeners(check_reference_error_message);
5375 }
5376
5377
5378 static void check_custom_error_tostring(
5379     v8::Handle<v8::Message> message,
5380     v8::Handle<v8::Value> data) {
5381   const char* uncaught_error = "Uncaught MyError toString";
5382   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5383 }
5384
5385
5386 TEST(CustomErrorToString) {
5387   LocalContext context;
5388   v8::HandleScope scope(context->GetIsolate());
5389   v8::V8::AddMessageListener(check_custom_error_tostring);
5390   CompileRun(
5391     "function MyError(name, message) {                   "
5392     "  this.name = name;                                 "
5393     "  this.message = message;                           "
5394     "}                                                   "
5395     "MyError.prototype = Object.create(Error.prototype); "
5396     "MyError.prototype.toString = function() {           "
5397     "  return 'MyError toString';                        "
5398     "};                                                  "
5399     "throw new MyError('my name', 'my message');         ");
5400   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5401 }
5402
5403
5404 static void check_custom_error_message(
5405     v8::Handle<v8::Message> message,
5406     v8::Handle<v8::Value> data) {
5407   const char* uncaught_error = "Uncaught MyError: my message";
5408   printf("%s\n", *v8::String::Utf8Value(message->Get()));
5409   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5410 }
5411
5412
5413 TEST(CustomErrorMessage) {
5414   LocalContext context;
5415   v8::HandleScope scope(context->GetIsolate());
5416   v8::V8::AddMessageListener(check_custom_error_message);
5417
5418   // Handlebars.
5419   CompileRun(
5420     "function MyError(msg) {                             "
5421     "  this.name = 'MyError';                            "
5422     "  this.message = msg;                               "
5423     "}                                                   "
5424     "MyError.prototype = new Error();                    "
5425     "throw new MyError('my message');                    ");
5426
5427   // Closure.
5428   CompileRun(
5429     "function MyError(msg) {                             "
5430     "  this.name = 'MyError';                            "
5431     "  this.message = msg;                               "
5432     "}                                                   "
5433     "inherits = function(childCtor, parentCtor) {        "
5434     "    function tempCtor() {};                         "
5435     "    tempCtor.prototype = parentCtor.prototype;      "
5436     "    childCtor.superClass_ = parentCtor.prototype;   "
5437     "    childCtor.prototype = new tempCtor();           "
5438     "    childCtor.prototype.constructor = childCtor;    "
5439     "};                                                  "
5440     "inherits(MyError, Error);                           "
5441     "throw new MyError('my message');                    ");
5442
5443   // Object.create.
5444   CompileRun(
5445     "function MyError(msg) {                             "
5446     "  this.name = 'MyError';                            "
5447     "  this.message = msg;                               "
5448     "}                                                   "
5449     "MyError.prototype = Object.create(Error.prototype); "
5450     "throw new MyError('my message');                    ");
5451
5452   v8::V8::RemoveMessageListeners(check_custom_error_message);
5453 }
5454
5455
5456 static void receive_message(v8::Handle<v8::Message> message,
5457                             v8::Handle<v8::Value> data) {
5458   message->Get();
5459   message_received = true;
5460 }
5461
5462
5463 TEST(APIThrowMessage) {
5464   message_received = false;
5465   v8::Isolate* isolate = CcTest::isolate();
5466   v8::HandleScope scope(isolate);
5467   v8::V8::AddMessageListener(receive_message);
5468   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5469   templ->Set(v8_str("ThrowFromC"),
5470              v8::FunctionTemplate::New(isolate, ThrowFromC));
5471   LocalContext context(0, templ);
5472   CompileRun("ThrowFromC();");
5473   CHECK(message_received);
5474   v8::V8::RemoveMessageListeners(receive_message);
5475 }
5476
5477
5478 TEST(APIThrowMessageAndVerboseTryCatch) {
5479   message_received = false;
5480   v8::Isolate* isolate = CcTest::isolate();
5481   v8::HandleScope scope(isolate);
5482   v8::V8::AddMessageListener(receive_message);
5483   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5484   templ->Set(v8_str("ThrowFromC"),
5485              v8::FunctionTemplate::New(isolate, ThrowFromC));
5486   LocalContext context(0, templ);
5487   v8::TryCatch try_catch;
5488   try_catch.SetVerbose(true);
5489   Local<Value> result = CompileRun("ThrowFromC();");
5490   CHECK(try_catch.HasCaught());
5491   CHECK(result.IsEmpty());
5492   CHECK(message_received);
5493   v8::V8::RemoveMessageListeners(receive_message);
5494 }
5495
5496
5497 TEST(APIStackOverflowAndVerboseTryCatch) {
5498   message_received = false;
5499   LocalContext context;
5500   v8::HandleScope scope(context->GetIsolate());
5501   v8::V8::AddMessageListener(receive_message);
5502   v8::TryCatch try_catch;
5503   try_catch.SetVerbose(true);
5504   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5505   CHECK(try_catch.HasCaught());
5506   CHECK(result.IsEmpty());
5507   CHECK(message_received);
5508   v8::V8::RemoveMessageListeners(receive_message);
5509 }
5510
5511
5512 THREADED_TEST(ExternalScriptException) {
5513   v8::Isolate* isolate = CcTest::isolate();
5514   v8::HandleScope scope(isolate);
5515   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5516   templ->Set(v8_str("ThrowFromC"),
5517              v8::FunctionTemplate::New(isolate, ThrowFromC));
5518   LocalContext context(0, templ);
5519
5520   v8::TryCatch try_catch;
5521   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5522   CHECK(result.IsEmpty());
5523   CHECK(try_catch.HasCaught());
5524   String::Utf8Value exception_value(try_catch.Exception());
5525   CHECK_EQ("konto", *exception_value);
5526 }
5527
5528
5529
5530 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5531   ApiTestFuzzer::Fuzz();
5532   CHECK_EQ(4, args.Length());
5533   int count = args[0]->Int32Value();
5534   int cInterval = args[2]->Int32Value();
5535   if (count == 0) {
5536     args.GetIsolate()->ThrowException(v8_str("FromC"));
5537     return;
5538   } else {
5539     Local<v8::Object> global =
5540         args.GetIsolate()->GetCurrentContext()->Global();
5541     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5542     v8::Handle<Value> argv[] = { v8_num(count - 1),
5543                                  args[1],
5544                                  args[2],
5545                                  args[3] };
5546     if (count % cInterval == 0) {
5547       v8::TryCatch try_catch;
5548       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5549       int expected = args[3]->Int32Value();
5550       if (try_catch.HasCaught()) {
5551         CHECK_EQ(expected, count);
5552         CHECK(result.IsEmpty());
5553         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5554       } else {
5555         CHECK_NE(expected, count);
5556       }
5557       args.GetReturnValue().Set(result);
5558       return;
5559     } else {
5560       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5561       return;
5562     }
5563   }
5564 }
5565
5566
5567 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5568   ApiTestFuzzer::Fuzz();
5569   CHECK_EQ(3, args.Length());
5570   bool equality = args[0]->BooleanValue();
5571   int count = args[1]->Int32Value();
5572   int expected = args[2]->Int32Value();
5573   if (equality) {
5574     CHECK_EQ(count, expected);
5575   } else {
5576     CHECK_NE(count, expected);
5577   }
5578 }
5579
5580
5581 THREADED_TEST(EvalInTryFinally) {
5582   LocalContext context;
5583   v8::HandleScope scope(context->GetIsolate());
5584   v8::TryCatch try_catch;
5585   CompileRun("(function() {"
5586              "  try {"
5587              "    eval('asldkf (*&^&*^');"
5588              "  } finally {"
5589              "    return;"
5590              "  }"
5591              "})()");
5592   CHECK(!try_catch.HasCaught());
5593 }
5594
5595
5596 // This test works by making a stack of alternating JavaScript and C
5597 // activations.  These activations set up exception handlers with regular
5598 // intervals, one interval for C activations and another for JavaScript
5599 // activations.  When enough activations have been created an exception is
5600 // thrown and we check that the right activation catches the exception and that
5601 // no other activations do.  The right activation is always the topmost one with
5602 // a handler, regardless of whether it is in JavaScript or C.
5603 //
5604 // The notation used to describe a test case looks like this:
5605 //
5606 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5607 //
5608 // Each entry is an activation, either JS or C.  The index is the count at that
5609 // level.  Stars identify activations with exception handlers, the @ identifies
5610 // the exception handler that should catch the exception.
5611 //
5612 // BUG(271): Some of the exception propagation does not work on the
5613 // ARM simulator because the simulator separates the C++ stack and the
5614 // JS stack.  This test therefore fails on the simulator.  The test is
5615 // not threaded to allow the threading tests to run on the simulator.
5616 TEST(ExceptionOrder) {
5617   v8::Isolate* isolate = CcTest::isolate();
5618   v8::HandleScope scope(isolate);
5619   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5620   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5621   templ->Set(v8_str("CThrowCountDown"),
5622              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5623   LocalContext context(0, templ);
5624   CompileRun(
5625     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5626     "  if (count == 0) throw 'FromJS';"
5627     "  if (count % jsInterval == 0) {"
5628     "    try {"
5629     "      var value = CThrowCountDown(count - 1,"
5630     "                                  jsInterval,"
5631     "                                  cInterval,"
5632     "                                  expected);"
5633     "      check(false, count, expected);"
5634     "      return value;"
5635     "    } catch (e) {"
5636     "      check(true, count, expected);"
5637     "    }"
5638     "  } else {"
5639     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5640     "  }"
5641     "}");
5642   Local<Function> fun =
5643       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5644
5645   const int argc = 4;
5646   //                             count      jsInterval cInterval  expected
5647
5648   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5649   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5650   fun->Call(fun, argc, a0);
5651
5652   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5653   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5654   fun->Call(fun, argc, a1);
5655
5656   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5657   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5658   fun->Call(fun, argc, a2);
5659
5660   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5661   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5662   fun->Call(fun, argc, a3);
5663
5664   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5665   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5666   fun->Call(fun, argc, a4);
5667
5668   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5669   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5670   fun->Call(fun, argc, a5);
5671 }
5672
5673
5674 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5675   ApiTestFuzzer::Fuzz();
5676   CHECK_EQ(1, args.Length());
5677   args.GetIsolate()->ThrowException(args[0]);
5678 }
5679
5680
5681 THREADED_TEST(ThrowValues) {
5682   v8::Isolate* isolate = CcTest::isolate();
5683   v8::HandleScope scope(isolate);
5684   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5685   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5686   LocalContext context(0, templ);
5687   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5688     "function Run(obj) {"
5689     "  try {"
5690     "    Throw(obj);"
5691     "  } catch (e) {"
5692     "    return e;"
5693     "  }"
5694     "  return 'no exception';"
5695     "}"
5696     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5697   CHECK_EQ(5, result->Length());
5698   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5699   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5700   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5701   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5702   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5703   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5704   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5705 }
5706
5707
5708 THREADED_TEST(CatchZero) {
5709   LocalContext context;
5710   v8::HandleScope scope(context->GetIsolate());
5711   v8::TryCatch try_catch;
5712   CHECK(!try_catch.HasCaught());
5713   CompileRun("throw 10");
5714   CHECK(try_catch.HasCaught());
5715   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5716   try_catch.Reset();
5717   CHECK(!try_catch.HasCaught());
5718   CompileRun("throw 0");
5719   CHECK(try_catch.HasCaught());
5720   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5721 }
5722
5723
5724 THREADED_TEST(CatchExceptionFromWith) {
5725   LocalContext context;
5726   v8::HandleScope scope(context->GetIsolate());
5727   v8::TryCatch try_catch;
5728   CHECK(!try_catch.HasCaught());
5729   CompileRun("var o = {}; with (o) { throw 42; }");
5730   CHECK(try_catch.HasCaught());
5731 }
5732
5733
5734 THREADED_TEST(TryCatchAndFinallyHidingException) {
5735   LocalContext context;
5736   v8::HandleScope scope(context->GetIsolate());
5737   v8::TryCatch try_catch;
5738   CHECK(!try_catch.HasCaught());
5739   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5740   CompileRun("f({toString: function() { throw 42; }});");
5741   CHECK(!try_catch.HasCaught());
5742 }
5743
5744
5745 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5746   v8::TryCatch try_catch;
5747 }
5748
5749
5750 THREADED_TEST(TryCatchAndFinally) {
5751   LocalContext context;
5752   v8::Isolate* isolate = context->GetIsolate();
5753   v8::HandleScope scope(isolate);
5754   context->Global()->Set(
5755       v8_str("native_with_try_catch"),
5756       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5757   v8::TryCatch try_catch;
5758   CHECK(!try_catch.HasCaught());
5759   CompileRun(
5760       "try {\n"
5761       "  throw new Error('a');\n"
5762       "} finally {\n"
5763       "  native_with_try_catch();\n"
5764       "}\n");
5765   CHECK(try_catch.HasCaught());
5766 }
5767
5768
5769 static void TryCatchNested1Helper(int depth) {
5770   if (depth > 0) {
5771     v8::TryCatch try_catch;
5772     try_catch.SetVerbose(true);
5773     TryCatchNested1Helper(depth - 1);
5774     CHECK(try_catch.HasCaught());
5775     try_catch.ReThrow();
5776   } else {
5777     CcTest::isolate()->ThrowException(v8_str("E1"));
5778   }
5779 }
5780
5781
5782 static void TryCatchNested2Helper(int depth) {
5783   if (depth > 0) {
5784     v8::TryCatch try_catch;
5785     try_catch.SetVerbose(true);
5786     TryCatchNested2Helper(depth - 1);
5787     CHECK(try_catch.HasCaught());
5788     try_catch.ReThrow();
5789   } else {
5790     CompileRun("throw 'E2';");
5791   }
5792 }
5793
5794
5795 TEST(TryCatchNested) {
5796   v8::V8::Initialize();
5797   LocalContext context;
5798   v8::HandleScope scope(context->GetIsolate());
5799
5800   {
5801     // Test nested try-catch with a native throw in the end.
5802     v8::TryCatch try_catch;
5803     TryCatchNested1Helper(5);
5804     CHECK(try_catch.HasCaught());
5805     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5806   }
5807
5808   {
5809     // Test nested try-catch with a JavaScript throw in the end.
5810     v8::TryCatch try_catch;
5811     TryCatchNested2Helper(5);
5812     CHECK(try_catch.HasCaught());
5813     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5814   }
5815 }
5816
5817
5818 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5819   CHECK(try_catch->HasCaught());
5820   Handle<Message> message = try_catch->Message();
5821   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5822   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5823   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5824                      "Uncaught Error: a"));
5825   CHECK_EQ(1, message->GetLineNumber());
5826   CHECK_EQ(6, message->GetStartColumn());
5827 }
5828
5829
5830 void TryCatchMixedNestingHelper(
5831     const v8::FunctionCallbackInfo<v8::Value>& args) {
5832   ApiTestFuzzer::Fuzz();
5833   v8::TryCatch try_catch;
5834   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5835   CHECK(try_catch.HasCaught());
5836   TryCatchMixedNestingCheck(&try_catch);
5837   try_catch.ReThrow();
5838 }
5839
5840
5841 // This test ensures that an outer TryCatch in the following situation:
5842 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5843 // does not clobber the Message object generated for the inner TryCatch.
5844 // This exercises the ability of TryCatch.ReThrow() to restore the
5845 // inner pending Message before throwing the exception again.
5846 TEST(TryCatchMixedNesting) {
5847   v8::Isolate* isolate = CcTest::isolate();
5848   v8::HandleScope scope(isolate);
5849   v8::V8::Initialize();
5850   v8::TryCatch try_catch;
5851   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5852   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5853              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5854   LocalContext context(0, templ);
5855   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5856   TryCatchMixedNestingCheck(&try_catch);
5857 }
5858
5859
5860 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5861   ApiTestFuzzer::Fuzz();
5862   v8::TryCatch try_catch;
5863   args.GetIsolate()->ThrowException(v8_str("boom"));
5864   CHECK(try_catch.HasCaught());
5865 }
5866
5867
5868 TEST(TryCatchNative) {
5869   v8::Isolate* isolate = CcTest::isolate();
5870   v8::HandleScope scope(isolate);
5871   v8::V8::Initialize();
5872   v8::TryCatch try_catch;
5873   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5874   templ->Set(v8_str("TryCatchNativeHelper"),
5875              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5876   LocalContext context(0, templ);
5877   CompileRun("TryCatchNativeHelper();");
5878   CHECK(!try_catch.HasCaught());
5879 }
5880
5881
5882 void TryCatchNativeResetHelper(
5883     const v8::FunctionCallbackInfo<v8::Value>& args) {
5884   ApiTestFuzzer::Fuzz();
5885   v8::TryCatch try_catch;
5886   args.GetIsolate()->ThrowException(v8_str("boom"));
5887   CHECK(try_catch.HasCaught());
5888   try_catch.Reset();
5889   CHECK(!try_catch.HasCaught());
5890 }
5891
5892
5893 TEST(TryCatchNativeReset) {
5894   v8::Isolate* isolate = CcTest::isolate();
5895   v8::HandleScope scope(isolate);
5896   v8::V8::Initialize();
5897   v8::TryCatch try_catch;
5898   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5899   templ->Set(v8_str("TryCatchNativeResetHelper"),
5900              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5901   LocalContext context(0, templ);
5902   CompileRun("TryCatchNativeResetHelper();");
5903   CHECK(!try_catch.HasCaught());
5904 }
5905
5906
5907 THREADED_TEST(Equality) {
5908   LocalContext context;
5909   v8::Isolate* isolate = context->GetIsolate();
5910   v8::HandleScope scope(context->GetIsolate());
5911   // Check that equality works at all before relying on CHECK_EQ
5912   CHECK(v8_str("a")->Equals(v8_str("a")));
5913   CHECK(!v8_str("a")->Equals(v8_str("b")));
5914
5915   CHECK_EQ(v8_str("a"), v8_str("a"));
5916   CHECK_NE(v8_str("a"), v8_str("b"));
5917   CHECK_EQ(v8_num(1), v8_num(1));
5918   CHECK_EQ(v8_num(1.00), v8_num(1));
5919   CHECK_NE(v8_num(1), v8_num(2));
5920
5921   // Assume String is not internalized.
5922   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5923   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5924   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5925   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5926   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5927   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5928   Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5929   CHECK(!not_a_number->StrictEquals(not_a_number));
5930   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5931   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5932
5933   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5934   v8::Persistent<v8::Object> alias(isolate, obj);
5935   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5936   alias.Reset();
5937
5938   CHECK(v8_str("a")->SameValue(v8_str("a")));
5939   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5940   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5941   CHECK(v8_num(1)->SameValue(v8_num(1)));
5942   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5943   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5944   CHECK(not_a_number->SameValue(not_a_number));
5945   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5946   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5947 }
5948
5949
5950 THREADED_TEST(MultiRun) {
5951   LocalContext context;
5952   v8::HandleScope scope(context->GetIsolate());
5953   Local<Script> script = v8_compile("x");
5954   for (int i = 0; i < 10; i++)
5955     script->Run();
5956 }
5957
5958
5959 static void GetXValue(Local<String> name,
5960                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5961   ApiTestFuzzer::Fuzz();
5962   CHECK_EQ(info.Data(), v8_str("donut"));
5963   CHECK_EQ(name, v8_str("x"));
5964   info.GetReturnValue().Set(name);
5965 }
5966
5967
5968 THREADED_TEST(SimplePropertyRead) {
5969   LocalContext context;
5970   v8::Isolate* isolate = context->GetIsolate();
5971   v8::HandleScope scope(isolate);
5972   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5973   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5974   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5975   Local<Script> script = v8_compile("obj.x");
5976   for (int i = 0; i < 10; i++) {
5977     Local<Value> result = script->Run();
5978     CHECK_EQ(result, v8_str("x"));
5979   }
5980 }
5981
5982
5983 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5984   LocalContext context;
5985   v8::Isolate* isolate = context->GetIsolate();
5986   v8::HandleScope scope(isolate);
5987   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5988   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5989   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5990
5991   // Uses getOwnPropertyDescriptor to check the configurable status
5992   Local<Script> script_desc = v8_compile(
5993       "var prop = Object.getOwnPropertyDescriptor( "
5994       "obj, 'x');"
5995       "prop.configurable;");
5996   Local<Value> result = script_desc->Run();
5997   CHECK_EQ(result->BooleanValue(), true);
5998
5999   // Redefine get - but still configurable
6000   Local<Script> script_define = v8_compile(
6001       "var desc = { get: function(){return 42; },"
6002       "            configurable: true };"
6003       "Object.defineProperty(obj, 'x', desc);"
6004       "obj.x");
6005   result = script_define->Run();
6006   CHECK_EQ(result, v8_num(42));
6007
6008   // Check that the accessor is still configurable
6009   result = script_desc->Run();
6010   CHECK_EQ(result->BooleanValue(), true);
6011
6012   // Redefine to a non-configurable
6013   script_define = v8_compile(
6014       "var desc = { get: function(){return 43; },"
6015       "             configurable: false };"
6016       "Object.defineProperty(obj, 'x', desc);"
6017       "obj.x");
6018   result = script_define->Run();
6019   CHECK_EQ(result, v8_num(43));
6020   result = script_desc->Run();
6021   CHECK_EQ(result->BooleanValue(), false);
6022
6023   // Make sure that it is not possible to redefine again
6024   v8::TryCatch try_catch;
6025   result = script_define->Run();
6026   CHECK(try_catch.HasCaught());
6027   String::Utf8Value exception_value(try_catch.Exception());
6028   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6029 }
6030
6031
6032 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6033   v8::Isolate* isolate = CcTest::isolate();
6034   v8::HandleScope scope(isolate);
6035   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6036   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
6037   LocalContext context;
6038   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6039
6040   Local<Script> script_desc = v8_compile(
6041       "var prop ="
6042       "Object.getOwnPropertyDescriptor( "
6043       "obj, 'x');"
6044       "prop.configurable;");
6045   Local<Value> result = script_desc->Run();
6046   CHECK_EQ(result->BooleanValue(), true);
6047
6048   Local<Script> script_define = v8_compile(
6049       "var desc = {get: function(){return 42; },"
6050       "            configurable: true };"
6051       "Object.defineProperty(obj, 'x', desc);"
6052       "obj.x");
6053   result = script_define->Run();
6054   CHECK_EQ(result, v8_num(42));
6055
6056
6057   result = script_desc->Run();
6058   CHECK_EQ(result->BooleanValue(), true);
6059
6060
6061   script_define = v8_compile(
6062       "var desc = {get: function(){return 43; },"
6063       "            configurable: false };"
6064       "Object.defineProperty(obj, 'x', desc);"
6065       "obj.x");
6066   result = script_define->Run();
6067   CHECK_EQ(result, v8_num(43));
6068   result = script_desc->Run();
6069
6070   CHECK_EQ(result->BooleanValue(), false);
6071
6072   v8::TryCatch try_catch;
6073   result = script_define->Run();
6074   CHECK(try_catch.HasCaught());
6075   String::Utf8Value exception_value(try_catch.Exception());
6076   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6077 }
6078
6079
6080 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
6081                                                 char const* name) {
6082   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
6083 }
6084
6085
6086 THREADED_TEST(DefineAPIAccessorOnObject) {
6087   v8::Isolate* isolate = CcTest::isolate();
6088   v8::HandleScope scope(isolate);
6089   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6090   LocalContext context;
6091
6092   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6093   CompileRun("var obj2 = {};");
6094
6095   CHECK(CompileRun("obj1.x")->IsUndefined());
6096   CHECK(CompileRun("obj2.x")->IsUndefined());
6097
6098   CHECK(GetGlobalProperty(&context, "obj1")->
6099       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6100
6101   ExpectString("obj1.x", "x");
6102   CHECK(CompileRun("obj2.x")->IsUndefined());
6103
6104   CHECK(GetGlobalProperty(&context, "obj2")->
6105       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6106
6107   ExpectString("obj1.x", "x");
6108   ExpectString("obj2.x", "x");
6109
6110   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6111   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6112
6113   CompileRun("Object.defineProperty(obj1, 'x',"
6114              "{ get: function() { return 'y'; }, configurable: true })");
6115
6116   ExpectString("obj1.x", "y");
6117   ExpectString("obj2.x", "x");
6118
6119   CompileRun("Object.defineProperty(obj2, 'x',"
6120              "{ get: function() { return 'y'; }, configurable: true })");
6121
6122   ExpectString("obj1.x", "y");
6123   ExpectString("obj2.x", "y");
6124
6125   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6126   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6127
6128   CHECK(GetGlobalProperty(&context, "obj1")->
6129       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6130   CHECK(GetGlobalProperty(&context, "obj2")->
6131       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6132
6133   ExpectString("obj1.x", "x");
6134   ExpectString("obj2.x", "x");
6135
6136   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6137   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6138
6139   // Define getters/setters, but now make them not configurable.
6140   CompileRun("Object.defineProperty(obj1, 'x',"
6141              "{ get: function() { return 'z'; }, configurable: false })");
6142   CompileRun("Object.defineProperty(obj2, 'x',"
6143              "{ get: function() { return 'z'; }, configurable: false })");
6144
6145   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6146   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6147
6148   ExpectString("obj1.x", "z");
6149   ExpectString("obj2.x", "z");
6150
6151   CHECK(!GetGlobalProperty(&context, "obj1")->
6152       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6153   CHECK(!GetGlobalProperty(&context, "obj2")->
6154       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6155
6156   ExpectString("obj1.x", "z");
6157   ExpectString("obj2.x", "z");
6158 }
6159
6160
6161 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6162   v8::Isolate* isolate = CcTest::isolate();
6163   v8::HandleScope scope(isolate);
6164   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6165   LocalContext context;
6166
6167   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6168   CompileRun("var obj2 = {};");
6169
6170   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6171         v8_str("x"),
6172         GetXValue, NULL,
6173         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
6174   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6175         v8_str("x"),
6176         GetXValue, NULL,
6177         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
6178
6179   ExpectString("obj1.x", "x");
6180   ExpectString("obj2.x", "x");
6181
6182   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6183   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6184
6185   CHECK(!GetGlobalProperty(&context, "obj1")->
6186       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6187   CHECK(!GetGlobalProperty(&context, "obj2")->
6188       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6189
6190   {
6191     v8::TryCatch try_catch;
6192     CompileRun("Object.defineProperty(obj1, 'x',"
6193         "{get: function() { return 'func'; }})");
6194     CHECK(try_catch.HasCaught());
6195     String::Utf8Value exception_value(try_catch.Exception());
6196     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6197   }
6198   {
6199     v8::TryCatch try_catch;
6200     CompileRun("Object.defineProperty(obj2, 'x',"
6201         "{get: function() { return 'func'; }})");
6202     CHECK(try_catch.HasCaught());
6203     String::Utf8Value exception_value(try_catch.Exception());
6204     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6205   }
6206 }
6207
6208
6209 static void Get239Value(Local<String> name,
6210                         const v8::PropertyCallbackInfo<v8::Value>& info) {
6211   ApiTestFuzzer::Fuzz();
6212   CHECK_EQ(info.Data(), v8_str("donut"));
6213   CHECK_EQ(name, v8_str("239"));
6214   info.GetReturnValue().Set(name);
6215 }
6216
6217
6218 THREADED_TEST(ElementAPIAccessor) {
6219   v8::Isolate* isolate = CcTest::isolate();
6220   v8::HandleScope scope(isolate);
6221   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6222   LocalContext context;
6223
6224   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6225   CompileRun("var obj2 = {};");
6226
6227   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6228         v8_str("239"),
6229         Get239Value, NULL,
6230         v8_str("donut")));
6231   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6232         v8_str("239"),
6233         Get239Value, NULL,
6234         v8_str("donut")));
6235
6236   ExpectString("obj1[239]", "239");
6237   ExpectString("obj2[239]", "239");
6238   ExpectString("obj1['239']", "239");
6239   ExpectString("obj2['239']", "239");
6240 }
6241
6242
6243 v8::Persistent<Value> xValue;
6244
6245
6246 static void SetXValue(Local<String> name,
6247                       Local<Value> value,
6248                       const v8::PropertyCallbackInfo<void>& info) {
6249   CHECK_EQ(value, v8_num(4));
6250   CHECK_EQ(info.Data(), v8_str("donut"));
6251   CHECK_EQ(name, v8_str("x"));
6252   CHECK(xValue.IsEmpty());
6253   xValue.Reset(info.GetIsolate(), value);
6254 }
6255
6256
6257 THREADED_TEST(SimplePropertyWrite) {
6258   v8::Isolate* isolate = CcTest::isolate();
6259   v8::HandleScope scope(isolate);
6260   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6261   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6262   LocalContext context;
6263   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6264   Local<Script> script = v8_compile("obj.x = 4");
6265   for (int i = 0; i < 10; i++) {
6266     CHECK(xValue.IsEmpty());
6267     script->Run();
6268     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6269     xValue.Reset();
6270   }
6271 }
6272
6273
6274 THREADED_TEST(SetterOnly) {
6275   v8::Isolate* isolate = CcTest::isolate();
6276   v8::HandleScope scope(isolate);
6277   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6278   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6279   LocalContext context;
6280   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6281   Local<Script> script = v8_compile("obj.x = 4; obj.x");
6282   for (int i = 0; i < 10; i++) {
6283     CHECK(xValue.IsEmpty());
6284     script->Run();
6285     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6286     xValue.Reset();
6287   }
6288 }
6289
6290
6291 THREADED_TEST(NoAccessors) {
6292   v8::Isolate* isolate = CcTest::isolate();
6293   v8::HandleScope scope(isolate);
6294   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6295   templ->SetAccessor(v8_str("x"),
6296                      static_cast<v8::AccessorGetterCallback>(NULL),
6297                      NULL,
6298                      v8_str("donut"));
6299   LocalContext context;
6300   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6301   Local<Script> script = v8_compile("obj.x = 4; obj.x");
6302   for (int i = 0; i < 10; i++) {
6303     script->Run();
6304   }
6305 }
6306
6307
6308 static void XPropertyGetter(Local<Name> property,
6309                             const v8::PropertyCallbackInfo<v8::Value>& info) {
6310   ApiTestFuzzer::Fuzz();
6311   CHECK(info.Data()->IsUndefined());
6312   info.GetReturnValue().Set(property);
6313 }
6314
6315
6316 THREADED_TEST(NamedInterceptorPropertyRead) {
6317   v8::Isolate* isolate = CcTest::isolate();
6318   v8::HandleScope scope(isolate);
6319   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6320   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
6321   LocalContext context;
6322   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6323   Local<Script> script = v8_compile("obj.x");
6324   for (int i = 0; i < 10; i++) {
6325     Local<Value> result = script->Run();
6326     CHECK_EQ(result, v8_str("x"));
6327   }
6328 }
6329
6330
6331 THREADED_TEST(NamedInterceptorDictionaryIC) {
6332   v8::Isolate* isolate = CcTest::isolate();
6333   v8::HandleScope scope(isolate);
6334   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6335   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
6336   LocalContext context;
6337   // Create an object with a named interceptor.
6338   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6339   Local<Script> script = v8_compile("interceptor_obj.x");
6340   for (int i = 0; i < 10; i++) {
6341     Local<Value> result = script->Run();
6342     CHECK_EQ(result, v8_str("x"));
6343   }
6344   // Create a slow case object and a function accessing a property in
6345   // that slow case object (with dictionary probing in generated
6346   // code). Then force object with a named interceptor into slow-case,
6347   // pass it to the function, and check that the interceptor is called
6348   // instead of accessing the local property.
6349   Local<Value> result =
6350       CompileRun("function get_x(o) { return o.x; };"
6351                  "var obj = { x : 42, y : 0 };"
6352                  "delete obj.y;"
6353                  "for (var i = 0; i < 10; i++) get_x(obj);"
6354                  "interceptor_obj.x = 42;"
6355                  "interceptor_obj.y = 10;"
6356                  "delete interceptor_obj.y;"
6357                  "get_x(interceptor_obj)");
6358   CHECK_EQ(result, v8_str("x"));
6359 }
6360
6361
6362 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6363   v8::Isolate* isolate = CcTest::isolate();
6364   v8::HandleScope scope(isolate);
6365   v8::Local<Context> context1 = Context::New(isolate);
6366
6367   context1->Enter();
6368   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6369   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
6370   // Create an object with a named interceptor.
6371   v8::Local<v8::Object> object = templ->NewInstance();
6372   context1->Global()->Set(v8_str("interceptor_obj"), object);
6373
6374   // Force the object into the slow case.
6375   CompileRun("interceptor_obj.y = 0;"
6376              "delete interceptor_obj.y;");
6377   context1->Exit();
6378
6379   {
6380     // Introduce the object into a different context.
6381     // Repeat named loads to exercise ICs.
6382     LocalContext context2;
6383     context2->Global()->Set(v8_str("interceptor_obj"), object);
6384     Local<Value> result =
6385       CompileRun("function get_x(o) { return o.x; }"
6386                  "interceptor_obj.x = 42;"
6387                  "for (var i=0; i != 10; i++) {"
6388                  "  get_x(interceptor_obj);"
6389                  "}"
6390                  "get_x(interceptor_obj)");
6391     // Check that the interceptor was actually invoked.
6392     CHECK_EQ(result, v8_str("x"));
6393   }
6394
6395   // Return to the original context and force some object to the slow case
6396   // to cause the NormalizedMapCache to verify.
6397   context1->Enter();
6398   CompileRun("var obj = { x : 0 }; delete obj.x;");
6399   context1->Exit();
6400 }
6401
6402
6403 static void SetXOnPrototypeGetter(
6404     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
6405   // Set x on the prototype object and do not handle the get request.
6406   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6407   proto.As<v8::Object>()->Set(v8_str("x"),
6408                               v8::Integer::New(info.GetIsolate(), 23));
6409 }
6410
6411
6412 // This is a regression test for http://crbug.com/20104. Map
6413 // transitions should not interfere with post interceptor lookup.
6414 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6415   v8::Isolate* isolate = CcTest::isolate();
6416   v8::HandleScope scope(isolate);
6417   Local<v8::FunctionTemplate> function_template =
6418       v8::FunctionTemplate::New(isolate);
6419   Local<v8::ObjectTemplate> instance_template
6420       = function_template->InstanceTemplate();
6421   instance_template->SetHandler(
6422       v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
6423   LocalContext context;
6424   context->Global()->Set(v8_str("F"), function_template->GetFunction());
6425   // Create an instance of F and introduce a map transition for x.
6426   CompileRun("var o = new F(); o.x = 23;");
6427   // Create an instance of F and invoke the getter. The result should be 23.
6428   Local<Value> result = CompileRun("o = new F(); o.x");
6429   CHECK_EQ(result->Int32Value(), 23);
6430 }
6431
6432
6433 static void IndexedPropertyGetter(
6434     uint32_t index,
6435     const v8::PropertyCallbackInfo<v8::Value>& info) {
6436   ApiTestFuzzer::Fuzz();
6437   if (index == 37) {
6438     info.GetReturnValue().Set(v8_num(625));
6439   }
6440 }
6441
6442
6443 static void IndexedPropertySetter(
6444     uint32_t index,
6445     Local<Value> value,
6446     const v8::PropertyCallbackInfo<v8::Value>& info) {
6447   ApiTestFuzzer::Fuzz();
6448   if (index == 39) {
6449     info.GetReturnValue().Set(value);
6450   }
6451 }
6452
6453
6454 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6455   v8::Isolate* isolate = CcTest::isolate();
6456   v8::HandleScope scope(isolate);
6457   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6458   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6459       IndexedPropertyGetter, IndexedPropertySetter));
6460   LocalContext context;
6461   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6462   Local<Script> getter_script = v8_compile(
6463       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6464   Local<Script> setter_script = v8_compile(
6465       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6466       "obj[17] = 23;"
6467       "obj.foo;");
6468   Local<Script> interceptor_setter_script = v8_compile(
6469       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6470       "obj[39] = 47;"
6471       "obj.foo;");  // This setter should not run, due to the interceptor.
6472   Local<Script> interceptor_getter_script = v8_compile(
6473       "obj[37];");
6474   Local<Value> result = getter_script->Run();
6475   CHECK_EQ(v8_num(5), result);
6476   result = setter_script->Run();
6477   CHECK_EQ(v8_num(23), result);
6478   result = interceptor_setter_script->Run();
6479   CHECK_EQ(v8_num(23), result);
6480   result = interceptor_getter_script->Run();
6481   CHECK_EQ(v8_num(625), result);
6482 }
6483
6484
6485 static void UnboxedDoubleIndexedPropertyGetter(
6486     uint32_t index,
6487     const v8::PropertyCallbackInfo<v8::Value>& info) {
6488   ApiTestFuzzer::Fuzz();
6489   if (index < 25) {
6490     info.GetReturnValue().Set(v8_num(index));
6491   }
6492 }
6493
6494
6495 static void UnboxedDoubleIndexedPropertySetter(
6496     uint32_t index,
6497     Local<Value> value,
6498     const v8::PropertyCallbackInfo<v8::Value>& info) {
6499   ApiTestFuzzer::Fuzz();
6500   if (index < 25) {
6501     info.GetReturnValue().Set(v8_num(index));
6502   }
6503 }
6504
6505
6506 void UnboxedDoubleIndexedPropertyEnumerator(
6507     const v8::PropertyCallbackInfo<v8::Array>& info) {
6508   // Force the list of returned keys to be stored in a FastDoubleArray.
6509   Local<Script> indexed_property_names_script = v8_compile(
6510       "keys = new Array(); keys[125000] = 1;"
6511       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6512       "keys.length = 25; keys;");
6513   Local<Value> result = indexed_property_names_script->Run();
6514   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6515 }
6516
6517
6518 // Make sure that the the interceptor code in the runtime properly handles
6519 // merging property name lists for double-array-backed arrays.
6520 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6521   v8::Isolate* isolate = CcTest::isolate();
6522   v8::HandleScope scope(isolate);
6523   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6524   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6525       UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
6526       0, UnboxedDoubleIndexedPropertyEnumerator));
6527   LocalContext context;
6528   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6529   // When obj is created, force it to be Stored in a FastDoubleArray.
6530   Local<Script> create_unboxed_double_script = v8_compile(
6531       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6532       "key_count = 0; "
6533       "for (x in obj) {key_count++;};"
6534       "obj;");
6535   Local<Value> result = create_unboxed_double_script->Run();
6536   CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
6537   Local<Script> key_count_check = v8_compile("key_count;");
6538   result = key_count_check->Run();
6539   CHECK_EQ(v8_num(40013), result);
6540 }
6541
6542
6543 void SloppyArgsIndexedPropertyEnumerator(
6544     const v8::PropertyCallbackInfo<v8::Array>& info) {
6545   // Force the list of returned keys to be stored in a Arguments object.
6546   Local<Script> indexed_property_names_script = v8_compile(
6547       "function f(w,x) {"
6548       " return arguments;"
6549       "}"
6550       "keys = f(0, 1, 2, 3);"
6551       "keys;");
6552   Local<Object> result =
6553       Local<Object>::Cast(indexed_property_names_script->Run());
6554   // Have to populate the handle manually, as it's not Cast-able.
6555   i::Handle<i::JSObject> o =
6556       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6557   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6558   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6559 }
6560
6561
6562 static void SloppyIndexedPropertyGetter(
6563     uint32_t index,
6564     const v8::PropertyCallbackInfo<v8::Value>& info) {
6565   ApiTestFuzzer::Fuzz();
6566   if (index < 4) {
6567     info.GetReturnValue().Set(v8_num(index));
6568   }
6569 }
6570
6571
6572 // Make sure that the the interceptor code in the runtime properly handles
6573 // merging property name lists for non-string arguments arrays.
6574 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6575   v8::Isolate* isolate = CcTest::isolate();
6576   v8::HandleScope scope(isolate);
6577   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6578   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6579       SloppyIndexedPropertyGetter, 0, 0, 0,
6580       SloppyArgsIndexedPropertyEnumerator));
6581   LocalContext context;
6582   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6583   Local<Script> create_args_script = v8_compile(
6584       "var key_count = 0;"
6585       "for (x in obj) {key_count++;} key_count;");
6586   Local<Value> result = create_args_script->Run();
6587   CHECK_EQ(v8_num(4), result);
6588 }
6589
6590
6591 static void IdentityIndexedPropertyGetter(
6592     uint32_t index,
6593     const v8::PropertyCallbackInfo<v8::Value>& info) {
6594   info.GetReturnValue().Set(index);
6595 }
6596
6597
6598 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6599   v8::Isolate* isolate = CcTest::isolate();
6600   v8::HandleScope scope(isolate);
6601   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6602   templ->SetHandler(
6603       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6604
6605   LocalContext context;
6606   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6607
6608   // Check fast object case.
6609   const char* fast_case_code =
6610       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6611   ExpectString(fast_case_code, "0");
6612
6613   // Check slow case.
6614   const char* slow_case_code =
6615       "obj.x = 1; delete obj.x;"
6616       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6617   ExpectString(slow_case_code, "1");
6618 }
6619
6620
6621 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6622   v8::Isolate* isolate = CcTest::isolate();
6623   v8::HandleScope scope(isolate);
6624   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6625   templ->SetHandler(
6626       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6627
6628   LocalContext context;
6629   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6630
6631   const char* code =
6632       "try {"
6633       "  obj[0] = 239;"
6634       "  for (var i = 0; i < 100; i++) {"
6635       "    var v = obj[0];"
6636       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6637       "  }"
6638       "  'PASSED'"
6639       "} catch(e) {"
6640       "  e"
6641       "}";
6642   ExpectString(code, "PASSED");
6643 }
6644
6645
6646 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6647   v8::Isolate* isolate = CcTest::isolate();
6648   v8::HandleScope scope(isolate);
6649   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6650   templ->SetHandler(
6651       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6652
6653   LocalContext context;
6654   Local<v8::Object> obj = templ->NewInstance();
6655   obj->TurnOnAccessCheck();
6656   context->Global()->Set(v8_str("obj"), obj);
6657
6658   const char* code =
6659       "var result = 'PASSED';"
6660       "for (var i = 0; i < 100; i++) {"
6661       "  try {"
6662       "    var v = obj[0];"
6663       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
6664       "    break;"
6665       "  } catch (e) {"
6666       "    /* pass */"
6667       "  }"
6668       "}"
6669       "result";
6670   ExpectString(code, "PASSED");
6671 }
6672
6673
6674 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6675   i::FLAG_allow_natives_syntax = true;
6676   v8::Isolate* isolate = CcTest::isolate();
6677   v8::HandleScope scope(isolate);
6678   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6679   templ->SetHandler(
6680       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6681
6682   LocalContext context;
6683   Local<v8::Object> obj = templ->NewInstance();
6684   context->Global()->Set(v8_str("obj"), obj);
6685
6686   const char* code =
6687       "var result = 'PASSED';"
6688       "for (var i = 0; i < 100; i++) {"
6689       "  var expected = i;"
6690       "  if (i == 5) {"
6691       "    %EnableAccessChecks(obj);"
6692       "  }"
6693       "  try {"
6694       "    var v = obj[i];"
6695       "    if (i == 5) {"
6696       "      result = 'Should not have reached this!';"
6697       "      break;"
6698       "    } else if (v != expected) {"
6699       "      result = 'Wrong value ' + v + ' at iteration ' + i;"
6700       "      break;"
6701       "    }"
6702       "  } catch (e) {"
6703       "    if (i != 5) {"
6704       "      result = e;"
6705       "    }"
6706       "  }"
6707       "  if (i == 5) %DisableAccessChecks(obj);"
6708       "}"
6709       "result";
6710   ExpectString(code, "PASSED");
6711 }
6712
6713
6714 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6715   v8::Isolate* isolate = CcTest::isolate();
6716   v8::HandleScope scope(isolate);
6717   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6718   templ->SetHandler(
6719       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6720
6721   LocalContext context;
6722   Local<v8::Object> obj = templ->NewInstance();
6723   context->Global()->Set(v8_str("obj"), obj);
6724
6725   const char* code =
6726       "try {"
6727       "  for (var i = 0; i < 100; i++) {"
6728       "    var v = obj[i];"
6729       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6730       "  }"
6731       "  'PASSED'"
6732       "} catch(e) {"
6733       "  e"
6734       "}";
6735   ExpectString(code, "PASSED");
6736 }
6737
6738
6739 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6740   v8::Isolate* isolate = CcTest::isolate();
6741   v8::HandleScope scope(isolate);
6742   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6743   templ->SetHandler(
6744       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6745
6746   LocalContext context;
6747   Local<v8::Object> obj = templ->NewInstance();
6748   context->Global()->Set(v8_str("obj"), obj);
6749
6750   const char* code =
6751       "try {"
6752       "  for (var i = 0; i < 100; i++) {"
6753       "    var expected = i;"
6754       "    var key = i;"
6755       "    if (i == 25) {"
6756       "       key = -1;"
6757       "       expected = undefined;"
6758       "    }"
6759       "    if (i == 50) {"
6760       "       /* probe minimal Smi number on 32-bit platforms */"
6761       "       key = -(1 << 30);"
6762       "       expected = undefined;"
6763       "    }"
6764       "    if (i == 75) {"
6765       "       /* probe minimal Smi number on 64-bit platforms */"
6766       "       key = 1 << 31;"
6767       "       expected = undefined;"
6768       "    }"
6769       "    var v = obj[key];"
6770       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6771       "  }"
6772       "  'PASSED'"
6773       "} catch(e) {"
6774       "  e"
6775       "}";
6776   ExpectString(code, "PASSED");
6777 }
6778
6779
6780 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6781   v8::Isolate* isolate = CcTest::isolate();
6782   v8::HandleScope scope(isolate);
6783   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6784   templ->SetHandler(
6785       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6786
6787   LocalContext context;
6788   Local<v8::Object> obj = templ->NewInstance();
6789   context->Global()->Set(v8_str("obj"), obj);
6790
6791   const char* code =
6792       "try {"
6793       "  for (var i = 0; i < 100; i++) {"
6794       "    var expected = i;"
6795       "    var key = i;"
6796       "    if (i == 50) {"
6797       "       key = 'foobar';"
6798       "       expected = undefined;"
6799       "    }"
6800       "    var v = obj[key];"
6801       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6802       "  }"
6803       "  'PASSED'"
6804       "} catch(e) {"
6805       "  e"
6806       "}";
6807   ExpectString(code, "PASSED");
6808 }
6809
6810
6811 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6812   v8::Isolate* isolate = CcTest::isolate();
6813   v8::HandleScope scope(isolate);
6814   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6815   templ->SetHandler(
6816       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6817
6818   LocalContext context;
6819   Local<v8::Object> obj = templ->NewInstance();
6820   context->Global()->Set(v8_str("obj"), obj);
6821
6822   const char* code =
6823       "var original = obj;"
6824       "try {"
6825       "  for (var i = 0; i < 100; i++) {"
6826       "    var expected = i;"
6827       "    if (i == 50) {"
6828       "       obj = {50: 'foobar'};"
6829       "       expected = 'foobar';"
6830       "    }"
6831       "    var v = obj[i];"
6832       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6833       "    if (i == 50) obj = original;"
6834       "  }"
6835       "  'PASSED'"
6836       "} catch(e) {"
6837       "  e"
6838       "}";
6839   ExpectString(code, "PASSED");
6840 }
6841
6842
6843 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6844   v8::Isolate* isolate = CcTest::isolate();
6845   v8::HandleScope scope(isolate);
6846   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6847   templ->SetHandler(
6848       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6849
6850   LocalContext context;
6851   Local<v8::Object> obj = templ->NewInstance();
6852   context->Global()->Set(v8_str("obj"), obj);
6853
6854   const char* code =
6855       "var original = obj;"
6856       "try {"
6857       "  for (var i = 0; i < 100; i++) {"
6858       "    var expected = i;"
6859       "    if (i == 5) {"
6860       "       obj = 239;"
6861       "       expected = undefined;"
6862       "    }"
6863       "    var v = obj[i];"
6864       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6865       "    if (i == 5) obj = original;"
6866       "  }"
6867       "  'PASSED'"
6868       "} catch(e) {"
6869       "  e"
6870       "}";
6871   ExpectString(code, "PASSED");
6872 }
6873
6874
6875 THREADED_TEST(IndexedInterceptorOnProto) {
6876   v8::Isolate* isolate = CcTest::isolate();
6877   v8::HandleScope scope(isolate);
6878   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6879   templ->SetHandler(
6880       v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6881
6882   LocalContext context;
6883   Local<v8::Object> obj = templ->NewInstance();
6884   context->Global()->Set(v8_str("obj"), obj);
6885
6886   const char* code =
6887       "var o = {__proto__: obj};"
6888       "try {"
6889       "  for (var i = 0; i < 100; i++) {"
6890       "    var v = o[i];"
6891       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6892       "  }"
6893       "  'PASSED'"
6894       "} catch(e) {"
6895       "  e"
6896       "}";
6897   ExpectString(code, "PASSED");
6898 }
6899
6900
6901 THREADED_TEST(MultiContexts) {
6902   v8::Isolate* isolate = CcTest::isolate();
6903   v8::HandleScope scope(isolate);
6904   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6905   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6906                                                         DummyCallHandler));
6907
6908   Local<String> password = v8_str("Password");
6909
6910   // Create an environment
6911   LocalContext context0(0, templ);
6912   context0->SetSecurityToken(password);
6913   v8::Handle<v8::Object> global0 = context0->Global();
6914   global0->Set(v8_str("custom"), v8_num(1234));
6915   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6916
6917   // Create an independent environment
6918   LocalContext context1(0, templ);
6919   context1->SetSecurityToken(password);
6920   v8::Handle<v8::Object> global1 = context1->Global();
6921   global1->Set(v8_str("custom"), v8_num(1234));
6922   CHECK_NE(global0, global1);
6923   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6924   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6925
6926   // Now create a new context with the old global
6927   LocalContext context2(0, templ, global1);
6928   context2->SetSecurityToken(password);
6929   v8::Handle<v8::Object> global2 = context2->Global();
6930   CHECK_EQ(global1, global2);
6931   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6932   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6933 }
6934
6935
6936 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6937   // Make sure that functions created by cloning boilerplates cannot
6938   // communicate through their __proto__ field.
6939
6940   v8::HandleScope scope(CcTest::isolate());
6941
6942   LocalContext env0;
6943   v8::Handle<v8::Object> global0 =
6944       env0->Global();
6945   v8::Handle<v8::Object> object0 =
6946       global0->Get(v8_str("Object")).As<v8::Object>();
6947   v8::Handle<v8::Object> tostring0 =
6948       object0->Get(v8_str("toString")).As<v8::Object>();
6949   v8::Handle<v8::Object> proto0 =
6950       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6951   proto0->Set(v8_str("custom"), v8_num(1234));
6952
6953   LocalContext env1;
6954   v8::Handle<v8::Object> global1 =
6955       env1->Global();
6956   v8::Handle<v8::Object> object1 =
6957       global1->Get(v8_str("Object")).As<v8::Object>();
6958   v8::Handle<v8::Object> tostring1 =
6959       object1->Get(v8_str("toString")).As<v8::Object>();
6960   v8::Handle<v8::Object> proto1 =
6961       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6962   CHECK(!proto1->Has(v8_str("custom")));
6963 }
6964
6965
6966 THREADED_TEST(Regress892105) {
6967   // Make sure that object and array literals created by cloning
6968   // boilerplates cannot communicate through their __proto__
6969   // field. This is rather difficult to check, but we try to add stuff
6970   // to Object.prototype and Array.prototype and create a new
6971   // environment. This should succeed.
6972
6973   v8::HandleScope scope(CcTest::isolate());
6974
6975   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6976                                 "Array.prototype.arr = 4567;"
6977                                 "8901");
6978
6979   LocalContext env0;
6980   Local<Script> script0 = v8_compile(source);
6981   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6982
6983   LocalContext env1;
6984   Local<Script> script1 = v8_compile(source);
6985   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6986 }
6987
6988
6989 THREADED_TEST(UndetectableObject) {
6990   LocalContext env;
6991   v8::HandleScope scope(env->GetIsolate());
6992
6993   Local<v8::FunctionTemplate> desc =
6994       v8::FunctionTemplate::New(env->GetIsolate());
6995   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6996
6997   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6998   env->Global()->Set(v8_str("undetectable"), obj);
6999
7000   ExpectString("undetectable.toString()", "[object Object]");
7001   ExpectString("typeof undetectable", "undefined");
7002   ExpectString("typeof(undetectable)", "undefined");
7003   ExpectBoolean("typeof undetectable == 'undefined'", true);
7004   ExpectBoolean("typeof undetectable == 'object'", false);
7005   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7006   ExpectBoolean("!undetectable", true);
7007
7008   ExpectObject("true&&undetectable", obj);
7009   ExpectBoolean("false&&undetectable", false);
7010   ExpectBoolean("true||undetectable", true);
7011   ExpectObject("false||undetectable", obj);
7012
7013   ExpectObject("undetectable&&true", obj);
7014   ExpectObject("undetectable&&false", obj);
7015   ExpectBoolean("undetectable||true", true);
7016   ExpectBoolean("undetectable||false", false);
7017
7018   ExpectBoolean("undetectable==null", true);
7019   ExpectBoolean("null==undetectable", true);
7020   ExpectBoolean("undetectable==undefined", true);
7021   ExpectBoolean("undefined==undetectable", true);
7022   ExpectBoolean("undetectable==undetectable", true);
7023
7024
7025   ExpectBoolean("undetectable===null", false);
7026   ExpectBoolean("null===undetectable", false);
7027   ExpectBoolean("undetectable===undefined", false);
7028   ExpectBoolean("undefined===undetectable", false);
7029   ExpectBoolean("undetectable===undetectable", true);
7030 }
7031
7032
7033 THREADED_TEST(VoidLiteral) {
7034   LocalContext env;
7035   v8::Isolate* isolate = env->GetIsolate();
7036   v8::HandleScope scope(isolate);
7037
7038   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7039   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
7040
7041   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
7042   env->Global()->Set(v8_str("undetectable"), obj);
7043
7044   ExpectBoolean("undefined == void 0", true);
7045   ExpectBoolean("undetectable == void 0", true);
7046   ExpectBoolean("null == void 0", true);
7047   ExpectBoolean("undefined === void 0", true);
7048   ExpectBoolean("undetectable === void 0", false);
7049   ExpectBoolean("null === void 0", false);
7050
7051   ExpectBoolean("void 0 == undefined", true);
7052   ExpectBoolean("void 0 == undetectable", true);
7053   ExpectBoolean("void 0 == null", true);
7054   ExpectBoolean("void 0 === undefined", true);
7055   ExpectBoolean("void 0 === undetectable", false);
7056   ExpectBoolean("void 0 === null", false);
7057
7058   ExpectString("(function() {"
7059                "  try {"
7060                "    return x === void 0;"
7061                "  } catch(e) {"
7062                "    return e.toString();"
7063                "  }"
7064                "})()",
7065                "ReferenceError: x is not defined");
7066   ExpectString("(function() {"
7067                "  try {"
7068                "    return void 0 === x;"
7069                "  } catch(e) {"
7070                "    return e.toString();"
7071                "  }"
7072                "})()",
7073                "ReferenceError: x is not defined");
7074 }
7075
7076
7077 THREADED_TEST(ExtensibleOnUndetectable) {
7078   LocalContext env;
7079   v8::Isolate* isolate = env->GetIsolate();
7080   v8::HandleScope scope(isolate);
7081
7082   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7083   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
7084
7085   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
7086   env->Global()->Set(v8_str("undetectable"), obj);
7087
7088   Local<String> source = v8_str("undetectable.x = 42;"
7089                                 "undetectable.x");
7090
7091   Local<Script> script = v8_compile(source);
7092
7093   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
7094
7095   ExpectBoolean("Object.isExtensible(undetectable)", true);
7096
7097   source = v8_str("Object.preventExtensions(undetectable);");
7098   script = v8_compile(source);
7099   script->Run();
7100   ExpectBoolean("Object.isExtensible(undetectable)", false);
7101
7102   source = v8_str("undetectable.y = 2000;");
7103   script = v8_compile(source);
7104   script->Run();
7105   ExpectBoolean("undetectable.y == undefined", true);
7106 }
7107
7108
7109
7110 THREADED_TEST(UndetectableString) {
7111   LocalContext env;
7112   v8::HandleScope scope(env->GetIsolate());
7113
7114   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
7115                                           String::kUndetectableString);
7116   env->Global()->Set(v8_str("undetectable"), obj);
7117
7118   ExpectString("undetectable", "foo");
7119   ExpectString("typeof undetectable", "undefined");
7120   ExpectString("typeof(undetectable)", "undefined");
7121   ExpectBoolean("typeof undetectable == 'undefined'", true);
7122   ExpectBoolean("typeof undetectable == 'string'", false);
7123   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7124   ExpectBoolean("!undetectable", true);
7125
7126   ExpectObject("true&&undetectable", obj);
7127   ExpectBoolean("false&&undetectable", false);
7128   ExpectBoolean("true||undetectable", true);
7129   ExpectObject("false||undetectable", obj);
7130
7131   ExpectObject("undetectable&&true", obj);
7132   ExpectObject("undetectable&&false", obj);
7133   ExpectBoolean("undetectable||true", true);
7134   ExpectBoolean("undetectable||false", false);
7135
7136   ExpectBoolean("undetectable==null", true);
7137   ExpectBoolean("null==undetectable", true);
7138   ExpectBoolean("undetectable==undefined", true);
7139   ExpectBoolean("undefined==undetectable", true);
7140   ExpectBoolean("undetectable==undetectable", true);
7141
7142
7143   ExpectBoolean("undetectable===null", false);
7144   ExpectBoolean("null===undetectable", false);
7145   ExpectBoolean("undetectable===undefined", false);
7146   ExpectBoolean("undefined===undetectable", false);
7147   ExpectBoolean("undetectable===undetectable", true);
7148 }
7149
7150
7151 TEST(UndetectableOptimized) {
7152   i::FLAG_allow_natives_syntax = true;
7153   LocalContext env;
7154   v8::HandleScope scope(env->GetIsolate());
7155
7156   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
7157                                           String::kUndetectableString);
7158   env->Global()->Set(v8_str("undetectable"), obj);
7159   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
7160
7161   ExpectString(
7162       "function testBranch() {"
7163       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
7164       "  if (%_IsUndetectableObject(detectable)) throw 2;"
7165       "}\n"
7166       "function testBool() {"
7167       "  var b1 = !%_IsUndetectableObject(undetectable);"
7168       "  var b2 = %_IsUndetectableObject(detectable);"
7169       "  if (b1) throw 3;"
7170       "  if (b2) throw 4;"
7171       "  return b1 == b2;"
7172       "}\n"
7173       "%OptimizeFunctionOnNextCall(testBranch);"
7174       "%OptimizeFunctionOnNextCall(testBool);"
7175       "for (var i = 0; i < 10; i++) {"
7176       "  testBranch();"
7177       "  testBool();"
7178       "}\n"
7179       "\"PASS\"",
7180       "PASS");
7181 }
7182
7183
7184 // The point of this test is type checking. We run it only so compilers
7185 // don't complain about an unused function.
7186 TEST(PersistentHandles) {
7187   LocalContext env;
7188   v8::Isolate* isolate = CcTest::isolate();
7189   v8::HandleScope scope(isolate);
7190   Local<String> str = v8_str("foo");
7191   v8::Persistent<String> p_str(isolate, str);
7192   p_str.Reset();
7193   Local<Script> scr = v8_compile("");
7194   v8::Persistent<Script> p_scr(isolate, scr);
7195   p_scr.Reset();
7196   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7197   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7198   p_templ.Reset();
7199 }
7200
7201
7202 static void HandleLogDelegator(
7203     const v8::FunctionCallbackInfo<v8::Value>& args) {
7204   ApiTestFuzzer::Fuzz();
7205 }
7206
7207
7208 THREADED_TEST(GlobalObjectTemplate) {
7209   v8::Isolate* isolate = CcTest::isolate();
7210   v8::HandleScope handle_scope(isolate);
7211   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7212   global_template->Set(v8_str("JSNI_Log"),
7213                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7214   v8::Local<Context> context = Context::New(isolate, 0, global_template);
7215   Context::Scope context_scope(context);
7216   CompileRun("JSNI_Log('LOG')");
7217 }
7218
7219
7220 static const char* kSimpleExtensionSource =
7221   "function Foo() {"
7222   "  return 4;"
7223   "}";
7224
7225
7226 TEST(SimpleExtensions) {
7227   v8::HandleScope handle_scope(CcTest::isolate());
7228   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7229   const char* extension_names[] = { "simpletest" };
7230   v8::ExtensionConfiguration extensions(1, extension_names);
7231   v8::Handle<Context> context =
7232       Context::New(CcTest::isolate(), &extensions);
7233   Context::Scope lock(context);
7234   v8::Handle<Value> result = CompileRun("Foo()");
7235   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7236 }
7237
7238
7239 static const char* kStackTraceFromExtensionSource =
7240   "function foo() {"
7241   "  throw new Error();"
7242   "}"
7243   "function bar() {"
7244   "  foo();"
7245   "}";
7246
7247
7248 TEST(StackTraceInExtension) {
7249   v8::HandleScope handle_scope(CcTest::isolate());
7250   v8::RegisterExtension(new Extension("stacktracetest",
7251                         kStackTraceFromExtensionSource));
7252   const char* extension_names[] = { "stacktracetest" };
7253   v8::ExtensionConfiguration extensions(1, extension_names);
7254   v8::Handle<Context> context =
7255       Context::New(CcTest::isolate(), &extensions);
7256   Context::Scope lock(context);
7257   CompileRun("function user() { bar(); }"
7258              "var error;"
7259              "try{ user(); } catch (e) { error = e; }");
7260   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7261   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7262   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7263 }
7264
7265
7266 TEST(NullExtensions) {
7267   v8::HandleScope handle_scope(CcTest::isolate());
7268   v8::RegisterExtension(new Extension("nulltest", NULL));
7269   const char* extension_names[] = { "nulltest" };
7270   v8::ExtensionConfiguration extensions(1, extension_names);
7271   v8::Handle<Context> context =
7272       Context::New(CcTest::isolate(), &extensions);
7273   Context::Scope lock(context);
7274   v8::Handle<Value> result = CompileRun("1+3");
7275   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7276 }
7277
7278
7279 static const char* kEmbeddedExtensionSource =
7280     "function Ret54321(){return 54321;}~~@@$"
7281     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7282 static const int kEmbeddedExtensionSourceValidLen = 34;
7283
7284
7285 TEST(ExtensionMissingSourceLength) {
7286   v8::HandleScope handle_scope(CcTest::isolate());
7287   v8::RegisterExtension(new Extension("srclentest_fail",
7288                                       kEmbeddedExtensionSource));
7289   const char* extension_names[] = { "srclentest_fail" };
7290   v8::ExtensionConfiguration extensions(1, extension_names);
7291   v8::Handle<Context> context =
7292       Context::New(CcTest::isolate(), &extensions);
7293   CHECK_EQ(0, *context);
7294 }
7295
7296
7297 TEST(ExtensionWithSourceLength) {
7298   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7299        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7300     v8::HandleScope handle_scope(CcTest::isolate());
7301     i::ScopedVector<char> extension_name(32);
7302     i::SNPrintF(extension_name, "ext #%d", source_len);
7303     v8::RegisterExtension(new Extension(extension_name.start(),
7304                                         kEmbeddedExtensionSource, 0, 0,
7305                                         source_len));
7306     const char* extension_names[1] = { extension_name.start() };
7307     v8::ExtensionConfiguration extensions(1, extension_names);
7308     v8::Handle<Context> context =
7309       Context::New(CcTest::isolate(), &extensions);
7310     if (source_len == kEmbeddedExtensionSourceValidLen) {
7311       Context::Scope lock(context);
7312       v8::Handle<Value> result = CompileRun("Ret54321()");
7313       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
7314     } else {
7315       // Anything but exactly the right length should fail to compile.
7316       CHECK_EQ(0, *context);
7317     }
7318   }
7319 }
7320
7321
7322 static const char* kEvalExtensionSource1 =
7323   "function UseEval1() {"
7324   "  var x = 42;"
7325   "  return eval('x');"
7326   "}";
7327
7328
7329 static const char* kEvalExtensionSource2 =
7330   "(function() {"
7331   "  var x = 42;"
7332   "  function e() {"
7333   "    return eval('x');"
7334   "  }"
7335   "  this.UseEval2 = e;"
7336   "})()";
7337
7338
7339 TEST(UseEvalFromExtension) {
7340   v8::HandleScope handle_scope(CcTest::isolate());
7341   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7342   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7343   const char* extension_names[] = { "evaltest1", "evaltest2" };
7344   v8::ExtensionConfiguration extensions(2, extension_names);
7345   v8::Handle<Context> context =
7346       Context::New(CcTest::isolate(), &extensions);
7347   Context::Scope lock(context);
7348   v8::Handle<Value> result = CompileRun("UseEval1()");
7349   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7350   result = CompileRun("UseEval2()");
7351   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7352 }
7353
7354
7355 static const char* kWithExtensionSource1 =
7356   "function UseWith1() {"
7357   "  var x = 42;"
7358   "  with({x:87}) { return x; }"
7359   "}";
7360
7361
7362
7363 static const char* kWithExtensionSource2 =
7364   "(function() {"
7365   "  var x = 42;"
7366   "  function e() {"
7367   "    with ({x:87}) { return x; }"
7368   "  }"
7369   "  this.UseWith2 = e;"
7370   "})()";
7371
7372
7373 TEST(UseWithFromExtension) {
7374   v8::HandleScope handle_scope(CcTest::isolate());
7375   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7376   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7377   const char* extension_names[] = { "withtest1", "withtest2" };
7378   v8::ExtensionConfiguration extensions(2, extension_names);
7379   v8::Handle<Context> context =
7380       Context::New(CcTest::isolate(), &extensions);
7381   Context::Scope lock(context);
7382   v8::Handle<Value> result = CompileRun("UseWith1()");
7383   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7384   result = CompileRun("UseWith2()");
7385   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7386 }
7387
7388
7389 TEST(AutoExtensions) {
7390   v8::HandleScope handle_scope(CcTest::isolate());
7391   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7392   extension->set_auto_enable(true);
7393   v8::RegisterExtension(extension);
7394   v8::Handle<Context> context =
7395       Context::New(CcTest::isolate());
7396   Context::Scope lock(context);
7397   v8::Handle<Value> result = CompileRun("Foo()");
7398   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7399 }
7400
7401
7402 static const char* kSyntaxErrorInExtensionSource =
7403     "[";
7404
7405
7406 // Test that a syntax error in an extension does not cause a fatal
7407 // error but results in an empty context.
7408 TEST(SyntaxErrorExtensions) {
7409   v8::HandleScope handle_scope(CcTest::isolate());
7410   v8::RegisterExtension(new Extension("syntaxerror",
7411                                       kSyntaxErrorInExtensionSource));
7412   const char* extension_names[] = { "syntaxerror" };
7413   v8::ExtensionConfiguration extensions(1, extension_names);
7414   v8::Handle<Context> context =
7415       Context::New(CcTest::isolate(), &extensions);
7416   CHECK(context.IsEmpty());
7417 }
7418
7419
7420 static const char* kExceptionInExtensionSource =
7421     "throw 42";
7422
7423
7424 // Test that an exception when installing an extension does not cause
7425 // a fatal error but results in an empty context.
7426 TEST(ExceptionExtensions) {
7427   v8::HandleScope handle_scope(CcTest::isolate());
7428   v8::RegisterExtension(new Extension("exception",
7429                                       kExceptionInExtensionSource));
7430   const char* extension_names[] = { "exception" };
7431   v8::ExtensionConfiguration extensions(1, extension_names);
7432   v8::Handle<Context> context =
7433       Context::New(CcTest::isolate(), &extensions);
7434   CHECK(context.IsEmpty());
7435 }
7436
7437
7438 static const char* kNativeCallInExtensionSource =
7439     "function call_runtime_last_index_of(x) {"
7440     "  return %StringLastIndexOf(x, 'bob', 10);"
7441     "}";
7442
7443
7444 static const char* kNativeCallTest =
7445     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7446
7447 // Test that a native runtime calls are supported in extensions.
7448 TEST(NativeCallInExtensions) {
7449   v8::HandleScope handle_scope(CcTest::isolate());
7450   v8::RegisterExtension(new Extension("nativecall",
7451                                       kNativeCallInExtensionSource));
7452   const char* extension_names[] = { "nativecall" };
7453   v8::ExtensionConfiguration extensions(1, extension_names);
7454   v8::Handle<Context> context =
7455       Context::New(CcTest::isolate(), &extensions);
7456   Context::Scope lock(context);
7457   v8::Handle<Value> result = CompileRun(kNativeCallTest);
7458   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7459 }
7460
7461
7462 class NativeFunctionExtension : public Extension {
7463  public:
7464   NativeFunctionExtension(const char* name,
7465                           const char* source,
7466                           v8::FunctionCallback fun = &Echo)
7467       : Extension(name, source),
7468         function_(fun) { }
7469
7470   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7471       v8::Isolate* isolate,
7472       v8::Handle<v8::String> name) {
7473     return v8::FunctionTemplate::New(isolate, function_);
7474   }
7475
7476   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7477     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7478   }
7479  private:
7480   v8::FunctionCallback function_;
7481 };
7482
7483
7484 TEST(NativeFunctionDeclaration) {
7485   v8::HandleScope handle_scope(CcTest::isolate());
7486   const char* name = "nativedecl";
7487   v8::RegisterExtension(new NativeFunctionExtension(name,
7488                                                     "native function foo();"));
7489   const char* extension_names[] = { name };
7490   v8::ExtensionConfiguration extensions(1, extension_names);
7491   v8::Handle<Context> context =
7492       Context::New(CcTest::isolate(), &extensions);
7493   Context::Scope lock(context);
7494   v8::Handle<Value> result = CompileRun("foo(42);");
7495   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7496 }
7497
7498
7499 TEST(NativeFunctionDeclarationError) {
7500   v8::HandleScope handle_scope(CcTest::isolate());
7501   const char* name = "nativedeclerr";
7502   // Syntax error in extension code.
7503   v8::RegisterExtension(new NativeFunctionExtension(name,
7504                                                     "native\nfunction foo();"));
7505   const char* extension_names[] = { name };
7506   v8::ExtensionConfiguration extensions(1, extension_names);
7507   v8::Handle<Context> context =
7508       Context::New(CcTest::isolate(), &extensions);
7509   CHECK(context.IsEmpty());
7510 }
7511
7512
7513 TEST(NativeFunctionDeclarationErrorEscape) {
7514   v8::HandleScope handle_scope(CcTest::isolate());
7515   const char* name = "nativedeclerresc";
7516   // Syntax error in extension code - escape code in "native" means that
7517   // it's not treated as a keyword.
7518   v8::RegisterExtension(new NativeFunctionExtension(
7519       name,
7520       "nativ\\u0065 function foo();"));
7521   const char* extension_names[] = { name };
7522   v8::ExtensionConfiguration extensions(1, extension_names);
7523   v8::Handle<Context> context =
7524       Context::New(CcTest::isolate(), &extensions);
7525   CHECK(context.IsEmpty());
7526 }
7527
7528
7529 static void CheckDependencies(const char* name, const char* expected) {
7530   v8::HandleScope handle_scope(CcTest::isolate());
7531   v8::ExtensionConfiguration config(1, &name);
7532   LocalContext context(&config);
7533   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7534            context->Global()->Get(v8_str("loaded")));
7535 }
7536
7537
7538 /*
7539  * Configuration:
7540  *
7541  *     /-- B <--\
7542  * A <-          -- D <-- E
7543  *     \-- C <--/
7544  */
7545 THREADED_TEST(ExtensionDependency) {
7546   static const char* kEDeps[] = { "D" };
7547   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7548   static const char* kDDeps[] = { "B", "C" };
7549   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7550   static const char* kBCDeps[] = { "A" };
7551   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7552   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7553   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7554   CheckDependencies("A", "undefinedA");
7555   CheckDependencies("B", "undefinedAB");
7556   CheckDependencies("C", "undefinedAC");
7557   CheckDependencies("D", "undefinedABCD");
7558   CheckDependencies("E", "undefinedABCDE");
7559   v8::HandleScope handle_scope(CcTest::isolate());
7560   static const char* exts[2] = { "C", "E" };
7561   v8::ExtensionConfiguration config(2, exts);
7562   LocalContext context(&config);
7563   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7564 }
7565
7566
7567 static const char* kExtensionTestScript =
7568   "native function A();"
7569   "native function B();"
7570   "native function C();"
7571   "function Foo(i) {"
7572   "  if (i == 0) return A();"
7573   "  if (i == 1) return B();"
7574   "  if (i == 2) return C();"
7575   "}";
7576
7577
7578 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7579   ApiTestFuzzer::Fuzz();
7580   if (args.IsConstructCall()) {
7581     args.This()->Set(v8_str("data"), args.Data());
7582     args.GetReturnValue().SetNull();
7583     return;
7584   }
7585   args.GetReturnValue().Set(args.Data());
7586 }
7587
7588
7589 class FunctionExtension : public Extension {
7590  public:
7591   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7592   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7593       v8::Isolate* isolate,
7594       v8::Handle<String> name);
7595 };
7596
7597
7598 static int lookup_count = 0;
7599 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7600     v8::Isolate* isolate, v8::Handle<String> name) {
7601   lookup_count++;
7602   if (name->Equals(v8_str("A"))) {
7603     return v8::FunctionTemplate::New(
7604         isolate, CallFun, v8::Integer::New(isolate, 8));
7605   } else if (name->Equals(v8_str("B"))) {
7606     return v8::FunctionTemplate::New(
7607         isolate, CallFun, v8::Integer::New(isolate, 7));
7608   } else if (name->Equals(v8_str("C"))) {
7609     return v8::FunctionTemplate::New(
7610         isolate, CallFun, v8::Integer::New(isolate, 6));
7611   } else {
7612     return v8::Handle<v8::FunctionTemplate>();
7613   }
7614 }
7615
7616
7617 THREADED_TEST(FunctionLookup) {
7618   v8::RegisterExtension(new FunctionExtension());
7619   v8::HandleScope handle_scope(CcTest::isolate());
7620   static const char* exts[1] = { "functiontest" };
7621   v8::ExtensionConfiguration config(1, exts);
7622   LocalContext context(&config);
7623   CHECK_EQ(3, lookup_count);
7624   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7625            CompileRun("Foo(0)"));
7626   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7627            CompileRun("Foo(1)"));
7628   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7629            CompileRun("Foo(2)"));
7630 }
7631
7632
7633 THREADED_TEST(NativeFunctionConstructCall) {
7634   v8::RegisterExtension(new FunctionExtension());
7635   v8::HandleScope handle_scope(CcTest::isolate());
7636   static const char* exts[1] = { "functiontest" };
7637   v8::ExtensionConfiguration config(1, exts);
7638   LocalContext context(&config);
7639   for (int i = 0; i < 10; i++) {
7640     // Run a few times to ensure that allocation of objects doesn't
7641     // change behavior of a constructor function.
7642     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7643              CompileRun("(new A()).data"));
7644     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7645              CompileRun("(new B()).data"));
7646     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7647              CompileRun("(new C()).data"));
7648   }
7649 }
7650
7651
7652 static const char* last_location;
7653 static const char* last_message;
7654 void StoringErrorCallback(const char* location, const char* message) {
7655   if (last_location == NULL) {
7656     last_location = location;
7657     last_message = message;
7658   }
7659 }
7660
7661
7662 // ErrorReporting creates a circular extensions configuration and
7663 // tests that the fatal error handler gets called.  This renders V8
7664 // unusable and therefore this test cannot be run in parallel.
7665 TEST(ErrorReporting) {
7666   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7667   static const char* aDeps[] = { "B" };
7668   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7669   static const char* bDeps[] = { "A" };
7670   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7671   last_location = NULL;
7672   v8::ExtensionConfiguration config(1, bDeps);
7673   v8::Handle<Context> context =
7674       Context::New(CcTest::isolate(), &config);
7675   CHECK(context.IsEmpty());
7676   CHECK_NE(last_location, NULL);
7677 }
7678
7679
7680 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7681                                              v8::Handle<Value> data) {
7682   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7683   CHECK_EQ(v8::Undefined(CcTest::isolate()),
7684       message->GetScriptOrigin().ResourceName());
7685   message->GetLineNumber();
7686   message->GetSourceLine();
7687 }
7688
7689
7690 THREADED_TEST(ErrorWithMissingScriptInfo) {
7691   LocalContext context;
7692   v8::HandleScope scope(context->GetIsolate());
7693   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7694   CompileRun("throw Error()");
7695   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7696 }
7697
7698
7699 struct FlagAndPersistent {
7700   bool flag;
7701   v8::Persistent<v8::Object> handle;
7702 };
7703
7704
7705 static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
7706   data.GetParameter()->flag = true;
7707 }
7708
7709
7710 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7711   v8::Isolate* iso = CcTest::isolate();
7712   v8::HandleScope scope(iso);
7713   v8::Handle<Context> context = Context::New(iso);
7714   Context::Scope context_scope(context);
7715
7716   FlagAndPersistent object_a, object_b;
7717
7718   intptr_t big_heap_size;
7719
7720   {
7721     v8::HandleScope handle_scope(iso);
7722     Local<Object> a(v8::Object::New(iso));
7723     Local<Object> b(v8::Object::New(iso));
7724     object_a.handle.Reset(iso, a);
7725     object_b.handle.Reset(iso, b);
7726     if (interlinked) {
7727       a->Set(v8_str("x"), b);
7728       b->Set(v8_str("x"), a);
7729     }
7730     if (global_gc) {
7731       CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7732     } else {
7733       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7734     }
7735     // We are relying on this creating a big flag array and reserving the space
7736     // up front.
7737     v8::Handle<Value> big_array = CompileRun("new Array(50000)");
7738     a->Set(v8_str("y"), big_array);
7739     big_heap_size = CcTest::heap()->SizeOfObjects();
7740   }
7741
7742   object_a.flag = false;
7743   object_b.flag = false;
7744   object_a.handle.SetPhantom(&object_a, &SetFlag);
7745   object_b.handle.SetPhantom(&object_b, &SetFlag);
7746   CHECK(!object_b.handle.IsIndependent());
7747   object_a.handle.MarkIndependent();
7748   object_b.handle.MarkIndependent();
7749   CHECK(object_b.handle.IsIndependent());
7750   if (global_gc) {
7751     CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7752   } else {
7753     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7754   }
7755   // A single GC should be enough to reclaim the memory, since we are using
7756   // phantom handles.
7757   CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
7758   CHECK(object_a.flag);
7759   CHECK(object_b.flag);
7760 }
7761
7762
7763 THREADED_TEST(IndependentWeakHandle) {
7764   IndependentWeakHandle(false, false);
7765   IndependentWeakHandle(false, true);
7766   IndependentWeakHandle(true, false);
7767   IndependentWeakHandle(true, true);
7768 }
7769
7770
7771 class Trivial {
7772  public:
7773   explicit Trivial(int x) : x_(x) {}
7774
7775   int x() { return x_; }
7776   void set_x(int x) { x_ = x; }
7777
7778  private:
7779   int x_;
7780 };
7781
7782
7783 class Trivial2 {
7784  public:
7785   Trivial2(int x, int y) : y_(y), x_(x) {}
7786
7787   int x() { return x_; }
7788   void set_x(int x) { x_ = x; }
7789
7790   int y() { return y_; }
7791   void set_y(int y) { y_ = y; }
7792
7793  private:
7794   int y_;
7795   int x_;
7796 };
7797
7798
7799 void CheckInternalFields(
7800     const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
7801   Trivial* t1 = data.GetInternalField1();
7802   Trivial2* t2 = data.GetInternalField2();
7803   CHECK_EQ(42, t1->x());
7804   CHECK_EQ(103, t2->x());
7805   t1->set_x(1729);
7806   t2->set_x(33550336);
7807 }
7808
7809
7810 void InternalFieldCallback(bool global_gc) {
7811   LocalContext env;
7812   v8::Isolate* isolate = env->GetIsolate();
7813   v8::HandleScope scope(isolate);
7814
7815   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
7816   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
7817   Trivial* t1;
7818   Trivial2* t2;
7819   instance_templ->SetInternalFieldCount(2);
7820   {
7821     v8::HandleScope scope(isolate);
7822     Local<v8::Object> obj = templ->GetFunction()->NewInstance();
7823     v8::Persistent<v8::Object> handle(isolate, obj);
7824     CHECK_EQ(2, obj->InternalFieldCount());
7825     CHECK(obj->GetInternalField(0)->IsUndefined());
7826     t1 = new Trivial(42);
7827     t2 = new Trivial2(103, 9);
7828
7829     obj->SetAlignedPointerInInternalField(0, t1);
7830     t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
7831     CHECK_EQ(42, t1->x());
7832
7833     obj->SetAlignedPointerInInternalField(1, t2);
7834     t2 =
7835         reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
7836     CHECK_EQ(103, t2->x());
7837
7838     handle.SetPhantom(CheckInternalFields, 0, 1);
7839     if (!global_gc) {
7840       handle.MarkIndependent();
7841     }
7842   }
7843   if (global_gc) {
7844     CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7845   } else {
7846     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7847   }
7848
7849   CHECK_EQ(1729, t1->x());
7850   CHECK_EQ(33550336, t2->x());
7851
7852   delete t1;
7853   delete t2;
7854 }
7855
7856
7857 THREADED_TEST(InternalFieldCallback) {
7858   InternalFieldCallback(false);
7859   InternalFieldCallback(true);
7860 }
7861
7862
7863 static void ResetUseValueAndSetFlag(
7864     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7865   // Blink will reset the handle, and then use the other handle, so they
7866   // can't use the same backing slot.
7867   data.GetParameter()->handle.Reset();
7868   data.GetValue()->IsBoolean();  // Make sure the handle still works.
7869   data.GetParameter()->flag = true;
7870 }
7871
7872
7873 static void ResetWeakHandle(bool global_gc) {
7874   v8::Isolate* iso = CcTest::isolate();
7875   v8::HandleScope scope(iso);
7876   v8::Handle<Context> context = Context::New(iso);
7877   Context::Scope context_scope(context);
7878
7879   FlagAndPersistent object_a, object_b;
7880
7881   {
7882     v8::HandleScope handle_scope(iso);
7883     Local<Object> a(v8::Object::New(iso));
7884     Local<Object> b(v8::Object::New(iso));
7885     object_a.handle.Reset(iso, a);
7886     object_b.handle.Reset(iso, b);
7887     if (global_gc) {
7888       CcTest::heap()->CollectAllGarbage(
7889           TestHeap::Heap::kAbortIncrementalMarkingMask);
7890     } else {
7891       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7892     }
7893   }
7894
7895   object_a.flag = false;
7896   object_b.flag = false;
7897   object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
7898   object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
7899   if (!global_gc) {
7900     object_a.handle.MarkIndependent();
7901     object_b.handle.MarkIndependent();
7902     CHECK(object_b.handle.IsIndependent());
7903   }
7904   if (global_gc) {
7905     CcTest::heap()->CollectAllGarbage(
7906         TestHeap::Heap::kAbortIncrementalMarkingMask);
7907   } else {
7908     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7909   }
7910   CHECK(object_a.flag);
7911   CHECK(object_b.flag);
7912 }
7913
7914
7915 THREADED_TEST(ResetWeakHandle) {
7916   ResetWeakHandle(false);
7917   ResetWeakHandle(true);
7918 }
7919
7920
7921 static void InvokeScavenge() {
7922   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7923 }
7924
7925
7926 static void InvokeMarkSweep() {
7927   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7928 }
7929
7930
7931 static void ForceScavenge(
7932     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7933   data.GetParameter()->handle.Reset();
7934   data.GetParameter()->flag = true;
7935   InvokeScavenge();
7936 }
7937
7938
7939 static void ForceMarkSweep(
7940     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7941   data.GetParameter()->handle.Reset();
7942   data.GetParameter()->flag = true;
7943   InvokeMarkSweep();
7944 }
7945
7946
7947 THREADED_TEST(GCFromWeakCallbacks) {
7948   v8::Isolate* isolate = CcTest::isolate();
7949   v8::HandleScope scope(isolate);
7950   v8::Handle<Context> context = Context::New(isolate);
7951   Context::Scope context_scope(context);
7952
7953   static const int kNumberOfGCTypes = 2;
7954   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7955       Callback;
7956   Callback gc_forcing_callback[kNumberOfGCTypes] =
7957       {&ForceScavenge, &ForceMarkSweep};
7958
7959   typedef void (*GCInvoker)();
7960   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7961
7962   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7963     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7964       FlagAndPersistent object;
7965       {
7966         v8::HandleScope handle_scope(isolate);
7967         object.handle.Reset(isolate, v8::Object::New(isolate));
7968       }
7969       object.flag = false;
7970       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7971       object.handle.MarkIndependent();
7972       invoke_gc[outer_gc]();
7973       CHECK(object.flag);
7974     }
7975   }
7976 }
7977
7978
7979 static void RevivingCallback(
7980     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7981   data.GetParameter()->handle.ClearWeak();
7982   data.GetParameter()->flag = true;
7983 }
7984
7985
7986 THREADED_TEST(IndependentHandleRevival) {
7987   v8::Isolate* isolate = CcTest::isolate();
7988   v8::HandleScope scope(isolate);
7989   v8::Handle<Context> context = Context::New(isolate);
7990   Context::Scope context_scope(context);
7991
7992   FlagAndPersistent object;
7993   {
7994     v8::HandleScope handle_scope(isolate);
7995     v8::Local<v8::Object> o = v8::Object::New(isolate);
7996     object.handle.Reset(isolate, o);
7997     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7998     v8::Local<String> y_str = v8_str("y");
7999     o->Set(y_str, y_str);
8000   }
8001   object.flag = false;
8002   object.handle.SetWeak(&object, &RevivingCallback);
8003   object.handle.MarkIndependent();
8004   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
8005   CHECK(object.flag);
8006   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
8007   {
8008     v8::HandleScope handle_scope(isolate);
8009     v8::Local<v8::Object> o =
8010         v8::Local<v8::Object>::New(isolate, object.handle);
8011     v8::Local<String> y_str = v8_str("y");
8012     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
8013     CHECK(o->Get(y_str)->Equals(y_str));
8014   }
8015 }
8016
8017
8018 v8::Handle<Function> args_fun;
8019
8020
8021 static void ArgumentsTestCallback(
8022     const v8::FunctionCallbackInfo<v8::Value>& args) {
8023   ApiTestFuzzer::Fuzz();
8024   v8::Isolate* isolate = args.GetIsolate();
8025   CHECK_EQ(args_fun, args.Callee());
8026   CHECK_EQ(3, args.Length());
8027   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
8028   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
8029   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
8030   CHECK_EQ(v8::Undefined(isolate), args[3]);
8031   v8::HandleScope scope(args.GetIsolate());
8032   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8033 }
8034
8035
8036 THREADED_TEST(Arguments) {
8037   v8::Isolate* isolate = CcTest::isolate();
8038   v8::HandleScope scope(isolate);
8039   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8040   global->Set(v8_str("f"),
8041               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8042   LocalContext context(NULL, global);
8043   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
8044   v8_compile("f(1, 2, 3)")->Run();
8045 }
8046
8047
8048 static void NoBlockGetterX(Local<Name> name,
8049                            const v8::PropertyCallbackInfo<v8::Value>&) {}
8050
8051
8052 static void NoBlockGetterI(uint32_t index,
8053                            const v8::PropertyCallbackInfo<v8::Value>&) {
8054 }
8055
8056
8057 static void PDeleter(Local<Name> name,
8058                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
8059   if (!name->Equals(v8_str("foo"))) {
8060     return;  // not intercepted
8061   }
8062
8063   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
8064 }
8065
8066
8067 static void IDeleter(uint32_t index,
8068                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
8069   if (index != 2) {
8070     return;  // not intercepted
8071   }
8072
8073   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
8074 }
8075
8076
8077 THREADED_TEST(Deleter) {
8078   v8::Isolate* isolate = CcTest::isolate();
8079   v8::HandleScope scope(isolate);
8080   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8081   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
8082                                                         NULL, PDeleter, NULL));
8083   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
8084       NoBlockGetterI, NULL, NULL, IDeleter, NULL));
8085   LocalContext context;
8086   context->Global()->Set(v8_str("k"), obj->NewInstance());
8087   CompileRun(
8088     "k.foo = 'foo';"
8089     "k.bar = 'bar';"
8090     "k[2] = 2;"
8091     "k[4] = 4;");
8092   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
8093   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
8094
8095   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
8096   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
8097
8098   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
8099   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
8100
8101   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
8102   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
8103 }
8104
8105
8106 static void GetK(Local<Name> name,
8107                  const v8::PropertyCallbackInfo<v8::Value>& info) {
8108   ApiTestFuzzer::Fuzz();
8109   if (name->Equals(v8_str("foo")) ||
8110       name->Equals(v8_str("bar")) ||
8111       name->Equals(v8_str("baz"))) {
8112     info.GetReturnValue().SetUndefined();
8113   }
8114 }
8115
8116
8117 static void IndexedGetK(uint32_t index,
8118                         const v8::PropertyCallbackInfo<v8::Value>& info) {
8119   ApiTestFuzzer::Fuzz();
8120   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
8121 }
8122
8123
8124 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
8125   ApiTestFuzzer::Fuzz();
8126   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
8127   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
8128   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
8129   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
8130   info.GetReturnValue().Set(result);
8131 }
8132
8133
8134 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
8135   ApiTestFuzzer::Fuzz();
8136   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
8137   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
8138   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
8139   info.GetReturnValue().Set(result);
8140 }
8141
8142
8143 THREADED_TEST(Enumerators) {
8144   v8::Isolate* isolate = CcTest::isolate();
8145   v8::HandleScope scope(isolate);
8146   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8147   obj->SetHandler(
8148       v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
8149   obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
8150       IndexedGetK, NULL, NULL, NULL, IndexedEnum));
8151   LocalContext context;
8152   context->Global()->Set(v8_str("k"), obj->NewInstance());
8153   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
8154     "k[10] = 0;"
8155     "k.a = 0;"
8156     "k[5] = 0;"
8157     "k.b = 0;"
8158     "k[4294967295] = 0;"
8159     "k.c = 0;"
8160     "k[4294967296] = 0;"
8161     "k.d = 0;"
8162     "k[140000] = 0;"
8163     "k.e = 0;"
8164     "k[30000000000] = 0;"
8165     "k.f = 0;"
8166     "var result = [];"
8167     "for (var prop in k) {"
8168     "  result.push(prop);"
8169     "}"
8170     "result"));
8171   // Check that we get all the property names returned including the
8172   // ones from the enumerators in the right order: indexed properties
8173   // in numerical order, indexed interceptor properties, named
8174   // properties in insertion order, named interceptor properties.
8175   // This order is not mandated by the spec, so this test is just
8176   // documenting our behavior.
8177   CHECK_EQ(17, result->Length());
8178   // Indexed properties in numerical order.
8179   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
8180   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
8181   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
8182   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
8183   // Indexed interceptor properties in the order they are returned
8184   // from the enumerator interceptor.
8185   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
8186   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
8187   // Named properties in insertion order.
8188   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
8189   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
8190   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
8191   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
8192   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
8193   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
8194   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
8195   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
8196   // Named interceptor properties.
8197   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
8198   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
8199   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
8200 }
8201
8202
8203 int p_getter_count;
8204 int p_getter_count2;
8205
8206
8207 static void PGetter(Local<String> name,
8208                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8209   ApiTestFuzzer::Fuzz();
8210   p_getter_count++;
8211   v8::Handle<v8::Object> global =
8212       info.GetIsolate()->GetCurrentContext()->Global();
8213   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
8214   if (name->Equals(v8_str("p1"))) {
8215     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
8216   } else if (name->Equals(v8_str("p2"))) {
8217     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
8218   } else if (name->Equals(v8_str("p3"))) {
8219     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
8220   } else if (name->Equals(v8_str("p4"))) {
8221     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
8222   }
8223 }
8224
8225
8226 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
8227   ApiTestFuzzer::Fuzz();
8228   LocalContext context;
8229   context->Global()->Set(v8_str("o1"), obj->NewInstance());
8230   CompileRun(
8231     "o1.__proto__ = { };"
8232     "var o2 = { __proto__: o1 };"
8233     "var o3 = { __proto__: o2 };"
8234     "var o4 = { __proto__: o3 };"
8235     "for (var i = 0; i < 10; i++) o4.p4;"
8236     "for (var i = 0; i < 10; i++) o3.p3;"
8237     "for (var i = 0; i < 10; i++) o2.p2;"
8238     "for (var i = 0; i < 10; i++) o1.p1;");
8239 }
8240
8241
8242 static void PGetter2(Local<Name> name,
8243                      const v8::PropertyCallbackInfo<v8::Value>& info) {
8244   ApiTestFuzzer::Fuzz();
8245   p_getter_count2++;
8246   v8::Handle<v8::Object> global =
8247       info.GetIsolate()->GetCurrentContext()->Global();
8248   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
8249   if (name->Equals(v8_str("p1"))) {
8250     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
8251   } else if (name->Equals(v8_str("p2"))) {
8252     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
8253   } else if (name->Equals(v8_str("p3"))) {
8254     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
8255   } else if (name->Equals(v8_str("p4"))) {
8256     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
8257   }
8258 }
8259
8260
8261 THREADED_TEST(GetterHolders) {
8262   v8::Isolate* isolate = CcTest::isolate();
8263   v8::HandleScope scope(isolate);
8264   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8265   obj->SetAccessor(v8_str("p1"), PGetter);
8266   obj->SetAccessor(v8_str("p2"), PGetter);
8267   obj->SetAccessor(v8_str("p3"), PGetter);
8268   obj->SetAccessor(v8_str("p4"), PGetter);
8269   p_getter_count = 0;
8270   RunHolderTest(obj);
8271   CHECK_EQ(40, p_getter_count);
8272 }
8273
8274
8275 THREADED_TEST(PreInterceptorHolders) {
8276   v8::Isolate* isolate = CcTest::isolate();
8277   v8::HandleScope scope(isolate);
8278   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8279   obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8280   p_getter_count2 = 0;
8281   RunHolderTest(obj);
8282   CHECK_EQ(40, p_getter_count2);
8283 }
8284
8285
8286 THREADED_TEST(ObjectInstantiation) {
8287   v8::Isolate* isolate = CcTest::isolate();
8288   v8::HandleScope scope(isolate);
8289   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8290   templ->SetAccessor(v8_str("t"), PGetter2);
8291   LocalContext context;
8292   context->Global()->Set(v8_str("o"), templ->NewInstance());
8293   for (int i = 0; i < 100; i++) {
8294     v8::HandleScope inner_scope(CcTest::isolate());
8295     v8::Handle<v8::Object> obj = templ->NewInstance();
8296     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
8297     context->Global()->Set(v8_str("o2"), obj);
8298     v8::Handle<Value> value =
8299         CompileRun("o.__proto__ === o2.__proto__");
8300     CHECK_EQ(v8::True(isolate), value);
8301     context->Global()->Set(v8_str("o"), obj);
8302   }
8303 }
8304
8305
8306 static int StrCmp16(uint16_t* a, uint16_t* b) {
8307   while (true) {
8308     if (*a == 0 && *b == 0) return 0;
8309     if (*a != *b) return 0 + *a - *b;
8310     a++;
8311     b++;
8312   }
8313 }
8314
8315
8316 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8317   while (true) {
8318     if (n-- == 0) return 0;
8319     if (*a == 0 && *b == 0) return 0;
8320     if (*a != *b) return 0 + *a - *b;
8321     a++;
8322     b++;
8323   }
8324 }
8325
8326
8327 int GetUtf8Length(Handle<String> str) {
8328   int len = str->Utf8Length();
8329   if (len < 0) {
8330     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8331     i::String::Flatten(istr);
8332     len = str->Utf8Length();
8333   }
8334   return len;
8335 }
8336
8337
8338 THREADED_TEST(StringWrite) {
8339   LocalContext context;
8340   v8::HandleScope scope(context->GetIsolate());
8341   v8::Handle<String> str = v8_str("abcde");
8342   // abc<Icelandic eth><Unicode snowman>.
8343   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
8344   v8::Handle<String> str3 = v8::String::NewFromUtf8(
8345       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
8346   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8347   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8348   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
8349       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
8350   // single lead surrogate
8351   uint16_t lead[1] = { 0xd800 };
8352   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
8353       context->GetIsolate(), lead, v8::String::kNormalString, 1);
8354   // single trail surrogate
8355   uint16_t trail[1] = { 0xdc00 };
8356   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
8357       context->GetIsolate(), trail, v8::String::kNormalString, 1);
8358   // surrogate pair
8359   uint16_t pair[2] = { 0xd800,  0xdc00 };
8360   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
8361       context->GetIsolate(), pair, v8::String::kNormalString, 2);
8362   const int kStride = 4;  // Must match stride in for loops in JS below.
8363   CompileRun(
8364       "var left = '';"
8365       "for (var i = 0; i < 0xd800; i += 4) {"
8366       "  left = left + String.fromCharCode(i);"
8367       "}");
8368   CompileRun(
8369       "var right = '';"
8370       "for (var i = 0; i < 0xd800; i += 4) {"
8371       "  right = String.fromCharCode(i) + right;"
8372       "}");
8373   v8::Handle<v8::Object> global = context->Global();
8374   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
8375   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
8376
8377   CHECK_EQ(5, str2->Length());
8378   CHECK_EQ(0xd800 / kStride, left_tree->Length());
8379   CHECK_EQ(0xd800 / kStride, right_tree->Length());
8380
8381   char buf[100];
8382   char utf8buf[0xd800 * 3];
8383   uint16_t wbuf[100];
8384   int len;
8385   int charlen;
8386
8387   memset(utf8buf, 0x1, 1000);
8388   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8389   CHECK_EQ(9, len);
8390   CHECK_EQ(5, charlen);
8391   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8392
8393   memset(utf8buf, 0x1, 1000);
8394   len = str2->WriteUtf8(utf8buf, 8, &charlen);
8395   CHECK_EQ(8, len);
8396   CHECK_EQ(5, charlen);
8397   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
8398
8399   memset(utf8buf, 0x1, 1000);
8400   len = str2->WriteUtf8(utf8buf, 7, &charlen);
8401   CHECK_EQ(5, len);
8402   CHECK_EQ(4, charlen);
8403   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8404
8405   memset(utf8buf, 0x1, 1000);
8406   len = str2->WriteUtf8(utf8buf, 6, &charlen);
8407   CHECK_EQ(5, len);
8408   CHECK_EQ(4, charlen);
8409   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8410
8411   memset(utf8buf, 0x1, 1000);
8412   len = str2->WriteUtf8(utf8buf, 5, &charlen);
8413   CHECK_EQ(5, len);
8414   CHECK_EQ(4, charlen);
8415   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8416
8417   memset(utf8buf, 0x1, 1000);
8418   len = str2->WriteUtf8(utf8buf, 4, &charlen);
8419   CHECK_EQ(3, len);
8420   CHECK_EQ(3, charlen);
8421   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8422
8423   memset(utf8buf, 0x1, 1000);
8424   len = str2->WriteUtf8(utf8buf, 3, &charlen);
8425   CHECK_EQ(3, len);
8426   CHECK_EQ(3, charlen);
8427   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8428
8429   memset(utf8buf, 0x1, 1000);
8430   len = str2->WriteUtf8(utf8buf, 2, &charlen);
8431   CHECK_EQ(2, len);
8432   CHECK_EQ(2, charlen);
8433   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
8434
8435   // allow orphan surrogates by default
8436   memset(utf8buf, 0x1, 1000);
8437   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8438   CHECK_EQ(13, len);
8439   CHECK_EQ(8, charlen);
8440   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8441
8442   // replace orphan surrogates with unicode replacement character
8443   memset(utf8buf, 0x1, 1000);
8444   len = orphans_str->WriteUtf8(utf8buf,
8445                                sizeof(utf8buf),
8446                                &charlen,
8447                                String::REPLACE_INVALID_UTF8);
8448   CHECK_EQ(13, len);
8449   CHECK_EQ(8, charlen);
8450   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8451
8452   // replace single lead surrogate with unicode replacement character
8453   memset(utf8buf, 0x1, 1000);
8454   len = lead_str->WriteUtf8(utf8buf,
8455                             sizeof(utf8buf),
8456                             &charlen,
8457                             String::REPLACE_INVALID_UTF8);
8458   CHECK_EQ(4, len);
8459   CHECK_EQ(1, charlen);
8460   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8461
8462   // replace single trail surrogate with unicode replacement character
8463   memset(utf8buf, 0x1, 1000);
8464   len = trail_str->WriteUtf8(utf8buf,
8465                              sizeof(utf8buf),
8466                              &charlen,
8467                              String::REPLACE_INVALID_UTF8);
8468   CHECK_EQ(4, len);
8469   CHECK_EQ(1, charlen);
8470   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8471
8472   // do not replace / write anything if surrogate pair does not fit the buffer
8473   // space
8474   memset(utf8buf, 0x1, 1000);
8475   len = pair_str->WriteUtf8(utf8buf,
8476                              3,
8477                              &charlen,
8478                              String::REPLACE_INVALID_UTF8);
8479   CHECK_EQ(0, len);
8480   CHECK_EQ(0, charlen);
8481
8482   memset(utf8buf, 0x1, sizeof(utf8buf));
8483   len = GetUtf8Length(left_tree);
8484   int utf8_expected =
8485       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8486   CHECK_EQ(utf8_expected, len);
8487   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8488   CHECK_EQ(utf8_expected, len);
8489   CHECK_EQ(0xd800 / kStride, charlen);
8490   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8491   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8492   CHECK_EQ(0xc0 - kStride,
8493            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8494   CHECK_EQ(1, utf8buf[utf8_expected]);
8495
8496   memset(utf8buf, 0x1, sizeof(utf8buf));
8497   len = GetUtf8Length(right_tree);
8498   CHECK_EQ(utf8_expected, len);
8499   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8500   CHECK_EQ(utf8_expected, len);
8501   CHECK_EQ(0xd800 / kStride, charlen);
8502   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8503   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8504   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8505   CHECK_EQ(1, utf8buf[utf8_expected]);
8506
8507   memset(buf, 0x1, sizeof(buf));
8508   memset(wbuf, 0x1, sizeof(wbuf));
8509   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8510   CHECK_EQ(5, len);
8511   len = str->Write(wbuf);
8512   CHECK_EQ(5, len);
8513   CHECK_EQ(0, strcmp("abcde", buf));
8514   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8515   CHECK_EQ(0, StrCmp16(answer1, wbuf));
8516
8517   memset(buf, 0x1, sizeof(buf));
8518   memset(wbuf, 0x1, sizeof(wbuf));
8519   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8520   CHECK_EQ(4, len);
8521   len = str->Write(wbuf, 0, 4);
8522   CHECK_EQ(4, len);
8523   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8524   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8525   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8526
8527   memset(buf, 0x1, sizeof(buf));
8528   memset(wbuf, 0x1, sizeof(wbuf));
8529   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8530   CHECK_EQ(5, len);
8531   len = str->Write(wbuf, 0, 5);
8532   CHECK_EQ(5, len);
8533   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8534   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8535   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8536
8537   memset(buf, 0x1, sizeof(buf));
8538   memset(wbuf, 0x1, sizeof(wbuf));
8539   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8540   CHECK_EQ(5, len);
8541   len = str->Write(wbuf, 0, 6);
8542   CHECK_EQ(5, len);
8543   CHECK_EQ(0, strcmp("abcde", buf));
8544   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8545   CHECK_EQ(0, StrCmp16(answer4, wbuf));
8546
8547   memset(buf, 0x1, sizeof(buf));
8548   memset(wbuf, 0x1, sizeof(wbuf));
8549   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8550   CHECK_EQ(1, len);
8551   len = str->Write(wbuf, 4, -1);
8552   CHECK_EQ(1, len);
8553   CHECK_EQ(0, strcmp("e", buf));
8554   uint16_t answer5[] = {'e', '\0'};
8555   CHECK_EQ(0, StrCmp16(answer5, wbuf));
8556
8557   memset(buf, 0x1, sizeof(buf));
8558   memset(wbuf, 0x1, sizeof(wbuf));
8559   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8560   CHECK_EQ(1, len);
8561   len = str->Write(wbuf, 4, 6);
8562   CHECK_EQ(1, len);
8563   CHECK_EQ(0, strcmp("e", buf));
8564   CHECK_EQ(0, StrCmp16(answer5, wbuf));
8565
8566   memset(buf, 0x1, sizeof(buf));
8567   memset(wbuf, 0x1, sizeof(wbuf));
8568   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8569   CHECK_EQ(1, len);
8570   len = str->Write(wbuf, 4, 1);
8571   CHECK_EQ(1, len);
8572   CHECK_EQ(0, strncmp("e\1", buf, 2));
8573   uint16_t answer6[] = {'e', 0x101};
8574   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8575
8576   memset(buf, 0x1, sizeof(buf));
8577   memset(wbuf, 0x1, sizeof(wbuf));
8578   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8579   CHECK_EQ(1, len);
8580   len = str->Write(wbuf, 3, 1);
8581   CHECK_EQ(1, len);
8582   CHECK_EQ(0, strncmp("d\1", buf, 2));
8583   uint16_t answer7[] = {'d', 0x101};
8584   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8585
8586   memset(wbuf, 0x1, sizeof(wbuf));
8587   wbuf[5] = 'X';
8588   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8589   CHECK_EQ(5, len);
8590   CHECK_EQ('X', wbuf[5]);
8591   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8592   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8593   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8594   CHECK_NE(0, StrCmp16(answer8b, wbuf));
8595   wbuf[5] = '\0';
8596   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8597
8598   memset(buf, 0x1, sizeof(buf));
8599   buf[5] = 'X';
8600   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8601                           0,
8602                           6,
8603                           String::NO_NULL_TERMINATION);
8604   CHECK_EQ(5, len);
8605   CHECK_EQ('X', buf[5]);
8606   CHECK_EQ(0, strncmp("abcde", buf, 5));
8607   CHECK_NE(0, strcmp("abcde", buf));
8608   buf[5] = '\0';
8609   CHECK_EQ(0, strcmp("abcde", buf));
8610
8611   memset(utf8buf, 0x1, sizeof(utf8buf));
8612   utf8buf[8] = 'X';
8613   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8614                         String::NO_NULL_TERMINATION);
8615   CHECK_EQ(8, len);
8616   CHECK_EQ('X', utf8buf[8]);
8617   CHECK_EQ(5, charlen);
8618   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8619   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8620   utf8buf[8] = '\0';
8621   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8622
8623   memset(utf8buf, 0x1, sizeof(utf8buf));
8624   utf8buf[5] = 'X';
8625   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8626                         String::NO_NULL_TERMINATION);
8627   CHECK_EQ(5, len);
8628   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
8629   CHECK_EQ(5, charlen);
8630   utf8buf[5] = '\0';
8631   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8632
8633   memset(buf, 0x1, sizeof(buf));
8634   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8635   CHECK_EQ(7, len);
8636   CHECK_EQ(0, strcmp("abc", buf));
8637   CHECK_EQ(0, buf[3]);
8638   CHECK_EQ(0, strcmp("def", buf + 4));
8639
8640   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8641   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8642   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8643 }
8644
8645
8646 static void Utf16Helper(
8647     LocalContext& context,  // NOLINT
8648     const char* name,
8649     const char* lengths_name,
8650     int len) {
8651   Local<v8::Array> a =
8652       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8653   Local<v8::Array> alens =
8654       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8655   for (int i = 0; i < len; i++) {
8656     Local<v8::String> string =
8657       Local<v8::String>::Cast(a->Get(i));
8658     Local<v8::Number> expected_len =
8659       Local<v8::Number>::Cast(alens->Get(i));
8660     int length = GetUtf8Length(string);
8661     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8662   }
8663 }
8664
8665
8666 static uint16_t StringGet(Handle<String> str, int index) {
8667   i::Handle<i::String> istring =
8668       v8::Utils::OpenHandle(String::Cast(*str));
8669   return istring->Get(index);
8670 }
8671
8672
8673 static void WriteUtf8Helper(
8674     LocalContext& context,  // NOLINT
8675     const char* name,
8676     const char* lengths_name,
8677     int len) {
8678   Local<v8::Array> b =
8679       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8680   Local<v8::Array> alens =
8681       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8682   char buffer[1000];
8683   char buffer2[1000];
8684   for (int i = 0; i < len; i++) {
8685     Local<v8::String> string =
8686       Local<v8::String>::Cast(b->Get(i));
8687     Local<v8::Number> expected_len =
8688       Local<v8::Number>::Cast(alens->Get(i));
8689     int utf8_length = static_cast<int>(expected_len->Value());
8690     for (int j = utf8_length + 1; j >= 0; j--) {
8691       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8692       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8693       int nchars;
8694       int utf8_written =
8695           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8696       int utf8_written2 =
8697           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8698       CHECK_GE(utf8_length + 1, utf8_written);
8699       CHECK_GE(utf8_length, utf8_written2);
8700       for (int k = 0; k < utf8_written2; k++) {
8701         CHECK_EQ(buffer[k], buffer2[k]);
8702       }
8703       CHECK(nchars * 3 >= utf8_written - 1);
8704       CHECK(nchars <= utf8_written);
8705       if (j == utf8_length + 1) {
8706         CHECK_EQ(utf8_written2, utf8_length);
8707         CHECK_EQ(utf8_written2 + 1, utf8_written);
8708       }
8709       CHECK_EQ(buffer[utf8_written], 42);
8710       if (j > utf8_length) {
8711         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8712         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8713         Handle<String> roundtrip = v8_str(buffer);
8714         CHECK(roundtrip->Equals(string));
8715       } else {
8716         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8717       }
8718       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8719       if (nchars >= 2) {
8720         uint16_t trail = StringGet(string, nchars - 1);
8721         uint16_t lead = StringGet(string, nchars - 2);
8722         if (((lead & 0xfc00) == 0xd800) &&
8723             ((trail & 0xfc00) == 0xdc00)) {
8724           unsigned char u1 = buffer2[utf8_written2 - 4];
8725           unsigned char u2 = buffer2[utf8_written2 - 3];
8726           unsigned char u3 = buffer2[utf8_written2 - 2];
8727           unsigned char u4 = buffer2[utf8_written2 - 1];
8728           CHECK_EQ((u1 & 0xf8), 0xf0);
8729           CHECK_EQ((u2 & 0xc0), 0x80);
8730           CHECK_EQ((u3 & 0xc0), 0x80);
8731           CHECK_EQ((u4 & 0xc0), 0x80);
8732           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8733           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8734           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8735           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8736           CHECK_EQ((u1 & 0x3), c >> 18);
8737         }
8738       }
8739     }
8740   }
8741 }
8742
8743
8744 THREADED_TEST(Utf16) {
8745   LocalContext context;
8746   v8::HandleScope scope(context->GetIsolate());
8747   CompileRun(
8748       "var pad = '01234567890123456789';"
8749       "var p = [];"
8750       "var plens = [20, 3, 3];"
8751       "p.push('01234567890123456789');"
8752       "var lead = 0xd800;"
8753       "var trail = 0xdc00;"
8754       "p.push(String.fromCharCode(0xd800));"
8755       "p.push(String.fromCharCode(0xdc00));"
8756       "var a = [];"
8757       "var b = [];"
8758       "var c = [];"
8759       "var alens = [];"
8760       "for (var i = 0; i < 3; i++) {"
8761       "  p[1] = String.fromCharCode(lead++);"
8762       "  for (var j = 0; j < 3; j++) {"
8763       "    p[2] = String.fromCharCode(trail++);"
8764       "    a.push(p[i] + p[j]);"
8765       "    b.push(p[i] + p[j]);"
8766       "    c.push(p[i] + p[j]);"
8767       "    alens.push(plens[i] + plens[j]);"
8768       "  }"
8769       "}"
8770       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8771       "var a2 = [];"
8772       "var b2 = [];"
8773       "var c2 = [];"
8774       "var a2lens = [];"
8775       "for (var m = 0; m < 9; m++) {"
8776       "  for (var n = 0; n < 9; n++) {"
8777       "    a2.push(a[m] + a[n]);"
8778       "    b2.push(b[m] + b[n]);"
8779       "    var newc = 'x' + c[m] + c[n] + 'y';"
8780       "    c2.push(newc.substring(1, newc.length - 1));"
8781       "    var utf = alens[m] + alens[n];"  // And here.
8782            // The 'n's that start with 0xdc.. are 6-8
8783            // The 'm's that end with 0xd8.. are 1, 4 and 7
8784       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8785       "    a2lens.push(utf);"
8786       "  }"
8787       "}");
8788   Utf16Helper(context, "a", "alens", 9);
8789   Utf16Helper(context, "a2", "a2lens", 81);
8790   WriteUtf8Helper(context, "b", "alens", 9);
8791   WriteUtf8Helper(context, "b2", "a2lens", 81);
8792   WriteUtf8Helper(context, "c2", "a2lens", 81);
8793 }
8794
8795
8796 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8797   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8798   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8799   return *is1 == *is2;
8800 }
8801
8802 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8803                              const char* b) {
8804   Handle<String> symbol1 =
8805       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8806   Handle<String> symbol2 =
8807       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8808   CHECK(SameSymbol(symbol1, symbol2));
8809 }
8810
8811
8812 THREADED_TEST(Utf16Symbol) {
8813   LocalContext context;
8814   v8::HandleScope scope(context->GetIsolate());
8815
8816   Handle<String> symbol1 = v8::String::NewFromUtf8(
8817       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8818   Handle<String> symbol2 = v8::String::NewFromUtf8(
8819       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8820   CHECK(SameSymbol(symbol1, symbol2));
8821
8822   SameSymbolHelper(context->GetIsolate(),
8823                    "\360\220\220\205",  // 4 byte encoding.
8824                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8825   SameSymbolHelper(context->GetIsolate(),
8826                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8827                    "\360\220\220\206");  // 4 byte encoding.
8828   SameSymbolHelper(context->GetIsolate(),
8829                    "x\360\220\220\205",  // 4 byte encoding.
8830                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8831   SameSymbolHelper(context->GetIsolate(),
8832                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8833                    "x\360\220\220\206");  // 4 byte encoding.
8834   CompileRun(
8835       "var sym0 = 'benedictus';"
8836       "var sym0b = 'S\303\270ren';"
8837       "var sym1 = '\355\240\201\355\260\207';"
8838       "var sym2 = '\360\220\220\210';"
8839       "var sym3 = 'x\355\240\201\355\260\207';"
8840       "var sym4 = 'x\360\220\220\210';"
8841       "if (sym1.length != 2) throw sym1;"
8842       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8843       "if (sym2.length != 2) throw sym2;"
8844       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8845       "if (sym3.length != 3) throw sym3;"
8846       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8847       "if (sym4.length != 3) throw sym4;"
8848       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8849   Handle<String> sym0 = v8::String::NewFromUtf8(
8850       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8851   Handle<String> sym0b = v8::String::NewFromUtf8(
8852       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8853   Handle<String> sym1 =
8854       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8855                               v8::String::kInternalizedString);
8856   Handle<String> sym2 =
8857       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8858                               v8::String::kInternalizedString);
8859   Handle<String> sym3 = v8::String::NewFromUtf8(
8860       context->GetIsolate(), "x\355\240\201\355\260\207",
8861       v8::String::kInternalizedString);
8862   Handle<String> sym4 =
8863       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8864                               v8::String::kInternalizedString);
8865   v8::Local<v8::Object> global = context->Global();
8866   Local<Value> s0 = global->Get(v8_str("sym0"));
8867   Local<Value> s0b = global->Get(v8_str("sym0b"));
8868   Local<Value> s1 = global->Get(v8_str("sym1"));
8869   Local<Value> s2 = global->Get(v8_str("sym2"));
8870   Local<Value> s3 = global->Get(v8_str("sym3"));
8871   Local<Value> s4 = global->Get(v8_str("sym4"));
8872   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8873   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8874   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8875   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8876   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8877   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8878 }
8879
8880
8881 THREADED_TEST(ToArrayIndex) {
8882   LocalContext context;
8883   v8::Isolate* isolate = context->GetIsolate();
8884   v8::HandleScope scope(isolate);
8885
8886   v8::Handle<String> str = v8_str("42");
8887   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8888   CHECK(!index.IsEmpty());
8889   CHECK_EQ(42.0, index->Uint32Value());
8890   str = v8_str("42asdf");
8891   index = str->ToArrayIndex();
8892   CHECK(index.IsEmpty());
8893   str = v8_str("-42");
8894   index = str->ToArrayIndex();
8895   CHECK(index.IsEmpty());
8896   str = v8_str("4294967295");
8897   index = str->ToArrayIndex();
8898   CHECK(!index.IsEmpty());
8899   CHECK_EQ(4294967295.0, index->Uint32Value());
8900   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8901   index = num->ToArrayIndex();
8902   CHECK(!index.IsEmpty());
8903   CHECK_EQ(1.0, index->Uint32Value());
8904   num = v8::Number::New(isolate, -1);
8905   index = num->ToArrayIndex();
8906   CHECK(index.IsEmpty());
8907   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8908   index = obj->ToArrayIndex();
8909   CHECK(index.IsEmpty());
8910 }
8911
8912
8913 THREADED_TEST(ErrorConstruction) {
8914   LocalContext context;
8915   v8::HandleScope scope(context->GetIsolate());
8916
8917   v8::Handle<String> foo = v8_str("foo");
8918   v8::Handle<String> message = v8_str("message");
8919   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8920   CHECK(range_error->IsObject());
8921   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8922   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8923   CHECK(reference_error->IsObject());
8924   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8925   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8926   CHECK(syntax_error->IsObject());
8927   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8928   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8929   CHECK(type_error->IsObject());
8930   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8931   v8::Handle<Value> error = v8::Exception::Error(foo);
8932   CHECK(error->IsObject());
8933   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8934 }
8935
8936
8937 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8938   ApiTestFuzzer::Fuzz();
8939   v8::Handle<String> foo = v8_str("foo");
8940   v8::Handle<String> message = v8_str("message");
8941   v8::Handle<Value> error = v8::Exception::Error(foo);
8942   CHECK(error->IsObject());
8943   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8944   info.GetIsolate()->ThrowException(error);
8945   info.GetReturnValue().SetUndefined();
8946 }
8947
8948
8949 THREADED_TEST(ExceptionCreateMessage) {
8950   LocalContext context;
8951   v8::HandleScope scope(context->GetIsolate());
8952   v8::Handle<String> foo_str = v8_str("foo");
8953   v8::Handle<String> message_str = v8_str("message");
8954
8955   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
8956
8957   Local<v8::FunctionTemplate> fun =
8958       v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8959   v8::Local<v8::Object> global = context->Global();
8960   global->Set(v8_str("throwV8Exception"), fun->GetFunction());
8961
8962   TryCatch try_catch;
8963   CompileRun(
8964       "function f1() {\n"
8965       "  throwV8Exception();\n"
8966       "};\n"
8967       "f1();");
8968   CHECK(try_catch.HasCaught());
8969
8970   v8::Handle<v8::Value> error = try_catch.Exception();
8971   CHECK(error->IsObject());
8972   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8973
8974   v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
8975   CHECK(!message.IsEmpty());
8976   CHECK_EQ(2, message->GetLineNumber());
8977   CHECK_EQ(2, message->GetStartColumn());
8978
8979   v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
8980   CHECK(!stackTrace.IsEmpty());
8981   CHECK_EQ(2, stackTrace->GetFrameCount());
8982
8983   stackTrace = v8::Exception::GetStackTrace(error);
8984   CHECK(!stackTrace.IsEmpty());
8985   CHECK_EQ(2, stackTrace->GetFrameCount());
8986
8987   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
8988
8989   // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8990   // is false.
8991   try_catch.Reset();
8992
8993   CompileRun(
8994       "function f2() {\n"
8995       "  return throwV8Exception();\n"
8996       "};\n"
8997       "f2();");
8998   CHECK(try_catch.HasCaught());
8999
9000   error = try_catch.Exception();
9001   CHECK(error->IsObject());
9002   CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
9003
9004   message = v8::Exception::CreateMessage(error);
9005   CHECK(!message.IsEmpty());
9006   CHECK_EQ(2, message->GetLineNumber());
9007   CHECK_EQ(9, message->GetStartColumn());
9008
9009   // Should be empty stack trace.
9010   stackTrace = message->GetStackTrace();
9011   CHECK(stackTrace.IsEmpty());
9012   CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9013 }
9014
9015
9016 static void YGetter(Local<String> name,
9017                     const v8::PropertyCallbackInfo<v8::Value>& info) {
9018   ApiTestFuzzer::Fuzz();
9019   info.GetReturnValue().Set(v8_num(10));
9020 }
9021
9022
9023 static void YSetter(Local<String> name,
9024                     Local<Value> value,
9025                     const v8::PropertyCallbackInfo<void>& info) {
9026   Local<Object> this_obj = Local<Object>::Cast(info.This());
9027   if (this_obj->Has(name)) this_obj->Delete(name);
9028   this_obj->Set(name, value);
9029 }
9030
9031
9032 THREADED_TEST(DeleteAccessor) {
9033   v8::Isolate* isolate = CcTest::isolate();
9034   v8::HandleScope scope(isolate);
9035   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
9036   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9037   LocalContext context;
9038   v8::Handle<v8::Object> holder = obj->NewInstance();
9039   context->Global()->Set(v8_str("holder"), holder);
9040   v8::Handle<Value> result = CompileRun(
9041       "holder.y = 11; holder.y = 12; holder.y");
9042   CHECK_EQ(12, result->Uint32Value());
9043 }
9044
9045
9046 THREADED_TEST(TypeSwitch) {
9047   v8::Isolate* isolate = CcTest::isolate();
9048   v8::HandleScope scope(isolate);
9049   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
9050   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
9051   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
9052   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
9053   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
9054   LocalContext context;
9055   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
9056   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
9057   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
9058   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
9059   for (int i = 0; i < 10; i++) {
9060     CHECK_EQ(0, type_switch->match(obj0));
9061     CHECK_EQ(1, type_switch->match(obj1));
9062     CHECK_EQ(2, type_switch->match(obj2));
9063     CHECK_EQ(3, type_switch->match(obj3));
9064     CHECK_EQ(3, type_switch->match(obj3));
9065     CHECK_EQ(2, type_switch->match(obj2));
9066     CHECK_EQ(1, type_switch->match(obj1));
9067     CHECK_EQ(0, type_switch->match(obj0));
9068   }
9069 }
9070
9071
9072 static int trouble_nesting = 0;
9073 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
9074   ApiTestFuzzer::Fuzz();
9075   trouble_nesting++;
9076
9077   // Call a JS function that throws an uncaught exception.
9078   Local<v8::Object> arg_this =
9079       args.GetIsolate()->GetCurrentContext()->Global();
9080   Local<Value> trouble_callee = (trouble_nesting == 3) ?
9081     arg_this->Get(v8_str("trouble_callee")) :
9082     arg_this->Get(v8_str("trouble_caller"));
9083   CHECK(trouble_callee->IsFunction());
9084   args.GetReturnValue().Set(
9085       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
9086 }
9087
9088
9089 static int report_count = 0;
9090 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
9091                                              v8::Handle<Value>) {
9092   report_count++;
9093 }
9094
9095
9096 // Counts uncaught exceptions, but other tests running in parallel
9097 // also have uncaught exceptions.
9098 TEST(ApiUncaughtException) {
9099   report_count = 0;
9100   LocalContext env;
9101   v8::Isolate* isolate = env->GetIsolate();
9102   v8::HandleScope scope(isolate);
9103   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
9104
9105   Local<v8::FunctionTemplate> fun =
9106       v8::FunctionTemplate::New(isolate, TroubleCallback);
9107   v8::Local<v8::Object> global = env->Global();
9108   global->Set(v8_str("trouble"), fun->GetFunction());
9109
9110   CompileRun(
9111       "function trouble_callee() {"
9112       "  var x = null;"
9113       "  return x.foo;"
9114       "};"
9115       "function trouble_caller() {"
9116       "  trouble();"
9117       "};");
9118   Local<Value> trouble = global->Get(v8_str("trouble"));
9119   CHECK(trouble->IsFunction());
9120   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
9121   CHECK(trouble_callee->IsFunction());
9122   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
9123   CHECK(trouble_caller->IsFunction());
9124   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
9125   CHECK_EQ(1, report_count);
9126   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9127 }
9128
9129
9130 TEST(ApiUncaughtExceptionInObjectObserve) {
9131   v8::internal::FLAG_stack_size = 150;
9132   report_count = 0;
9133   LocalContext env;
9134   v8::Isolate* isolate = env->GetIsolate();
9135   v8::HandleScope scope(isolate);
9136   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
9137   CompileRun(
9138       "var obj = {};"
9139       "var observe_count = 0;"
9140       "function observer1() { ++observe_count; };"
9141       "function observer2() { ++observe_count; };"
9142       "function observer_throws() { throw new Error(); };"
9143       "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
9144       "Object.observe(obj, observer_throws.bind());"
9145       "Object.observe(obj, observer1);"
9146       "Object.observe(obj, stack_overflow);"
9147       "Object.observe(obj, observer2);"
9148       "Object.observe(obj, observer_throws.bind());"
9149       "obj.foo = 'bar';");
9150   CHECK_EQ(3, report_count);
9151   ExpectInt32("observe_count", 2);
9152   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9153 }
9154
9155
9156 static const char* script_resource_name = "ExceptionInNativeScript.js";
9157 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
9158                                                 v8::Handle<Value>) {
9159   v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9160   CHECK(!name_val.IsEmpty() && name_val->IsString());
9161   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
9162   CHECK_EQ(script_resource_name, *name);
9163   CHECK_EQ(3, message->GetLineNumber());
9164   v8::String::Utf8Value source_line(message->GetSourceLine());
9165   CHECK_EQ("  new o.foo();", *source_line);
9166 }
9167
9168
9169 TEST(ExceptionInNativeScript) {
9170   LocalContext env;
9171   v8::Isolate* isolate = env->GetIsolate();
9172   v8::HandleScope scope(isolate);
9173   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
9174
9175   Local<v8::FunctionTemplate> fun =
9176       v8::FunctionTemplate::New(isolate, TroubleCallback);
9177   v8::Local<v8::Object> global = env->Global();
9178   global->Set(v8_str("trouble"), fun->GetFunction());
9179
9180   CompileRunWithOrigin(
9181       "function trouble() {\n"
9182       "  var o = {};\n"
9183       "  new o.foo();\n"
9184       "};",
9185       script_resource_name);
9186   Local<Value> trouble = global->Get(v8_str("trouble"));
9187   CHECK(trouble->IsFunction());
9188   Function::Cast(*trouble)->Call(global, 0, NULL);
9189   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9190 }
9191
9192
9193 TEST(CompilationErrorUsingTryCatchHandler) {
9194   LocalContext env;
9195   v8::HandleScope scope(env->GetIsolate());
9196   v8::TryCatch try_catch;
9197   v8_compile("This doesn't &*&@#$&*^ compile.");
9198   CHECK_NE(NULL, *try_catch.Exception());
9199   CHECK(try_catch.HasCaught());
9200 }
9201
9202
9203 TEST(TryCatchFinallyUsingTryCatchHandler) {
9204   LocalContext env;
9205   v8::HandleScope scope(env->GetIsolate());
9206   v8::TryCatch try_catch;
9207   CompileRun("try { throw ''; } catch (e) {}");
9208   CHECK(!try_catch.HasCaught());
9209   CompileRun("try { throw ''; } finally {}");
9210   CHECK(try_catch.HasCaught());
9211   try_catch.Reset();
9212   CompileRun(
9213       "(function() {"
9214       "try { throw ''; } finally { return; }"
9215       "})()");
9216   CHECK(!try_catch.HasCaught());
9217   CompileRun(
9218       "(function()"
9219       "  { try { throw ''; } finally { throw 0; }"
9220       "})()");
9221   CHECK(try_catch.HasCaught());
9222 }
9223
9224
9225 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9226   v8::HandleScope scope(args.GetIsolate());
9227   CompileRun(args[0]->ToString(args.GetIsolate()));
9228 }
9229
9230
9231 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9232   v8::Isolate* isolate = CcTest::isolate();
9233   v8::HandleScope scope(isolate);
9234   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9235   templ->Set(v8_str("CEvaluate"),
9236              v8::FunctionTemplate::New(isolate, CEvaluate));
9237   LocalContext context(0, templ);
9238   v8::TryCatch try_catch;
9239   CompileRun("try {"
9240              "  CEvaluate('throw 1;');"
9241              "} finally {"
9242              "}");
9243   CHECK(try_catch.HasCaught());
9244   CHECK(!try_catch.Message().IsEmpty());
9245   String::Utf8Value exception_value(try_catch.Exception());
9246   CHECK_EQ(*exception_value, "1");
9247   try_catch.Reset();
9248   CompileRun("try {"
9249              "  CEvaluate('throw 1;');"
9250              "} finally {"
9251              "  throw 2;"
9252              "}");
9253   CHECK(try_catch.HasCaught());
9254   CHECK(!try_catch.Message().IsEmpty());
9255   String::Utf8Value finally_exception_value(try_catch.Exception());
9256   CHECK_EQ(*finally_exception_value, "2");
9257 }
9258
9259
9260 // For use within the TestSecurityHandler() test.
9261 static bool g_security_callback_result = false;
9262 static bool NamedSecurityTestCallback(Local<v8::Object> global,
9263                                       Local<Value> name,
9264                                       v8::AccessType type,
9265                                       Local<Value> data) {
9266   printf("a\n");
9267   // Always allow read access.
9268   if (type == v8::ACCESS_GET)
9269     return true;
9270
9271   // Sometimes allow other access.
9272   return g_security_callback_result;
9273 }
9274
9275
9276 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
9277                                         uint32_t key,
9278                                         v8::AccessType type,
9279                                         Local<Value> data) {
9280   printf("b\n");
9281   // Always allow read access.
9282   if (type == v8::ACCESS_GET)
9283     return true;
9284
9285   // Sometimes allow other access.
9286   return g_security_callback_result;
9287 }
9288
9289
9290 // SecurityHandler can't be run twice
9291 TEST(SecurityHandler) {
9292   v8::Isolate* isolate = CcTest::isolate();
9293   v8::HandleScope scope0(isolate);
9294   v8::Handle<v8::ObjectTemplate> global_template =
9295       v8::ObjectTemplate::New(isolate);
9296   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
9297                                            IndexedSecurityTestCallback);
9298   // Create an environment
9299   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
9300   context0->Enter();
9301
9302   v8::Handle<v8::Object> global0 = context0->Global();
9303   v8::Handle<Script> script0 = v8_compile("foo = 111");
9304   script0->Run();
9305   global0->Set(v8_str("0"), v8_num(999));
9306   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
9307   CHECK_EQ(111, foo0->Int32Value());
9308   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
9309   CHECK_EQ(999, z0->Int32Value());
9310
9311   // Create another environment, should fail security checks.
9312   v8::HandleScope scope1(isolate);
9313
9314   v8::Handle<Context> context1 =
9315     Context::New(isolate, NULL, global_template);
9316   context1->Enter();
9317
9318   v8::Handle<v8::Object> global1 = context1->Global();
9319   global1->Set(v8_str("othercontext"), global0);
9320   // This set will fail the security check.
9321   v8::Handle<Script> script1 =
9322     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9323   script1->Run();
9324   // This read will pass the security check.
9325   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
9326   CHECK_EQ(111, foo1->Int32Value());
9327   // This read will pass the security check.
9328   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
9329   CHECK_EQ(999, z1->Int32Value());
9330
9331   // Create another environment, should pass security checks.
9332   { g_security_callback_result = true;  // allow security handler to pass.
9333     v8::HandleScope scope2(isolate);
9334     LocalContext context2;
9335     v8::Handle<v8::Object> global2 = context2->Global();
9336     global2->Set(v8_str("othercontext"), global0);
9337     v8::Handle<Script> script2 =
9338         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9339     script2->Run();
9340     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
9341     CHECK_EQ(333, foo2->Int32Value());
9342     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
9343     CHECK_EQ(888, z2->Int32Value());
9344   }
9345
9346   context1->Exit();
9347   context0->Exit();
9348 }
9349
9350
9351 THREADED_TEST(SecurityChecks) {
9352   LocalContext env1;
9353   v8::HandleScope handle_scope(env1->GetIsolate());
9354   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9355
9356   Local<Value> foo = v8_str("foo");
9357   Local<Value> bar = v8_str("bar");
9358
9359   // Set to the same domain.
9360   env1->SetSecurityToken(foo);
9361
9362   // Create a function in env1.
9363   CompileRun("spy=function(){return spy;}");
9364   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
9365   CHECK(spy->IsFunction());
9366
9367   // Create another function accessing global objects.
9368   CompileRun("spy2=function(){return new this.Array();}");
9369   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
9370   CHECK(spy2->IsFunction());
9371
9372   // Switch to env2 in the same domain and invoke spy on env2.
9373   {
9374     env2->SetSecurityToken(foo);
9375     // Enter env2
9376     Context::Scope scope_env2(env2);
9377     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
9378     CHECK(result->IsFunction());
9379   }
9380
9381   {
9382     env2->SetSecurityToken(bar);
9383     Context::Scope scope_env2(env2);
9384
9385     // Call cross_domain_call, it should throw an exception
9386     v8::TryCatch try_catch;
9387     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
9388     CHECK(try_catch.HasCaught());
9389   }
9390 }
9391
9392
9393 // Regression test case for issue 1183439.
9394 THREADED_TEST(SecurityChecksForPrototypeChain) {
9395   LocalContext current;
9396   v8::HandleScope scope(current->GetIsolate());
9397   v8::Handle<Context> other = Context::New(current->GetIsolate());
9398
9399   // Change context to be able to get to the Object function in the
9400   // other context without hitting the security checks.
9401   v8::Local<Value> other_object;
9402   { Context::Scope scope(other);
9403     other_object = other->Global()->Get(v8_str("Object"));
9404     other->Global()->Set(v8_num(42), v8_num(87));
9405   }
9406
9407   current->Global()->Set(v8_str("other"), other->Global());
9408   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
9409
9410   // Make sure the security check fails here and we get an undefined
9411   // result instead of getting the Object function. Repeat in a loop
9412   // to make sure to exercise the IC code.
9413   v8::Local<Script> access_other0 = v8_compile("other.Object");
9414   v8::Local<Script> access_other1 = v8_compile("other[42]");
9415   for (int i = 0; i < 5; i++) {
9416     CHECK(access_other0->Run().IsEmpty());
9417     CHECK(access_other1->Run().IsEmpty());
9418   }
9419
9420   // Create an object that has 'other' in its prototype chain and make
9421   // sure we cannot access the Object function indirectly through
9422   // that. Repeat in a loop to make sure to exercise the IC code.
9423   v8_compile("function F() { };"
9424              "F.prototype = other;"
9425              "var f = new F();")->Run();
9426   v8::Local<Script> access_f0 = v8_compile("f.Object");
9427   v8::Local<Script> access_f1 = v8_compile("f[42]");
9428   for (int j = 0; j < 5; j++) {
9429     CHECK(access_f0->Run().IsEmpty());
9430     CHECK(access_f1->Run().IsEmpty());
9431   }
9432
9433   // Now it gets hairy: Set the prototype for the other global object
9434   // to be the current global object. The prototype chain for 'f' now
9435   // goes through 'other' but ends up in the current global object.
9436   { Context::Scope scope(other);
9437     other->Global()->Set(v8_str("__proto__"), current->Global());
9438   }
9439   // Set a named and an index property on the current global
9440   // object. To force the lookup to go through the other global object,
9441   // the properties must not exist in the other global object.
9442   current->Global()->Set(v8_str("foo"), v8_num(100));
9443   current->Global()->Set(v8_num(99), v8_num(101));
9444   // Try to read the properties from f and make sure that the access
9445   // gets stopped by the security checks on the other global object.
9446   Local<Script> access_f2 = v8_compile("f.foo");
9447   Local<Script> access_f3 = v8_compile("f[99]");
9448   for (int k = 0; k < 5; k++) {
9449     CHECK(access_f2->Run().IsEmpty());
9450     CHECK(access_f3->Run().IsEmpty());
9451   }
9452 }
9453
9454
9455 static bool named_security_check_with_gc_called;
9456
9457 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
9458                                         Local<Value> name,
9459                                         v8::AccessType type,
9460                                         Local<Value> data) {
9461   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9462   named_security_check_with_gc_called = true;
9463   return true;
9464 }
9465
9466
9467 static bool indexed_security_check_with_gc_called;
9468
9469 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
9470                                               uint32_t key,
9471                                               v8::AccessType type,
9472                                               Local<Value> data) {
9473   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9474   indexed_security_check_with_gc_called = true;
9475   return true;
9476 }
9477
9478
9479 TEST(SecurityTestGCAllowed) {
9480   v8::Isolate* isolate = CcTest::isolate();
9481   v8::HandleScope handle_scope(isolate);
9482   v8::Handle<v8::ObjectTemplate> object_template =
9483       v8::ObjectTemplate::New(isolate);
9484   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
9485                                            IndexedSecurityTestCallbackWithGC);
9486
9487   v8::Handle<Context> context = Context::New(isolate);
9488   v8::Context::Scope context_scope(context);
9489
9490   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
9491
9492   named_security_check_with_gc_called = false;
9493   CompileRun("obj.foo = new String(1001);");
9494   CHECK(named_security_check_with_gc_called);
9495
9496   indexed_security_check_with_gc_called = false;
9497   CompileRun("obj[0] = new String(1002);");
9498   CHECK(indexed_security_check_with_gc_called);
9499
9500   named_security_check_with_gc_called = false;
9501   CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
9502   CHECK(named_security_check_with_gc_called);
9503
9504   indexed_security_check_with_gc_called = false;
9505   CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
9506   CHECK(indexed_security_check_with_gc_called);
9507 }
9508
9509
9510 THREADED_TEST(CrossDomainDelete) {
9511   LocalContext env1;
9512   v8::HandleScope handle_scope(env1->GetIsolate());
9513   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9514
9515   Local<Value> foo = v8_str("foo");
9516   Local<Value> bar = v8_str("bar");
9517
9518   // Set to the same domain.
9519   env1->SetSecurityToken(foo);
9520   env2->SetSecurityToken(foo);
9521
9522   env1->Global()->Set(v8_str("prop"), v8_num(3));
9523   env2->Global()->Set(v8_str("env1"), env1->Global());
9524
9525   // Change env2 to a different domain and delete env1.prop.
9526   env2->SetSecurityToken(bar);
9527   {
9528     Context::Scope scope_env2(env2);
9529     Local<Value> result =
9530         CompileRun("delete env1.prop");
9531     CHECK(result.IsEmpty());
9532   }
9533
9534   // Check that env1.prop still exists.
9535   Local<Value> v = env1->Global()->Get(v8_str("prop"));
9536   CHECK(v->IsNumber());
9537   CHECK_EQ(3, v->Int32Value());
9538 }
9539
9540
9541 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
9542   LocalContext env1;
9543   v8::HandleScope handle_scope(env1->GetIsolate());
9544   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9545
9546   Local<Value> foo = v8_str("foo");
9547   Local<Value> bar = v8_str("bar");
9548
9549   // Set to the same domain.
9550   env1->SetSecurityToken(foo);
9551   env2->SetSecurityToken(foo);
9552
9553   env1->Global()->Set(v8_str("prop"), v8_num(3));
9554   env2->Global()->Set(v8_str("env1"), env1->Global());
9555
9556   // env1.prop is enumerable in env2.
9557   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9558   {
9559     Context::Scope scope_env2(env2);
9560     Local<Value> result = CompileRun(test);
9561     CHECK(result->IsTrue());
9562   }
9563
9564   // Change env2 to a different domain and test again.
9565   env2->SetSecurityToken(bar);
9566   {
9567     Context::Scope scope_env2(env2);
9568     Local<Value> result = CompileRun(test);
9569     CHECK(result.IsEmpty());
9570   }
9571 }
9572
9573
9574 THREADED_TEST(CrossDomainForIn) {
9575   LocalContext env1;
9576   v8::HandleScope handle_scope(env1->GetIsolate());
9577   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9578
9579   Local<Value> foo = v8_str("foo");
9580   Local<Value> bar = v8_str("bar");
9581
9582   // Set to the same domain.
9583   env1->SetSecurityToken(foo);
9584   env2->SetSecurityToken(foo);
9585
9586   env1->Global()->Set(v8_str("prop"), v8_num(3));
9587   env2->Global()->Set(v8_str("env1"), env1->Global());
9588
9589   // Change env2 to a different domain and set env1's global object
9590   // as the __proto__ of an object in env2 and enumerate properties
9591   // in for-in. It shouldn't enumerate properties on env1's global
9592   // object.
9593   env2->SetSecurityToken(bar);
9594   {
9595     Context::Scope scope_env2(env2);
9596     Local<Value> result = CompileRun(
9597         "(function() {"
9598         "  var obj = { '__proto__': env1 };"
9599         "  try {"
9600         "    for (var p in obj) {"
9601         "      if (p == 'prop') return false;"
9602         "    }"
9603         "    return false;"
9604         "  } catch (e) {"
9605         "    return true;"
9606         "  }"
9607         "})()");
9608     CHECK(result->IsTrue());
9609   }
9610 }
9611
9612
9613 TEST(ContextDetachGlobal) {
9614   LocalContext env1;
9615   v8::HandleScope handle_scope(env1->GetIsolate());
9616   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9617
9618   Local<v8::Object> global1 = env1->Global();
9619
9620   Local<Value> foo = v8_str("foo");
9621
9622   // Set to the same domain.
9623   env1->SetSecurityToken(foo);
9624   env2->SetSecurityToken(foo);
9625
9626   // Enter env2
9627   env2->Enter();
9628
9629   // Create a function in env2 and add a reference to it in env1.
9630   Local<v8::Object> global2 = env2->Global();
9631   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9632   CompileRun("function getProp() {return prop;}");
9633
9634   env1->Global()->Set(v8_str("getProp"),
9635                       global2->Get(v8_str("getProp")));
9636
9637   // Detach env2's global, and reuse the global object of env2
9638   env2->Exit();
9639   env2->DetachGlobal();
9640
9641   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9642                                           0,
9643                                           v8::Handle<v8::ObjectTemplate>(),
9644                                           global2);
9645   env3->SetSecurityToken(v8_str("bar"));
9646   env3->Enter();
9647
9648   Local<v8::Object> global3 = env3->Global();
9649   CHECK_EQ(global2, global3);
9650   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9651   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9652   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9653   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9654   env3->Exit();
9655
9656   // Call getProp in env1, and it should return the value 1
9657   {
9658     Local<Value> get_prop = global1->Get(v8_str("getProp"));
9659     CHECK(get_prop->IsFunction());
9660     v8::TryCatch try_catch;
9661     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9662     CHECK(!try_catch.HasCaught());
9663     CHECK_EQ(1, r->Int32Value());
9664   }
9665
9666   // Check that env3 is not accessible from env1
9667   {
9668     Local<Value> r = global3->Get(v8_str("prop2"));
9669     CHECK(r.IsEmpty());
9670   }
9671 }
9672
9673
9674 TEST(DetachGlobal) {
9675   LocalContext env1;
9676   v8::HandleScope scope(env1->GetIsolate());
9677
9678   // Create second environment.
9679   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9680
9681   Local<Value> foo = v8_str("foo");
9682
9683   // Set same security token for env1 and env2.
9684   env1->SetSecurityToken(foo);
9685   env2->SetSecurityToken(foo);
9686
9687   // Create a property on the global object in env2.
9688   {
9689     v8::Context::Scope scope(env2);
9690     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9691   }
9692
9693   // Create a reference to env2 global from env1 global.
9694   env1->Global()->Set(v8_str("other"), env2->Global());
9695
9696   // Check that we have access to other.p in env2 from env1.
9697   Local<Value> result = CompileRun("other.p");
9698   CHECK(result->IsInt32());
9699   CHECK_EQ(42, result->Int32Value());
9700
9701   // Hold on to global from env2 and detach global from env2.
9702   Local<v8::Object> global2 = env2->Global();
9703   env2->DetachGlobal();
9704
9705   // Check that the global has been detached. No other.p property can
9706   // be found.
9707   result = CompileRun("other.p");
9708   CHECK(result.IsEmpty());
9709
9710   // Reuse global2 for env3.
9711   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9712                                           0,
9713                                           v8::Handle<v8::ObjectTemplate>(),
9714                                           global2);
9715   CHECK_EQ(global2, env3->Global());
9716
9717   // Start by using the same security token for env3 as for env1 and env2.
9718   env3->SetSecurityToken(foo);
9719
9720   // Create a property on the global object in env3.
9721   {
9722     v8::Context::Scope scope(env3);
9723     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9724   }
9725
9726   // Check that other.p is now the property in env3 and that we have access.
9727   result = CompileRun("other.p");
9728   CHECK(result->IsInt32());
9729   CHECK_EQ(24, result->Int32Value());
9730
9731   // Change security token for env3 to something different from env1 and env2.
9732   env3->SetSecurityToken(v8_str("bar"));
9733
9734   // Check that we do not have access to other.p in env1. |other| is now
9735   // the global object for env3 which has a different security token,
9736   // so access should be blocked.
9737   result = CompileRun("other.p");
9738   CHECK(result.IsEmpty());
9739 }
9740
9741
9742 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9743   info.GetReturnValue().Set(
9744       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9745 }
9746
9747
9748 TEST(DetachedAccesses) {
9749   LocalContext env1;
9750   v8::HandleScope scope(env1->GetIsolate());
9751
9752   // Create second environment.
9753   Local<ObjectTemplate> inner_global_template =
9754       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9755   inner_global_template ->SetAccessorProperty(
9756       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9757   v8::Local<Context> env2 =
9758       Context::New(env1->GetIsolate(), NULL, inner_global_template);
9759
9760   Local<Value> foo = v8_str("foo");
9761
9762   // Set same security token for env1 and env2.
9763   env1->SetSecurityToken(foo);
9764   env2->SetSecurityToken(foo);
9765
9766   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9767
9768   {
9769     v8::Context::Scope scope(env2);
9770     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9771     CompileRun(
9772         "function bound_x() { return x; }"
9773         "function get_x()   { return this.x; }"
9774         "function get_x_w() { return (function() {return this.x;})(); }");
9775     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9776     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9777     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9778     env1->Global()->Set(
9779         v8_str("this_x"),
9780         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9781   }
9782
9783   Local<Object> env2_global = env2->Global();
9784   env2_global->TurnOnAccessCheck();
9785   env2->DetachGlobal();
9786
9787   Local<Value> result;
9788   result = CompileRun("bound_x()");
9789   CHECK_EQ(v8_str("env2_x"), result);
9790   result = CompileRun("get_x()");
9791   CHECK(result.IsEmpty());
9792   result = CompileRun("get_x_w()");
9793   CHECK(result.IsEmpty());
9794   result = CompileRun("this_x()");
9795   CHECK_EQ(v8_str("env2_x"), result);
9796
9797   // Reattach env2's proxy
9798   env2 = Context::New(env1->GetIsolate(),
9799                       0,
9800                       v8::Handle<v8::ObjectTemplate>(),
9801                       env2_global);
9802   env2->SetSecurityToken(foo);
9803   {
9804     v8::Context::Scope scope(env2);
9805     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9806     env2->Global()->Set(v8_str("env1"), env1->Global());
9807     result = CompileRun(
9808         "results = [];"
9809         "for (var i = 0; i < 4; i++ ) {"
9810         "  results.push(env1.bound_x());"
9811         "  results.push(env1.get_x());"
9812         "  results.push(env1.get_x_w());"
9813         "  results.push(env1.this_x());"
9814         "}"
9815         "results");
9816     Local<v8::Array> results = Local<v8::Array>::Cast(result);
9817     CHECK_EQ(16, results->Length());
9818     for (int i = 0; i < 16; i += 4) {
9819       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9820       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9821       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9822       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9823     }
9824   }
9825
9826   result = CompileRun(
9827       "results = [];"
9828       "for (var i = 0; i < 4; i++ ) {"
9829       "  results.push(bound_x());"
9830       "  results.push(get_x());"
9831       "  results.push(get_x_w());"
9832       "  results.push(this_x());"
9833       "}"
9834       "results");
9835   Local<v8::Array> results = Local<v8::Array>::Cast(result);
9836   CHECK_EQ(16, results->Length());
9837   for (int i = 0; i < 16; i += 4) {
9838     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9839     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9840     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9841     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9842   }
9843
9844   result = CompileRun(
9845       "results = [];"
9846       "for (var i = 0; i < 4; i++ ) {"
9847       "  results.push(this.bound_x());"
9848       "  results.push(this.get_x());"
9849       "  results.push(this.get_x_w());"
9850       "  results.push(this.this_x());"
9851       "}"
9852       "results");
9853   results = Local<v8::Array>::Cast(result);
9854   CHECK_EQ(16, results->Length());
9855   for (int i = 0; i < 16; i += 4) {
9856     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9857     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9858     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9859     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9860   }
9861 }
9862
9863
9864 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9865 static bool NamedAccessBlocker(Local<v8::Object> global,
9866                                Local<Value> name,
9867                                v8::AccessType type,
9868                                Local<Value> data) {
9869   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9870       allowed_access_type[type];
9871 }
9872
9873
9874 static bool IndexedAccessBlocker(Local<v8::Object> global,
9875                                  uint32_t key,
9876                                  v8::AccessType type,
9877                                  Local<Value> data) {
9878   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9879       allowed_access_type[type];
9880 }
9881
9882
9883 static int g_echo_value = -1;
9884
9885
9886 static void EchoGetter(
9887     Local<String> name,
9888     const v8::PropertyCallbackInfo<v8::Value>& info) {
9889   info.GetReturnValue().Set(v8_num(g_echo_value));
9890 }
9891
9892
9893 static void EchoSetter(Local<String> name,
9894                        Local<Value> value,
9895                        const v8::PropertyCallbackInfo<void>&) {
9896   if (value->IsNumber())
9897     g_echo_value = value->Int32Value();
9898 }
9899
9900
9901 static void UnreachableGetter(
9902     Local<String> name,
9903     const v8::PropertyCallbackInfo<v8::Value>& info) {
9904   CHECK(false);  // This function should not be called..
9905 }
9906
9907
9908 static void UnreachableSetter(Local<String>,
9909                               Local<Value>,
9910                               const v8::PropertyCallbackInfo<void>&) {
9911   CHECK(false);  // This function should nto be called.
9912 }
9913
9914
9915 static void UnreachableFunction(
9916     const v8::FunctionCallbackInfo<v8::Value>& info) {
9917   CHECK(false);  // This function should not be called..
9918 }
9919
9920
9921 TEST(AccessControl) {
9922   v8::Isolate* isolate = CcTest::isolate();
9923   v8::HandleScope handle_scope(isolate);
9924   v8::Handle<v8::ObjectTemplate> global_template =
9925       v8::ObjectTemplate::New(isolate);
9926
9927   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9928                                            IndexedAccessBlocker);
9929
9930   // Add an accessor accessible by cross-domain JS code.
9931   global_template->SetAccessor(
9932       v8_str("accessible_prop"),
9933       EchoGetter, EchoSetter,
9934       v8::Handle<Value>(),
9935       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9936
9937
9938   // Add an accessor that is not accessible by cross-domain JS code.
9939   global_template->SetAccessor(v8_str("blocked_prop"),
9940                                UnreachableGetter, UnreachableSetter,
9941                                v8::Handle<Value>(),
9942                                v8::DEFAULT);
9943
9944   global_template->SetAccessorProperty(
9945       v8_str("blocked_js_prop"),
9946       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9947       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9948       v8::None,
9949       v8::DEFAULT);
9950
9951   // Create an environment
9952   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9953   context0->Enter();
9954
9955   v8::Handle<v8::Object> global0 = context0->Global();
9956
9957   // Define a property with JS getter and setter.
9958   CompileRun(
9959       "function getter() { return 'getter'; };\n"
9960       "function setter() { return 'setter'; }\n"
9961       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9962
9963   Local<Value> getter = global0->Get(v8_str("getter"));
9964   Local<Value> setter = global0->Get(v8_str("setter"));
9965
9966   // And define normal element.
9967   global0->Set(239, v8_str("239"));
9968
9969   // Define an element with JS getter and setter.
9970   CompileRun(
9971       "function el_getter() { return 'el_getter'; };\n"
9972       "function el_setter() { return 'el_setter'; };\n"
9973       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9974
9975   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9976   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9977
9978   v8::HandleScope scope1(isolate);
9979
9980   v8::Local<Context> context1 = Context::New(isolate);
9981   context1->Enter();
9982
9983   v8::Handle<v8::Object> global1 = context1->Global();
9984   global1->Set(v8_str("other"), global0);
9985
9986   // Access blocked property.
9987   CompileRun("other.blocked_prop = 1");
9988
9989   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9990   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9991             .IsEmpty());
9992   CHECK(
9993       CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9994
9995   // Access blocked element.
9996   CHECK(CompileRun("other[239] = 1").IsEmpty());
9997
9998   CHECK(CompileRun("other[239]").IsEmpty());
9999   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10000   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
10001
10002   // Enable ACCESS_HAS
10003   allowed_access_type[v8::ACCESS_HAS] = true;
10004   CHECK(CompileRun("other[239]").IsEmpty());
10005   // ... and now we can get the descriptor...
10006   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
10007             .IsEmpty());
10008   // ... and enumerate the property.
10009   ExpectTrue("propertyIsEnumerable.call(other, '239')");
10010   allowed_access_type[v8::ACCESS_HAS] = false;
10011
10012   // Access a property with JS accessor.
10013   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
10014
10015   CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10016   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10017             .IsEmpty());
10018
10019   // Enable both ACCESS_HAS and ACCESS_GET.
10020   allowed_access_type[v8::ACCESS_HAS] = true;
10021   allowed_access_type[v8::ACCESS_GET] = true;
10022
10023   ExpectString("other.js_accessor_p", "getter");
10024   ExpectObject(
10025       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
10026   ExpectObject(
10027       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10028   ExpectUndefined(
10029       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10030
10031   allowed_access_type[v8::ACCESS_HAS] = false;
10032   allowed_access_type[v8::ACCESS_GET] = false;
10033
10034   // Access an element with JS accessor.
10035   CHECK(CompileRun("other[42] = 2").IsEmpty());
10036
10037   CHECK(CompileRun("other[42]").IsEmpty());
10038   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10039
10040   // Enable both ACCESS_HAS and ACCESS_GET.
10041   allowed_access_type[v8::ACCESS_HAS] = true;
10042   allowed_access_type[v8::ACCESS_GET] = true;
10043
10044   ExpectString("other[42]", "el_getter");
10045   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10046   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10047   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10048
10049   allowed_access_type[v8::ACCESS_HAS] = false;
10050   allowed_access_type[v8::ACCESS_GET] = false;
10051
10052   v8::Handle<Value> value;
10053
10054   // Access accessible property
10055   value = CompileRun("other.accessible_prop = 3");
10056   CHECK(value->IsNumber());
10057   CHECK_EQ(3, value->Int32Value());
10058   CHECK_EQ(3, g_echo_value);
10059
10060   value = CompileRun("other.accessible_prop");
10061   CHECK(value->IsNumber());
10062   CHECK_EQ(3, value->Int32Value());
10063
10064   value = CompileRun(
10065       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10066   CHECK(value->IsNumber());
10067   CHECK_EQ(3, value->Int32Value());
10068
10069   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10070   CHECK(value->IsTrue());
10071
10072   // Enumeration doesn't enumerate accessors from inaccessible objects in
10073   // the prototype chain even if the accessors are in themselves accessible.
10074   value = CompileRun(
10075       "(function() {"
10076       "  var obj = { '__proto__': other };"
10077       "  try {"
10078       "    for (var p in obj) {"
10079       "      if (p == 'accessible_prop' ||"
10080       "          p == 'blocked_js_prop' ||"
10081       "          p == 'blocked_js_prop') {"
10082       "        return false;"
10083       "      }"
10084       "    }"
10085       "    return false;"
10086       "  } catch (e) {"
10087       "    return true;"
10088       "  }"
10089       "})()");
10090   CHECK(value->IsTrue());
10091
10092   context1->Exit();
10093   context0->Exit();
10094 }
10095
10096
10097 TEST(AccessControlES5) {
10098   v8::Isolate* isolate = CcTest::isolate();
10099   v8::HandleScope handle_scope(isolate);
10100   v8::Handle<v8::ObjectTemplate> global_template =
10101       v8::ObjectTemplate::New(isolate);
10102
10103   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
10104                                            IndexedAccessBlocker);
10105
10106   // Add accessible accessor.
10107   global_template->SetAccessor(
10108       v8_str("accessible_prop"),
10109       EchoGetter, EchoSetter,
10110       v8::Handle<Value>(),
10111       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10112
10113
10114   // Add an accessor that is not accessible by cross-domain JS code.
10115   global_template->SetAccessor(v8_str("blocked_prop"),
10116                                UnreachableGetter, UnreachableSetter,
10117                                v8::Handle<Value>(),
10118                                v8::DEFAULT);
10119
10120   // Create an environment
10121   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10122   context0->Enter();
10123
10124   v8::Handle<v8::Object> global0 = context0->Global();
10125
10126   v8::Local<Context> context1 = Context::New(isolate);
10127   context1->Enter();
10128   v8::Handle<v8::Object> global1 = context1->Global();
10129   global1->Set(v8_str("other"), global0);
10130
10131   // Regression test for issue 1154.
10132   CHECK(CompileRun("Object.keys(other)").IsEmpty());
10133   CHECK(CompileRun("other.blocked_prop").IsEmpty());
10134
10135   // Regression test for issue 1027.
10136   CompileRun("Object.defineProperty(\n"
10137              "  other, 'blocked_prop', {configurable: false})");
10138   CHECK(CompileRun("other.blocked_prop").IsEmpty());
10139   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10140             .IsEmpty());
10141
10142   // Regression test for issue 1171.
10143   ExpectTrue("Object.isExtensible(other)");
10144   CompileRun("Object.preventExtensions(other)");
10145   ExpectTrue("Object.isExtensible(other)");
10146
10147   // Object.seal and Object.freeze.
10148   CompileRun("Object.freeze(other)");
10149   ExpectTrue("Object.isExtensible(other)");
10150
10151   CompileRun("Object.seal(other)");
10152   ExpectTrue("Object.isExtensible(other)");
10153
10154   // Regression test for issue 1250.
10155   // Make sure that we can set the accessible accessors value using normal
10156   // assignment.
10157   CompileRun("other.accessible_prop = 42");
10158   CHECK_EQ(42, g_echo_value);
10159
10160   v8::Handle<Value> value;
10161   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
10162   value = CompileRun("other.accessible_prop == 42");
10163   CHECK(value->IsTrue());
10164 }
10165
10166
10167 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
10168                                  v8::AccessType type, Local<Value> data) {
10169   return false;
10170 }
10171
10172
10173 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
10174                                    v8::AccessType type, Local<Value> data) {
10175   return false;
10176 }
10177
10178
10179 THREADED_TEST(AccessControlGetOwnPropertyNames) {
10180   v8::Isolate* isolate = CcTest::isolate();
10181   v8::HandleScope handle_scope(isolate);
10182   v8::Handle<v8::ObjectTemplate> obj_template =
10183       v8::ObjectTemplate::New(isolate);
10184
10185   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10186   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
10187                                         BlockEverythingIndexed);
10188
10189   // Create an environment
10190   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
10191   context0->Enter();
10192
10193   v8::Handle<v8::Object> global0 = context0->Global();
10194
10195   v8::HandleScope scope1(CcTest::isolate());
10196
10197   v8::Local<Context> context1 = Context::New(isolate);
10198   context1->Enter();
10199
10200   v8::Handle<v8::Object> global1 = context1->Global();
10201   global1->Set(v8_str("other"), global0);
10202   global1->Set(v8_str("object"), obj_template->NewInstance());
10203
10204   v8::Handle<Value> value;
10205
10206   // Attempt to get the property names of the other global object and
10207   // of an object that requires access checks.  Accessing the other
10208   // global object should be blocked by access checks on the global
10209   // proxy object.  Accessing the object that requires access checks
10210   // is blocked by the access checks on the object itself.
10211   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
10212   CHECK(value.IsEmpty());
10213
10214   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
10215   CHECK(value.IsEmpty());
10216
10217   context1->Exit();
10218   context0->Exit();
10219 }
10220
10221
10222 TEST(SuperAccessControl) {
10223   i::FLAG_harmony_classes = true;
10224   v8::Isolate* isolate = CcTest::isolate();
10225   v8::HandleScope handle_scope(isolate);
10226   v8::Handle<v8::ObjectTemplate> obj_template =
10227       v8::ObjectTemplate::New(isolate);
10228   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
10229                                         BlockEverythingIndexed);
10230   LocalContext env;
10231   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
10232
10233   {
10234     v8::TryCatch try_catch;
10235     CompileRun(
10236         "function f() { return super.hasOwnProperty; };"
10237         "var m = f.toMethod(prohibited);"
10238         "m();");
10239     CHECK(try_catch.HasCaught());
10240   }
10241
10242   {
10243     v8::TryCatch try_catch;
10244     CompileRun(
10245         "function f() { return super[42]; };"
10246         "var m = f.toMethod(prohibited);"
10247         "m();");
10248     CHECK(try_catch.HasCaught());
10249   }
10250
10251   {
10252     v8::TryCatch try_catch;
10253     CompileRun(
10254         "function f() { super.hasOwnProperty = function () {}; };"
10255         "var m = f.toMethod(prohibited);"
10256         "m();");
10257     CHECK(try_catch.HasCaught());
10258   }
10259
10260   {
10261     v8::TryCatch try_catch;
10262     CompileRun(
10263         "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
10264         "function f() { "
10265         "     'use strict';"
10266         "     super.x = function () {}; "
10267         "};"
10268         "var m = f.toMethod(prohibited);"
10269         "m();");
10270     CHECK(try_catch.HasCaught());
10271   }
10272 }
10273
10274
10275 static void IndexedPropertyEnumerator(
10276     const v8::PropertyCallbackInfo<v8::Array>& info) {
10277   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
10278   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
10279   info.GetReturnValue().Set(result);
10280 }
10281
10282
10283 static void NamedPropertyEnumerator(
10284     const v8::PropertyCallbackInfo<v8::Array>& info) {
10285   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
10286   result->Set(0, v8_str("x"));
10287   result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
10288   info.GetReturnValue().Set(result);
10289 }
10290
10291
10292 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
10293   v8::Isolate* isolate = CcTest::isolate();
10294   v8::HandleScope handle_scope(isolate);
10295   v8::Handle<v8::ObjectTemplate> obj_template =
10296       v8::ObjectTemplate::New(isolate);
10297
10298   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
10299   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
10300   obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
10301       NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
10302   obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
10303       NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
10304
10305   LocalContext context;
10306   v8::Handle<v8::Object> global = context->Global();
10307   global->Set(v8_str("object"), obj_template->NewInstance());
10308
10309   v8::Handle<v8::Value> result =
10310       CompileRun("Object.getOwnPropertyNames(object)");
10311   CHECK(result->IsArray());
10312   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
10313   CHECK_EQ(2, result_array->Length());
10314   CHECK(result_array->Get(0)->IsString());
10315   CHECK(result_array->Get(1)->IsString());
10316   CHECK_EQ(v8_str("7"), result_array->Get(0));
10317   CHECK_EQ(v8_str("x"), result_array->Get(1));
10318
10319   result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
10320   CHECK(result->IsArray());
10321   result_array = v8::Handle<v8::Array>::Cast(result);
10322   CHECK_EQ(2, result_array->Length());
10323   CHECK(result_array->Get(0)->IsString());
10324   CHECK(result_array->Get(1)->IsString());
10325   CHECK_EQ(v8_str("7"), result_array->Get(0));
10326   CHECK_EQ(v8_str("x"), result_array->Get(1));
10327
10328   result = CompileRun("Object.getOwnPropertySymbols(object)");
10329   CHECK(result->IsArray());
10330   result_array = v8::Handle<v8::Array>::Cast(result);
10331   CHECK_EQ(1, result_array->Length());
10332   CHECK_EQ(result_array->Get(0), v8::Symbol::GetIterator(isolate));
10333 }
10334
10335
10336 static void ConstTenGetter(Local<String> name,
10337                            const v8::PropertyCallbackInfo<v8::Value>& info) {
10338   info.GetReturnValue().Set(v8_num(10));
10339 }
10340
10341
10342 THREADED_TEST(CrossDomainAccessors) {
10343   v8::Isolate* isolate = CcTest::isolate();
10344   v8::HandleScope handle_scope(isolate);
10345
10346   v8::Handle<v8::FunctionTemplate> func_template =
10347       v8::FunctionTemplate::New(isolate);
10348
10349   v8::Handle<v8::ObjectTemplate> global_template =
10350       func_template->InstanceTemplate();
10351
10352   v8::Handle<v8::ObjectTemplate> proto_template =
10353       func_template->PrototypeTemplate();
10354
10355   // Add an accessor to proto that's accessible by cross-domain JS code.
10356   proto_template->SetAccessor(v8_str("accessible"),
10357                               ConstTenGetter, 0,
10358                               v8::Handle<Value>(),
10359                               v8::ALL_CAN_READ);
10360
10361   // Add an accessor that is not accessible by cross-domain JS code.
10362   global_template->SetAccessor(v8_str("unreachable"),
10363                                UnreachableGetter, 0,
10364                                v8::Handle<Value>(),
10365                                v8::DEFAULT);
10366
10367   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10368   context0->Enter();
10369
10370   Local<v8::Object> global = context0->Global();
10371   // Add a normal property that shadows 'accessible'
10372   global->Set(v8_str("accessible"), v8_num(11));
10373
10374   // Enter a new context.
10375   v8::HandleScope scope1(CcTest::isolate());
10376   v8::Local<Context> context1 = Context::New(isolate);
10377   context1->Enter();
10378
10379   v8::Handle<v8::Object> global1 = context1->Global();
10380   global1->Set(v8_str("other"), global);
10381
10382   // Should return 10, instead of 11
10383   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
10384   CHECK(value->IsNumber());
10385   CHECK_EQ(10, value->Int32Value());
10386
10387   value = v8_compile("other.unreachable")->Run();
10388   CHECK(value.IsEmpty());
10389
10390   context1->Exit();
10391   context0->Exit();
10392 }
10393
10394
10395 static int named_access_count = 0;
10396 static int indexed_access_count = 0;
10397
10398 static bool NamedAccessCounter(Local<v8::Object> global,
10399                                Local<Value> name,
10400                                v8::AccessType type,
10401                                Local<Value> data) {
10402   named_access_count++;
10403   return true;
10404 }
10405
10406
10407 static bool IndexedAccessCounter(Local<v8::Object> global,
10408                                  uint32_t key,
10409                                  v8::AccessType type,
10410                                  Local<Value> data) {
10411   indexed_access_count++;
10412   return true;
10413 }
10414
10415
10416 // This one is too easily disturbed by other tests.
10417 TEST(AccessControlIC) {
10418   named_access_count = 0;
10419   indexed_access_count = 0;
10420
10421   v8::Isolate* isolate = CcTest::isolate();
10422   v8::HandleScope handle_scope(isolate);
10423
10424   // Create an environment.
10425   v8::Local<Context> context0 = Context::New(isolate);
10426   context0->Enter();
10427
10428   // Create an object that requires access-check functions to be
10429   // called for cross-domain access.
10430   v8::Handle<v8::ObjectTemplate> object_template =
10431       v8::ObjectTemplate::New(isolate);
10432   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10433                                            IndexedAccessCounter);
10434   Local<v8::Object> object = object_template->NewInstance();
10435
10436   v8::HandleScope scope1(isolate);
10437
10438   // Create another environment.
10439   v8::Local<Context> context1 = Context::New(isolate);
10440   context1->Enter();
10441
10442   // Make easy access to the object from the other environment.
10443   v8::Handle<v8::Object> global1 = context1->Global();
10444   global1->Set(v8_str("obj"), object);
10445
10446   v8::Handle<Value> value;
10447
10448   // Check that the named access-control function is called every time.
10449   CompileRun("function testProp(obj) {"
10450              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
10451              "  for (var j = 0; j < 10; j++) obj.prop;"
10452              "  return obj.prop"
10453              "}");
10454   value = CompileRun("testProp(obj)");
10455   CHECK(value->IsNumber());
10456   CHECK_EQ(1, value->Int32Value());
10457   CHECK_EQ(21, named_access_count);
10458
10459   // Check that the named access-control function is called every time.
10460   CompileRun("var p = 'prop';"
10461              "function testKeyed(obj) {"
10462              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
10463              "  for (var j = 0; j < 10; j++) obj[p];"
10464              "  return obj[p];"
10465              "}");
10466   // Use obj which requires access checks.  No inline caching is used
10467   // in that case.
10468   value = CompileRun("testKeyed(obj)");
10469   CHECK(value->IsNumber());
10470   CHECK_EQ(1, value->Int32Value());
10471   CHECK_EQ(42, named_access_count);
10472   // Force the inline caches into generic state and try again.
10473   CompileRun("testKeyed({ a: 0 })");
10474   CompileRun("testKeyed({ b: 0 })");
10475   value = CompileRun("testKeyed(obj)");
10476   CHECK(value->IsNumber());
10477   CHECK_EQ(1, value->Int32Value());
10478   CHECK_EQ(63, named_access_count);
10479
10480   // Check that the indexed access-control function is called every time.
10481   CompileRun("function testIndexed(obj) {"
10482              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
10483              "  for (var j = 0; j < 10; j++) obj[0];"
10484              "  return obj[0]"
10485              "}");
10486   value = CompileRun("testIndexed(obj)");
10487   CHECK(value->IsNumber());
10488   CHECK_EQ(1, value->Int32Value());
10489   CHECK_EQ(21, indexed_access_count);
10490   // Force the inline caches into generic state.
10491   CompileRun("testIndexed(new Array(1))");
10492   // Test that the indexed access check is called.
10493   value = CompileRun("testIndexed(obj)");
10494   CHECK(value->IsNumber());
10495   CHECK_EQ(1, value->Int32Value());
10496   CHECK_EQ(42, indexed_access_count);
10497
10498   // Check that the named access check is called when invoking
10499   // functions on an object that requires access checks.
10500   CompileRun("obj.f = function() {}");
10501   CompileRun("function testCallNormal(obj) {"
10502              "  for (var i = 0; i < 10; i++) obj.f();"
10503              "}");
10504   CompileRun("testCallNormal(obj)");
10505   CHECK_EQ(74, named_access_count);
10506
10507   // Force obj into slow case.
10508   value = CompileRun("delete obj.prop");
10509   CHECK(value->BooleanValue());
10510   // Force inline caches into dictionary probing mode.
10511   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10512   // Test that the named access check is called.
10513   value = CompileRun("testProp(obj);");
10514   CHECK(value->IsNumber());
10515   CHECK_EQ(1, value->Int32Value());
10516   CHECK_EQ(96, named_access_count);
10517
10518   // Force the call inline cache into dictionary probing mode.
10519   CompileRun("o.f = function() {}; testCallNormal(o)");
10520   // Test that the named access check is still called for each
10521   // invocation of the function.
10522   value = CompileRun("testCallNormal(obj)");
10523   CHECK_EQ(106, named_access_count);
10524
10525   context1->Exit();
10526   context0->Exit();
10527 }
10528
10529
10530 static bool NamedAccessFlatten(Local<v8::Object> global,
10531                                Local<Value> name,
10532                                v8::AccessType type,
10533                                Local<Value> data) {
10534   char buf[100];
10535   int len;
10536
10537   CHECK(name->IsString());
10538
10539   memset(buf, 0x1, sizeof(buf));
10540   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
10541   CHECK_EQ(4, len);
10542
10543   uint16_t buf2[100];
10544
10545   memset(buf, 0x1, sizeof(buf));
10546   len = name.As<String>()->Write(buf2);
10547   CHECK_EQ(4, len);
10548
10549   return true;
10550 }
10551
10552
10553 static bool IndexedAccessFlatten(Local<v8::Object> global,
10554                                  uint32_t key,
10555                                  v8::AccessType type,
10556                                  Local<Value> data) {
10557   return true;
10558 }
10559
10560
10561 // Regression test.  In access checks, operations that may cause
10562 // garbage collection are not allowed.  It used to be the case that
10563 // using the Write operation on a string could cause a garbage
10564 // collection due to flattening of the string.  This is no longer the
10565 // case.
10566 THREADED_TEST(AccessControlFlatten) {
10567   named_access_count = 0;
10568   indexed_access_count = 0;
10569
10570   v8::Isolate* isolate = CcTest::isolate();
10571   v8::HandleScope handle_scope(isolate);
10572
10573   // Create an environment.
10574   v8::Local<Context> context0 = Context::New(isolate);
10575   context0->Enter();
10576
10577   // Create an object that requires access-check functions to be
10578   // called for cross-domain access.
10579   v8::Handle<v8::ObjectTemplate> object_template =
10580       v8::ObjectTemplate::New(isolate);
10581   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10582                                            IndexedAccessFlatten);
10583   Local<v8::Object> object = object_template->NewInstance();
10584
10585   v8::HandleScope scope1(isolate);
10586
10587   // Create another environment.
10588   v8::Local<Context> context1 = Context::New(isolate);
10589   context1->Enter();
10590
10591   // Make easy access to the object from the other environment.
10592   v8::Handle<v8::Object> global1 = context1->Global();
10593   global1->Set(v8_str("obj"), object);
10594
10595   v8::Handle<Value> value;
10596
10597   value = v8_compile("var p = 'as' + 'df';")->Run();
10598   value = v8_compile("obj[p];")->Run();
10599
10600   context1->Exit();
10601   context0->Exit();
10602 }
10603
10604
10605 static void AccessControlNamedGetter(
10606     Local<Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
10607   info.GetReturnValue().Set(42);
10608 }
10609
10610
10611 static void AccessControlNamedSetter(
10612     Local<Name>, Local<Value> value,
10613     const v8::PropertyCallbackInfo<v8::Value>& info) {
10614   info.GetReturnValue().Set(value);
10615 }
10616
10617
10618 static void AccessControlIndexedGetter(
10619       uint32_t index,
10620       const v8::PropertyCallbackInfo<v8::Value>& info) {
10621   info.GetReturnValue().Set(v8_num(42));
10622 }
10623
10624
10625 static void AccessControlIndexedSetter(
10626     uint32_t,
10627     Local<Value> value,
10628     const v8::PropertyCallbackInfo<v8::Value>& info) {
10629   info.GetReturnValue().Set(value);
10630 }
10631
10632
10633 THREADED_TEST(AccessControlInterceptorIC) {
10634   named_access_count = 0;
10635   indexed_access_count = 0;
10636
10637   v8::Isolate* isolate = CcTest::isolate();
10638   v8::HandleScope handle_scope(isolate);
10639
10640   // Create an environment.
10641   v8::Local<Context> context0 = Context::New(isolate);
10642   context0->Enter();
10643
10644   // Create an object that requires access-check functions to be
10645   // called for cross-domain access.  The object also has interceptors
10646   // interceptor.
10647   v8::Handle<v8::ObjectTemplate> object_template =
10648       v8::ObjectTemplate::New(isolate);
10649   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10650                                            IndexedAccessCounter);
10651   object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
10652       AccessControlNamedGetter, AccessControlNamedSetter));
10653   object_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
10654       AccessControlIndexedGetter, AccessControlIndexedSetter));
10655   Local<v8::Object> object = object_template->NewInstance();
10656
10657   v8::HandleScope scope1(isolate);
10658
10659   // Create another environment.
10660   v8::Local<Context> context1 = Context::New(isolate);
10661   context1->Enter();
10662
10663   // Make easy access to the object from the other environment.
10664   v8::Handle<v8::Object> global1 = context1->Global();
10665   global1->Set(v8_str("obj"), object);
10666
10667   v8::Handle<Value> value;
10668
10669   // Check that the named access-control function is called every time
10670   // eventhough there is an interceptor on the object.
10671   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10672   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10673                      "obj.x")->Run();
10674   CHECK(value->IsNumber());
10675   CHECK_EQ(42, value->Int32Value());
10676   CHECK_EQ(21, named_access_count);
10677
10678   value = v8_compile("var p = 'x';")->Run();
10679   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10680   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10681                      "obj[p]")->Run();
10682   CHECK(value->IsNumber());
10683   CHECK_EQ(42, value->Int32Value());
10684   CHECK_EQ(42, named_access_count);
10685
10686   // Check that the indexed access-control function is called every
10687   // time eventhough there is an interceptor on the object.
10688   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10689   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10690                      "obj[0]")->Run();
10691   CHECK(value->IsNumber());
10692   CHECK_EQ(42, value->Int32Value());
10693   CHECK_EQ(21, indexed_access_count);
10694
10695   context1->Exit();
10696   context0->Exit();
10697 }
10698
10699
10700 THREADED_TEST(Version) {
10701   v8::V8::GetVersion();
10702 }
10703
10704
10705 static void InstanceFunctionCallback(
10706     const v8::FunctionCallbackInfo<v8::Value>& args) {
10707   ApiTestFuzzer::Fuzz();
10708   args.GetReturnValue().Set(v8_num(12));
10709 }
10710
10711
10712 THREADED_TEST(InstanceProperties) {
10713   LocalContext context;
10714   v8::Isolate* isolate = context->GetIsolate();
10715   v8::HandleScope handle_scope(isolate);
10716
10717   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10718   Local<ObjectTemplate> instance = t->InstanceTemplate();
10719
10720   instance->Set(v8_str("x"), v8_num(42));
10721   instance->Set(v8_str("f"),
10722                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10723
10724   Local<Value> o = t->GetFunction()->NewInstance();
10725
10726   context->Global()->Set(v8_str("i"), o);
10727   Local<Value> value = CompileRun("i.x");
10728   CHECK_EQ(42, value->Int32Value());
10729
10730   value = CompileRun("i.f()");
10731   CHECK_EQ(12, value->Int32Value());
10732 }
10733
10734
10735 static void GlobalObjectInstancePropertiesGet(
10736     Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10737   ApiTestFuzzer::Fuzz();
10738 }
10739
10740
10741 THREADED_TEST(GlobalObjectInstanceProperties) {
10742   v8::Isolate* isolate = CcTest::isolate();
10743   v8::HandleScope handle_scope(isolate);
10744
10745   Local<Value> global_object;
10746
10747   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10748   t->InstanceTemplate()->SetHandler(
10749       v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10750   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10751   instance_template->Set(v8_str("x"), v8_num(42));
10752   instance_template->Set(v8_str("f"),
10753                          v8::FunctionTemplate::New(isolate,
10754                                                    InstanceFunctionCallback));
10755
10756   // The script to check how Crankshaft compiles missing global function
10757   // invocations.  function g is not defined and should throw on call.
10758   const char* script =
10759       "function wrapper(call) {"
10760       "  var x = 0, y = 1;"
10761       "  for (var i = 0; i < 1000; i++) {"
10762       "    x += i * 100;"
10763       "    y += i * 100;"
10764       "  }"
10765       "  if (call) g();"
10766       "}"
10767       "for (var i = 0; i < 17; i++) wrapper(false);"
10768       "var thrown = 0;"
10769       "try { wrapper(true); } catch (e) { thrown = 1; };"
10770       "thrown";
10771
10772   {
10773     LocalContext env(NULL, instance_template);
10774     // Hold on to the global object so it can be used again in another
10775     // environment initialization.
10776     global_object = env->Global();
10777
10778     Local<Value> value = CompileRun("x");
10779     CHECK_EQ(42, value->Int32Value());
10780     value = CompileRun("f()");
10781     CHECK_EQ(12, value->Int32Value());
10782     value = CompileRun(script);
10783     CHECK_EQ(1, value->Int32Value());
10784   }
10785
10786   {
10787     // Create new environment reusing the global object.
10788     LocalContext env(NULL, instance_template, global_object);
10789     Local<Value> value = CompileRun("x");
10790     CHECK_EQ(42, value->Int32Value());
10791     value = CompileRun("f()");
10792     CHECK_EQ(12, value->Int32Value());
10793     value = CompileRun(script);
10794     CHECK_EQ(1, value->Int32Value());
10795   }
10796 }
10797
10798
10799 THREADED_TEST(CallKnownGlobalReceiver) {
10800   v8::Isolate* isolate = CcTest::isolate();
10801   v8::HandleScope handle_scope(isolate);
10802
10803   Local<Value> global_object;
10804
10805   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10806   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10807
10808   // The script to check that we leave global object not
10809   // global object proxy on stack when we deoptimize from inside
10810   // arguments evaluation.
10811   // To provoke error we need to both force deoptimization
10812   // from arguments evaluation and to force CallIC to take
10813   // CallIC_Miss code path that can't cope with global proxy.
10814   const char* script =
10815       "function bar(x, y) { try { } finally { } }"
10816       "function baz(x) { try { } finally { } }"
10817       "function bom(x) { try { } finally { } }"
10818       "function foo(x) { bar([x], bom(2)); }"
10819       "for (var i = 0; i < 10000; i++) foo(1);"
10820       "foo";
10821
10822   Local<Value> foo;
10823   {
10824     LocalContext env(NULL, instance_template);
10825     // Hold on to the global object so it can be used again in another
10826     // environment initialization.
10827     global_object = env->Global();
10828     foo = CompileRun(script);
10829   }
10830
10831   {
10832     // Create new environment reusing the global object.
10833     LocalContext env(NULL, instance_template, global_object);
10834     env->Global()->Set(v8_str("foo"), foo);
10835     CompileRun("foo()");
10836   }
10837 }
10838
10839
10840 static void ShadowFunctionCallback(
10841     const v8::FunctionCallbackInfo<v8::Value>& args) {
10842   ApiTestFuzzer::Fuzz();
10843   args.GetReturnValue().Set(v8_num(42));
10844 }
10845
10846
10847 static int shadow_y;
10848 static int shadow_y_setter_call_count;
10849 static int shadow_y_getter_call_count;
10850
10851
10852 static void ShadowYSetter(Local<String>,
10853                           Local<Value>,
10854                           const v8::PropertyCallbackInfo<void>&) {
10855   shadow_y_setter_call_count++;
10856   shadow_y = 42;
10857 }
10858
10859
10860 static void ShadowYGetter(Local<String> name,
10861                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10862   ApiTestFuzzer::Fuzz();
10863   shadow_y_getter_call_count++;
10864   info.GetReturnValue().Set(v8_num(shadow_y));
10865 }
10866
10867
10868 static void ShadowIndexedGet(uint32_t index,
10869                              const v8::PropertyCallbackInfo<v8::Value>&) {
10870 }
10871
10872
10873 static void ShadowNamedGet(Local<Name> key,
10874                            const v8::PropertyCallbackInfo<v8::Value>&) {}
10875
10876
10877 THREADED_TEST(ShadowObject) {
10878   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10879   v8::Isolate* isolate = CcTest::isolate();
10880   v8::HandleScope handle_scope(isolate);
10881
10882   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10883   LocalContext context(NULL, global_template);
10884
10885   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10886   t->InstanceTemplate()->SetHandler(
10887       v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10888   t->InstanceTemplate()->SetHandler(
10889       v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10890   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10891   Local<ObjectTemplate> instance = t->InstanceTemplate();
10892
10893   proto->Set(v8_str("f"),
10894              v8::FunctionTemplate::New(isolate,
10895                                        ShadowFunctionCallback,
10896                                        Local<Value>()));
10897   proto->Set(v8_str("x"), v8_num(12));
10898
10899   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10900
10901   Local<Value> o = t->GetFunction()->NewInstance();
10902   context->Global()->Set(v8_str("__proto__"), o);
10903
10904   Local<Value> value =
10905       CompileRun("this.propertyIsEnumerable(0)");
10906   CHECK(value->IsBoolean());
10907   CHECK(!value->BooleanValue());
10908
10909   value = CompileRun("x");
10910   CHECK_EQ(12, value->Int32Value());
10911
10912   value = CompileRun("f()");
10913   CHECK_EQ(42, value->Int32Value());
10914
10915   CompileRun("y = 43");
10916   CHECK_EQ(1, shadow_y_setter_call_count);
10917   value = CompileRun("y");
10918   CHECK_EQ(1, shadow_y_getter_call_count);
10919   CHECK_EQ(42, value->Int32Value());
10920 }
10921
10922
10923 THREADED_TEST(HiddenPrototype) {
10924   LocalContext context;
10925   v8::Isolate* isolate = context->GetIsolate();
10926   v8::HandleScope handle_scope(isolate);
10927
10928   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10929   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10930   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10931   t1->SetHiddenPrototype(true);
10932   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10933   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10934   t2->SetHiddenPrototype(true);
10935   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10936   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10937   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10938
10939   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10940   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10941   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10942   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10943
10944   // Setting the prototype on an object skips hidden prototypes.
10945   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10946   o0->Set(v8_str("__proto__"), o1);
10947   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10948   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10949   o0->Set(v8_str("__proto__"), o2);
10950   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10951   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10952   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10953   o0->Set(v8_str("__proto__"), o3);
10954   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10955   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10956   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10957   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10958
10959   // Getting the prototype of o0 should get the first visible one
10960   // which is o3.  Therefore, z should not be defined on the prototype
10961   // object.
10962   Local<Value> proto = o0->Get(v8_str("__proto__"));
10963   CHECK(proto->IsObject());
10964   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10965 }
10966
10967
10968 THREADED_TEST(HiddenPrototypeSet) {
10969   LocalContext context;
10970   v8::Isolate* isolate = context->GetIsolate();
10971   v8::HandleScope handle_scope(isolate);
10972
10973   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10974   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10975   ht->SetHiddenPrototype(true);
10976   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10977   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10978
10979   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10980   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10981   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10982   o->Set(v8_str("__proto__"), h);
10983   h->Set(v8_str("__proto__"), p);
10984
10985   // Setting a property that exists on the hidden prototype goes there.
10986   o->Set(v8_str("x"), v8_num(7));
10987   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10988   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10989   CHECK(p->Get(v8_str("x"))->IsUndefined());
10990
10991   // Setting a new property should not be forwarded to the hidden prototype.
10992   o->Set(v8_str("y"), v8_num(6));
10993   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10994   CHECK(h->Get(v8_str("y"))->IsUndefined());
10995   CHECK(p->Get(v8_str("y"))->IsUndefined());
10996
10997   // Setting a property that only exists on a prototype of the hidden prototype
10998   // is treated normally again.
10999   p->Set(v8_str("z"), v8_num(8));
11000   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
11001   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
11002   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
11003   o->Set(v8_str("z"), v8_num(9));
11004   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
11005   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
11006   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
11007 }
11008
11009
11010 // Regression test for issue 2457.
11011 THREADED_TEST(HiddenPrototypeIdentityHash) {
11012   LocalContext context;
11013   v8::HandleScope handle_scope(context->GetIsolate());
11014
11015   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
11016   t->SetHiddenPrototype(true);
11017   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
11018   Handle<Object> p = t->GetFunction()->NewInstance();
11019   Handle<Object> o = Object::New(context->GetIsolate());
11020   o->SetPrototype(p);
11021
11022   int hash = o->GetIdentityHash();
11023   USE(hash);
11024   o->Set(v8_str("foo"), v8_num(42));
11025   DCHECK_EQ(hash, o->GetIdentityHash());
11026 }
11027
11028
11029 THREADED_TEST(SetPrototype) {
11030   LocalContext context;
11031   v8::Isolate* isolate = context->GetIsolate();
11032   v8::HandleScope handle_scope(isolate);
11033
11034   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11035   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11036   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11037   t1->SetHiddenPrototype(true);
11038   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11039   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11040   t2->SetHiddenPrototype(true);
11041   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11042   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11043   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11044
11045   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
11046   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11047   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11048   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
11049
11050   // Setting the prototype on an object does not skip hidden prototypes.
11051   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11052   CHECK(o0->SetPrototype(o1));
11053   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11054   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11055   CHECK(o1->SetPrototype(o2));
11056   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11057   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11058   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
11059   CHECK(o2->SetPrototype(o3));
11060   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11061   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11062   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
11063   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
11064
11065   // Getting the prototype of o0 should get the first visible one
11066   // which is o3.  Therefore, z should not be defined on the prototype
11067   // object.
11068   Local<Value> proto = o0->Get(v8_str("__proto__"));
11069   CHECK(proto->IsObject());
11070   CHECK_EQ(proto.As<v8::Object>(), o3);
11071
11072   // However, Object::GetPrototype ignores hidden prototype.
11073   Local<Value> proto0 = o0->GetPrototype();
11074   CHECK(proto0->IsObject());
11075   CHECK_EQ(proto0.As<v8::Object>(), o1);
11076
11077   Local<Value> proto1 = o1->GetPrototype();
11078   CHECK(proto1->IsObject());
11079   CHECK_EQ(proto1.As<v8::Object>(), o2);
11080
11081   Local<Value> proto2 = o2->GetPrototype();
11082   CHECK(proto2->IsObject());
11083   CHECK_EQ(proto2.As<v8::Object>(), o3);
11084 }
11085
11086
11087 // Getting property names of an object with a prototype chain that
11088 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
11089 // crash the runtime.
11090 THREADED_TEST(Regress91517) {
11091   i::FLAG_allow_natives_syntax = true;
11092   LocalContext context;
11093   v8::Isolate* isolate = context->GetIsolate();
11094   v8::HandleScope handle_scope(isolate);
11095
11096   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11097   t1->SetHiddenPrototype(true);
11098   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11099   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11100   t2->SetHiddenPrototype(true);
11101   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11102   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
11103   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11104   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11105   t3->SetHiddenPrototype(true);
11106   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11107   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11108   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11109
11110   // Force dictionary-based properties.
11111   i::ScopedVector<char> name_buf(1024);
11112   for (int i = 1; i <= 1000; i++) {
11113     i::SNPrintF(name_buf, "sdf%d", i);
11114     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11115   }
11116
11117   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11118   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11119   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
11120   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
11121
11122   // Create prototype chain of hidden prototypes.
11123   CHECK(o4->SetPrototype(o3));
11124   CHECK(o3->SetPrototype(o2));
11125   CHECK(o2->SetPrototype(o1));
11126
11127   // Call the runtime version of GetOwnPropertyNames() on the natively
11128   // created object through JavaScript.
11129   context->Global()->Set(v8_str("obj"), o4);
11130   // PROPERTY_ATTRIBUTES_NONE = 0
11131   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
11132
11133   ExpectInt32("names.length", 1006);
11134   ExpectTrue("names.indexOf(\"baz\") >= 0");
11135   ExpectTrue("names.indexOf(\"boo\") >= 0");
11136   ExpectTrue("names.indexOf(\"foo\") >= 0");
11137   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
11138   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
11139   ExpectFalse("names[1005] == undefined");
11140 }
11141
11142
11143 // Getting property names of an object with a hidden and inherited
11144 // prototype should not duplicate the accessor properties inherited.
11145 THREADED_TEST(Regress269562) {
11146   i::FLAG_allow_natives_syntax = true;
11147   LocalContext context;
11148   v8::HandleScope handle_scope(context->GetIsolate());
11149
11150   Local<v8::FunctionTemplate> t1 =
11151       v8::FunctionTemplate::New(context->GetIsolate());
11152   t1->SetHiddenPrototype(true);
11153
11154   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
11155   i1->SetAccessor(v8_str("foo"),
11156                   SimpleAccessorGetter, SimpleAccessorSetter);
11157   i1->SetAccessor(v8_str("bar"),
11158                   SimpleAccessorGetter, SimpleAccessorSetter);
11159   i1->SetAccessor(v8_str("baz"),
11160                   SimpleAccessorGetter, SimpleAccessorSetter);
11161   i1->Set(v8_str("n1"), v8_num(1));
11162   i1->Set(v8_str("n2"), v8_num(2));
11163
11164   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11165   Local<v8::FunctionTemplate> t2 =
11166       v8::FunctionTemplate::New(context->GetIsolate());
11167   t2->SetHiddenPrototype(true);
11168
11169   // Inherit from t1 and mark prototype as hidden.
11170   t2->Inherit(t1);
11171   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
11172
11173   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11174   CHECK(o2->SetPrototype(o1));
11175
11176   v8::Local<v8::Symbol> sym =
11177       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
11178   o1->Set(sym, v8_num(3));
11179   o1->SetHiddenValue(
11180       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
11181
11182   // Call the runtime version of GetOwnPropertyNames() on
11183   // the natively created object through JavaScript.
11184   context->Global()->Set(v8_str("obj"), o2);
11185   context->Global()->Set(v8_str("sym"), sym);
11186   // PROPERTY_ATTRIBUTES_NONE = 0
11187   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
11188
11189   ExpectInt32("names.length", 7);
11190   ExpectTrue("names.indexOf(\"foo\") >= 0");
11191   ExpectTrue("names.indexOf(\"bar\") >= 0");
11192   ExpectTrue("names.indexOf(\"baz\") >= 0");
11193   ExpectTrue("names.indexOf(\"n1\") >= 0");
11194   ExpectTrue("names.indexOf(\"n2\") >= 0");
11195   ExpectTrue("names.indexOf(sym) >= 0");
11196   ExpectTrue("names.indexOf(\"mine\") >= 0");
11197 }
11198
11199
11200 THREADED_TEST(FunctionReadOnlyPrototype) {
11201   LocalContext context;
11202   v8::Isolate* isolate = context->GetIsolate();
11203   v8::HandleScope handle_scope(isolate);
11204
11205   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11206   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11207   t1->ReadOnlyPrototype();
11208   context->Global()->Set(v8_str("func1"), t1->GetFunction());
11209   // Configured value of ReadOnly flag.
11210   CHECK(CompileRun(
11211       "(function() {"
11212       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11213       "  return (descriptor['writable'] == false);"
11214       "})()")->BooleanValue());
11215   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
11216   CHECK_EQ(42,
11217            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
11218
11219   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11220   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11221   context->Global()->Set(v8_str("func2"), t2->GetFunction());
11222   // Default value of ReadOnly flag.
11223   CHECK(CompileRun(
11224       "(function() {"
11225       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11226       "  return (descriptor['writable'] == true);"
11227       "})()")->BooleanValue());
11228   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
11229 }
11230
11231
11232 THREADED_TEST(SetPrototypeThrows) {
11233   LocalContext context;
11234   v8::Isolate* isolate = context->GetIsolate();
11235   v8::HandleScope handle_scope(isolate);
11236
11237   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11238
11239   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
11240   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
11241
11242   CHECK(o0->SetPrototype(o1));
11243   // If setting the prototype leads to the cycle, SetPrototype should
11244   // return false and keep VM in sane state.
11245   v8::TryCatch try_catch;
11246   CHECK(!o1->SetPrototype(o0));
11247   CHECK(!try_catch.HasCaught());
11248   DCHECK(!CcTest::i_isolate()->has_pending_exception());
11249
11250   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
11251 }
11252
11253
11254 THREADED_TEST(FunctionRemovePrototype) {
11255   LocalContext context;
11256   v8::Isolate* isolate = context->GetIsolate();
11257   v8::HandleScope handle_scope(isolate);
11258
11259   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11260   t1->RemovePrototype();
11261   Local<v8::Function> fun = t1->GetFunction();
11262   context->Global()->Set(v8_str("fun"), fun);
11263   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
11264
11265   v8::TryCatch try_catch;
11266   CompileRun("new fun()");
11267   CHECK(try_catch.HasCaught());
11268
11269   try_catch.Reset();
11270   fun->NewInstance();
11271   CHECK(try_catch.HasCaught());
11272 }
11273
11274
11275 THREADED_TEST(GetterSetterExceptions) {
11276   LocalContext context;
11277   v8::Isolate* isolate = context->GetIsolate();
11278   v8::HandleScope handle_scope(isolate);
11279   CompileRun(
11280     "function Foo() { };"
11281     "function Throw() { throw 5; };"
11282     "var x = { };"
11283     "x.__defineSetter__('set', Throw);"
11284     "x.__defineGetter__('get', Throw);");
11285   Local<v8::Object> x =
11286       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
11287   v8::TryCatch try_catch;
11288   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11289   x->Get(v8_str("get"));
11290   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11291   x->Get(v8_str("get"));
11292   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11293   x->Get(v8_str("get"));
11294   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11295   x->Get(v8_str("get"));
11296 }
11297
11298
11299 THREADED_TEST(Constructor) {
11300   LocalContext context;
11301   v8::Isolate* isolate = context->GetIsolate();
11302   v8::HandleScope handle_scope(isolate);
11303   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11304   templ->SetClassName(v8_str("Fun"));
11305   Local<Function> cons = templ->GetFunction();
11306   context->Global()->Set(v8_str("Fun"), cons);
11307   Local<v8::Object> inst = cons->NewInstance();
11308   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
11309   CHECK(obj->IsJSObject());
11310   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11311   CHECK(value->BooleanValue());
11312 }
11313
11314
11315 static void ConstructorCallback(
11316     const v8::FunctionCallbackInfo<v8::Value>& args) {
11317   ApiTestFuzzer::Fuzz();
11318   Local<Object> This;
11319
11320   if (args.IsConstructCall()) {
11321     Local<Object> Holder = args.Holder();
11322     This = Object::New(args.GetIsolate());
11323     Local<Value> proto = Holder->GetPrototype();
11324     if (proto->IsObject()) {
11325       This->SetPrototype(proto);
11326     }
11327   } else {
11328     This = args.This();
11329   }
11330
11331   This->Set(v8_str("a"), args[0]);
11332   args.GetReturnValue().Set(This);
11333 }
11334
11335
11336 static void FakeConstructorCallback(
11337     const v8::FunctionCallbackInfo<v8::Value>& args) {
11338   ApiTestFuzzer::Fuzz();
11339   args.GetReturnValue().Set(args[0]);
11340 }
11341
11342
11343 THREADED_TEST(ConstructorForObject) {
11344   LocalContext context;
11345   v8::Isolate* isolate = context->GetIsolate();
11346   v8::HandleScope handle_scope(isolate);
11347
11348   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11349     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
11350     Local<Object> instance = instance_template->NewInstance();
11351     context->Global()->Set(v8_str("obj"), instance);
11352     v8::TryCatch try_catch;
11353     Local<Value> value;
11354     CHECK(!try_catch.HasCaught());
11355
11356     // Call the Object's constructor with a 32-bit signed integer.
11357     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11358     CHECK(!try_catch.HasCaught());
11359     CHECK(value->IsInt32());
11360     CHECK_EQ(28, value->Int32Value());
11361
11362     Local<Value> args1[] = { v8_num(28) };
11363     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
11364     CHECK(value_obj1->IsObject());
11365     Local<Object> object1 = Local<Object>::Cast(value_obj1);
11366     value = object1->Get(v8_str("a"));
11367     CHECK(value->IsInt32());
11368     CHECK(!try_catch.HasCaught());
11369     CHECK_EQ(28, value->Int32Value());
11370
11371     // Call the Object's constructor with a String.
11372     value = CompileRun(
11373         "(function() { var o = new obj('tipli'); return o.a; })()");
11374     CHECK(!try_catch.HasCaught());
11375     CHECK(value->IsString());
11376     String::Utf8Value string_value1(value->ToString(isolate));
11377     CHECK_EQ("tipli", *string_value1);
11378
11379     Local<Value> args2[] = { v8_str("tipli") };
11380     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
11381     CHECK(value_obj2->IsObject());
11382     Local<Object> object2 = Local<Object>::Cast(value_obj2);
11383     value = object2->Get(v8_str("a"));
11384     CHECK(!try_catch.HasCaught());
11385     CHECK(value->IsString());
11386     String::Utf8Value string_value2(value->ToString(isolate));
11387     CHECK_EQ("tipli", *string_value2);
11388
11389     // Call the Object's constructor with a Boolean.
11390     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11391     CHECK(!try_catch.HasCaught());
11392     CHECK(value->IsBoolean());
11393     CHECK_EQ(true, value->BooleanValue());
11394
11395     Handle<Value> args3[] = { v8::True(isolate) };
11396     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
11397     CHECK(value_obj3->IsObject());
11398     Local<Object> object3 = Local<Object>::Cast(value_obj3);
11399     value = object3->Get(v8_str("a"));
11400     CHECK(!try_catch.HasCaught());
11401     CHECK(value->IsBoolean());
11402     CHECK_EQ(true, value->BooleanValue());
11403
11404     // Call the Object's constructor with undefined.
11405     Handle<Value> args4[] = { v8::Undefined(isolate) };
11406     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
11407     CHECK(value_obj4->IsObject());
11408     Local<Object> object4 = Local<Object>::Cast(value_obj4);
11409     value = object4->Get(v8_str("a"));
11410     CHECK(!try_catch.HasCaught());
11411     CHECK(value->IsUndefined());
11412
11413     // Call the Object's constructor with null.
11414     Handle<Value> args5[] = { v8::Null(isolate) };
11415     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
11416     CHECK(value_obj5->IsObject());
11417     Local<Object> object5 = Local<Object>::Cast(value_obj5);
11418     value = object5->Get(v8_str("a"));
11419     CHECK(!try_catch.HasCaught());
11420     CHECK(value->IsNull());
11421   }
11422
11423   // Check exception handling when there is no constructor set for the Object.
11424   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11425     Local<Object> instance = instance_template->NewInstance();
11426     context->Global()->Set(v8_str("obj2"), instance);
11427     v8::TryCatch try_catch;
11428     Local<Value> value;
11429     CHECK(!try_catch.HasCaught());
11430
11431     value = CompileRun("new obj2(28)");
11432     CHECK(try_catch.HasCaught());
11433     String::Utf8Value exception_value1(try_catch.Exception());
11434     CHECK_EQ("TypeError: object is not a function", *exception_value1);
11435     try_catch.Reset();
11436
11437     Local<Value> args[] = { v8_num(29) };
11438     value = instance->CallAsConstructor(1, args);
11439     CHECK(try_catch.HasCaught());
11440     String::Utf8Value exception_value2(try_catch.Exception());
11441     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
11442     try_catch.Reset();
11443   }
11444
11445   // Check the case when constructor throws exception.
11446   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11447     instance_template->SetCallAsFunctionHandler(ThrowValue);
11448     Local<Object> instance = instance_template->NewInstance();
11449     context->Global()->Set(v8_str("obj3"), instance);
11450     v8::TryCatch try_catch;
11451     Local<Value> value;
11452     CHECK(!try_catch.HasCaught());
11453
11454     value = CompileRun("new obj3(22)");
11455     CHECK(try_catch.HasCaught());
11456     String::Utf8Value exception_value1(try_catch.Exception());
11457     CHECK_EQ("22", *exception_value1);
11458     try_catch.Reset();
11459
11460     Local<Value> args[] = { v8_num(23) };
11461     value = instance->CallAsConstructor(1, args);
11462     CHECK(try_catch.HasCaught());
11463     String::Utf8Value exception_value2(try_catch.Exception());
11464     CHECK_EQ("23", *exception_value2);
11465     try_catch.Reset();
11466   }
11467
11468   // Check whether constructor returns with an object or non-object.
11469   { Local<FunctionTemplate> function_template =
11470         FunctionTemplate::New(isolate, FakeConstructorCallback);
11471     Local<Function> function = function_template->GetFunction();
11472     Local<Object> instance1 = function;
11473     context->Global()->Set(v8_str("obj4"), instance1);
11474     v8::TryCatch try_catch;
11475     Local<Value> value;
11476     CHECK(!try_catch.HasCaught());
11477
11478     CHECK(instance1->IsObject());
11479     CHECK(instance1->IsFunction());
11480
11481     value = CompileRun("new obj4(28)");
11482     CHECK(!try_catch.HasCaught());
11483     CHECK(value->IsObject());
11484
11485     Local<Value> args1[] = { v8_num(28) };
11486     value = instance1->CallAsConstructor(1, args1);
11487     CHECK(!try_catch.HasCaught());
11488     CHECK(value->IsObject());
11489
11490     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11491     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11492     Local<Object> instance2 = instance_template->NewInstance();
11493     context->Global()->Set(v8_str("obj5"), instance2);
11494     CHECK(!try_catch.HasCaught());
11495
11496     CHECK(instance2->IsObject());
11497     CHECK(!instance2->IsFunction());
11498
11499     value = CompileRun("new obj5(28)");
11500     CHECK(!try_catch.HasCaught());
11501     CHECK(!value->IsObject());
11502
11503     Local<Value> args2[] = { v8_num(28) };
11504     value = instance2->CallAsConstructor(1, args2);
11505     CHECK(!try_catch.HasCaught());
11506     CHECK(!value->IsObject());
11507   }
11508 }
11509
11510
11511 THREADED_TEST(FunctionDescriptorException) {
11512   LocalContext context;
11513   v8::Isolate* isolate = context->GetIsolate();
11514   v8::HandleScope handle_scope(isolate);
11515   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11516   templ->SetClassName(v8_str("Fun"));
11517   Local<Function> cons = templ->GetFunction();
11518   context->Global()->Set(v8_str("Fun"), cons);
11519   Local<Value> value = CompileRun(
11520     "function test() {"
11521     "  try {"
11522     "    (new Fun()).blah()"
11523     "  } catch (e) {"
11524     "    var str = String(e);"
11525     // "    if (str.indexOf('TypeError') == -1) return 1;"
11526     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
11527     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
11528     "    return 0;"
11529     "  }"
11530     "  return 4;"
11531     "}"
11532     "test();");
11533   CHECK_EQ(0, value->Int32Value());
11534 }
11535
11536
11537 THREADED_TEST(EvalAliasedDynamic) {
11538   LocalContext current;
11539   v8::HandleScope scope(current->GetIsolate());
11540
11541   // Tests where aliased eval can only be resolved dynamically.
11542   Local<Script> script = v8_compile(
11543       "function f(x) { "
11544       "  var foo = 2;"
11545       "  with (x) { return eval('foo'); }"
11546       "}"
11547       "foo = 0;"
11548       "result1 = f(new Object());"
11549       "result2 = f(this);"
11550       "var x = new Object();"
11551       "x.eval = function(x) { return 1; };"
11552       "result3 = f(x);");
11553   script->Run();
11554   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
11555   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
11556   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
11557
11558   v8::TryCatch try_catch;
11559   script = v8_compile(
11560       "function f(x) { "
11561       "  var bar = 2;"
11562       "  with (x) { return eval('bar'); }"
11563       "}"
11564       "result4 = f(this)");
11565   script->Run();
11566   CHECK(!try_catch.HasCaught());
11567   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11568
11569   try_catch.Reset();
11570 }
11571
11572
11573 THREADED_TEST(CrossEval) {
11574   v8::HandleScope scope(CcTest::isolate());
11575   LocalContext other;
11576   LocalContext current;
11577
11578   Local<String> token = v8_str("<security token>");
11579   other->SetSecurityToken(token);
11580   current->SetSecurityToken(token);
11581
11582   // Set up reference from current to other.
11583   current->Global()->Set(v8_str("other"), other->Global());
11584
11585   // Check that new variables are introduced in other context.
11586   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11587   script->Run();
11588   Local<Value> foo = other->Global()->Get(v8_str("foo"));
11589   CHECK_EQ(1234, foo->Int32Value());
11590   CHECK(!current->Global()->Has(v8_str("foo")));
11591
11592   // Check that writing to non-existing properties introduces them in
11593   // the other context.
11594   script = v8_compile("other.eval('na = 1234')");
11595   script->Run();
11596   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11597   CHECK(!current->Global()->Has(v8_str("na")));
11598
11599   // Check that global variables in current context are not visible in other
11600   // context.
11601   v8::TryCatch try_catch;
11602   script = v8_compile("var bar = 42; other.eval('bar');");
11603   Local<Value> result = script->Run();
11604   CHECK(try_catch.HasCaught());
11605   try_catch.Reset();
11606
11607   // Check that local variables in current context are not visible in other
11608   // context.
11609   script = v8_compile(
11610       "(function() { "
11611       "  var baz = 87;"
11612       "  return other.eval('baz');"
11613       "})();");
11614   result = script->Run();
11615   CHECK(try_catch.HasCaught());
11616   try_catch.Reset();
11617
11618   // Check that global variables in the other environment are visible
11619   // when evaluting code.
11620   other->Global()->Set(v8_str("bis"), v8_num(1234));
11621   script = v8_compile("other.eval('bis')");
11622   CHECK_EQ(1234, script->Run()->Int32Value());
11623   CHECK(!try_catch.HasCaught());
11624
11625   // Check that the 'this' pointer points to the global object evaluating
11626   // code.
11627   other->Global()->Set(v8_str("t"), other->Global());
11628   script = v8_compile("other.eval('this == t')");
11629   result = script->Run();
11630   CHECK(result->IsTrue());
11631   CHECK(!try_catch.HasCaught());
11632
11633   // Check that variables introduced in with-statement are not visible in
11634   // other context.
11635   script = v8_compile("with({x:2}){other.eval('x')}");
11636   result = script->Run();
11637   CHECK(try_catch.HasCaught());
11638   try_catch.Reset();
11639
11640   // Check that you cannot use 'eval.call' with another object than the
11641   // current global object.
11642   script = v8_compile("other.y = 1; eval.call(other, 'y')");
11643   result = script->Run();
11644   CHECK(try_catch.HasCaught());
11645 }
11646
11647
11648 // Test that calling eval in a context which has been detached from
11649 // its global proxy works.
11650 THREADED_TEST(EvalInDetachedGlobal) {
11651   v8::Isolate* isolate = CcTest::isolate();
11652   v8::HandleScope scope(isolate);
11653
11654   v8::Local<Context> context0 = Context::New(isolate);
11655   v8::Local<Context> context1 = Context::New(isolate);
11656
11657   // Set up function in context0 that uses eval from context0.
11658   context0->Enter();
11659   v8::Handle<v8::Value> fun =
11660       CompileRun("var x = 42;"
11661                  "(function() {"
11662                  "  var e = eval;"
11663                  "  return function(s) { return e(s); }"
11664                  "})()");
11665   context0->Exit();
11666
11667   // Put the function into context1 and call it before and after
11668   // detaching the global.  Before detaching, the call succeeds and
11669   // after detaching and exception is thrown.
11670   context1->Enter();
11671   context1->Global()->Set(v8_str("fun"), fun);
11672   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11673   CHECK_EQ(42, x_value->Int32Value());
11674   context0->DetachGlobal();
11675   v8::TryCatch catcher;
11676   x_value = CompileRun("fun('x')");
11677   CHECK_EQ(42, x_value->Int32Value());
11678   context1->Exit();
11679 }
11680
11681
11682 THREADED_TEST(CrossLazyLoad) {
11683   v8::HandleScope scope(CcTest::isolate());
11684   LocalContext other;
11685   LocalContext current;
11686
11687   Local<String> token = v8_str("<security token>");
11688   other->SetSecurityToken(token);
11689   current->SetSecurityToken(token);
11690
11691   // Set up reference from current to other.
11692   current->Global()->Set(v8_str("other"), other->Global());
11693
11694   // Trigger lazy loading in other context.
11695   Local<Script> script = v8_compile("other.eval('new Date(42)')");
11696   Local<Value> value = script->Run();
11697   CHECK_EQ(42.0, value->NumberValue());
11698 }
11699
11700
11701 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11702   ApiTestFuzzer::Fuzz();
11703   if (args.IsConstructCall()) {
11704     if (args[0]->IsInt32()) {
11705       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11706       return;
11707     }
11708   }
11709
11710   args.GetReturnValue().Set(args[0]);
11711 }
11712
11713
11714 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11715   args.GetReturnValue().Set(args.This());
11716 }
11717
11718
11719 // Test that a call handler can be set for objects which will allow
11720 // non-function objects created through the API to be called as
11721 // functions.
11722 THREADED_TEST(CallAsFunction) {
11723   LocalContext context;
11724   v8::Isolate* isolate = context->GetIsolate();
11725   v8::HandleScope scope(isolate);
11726
11727   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11728     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11729     instance_template->SetCallAsFunctionHandler(call_as_function);
11730     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11731     context->Global()->Set(v8_str("obj"), instance);
11732     v8::TryCatch try_catch;
11733     Local<Value> value;
11734     CHECK(!try_catch.HasCaught());
11735
11736     value = CompileRun("obj(42)");
11737     CHECK(!try_catch.HasCaught());
11738     CHECK_EQ(42, value->Int32Value());
11739
11740     value = CompileRun("(function(o){return o(49)})(obj)");
11741     CHECK(!try_catch.HasCaught());
11742     CHECK_EQ(49, value->Int32Value());
11743
11744     // test special case of call as function
11745     value = CompileRun("[obj]['0'](45)");
11746     CHECK(!try_catch.HasCaught());
11747     CHECK_EQ(45, value->Int32Value());
11748
11749     value = CompileRun("obj.call = Function.prototype.call;"
11750                        "obj.call(null, 87)");
11751     CHECK(!try_catch.HasCaught());
11752     CHECK_EQ(87, value->Int32Value());
11753
11754     // Regression tests for bug #1116356: Calling call through call/apply
11755     // must work for non-function receivers.
11756     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11757     value = CompileRun(apply_99);
11758     CHECK(!try_catch.HasCaught());
11759     CHECK_EQ(99, value->Int32Value());
11760
11761     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11762     value = CompileRun(call_17);
11763     CHECK(!try_catch.HasCaught());
11764     CHECK_EQ(17, value->Int32Value());
11765
11766     // Check that the call-as-function handler can be called through
11767     // new.
11768     value = CompileRun("new obj(43)");
11769     CHECK(!try_catch.HasCaught());
11770     CHECK_EQ(-43, value->Int32Value());
11771
11772     // Check that the call-as-function handler can be called through
11773     // the API.
11774     v8::Handle<Value> args[] = { v8_num(28) };
11775     value = instance->CallAsFunction(instance, 1, args);
11776     CHECK(!try_catch.HasCaught());
11777     CHECK_EQ(28, value->Int32Value());
11778   }
11779
11780   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11781     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11782     USE(instance_template);
11783     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11784     context->Global()->Set(v8_str("obj2"), instance);
11785     v8::TryCatch try_catch;
11786     Local<Value> value;
11787     CHECK(!try_catch.HasCaught());
11788
11789     // Call an object without call-as-function handler through the JS
11790     value = CompileRun("obj2(28)");
11791     CHECK(value.IsEmpty());
11792     CHECK(try_catch.HasCaught());
11793     String::Utf8Value exception_value1(try_catch.Exception());
11794     // TODO(verwaest): Better message
11795     CHECK_EQ("TypeError: object is not a function",
11796              *exception_value1);
11797     try_catch.Reset();
11798
11799     // Call an object without call-as-function handler through the API
11800     value = CompileRun("obj2(28)");
11801     v8::Handle<Value> args[] = { v8_num(28) };
11802     value = instance->CallAsFunction(instance, 1, args);
11803     CHECK(value.IsEmpty());
11804     CHECK(try_catch.HasCaught());
11805     String::Utf8Value exception_value2(try_catch.Exception());
11806     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11807     try_catch.Reset();
11808   }
11809
11810   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11811     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11812     instance_template->SetCallAsFunctionHandler(ThrowValue);
11813     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11814     context->Global()->Set(v8_str("obj3"), instance);
11815     v8::TryCatch try_catch;
11816     Local<Value> value;
11817     CHECK(!try_catch.HasCaught());
11818
11819     // Catch the exception which is thrown by call-as-function handler
11820     value = CompileRun("obj3(22)");
11821     CHECK(try_catch.HasCaught());
11822     String::Utf8Value exception_value1(try_catch.Exception());
11823     CHECK_EQ("22", *exception_value1);
11824     try_catch.Reset();
11825
11826     v8::Handle<Value> args[] = { v8_num(23) };
11827     value = instance->CallAsFunction(instance, 1, args);
11828     CHECK(try_catch.HasCaught());
11829     String::Utf8Value exception_value2(try_catch.Exception());
11830     CHECK_EQ("23", *exception_value2);
11831     try_catch.Reset();
11832   }
11833
11834   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11835     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11836     instance_template->SetCallAsFunctionHandler(ReturnThis);
11837     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11838
11839     Local<v8::Value> a1 =
11840         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11841     CHECK(a1->StrictEquals(instance));
11842     Local<v8::Value> a2 =
11843         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11844     CHECK(a2->StrictEquals(instance));
11845     Local<v8::Value> a3 =
11846         instance->CallAsFunction(v8_num(42), 0, NULL);
11847     CHECK(a3->StrictEquals(instance));
11848     Local<v8::Value> a4 =
11849         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11850     CHECK(a4->StrictEquals(instance));
11851     Local<v8::Value> a5 =
11852         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11853     CHECK(a5->StrictEquals(instance));
11854   }
11855
11856   { CompileRun(
11857       "function ReturnThisSloppy() {"
11858       "  return this;"
11859       "}"
11860       "function ReturnThisStrict() {"
11861       "  'use strict';"
11862       "  return this;"
11863       "}");
11864     Local<Function> ReturnThisSloppy =
11865         Local<Function>::Cast(
11866             context->Global()->Get(v8_str("ReturnThisSloppy")));
11867     Local<Function> ReturnThisStrict =
11868         Local<Function>::Cast(
11869             context->Global()->Get(v8_str("ReturnThisStrict")));
11870
11871     Local<v8::Value> a1 =
11872         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11873     CHECK(a1->StrictEquals(context->Global()));
11874     Local<v8::Value> a2 =
11875         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11876     CHECK(a2->StrictEquals(context->Global()));
11877     Local<v8::Value> a3 =
11878         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11879     CHECK(a3->IsNumberObject());
11880     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11881     Local<v8::Value> a4 =
11882         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11883     CHECK(a4->IsStringObject());
11884     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11885     Local<v8::Value> a5 =
11886         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11887     CHECK(a5->IsBooleanObject());
11888     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11889
11890     Local<v8::Value> a6 =
11891         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11892     CHECK(a6->IsUndefined());
11893     Local<v8::Value> a7 =
11894         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11895     CHECK(a7->IsNull());
11896     Local<v8::Value> a8 =
11897         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11898     CHECK(a8->StrictEquals(v8_num(42)));
11899     Local<v8::Value> a9 =
11900         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11901     CHECK(a9->StrictEquals(v8_str("hello")));
11902     Local<v8::Value> a10 =
11903         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11904     CHECK(a10->StrictEquals(v8::True(isolate)));
11905   }
11906 }
11907
11908
11909 // Check whether a non-function object is callable.
11910 THREADED_TEST(CallableObject) {
11911   LocalContext context;
11912   v8::Isolate* isolate = context->GetIsolate();
11913   v8::HandleScope scope(isolate);
11914
11915   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11916     instance_template->SetCallAsFunctionHandler(call_as_function);
11917     Local<Object> instance = instance_template->NewInstance();
11918     v8::TryCatch try_catch;
11919
11920     CHECK(instance->IsCallable());
11921     CHECK(!try_catch.HasCaught());
11922   }
11923
11924   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11925     Local<Object> instance = instance_template->NewInstance();
11926     v8::TryCatch try_catch;
11927
11928     CHECK(!instance->IsCallable());
11929     CHECK(!try_catch.HasCaught());
11930   }
11931
11932   { Local<FunctionTemplate> function_template =
11933         FunctionTemplate::New(isolate, call_as_function);
11934     Local<Function> function = function_template->GetFunction();
11935     Local<Object> instance = function;
11936     v8::TryCatch try_catch;
11937
11938     CHECK(instance->IsCallable());
11939     CHECK(!try_catch.HasCaught());
11940   }
11941
11942   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11943     Local<Function> function = function_template->GetFunction();
11944     Local<Object> instance = function;
11945     v8::TryCatch try_catch;
11946
11947     CHECK(instance->IsCallable());
11948     CHECK(!try_catch.HasCaught());
11949   }
11950 }
11951
11952
11953 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11954   v8::HandleScope scope(isolate);
11955   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11956   for (int i = 0; i < iterations; i++) {
11957     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11958   }
11959   return Recurse(isolate, depth - 1, iterations);
11960 }
11961
11962
11963 THREADED_TEST(HandleIteration) {
11964   static const int kIterations = 500;
11965   static const int kNesting = 200;
11966   LocalContext context;
11967   v8::Isolate* isolate = context->GetIsolate();
11968   v8::HandleScope scope0(isolate);
11969   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11970   {
11971     v8::HandleScope scope1(isolate);
11972     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11973     for (int i = 0; i < kIterations; i++) {
11974       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11975       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11976     }
11977
11978     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11979     {
11980       v8::HandleScope scope2(CcTest::isolate());
11981       for (int j = 0; j < kIterations; j++) {
11982         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11983         CHECK_EQ(j + 1 + kIterations,
11984                  v8::HandleScope::NumberOfHandles(isolate));
11985       }
11986     }
11987     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11988   }
11989   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11990   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11991 }
11992
11993
11994 static void InterceptorHasOwnPropertyGetter(
11995     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
11996   ApiTestFuzzer::Fuzz();
11997 }
11998
11999
12000 THREADED_TEST(InterceptorHasOwnProperty) {
12001   LocalContext context;
12002   v8::Isolate* isolate = context->GetIsolate();
12003   v8::HandleScope scope(isolate);
12004   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
12005   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
12006   instance_templ->SetHandler(
12007       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
12008   Local<Function> function = fun_templ->GetFunction();
12009   context->Global()->Set(v8_str("constructor"), function);
12010   v8::Handle<Value> value = CompileRun(
12011       "var o = new constructor();"
12012       "o.hasOwnProperty('ostehaps');");
12013   CHECK_EQ(false, value->BooleanValue());
12014   value = CompileRun(
12015       "o.ostehaps = 42;"
12016       "o.hasOwnProperty('ostehaps');");
12017   CHECK_EQ(true, value->BooleanValue());
12018   value = CompileRun(
12019       "var p = new constructor();"
12020       "p.hasOwnProperty('ostehaps');");
12021   CHECK_EQ(false, value->BooleanValue());
12022 }
12023
12024
12025 static void InterceptorHasOwnPropertyGetterGC(
12026     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12027   ApiTestFuzzer::Fuzz();
12028   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12029 }
12030
12031
12032 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
12033   LocalContext context;
12034   v8::Isolate* isolate = context->GetIsolate();
12035   v8::HandleScope scope(isolate);
12036   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
12037   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
12038   instance_templ->SetHandler(
12039       v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
12040   Local<Function> function = fun_templ->GetFunction();
12041   context->Global()->Set(v8_str("constructor"), function);
12042   // Let's first make some stuff so we can be sure to get a good GC.
12043   CompileRun(
12044       "function makestr(size) {"
12045       "  switch (size) {"
12046       "    case 1: return 'f';"
12047       "    case 2: return 'fo';"
12048       "    case 3: return 'foo';"
12049       "  }"
12050       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
12051       "}"
12052       "var x = makestr(12345);"
12053       "x = makestr(31415);"
12054       "x = makestr(23456);");
12055   v8::Handle<Value> value = CompileRun(
12056       "var o = new constructor();"
12057       "o.__proto__ = new String(x);"
12058       "o.hasOwnProperty('ostehaps');");
12059   CHECK_EQ(false, value->BooleanValue());
12060 }
12061
12062
12063 static void CheckInterceptorLoadIC(
12064     v8::GenericNamedPropertyGetterCallback getter, const char* source,
12065     int expected) {
12066   v8::Isolate* isolate = CcTest::isolate();
12067   v8::HandleScope scope(isolate);
12068   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12069   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
12070                                                           v8_str("data")));
12071   LocalContext context;
12072   context->Global()->Set(v8_str("o"), templ->NewInstance());
12073   v8::Handle<Value> value = CompileRun(source);
12074   CHECK_EQ(expected, value->Int32Value());
12075 }
12076
12077
12078 static void InterceptorLoadICGetter(
12079     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12080   ApiTestFuzzer::Fuzz();
12081   v8::Isolate* isolate = CcTest::isolate();
12082   CHECK_EQ(isolate, info.GetIsolate());
12083   CHECK_EQ(v8_str("data"), info.Data());
12084   CHECK_EQ(v8_str("x"), name);
12085   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
12086 }
12087
12088
12089 // This test should hit the load IC for the interceptor case.
12090 THREADED_TEST(InterceptorLoadIC) {
12091   CheckInterceptorLoadIC(InterceptorLoadICGetter,
12092     "var result = 0;"
12093     "for (var i = 0; i < 1000; i++) {"
12094     "  result = o.x;"
12095     "}",
12096     42);
12097 }
12098
12099
12100 // Below go several tests which verify that JITing for various
12101 // configurations of interceptor and explicit fields works fine
12102 // (those cases are special cased to get better performance).
12103
12104 static void InterceptorLoadXICGetter(
12105     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12106   ApiTestFuzzer::Fuzz();
12107   info.GetReturnValue().Set(
12108       v8_str("x")->Equals(name) ?
12109           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
12110           v8::Handle<v8::Value>());
12111 }
12112
12113
12114 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
12115   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12116     "var result = 0;"
12117     "o.y = 239;"
12118     "for (var i = 0; i < 1000; i++) {"
12119     "  result = o.y;"
12120     "}",
12121     239);
12122 }
12123
12124
12125 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
12126   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12127     "var result = 0;"
12128     "o.__proto__ = { 'y': 239 };"
12129     "for (var i = 0; i < 1000; i++) {"
12130     "  result = o.y + o.x;"
12131     "}",
12132     239 + 42);
12133 }
12134
12135
12136 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
12137   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12138     "var result = 0;"
12139     "o.__proto__.y = 239;"
12140     "for (var i = 0; i < 1000; i++) {"
12141     "  result = o.y + o.x;"
12142     "}",
12143     239 + 42);
12144 }
12145
12146
12147 THREADED_TEST(InterceptorLoadICUndefined) {
12148   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12149     "var result = 0;"
12150     "for (var i = 0; i < 1000; i++) {"
12151     "  result = (o.y == undefined) ? 239 : 42;"
12152     "}",
12153     239);
12154 }
12155
12156
12157 THREADED_TEST(InterceptorLoadICWithOverride) {
12158   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12159     "fst = new Object();  fst.__proto__ = o;"
12160     "snd = new Object();  snd.__proto__ = fst;"
12161     "var result1 = 0;"
12162     "for (var i = 0; i < 1000;  i++) {"
12163     "  result1 = snd.x;"
12164     "}"
12165     "fst.x = 239;"
12166     "var result = 0;"
12167     "for (var i = 0; i < 1000; i++) {"
12168     "  result = snd.x;"
12169     "}"
12170     "result + result1",
12171     239 + 42);
12172 }
12173
12174
12175 // Test the case when we stored field into
12176 // a stub, but interceptor produced value on its own.
12177 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
12178   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12179     "proto = new Object();"
12180     "o.__proto__ = proto;"
12181     "proto.x = 239;"
12182     "for (var i = 0; i < 1000; i++) {"
12183     "  o.x;"
12184     // Now it should be ICed and keep a reference to x defined on proto
12185     "}"
12186     "var result = 0;"
12187     "for (var i = 0; i < 1000; i++) {"
12188     "  result += o.x;"
12189     "}"
12190     "result;",
12191     42 * 1000);
12192 }
12193
12194
12195 // Test the case when we stored field into
12196 // a stub, but it got invalidated later on.
12197 THREADED_TEST(InterceptorLoadICInvalidatedField) {
12198   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12199     "proto1 = new Object();"
12200     "proto2 = new Object();"
12201     "o.__proto__ = proto1;"
12202     "proto1.__proto__ = proto2;"
12203     "proto2.y = 239;"
12204     "for (var i = 0; i < 1000; i++) {"
12205     "  o.y;"
12206     // Now it should be ICed and keep a reference to y defined on proto2
12207     "}"
12208     "proto1.y = 42;"
12209     "var result = 0;"
12210     "for (var i = 0; i < 1000; i++) {"
12211     "  result += o.y;"
12212     "}"
12213     "result;",
12214     42 * 1000);
12215 }
12216
12217
12218 static int interceptor_load_not_handled_calls = 0;
12219 static void InterceptorLoadNotHandled(
12220     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12221   ++interceptor_load_not_handled_calls;
12222 }
12223
12224
12225 // Test how post-interceptor lookups are done in the non-cacheable
12226 // case: the interceptor should not be invoked during this lookup.
12227 THREADED_TEST(InterceptorLoadICPostInterceptor) {
12228   interceptor_load_not_handled_calls = 0;
12229   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
12230     "receiver = new Object();"
12231     "receiver.__proto__ = o;"
12232     "proto = new Object();"
12233     "/* Make proto a slow-case object. */"
12234     "for (var i = 0; i < 1000; i++) {"
12235     "  proto[\"xxxxxxxx\" + i] = [];"
12236     "}"
12237     "proto.x = 17;"
12238     "o.__proto__ = proto;"
12239     "var result = 0;"
12240     "for (var i = 0; i < 1000; i++) {"
12241     "  result += receiver.x;"
12242     "}"
12243     "result;",
12244     17 * 1000);
12245   CHECK_EQ(1000, interceptor_load_not_handled_calls);
12246 }
12247
12248
12249 // Test the case when we stored field into
12250 // a stub, but it got invalidated later on due to override on
12251 // global object which is between interceptor and fields' holders.
12252 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
12253   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12254     "o.__proto__ = this;"  // set a global to be a proto of o.
12255     "this.__proto__.y = 239;"
12256     "for (var i = 0; i < 10; i++) {"
12257     "  if (o.y != 239) throw 'oops: ' + o.y;"
12258     // Now it should be ICed and keep a reference to y defined on field_holder.
12259     "}"
12260     "this.y = 42;"  // Assign on a global.
12261     "var result = 0;"
12262     "for (var i = 0; i < 10; i++) {"
12263     "  result += o.y;"
12264     "}"
12265     "result;",
12266     42 * 10);
12267 }
12268
12269
12270 static void SetOnThis(Local<String> name,
12271                       Local<Value> value,
12272                       const v8::PropertyCallbackInfo<void>& info) {
12273   Local<Object>::Cast(info.This())->ForceSet(name, value);
12274 }
12275
12276
12277 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
12278   v8::Isolate* isolate = CcTest::isolate();
12279   v8::HandleScope scope(isolate);
12280   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12281   templ->SetHandler(
12282       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12283   templ->SetAccessor(v8_str("y"), Return239Callback);
12284   LocalContext context;
12285   context->Global()->Set(v8_str("o"), templ->NewInstance());
12286
12287   // Check the case when receiver and interceptor's holder
12288   // are the same objects.
12289   v8::Handle<Value> value = CompileRun(
12290       "var result = 0;"
12291       "for (var i = 0; i < 7; i++) {"
12292       "  result = o.y;"
12293       "}");
12294   CHECK_EQ(239, value->Int32Value());
12295
12296   // Check the case when interceptor's holder is in proto chain
12297   // of receiver.
12298   value = CompileRun(
12299       "r = { __proto__: o };"
12300       "var result = 0;"
12301       "for (var i = 0; i < 7; i++) {"
12302       "  result = r.y;"
12303       "}");
12304   CHECK_EQ(239, value->Int32Value());
12305 }
12306
12307
12308 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
12309   v8::Isolate* isolate = CcTest::isolate();
12310   v8::HandleScope scope(isolate);
12311   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12312   templ_o->SetHandler(
12313       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12314   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12315   templ_p->SetAccessor(v8_str("y"), Return239Callback);
12316
12317   LocalContext context;
12318   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12319   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12320
12321   // Check the case when receiver and interceptor's holder
12322   // are the same objects.
12323   v8::Handle<Value> value = CompileRun(
12324       "o.__proto__ = p;"
12325       "var result = 0;"
12326       "for (var i = 0; i < 7; i++) {"
12327       "  result = o.x + o.y;"
12328       "}");
12329   CHECK_EQ(239 + 42, value->Int32Value());
12330
12331   // Check the case when interceptor's holder is in proto chain
12332   // of receiver.
12333   value = CompileRun(
12334       "r = { __proto__: o };"
12335       "var result = 0;"
12336       "for (var i = 0; i < 7; i++) {"
12337       "  result = r.x + r.y;"
12338       "}");
12339   CHECK_EQ(239 + 42, value->Int32Value());
12340 }
12341
12342
12343 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
12344   v8::Isolate* isolate = CcTest::isolate();
12345   v8::HandleScope scope(isolate);
12346   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12347   templ->SetHandler(
12348       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12349   templ->SetAccessor(v8_str("y"), Return239Callback);
12350
12351   LocalContext context;
12352   context->Global()->Set(v8_str("o"), templ->NewInstance());
12353
12354   v8::Handle<Value> value = CompileRun(
12355     "fst = new Object();  fst.__proto__ = o;"
12356     "snd = new Object();  snd.__proto__ = fst;"
12357     "var result1 = 0;"
12358     "for (var i = 0; i < 7;  i++) {"
12359     "  result1 = snd.x;"
12360     "}"
12361     "fst.x = 239;"
12362     "var result = 0;"
12363     "for (var i = 0; i < 7; i++) {"
12364     "  result = snd.x;"
12365     "}"
12366     "result + result1");
12367   CHECK_EQ(239 + 42, value->Int32Value());
12368 }
12369
12370
12371 // Test the case when we stored callback into
12372 // a stub, but interceptor produced value on its own.
12373 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
12374   v8::Isolate* isolate = CcTest::isolate();
12375   v8::HandleScope scope(isolate);
12376   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12377   templ_o->SetHandler(
12378       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12379   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12380   templ_p->SetAccessor(v8_str("y"), Return239Callback);
12381
12382   LocalContext context;
12383   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12384   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12385
12386   v8::Handle<Value> value = CompileRun(
12387     "o.__proto__ = p;"
12388     "for (var i = 0; i < 7; i++) {"
12389     "  o.x;"
12390     // Now it should be ICed and keep a reference to x defined on p
12391     "}"
12392     "var result = 0;"
12393     "for (var i = 0; i < 7; i++) {"
12394     "  result += o.x;"
12395     "}"
12396     "result");
12397   CHECK_EQ(42 * 7, value->Int32Value());
12398 }
12399
12400
12401 // Test the case when we stored callback into
12402 // a stub, but it got invalidated later on.
12403 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
12404   v8::Isolate* isolate = CcTest::isolate();
12405   v8::HandleScope scope(isolate);
12406   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12407   templ_o->SetHandler(
12408       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12409   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12410   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12411
12412   LocalContext context;
12413   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12414   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12415
12416   v8::Handle<Value> value = CompileRun(
12417     "inbetween = new Object();"
12418     "o.__proto__ = inbetween;"
12419     "inbetween.__proto__ = p;"
12420     "for (var i = 0; i < 10; i++) {"
12421     "  o.y;"
12422     // Now it should be ICed and keep a reference to y defined on p
12423     "}"
12424     "inbetween.y = 42;"
12425     "var result = 0;"
12426     "for (var i = 0; i < 10; i++) {"
12427     "  result += o.y;"
12428     "}"
12429     "result");
12430   CHECK_EQ(42 * 10, value->Int32Value());
12431 }
12432
12433
12434 // Test the case when we stored callback into
12435 // a stub, but it got invalidated later on due to override on
12436 // global object which is between interceptor and callbacks' holders.
12437 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
12438   v8::Isolate* isolate = CcTest::isolate();
12439   v8::HandleScope scope(isolate);
12440   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12441   templ_o->SetHandler(
12442       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12443   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12444   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12445
12446   LocalContext context;
12447   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12448   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12449
12450   v8::Handle<Value> value = CompileRun(
12451     "o.__proto__ = this;"
12452     "this.__proto__ = p;"
12453     "for (var i = 0; i < 10; i++) {"
12454     "  if (o.y != 239) throw 'oops: ' + o.y;"
12455     // Now it should be ICed and keep a reference to y defined on p
12456     "}"
12457     "this.y = 42;"
12458     "var result = 0;"
12459     "for (var i = 0; i < 10; i++) {"
12460     "  result += o.y;"
12461     "}"
12462     "result");
12463   CHECK_EQ(42 * 10, value->Int32Value());
12464 }
12465
12466
12467 static void InterceptorLoadICGetter0(
12468     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12469   ApiTestFuzzer::Fuzz();
12470   CHECK(v8_str("x")->Equals(name));
12471   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
12472 }
12473
12474
12475 THREADED_TEST(InterceptorReturningZero) {
12476   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
12477      "o.x == undefined ? 1 : 0",
12478      0);
12479 }
12480
12481
12482 static void InterceptorStoreICSetter(
12483     Local<Name> key, Local<Value> value,
12484     const v8::PropertyCallbackInfo<v8::Value>& info) {
12485   CHECK(v8_str("x")->Equals(key));
12486   CHECK_EQ(42, value->Int32Value());
12487   info.GetReturnValue().Set(value);
12488 }
12489
12490
12491 // This test should hit the store IC for the interceptor case.
12492 THREADED_TEST(InterceptorStoreIC) {
12493   v8::Isolate* isolate = CcTest::isolate();
12494   v8::HandleScope scope(isolate);
12495   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12496   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12497       InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
12498       v8_str("data")));
12499   LocalContext context;
12500   context->Global()->Set(v8_str("o"), templ->NewInstance());
12501   CompileRun(
12502       "for (var i = 0; i < 1000; i++) {"
12503       "  o.x = 42;"
12504       "}");
12505 }
12506
12507
12508 THREADED_TEST(InterceptorStoreICWithNoSetter) {
12509   v8::Isolate* isolate = CcTest::isolate();
12510   v8::HandleScope scope(isolate);
12511   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12512   templ->SetHandler(
12513       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12514   LocalContext context;
12515   context->Global()->Set(v8_str("o"), templ->NewInstance());
12516   v8::Handle<Value> value = CompileRun(
12517     "for (var i = 0; i < 1000; i++) {"
12518     "  o.y = 239;"
12519     "}"
12520     "42 + o.y");
12521   CHECK_EQ(239 + 42, value->Int32Value());
12522 }
12523
12524
12525
12526
12527 v8::Handle<Value> call_ic_function;
12528 v8::Handle<Value> call_ic_function2;
12529 v8::Handle<Value> call_ic_function3;
12530
12531 static void InterceptorCallICGetter(
12532     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12533   ApiTestFuzzer::Fuzz();
12534   CHECK(v8_str("x")->Equals(name));
12535   info.GetReturnValue().Set(call_ic_function);
12536 }
12537
12538
12539 // This test should hit the call IC for the interceptor case.
12540 THREADED_TEST(InterceptorCallIC) {
12541   v8::Isolate* isolate = CcTest::isolate();
12542   v8::HandleScope scope(isolate);
12543   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12544   templ->SetHandler(
12545       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
12546   LocalContext context;
12547   context->Global()->Set(v8_str("o"), templ->NewInstance());
12548   call_ic_function =
12549       v8_compile("function f(x) { return x + 1; }; f")->Run();
12550   v8::Handle<Value> value = CompileRun(
12551     "var result = 0;"
12552     "for (var i = 0; i < 1000; i++) {"
12553     "  result = o.x(41);"
12554     "}");
12555   CHECK_EQ(42, value->Int32Value());
12556 }
12557
12558
12559 // This test checks that if interceptor doesn't provide
12560 // a value, we can fetch regular value.
12561 THREADED_TEST(InterceptorCallICSeesOthers) {
12562   v8::Isolate* isolate = CcTest::isolate();
12563   v8::HandleScope scope(isolate);
12564   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12565   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12566   LocalContext context;
12567   context->Global()->Set(v8_str("o"), templ->NewInstance());
12568   v8::Handle<Value> value = CompileRun(
12569     "o.x = function f(x) { return x + 1; };"
12570     "var result = 0;"
12571     "for (var i = 0; i < 7; i++) {"
12572     "  result = o.x(41);"
12573     "}");
12574   CHECK_EQ(42, value->Int32Value());
12575 }
12576
12577
12578 static v8::Handle<Value> call_ic_function4;
12579 static void InterceptorCallICGetter4(
12580     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12581   ApiTestFuzzer::Fuzz();
12582   CHECK(v8_str("x")->Equals(name));
12583   info.GetReturnValue().Set(call_ic_function4);
12584 }
12585
12586
12587 // This test checks that if interceptor provides a function,
12588 // even if we cached shadowed variant, interceptor's function
12589 // is invoked
12590 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
12591   v8::Isolate* isolate = CcTest::isolate();
12592   v8::HandleScope scope(isolate);
12593   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12594   templ->SetHandler(
12595       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
12596   LocalContext context;
12597   context->Global()->Set(v8_str("o"), templ->NewInstance());
12598   call_ic_function4 =
12599       v8_compile("function f(x) { return x - 1; }; f")->Run();
12600   v8::Handle<Value> value = CompileRun(
12601     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
12602     "var result = 0;"
12603     "for (var i = 0; i < 1000; i++) {"
12604     "  result = o.x(42);"
12605     "}");
12606   CHECK_EQ(41, value->Int32Value());
12607 }
12608
12609
12610 // Test the case when we stored cacheable lookup into
12611 // a stub, but it got invalidated later on
12612 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
12613   v8::Isolate* isolate = CcTest::isolate();
12614   v8::HandleScope scope(isolate);
12615   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12616   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12617   LocalContext context;
12618   context->Global()->Set(v8_str("o"), templ->NewInstance());
12619   v8::Handle<Value> value = CompileRun(
12620     "proto1 = new Object();"
12621     "proto2 = new Object();"
12622     "o.__proto__ = proto1;"
12623     "proto1.__proto__ = proto2;"
12624     "proto2.y = function(x) { return x + 1; };"
12625     // Invoke it many times to compile a stub
12626     "for (var i = 0; i < 7; i++) {"
12627     "  o.y(42);"
12628     "}"
12629     "proto1.y = function(x) { return x - 1; };"
12630     "var result = 0;"
12631     "for (var i = 0; i < 7; i++) {"
12632     "  result += o.y(42);"
12633     "}");
12634   CHECK_EQ(41 * 7, value->Int32Value());
12635 }
12636
12637
12638 // This test checks that if interceptor doesn't provide a function,
12639 // cached constant function is used
12640 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
12641   v8::Isolate* isolate = CcTest::isolate();
12642   v8::HandleScope scope(isolate);
12643   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12644   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12645   LocalContext context;
12646   context->Global()->Set(v8_str("o"), templ->NewInstance());
12647   v8::Handle<Value> value = CompileRun(
12648     "function inc(x) { return x + 1; };"
12649     "inc(1);"
12650     "o.x = inc;"
12651     "var result = 0;"
12652     "for (var i = 0; i < 1000; i++) {"
12653     "  result = o.x(42);"
12654     "}");
12655   CHECK_EQ(43, value->Int32Value());
12656 }
12657
12658
12659 static v8::Handle<Value> call_ic_function5;
12660 static void InterceptorCallICGetter5(
12661     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12662   ApiTestFuzzer::Fuzz();
12663   if (v8_str("x")->Equals(name))
12664     info.GetReturnValue().Set(call_ic_function5);
12665 }
12666
12667
12668 // This test checks that if interceptor provides a function,
12669 // even if we cached constant function, interceptor's function
12670 // is invoked
12671 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12672   v8::Isolate* isolate = CcTest::isolate();
12673   v8::HandleScope scope(isolate);
12674   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12675   templ->SetHandler(
12676       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
12677   LocalContext context;
12678   context->Global()->Set(v8_str("o"), templ->NewInstance());
12679   call_ic_function5 =
12680       v8_compile("function f(x) { return x - 1; }; f")->Run();
12681   v8::Handle<Value> value = CompileRun(
12682     "function inc(x) { return x + 1; };"
12683     "inc(1);"
12684     "o.x = inc;"
12685     "var result = 0;"
12686     "for (var i = 0; i < 1000; i++) {"
12687     "  result = o.x(42);"
12688     "}");
12689   CHECK_EQ(41, value->Int32Value());
12690 }
12691
12692
12693 static v8::Handle<Value> call_ic_function6;
12694 static void InterceptorCallICGetter6(
12695     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12696   ApiTestFuzzer::Fuzz();
12697   if (v8_str("x")->Equals(name))
12698     info.GetReturnValue().Set(call_ic_function6);
12699 }
12700
12701
12702 // Same test as above, except the code is wrapped in a function
12703 // to test the optimized compiler.
12704 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12705   i::FLAG_allow_natives_syntax = true;
12706   v8::Isolate* isolate = CcTest::isolate();
12707   v8::HandleScope scope(isolate);
12708   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12709   templ->SetHandler(
12710       v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
12711   LocalContext context;
12712   context->Global()->Set(v8_str("o"), templ->NewInstance());
12713   call_ic_function6 =
12714       v8_compile("function f(x) { return x - 1; }; f")->Run();
12715   v8::Handle<Value> value = CompileRun(
12716     "function inc(x) { return x + 1; };"
12717     "inc(1);"
12718     "o.x = inc;"
12719     "function test() {"
12720     "  var result = 0;"
12721     "  for (var i = 0; i < 1000; i++) {"
12722     "    result = o.x(42);"
12723     "  }"
12724     "  return result;"
12725     "};"
12726     "test();"
12727     "test();"
12728     "test();"
12729     "%OptimizeFunctionOnNextCall(test);"
12730     "test()");
12731   CHECK_EQ(41, value->Int32Value());
12732 }
12733
12734
12735 // Test the case when we stored constant function into
12736 // a stub, but it got invalidated later on
12737 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12738   v8::Isolate* isolate = CcTest::isolate();
12739   v8::HandleScope scope(isolate);
12740   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12741   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12742   LocalContext context;
12743   context->Global()->Set(v8_str("o"), templ->NewInstance());
12744   v8::Handle<Value> value = CompileRun(
12745     "function inc(x) { return x + 1; };"
12746     "inc(1);"
12747     "proto1 = new Object();"
12748     "proto2 = new Object();"
12749     "o.__proto__ = proto1;"
12750     "proto1.__proto__ = proto2;"
12751     "proto2.y = inc;"
12752     // Invoke it many times to compile a stub
12753     "for (var i = 0; i < 7; i++) {"
12754     "  o.y(42);"
12755     "}"
12756     "proto1.y = function(x) { return x - 1; };"
12757     "var result = 0;"
12758     "for (var i = 0; i < 7; i++) {"
12759     "  result += o.y(42);"
12760     "}");
12761   CHECK_EQ(41 * 7, value->Int32Value());
12762 }
12763
12764
12765 // Test the case when we stored constant function into
12766 // a stub, but it got invalidated later on due to override on
12767 // global object which is between interceptor and constant function' holders.
12768 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12769   v8::Isolate* isolate = CcTest::isolate();
12770   v8::HandleScope scope(isolate);
12771   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12772   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12773   LocalContext context;
12774   context->Global()->Set(v8_str("o"), templ->NewInstance());
12775   v8::Handle<Value> value = CompileRun(
12776     "function inc(x) { return x + 1; };"
12777     "inc(1);"
12778     "o.__proto__ = this;"
12779     "this.__proto__.y = inc;"
12780     // Invoke it many times to compile a stub
12781     "for (var i = 0; i < 7; i++) {"
12782     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12783     "}"
12784     "this.y = function(x) { return x - 1; };"
12785     "var result = 0;"
12786     "for (var i = 0; i < 7; i++) {"
12787     "  result += o.y(42);"
12788     "}");
12789   CHECK_EQ(41 * 7, value->Int32Value());
12790 }
12791
12792
12793 // Test the case when actual function to call sits on global object.
12794 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12795   v8::Isolate* isolate = CcTest::isolate();
12796   v8::HandleScope scope(isolate);
12797   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12798   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12799
12800   LocalContext context;
12801   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12802
12803   v8::Handle<Value> value = CompileRun(
12804     "try {"
12805     "  o.__proto__ = this;"
12806     "  for (var i = 0; i < 10; i++) {"
12807     "    var v = o.parseFloat('239');"
12808     "    if (v != 239) throw v;"
12809       // Now it should be ICed and keep a reference to parseFloat.
12810     "  }"
12811     "  var result = 0;"
12812     "  for (var i = 0; i < 10; i++) {"
12813     "    result += o.parseFloat('239');"
12814     "  }"
12815     "  result"
12816     "} catch(e) {"
12817     "  e"
12818     "};");
12819   CHECK_EQ(239 * 10, value->Int32Value());
12820 }
12821
12822 static void InterceptorCallICFastApi(
12823     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12824   ApiTestFuzzer::Fuzz();
12825   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12826   int* call_count =
12827       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12828   ++(*call_count);
12829   if ((*call_count) % 20 == 0) {
12830     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12831   }
12832 }
12833
12834 static void FastApiCallback_TrivialSignature(
12835     const v8::FunctionCallbackInfo<v8::Value>& args) {
12836   ApiTestFuzzer::Fuzz();
12837   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12838   v8::Isolate* isolate = CcTest::isolate();
12839   CHECK_EQ(isolate, args.GetIsolate());
12840   CHECK_EQ(args.This(), args.Holder());
12841   CHECK(args.Data()->Equals(v8_str("method_data")));
12842   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12843 }
12844
12845 static void FastApiCallback_SimpleSignature(
12846     const v8::FunctionCallbackInfo<v8::Value>& args) {
12847   ApiTestFuzzer::Fuzz();
12848   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12849   v8::Isolate* isolate = CcTest::isolate();
12850   CHECK_EQ(isolate, args.GetIsolate());
12851   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12852   CHECK(args.Data()->Equals(v8_str("method_data")));
12853   // Note, we're using HasRealNamedProperty instead of Has to avoid
12854   // invoking the interceptor again.
12855   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12856   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12857 }
12858
12859
12860 // Helper to maximize the odds of object moving.
12861 static void GenerateSomeGarbage() {
12862   CompileRun(
12863       "var garbage;"
12864       "for (var i = 0; i < 1000; i++) {"
12865       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12866       "}"
12867       "garbage = undefined;");
12868 }
12869
12870
12871 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12872   static int count = 0;
12873   if (count++ % 3 == 0) {
12874     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12875         // This should move the stub
12876     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12877   }
12878 }
12879
12880
12881 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12882   LocalContext context;
12883   v8::Isolate* isolate = context->GetIsolate();
12884   v8::HandleScope scope(isolate);
12885   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12886       v8::ObjectTemplate::New(isolate);
12887   nativeobject_templ->Set(isolate, "callback",
12888                           v8::FunctionTemplate::New(isolate,
12889                                                     DirectApiCallback));
12890   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12891   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12892   // call the api function multiple times to ensure direct call stub creation.
12893   CompileRun(
12894         "function f() {"
12895         "  for (var i = 1; i <= 30; i++) {"
12896         "    nativeobject.callback();"
12897         "  }"
12898         "}"
12899         "f();");
12900 }
12901
12902
12903 void ThrowingDirectApiCallback(
12904     const v8::FunctionCallbackInfo<v8::Value>& args) {
12905   args.GetIsolate()->ThrowException(v8_str("g"));
12906 }
12907
12908
12909 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12910   LocalContext context;
12911   v8::Isolate* isolate = context->GetIsolate();
12912   v8::HandleScope scope(isolate);
12913   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12914       v8::ObjectTemplate::New(isolate);
12915   nativeobject_templ->Set(isolate, "callback",
12916                           v8::FunctionTemplate::New(isolate,
12917                                                     ThrowingDirectApiCallback));
12918   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12919   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12920   // call the api function multiple times to ensure direct call stub creation.
12921   v8::Handle<Value> result = CompileRun(
12922       "var result = '';"
12923       "function f() {"
12924       "  for (var i = 1; i <= 5; i++) {"
12925       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12926       "  }"
12927       "}"
12928       "f(); result;");
12929   CHECK_EQ(v8_str("ggggg"), result);
12930 }
12931
12932
12933 static Handle<Value> DoDirectGetter() {
12934   if (++p_getter_count % 3 == 0) {
12935     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12936     GenerateSomeGarbage();
12937   }
12938   return v8_str("Direct Getter Result");
12939 }
12940
12941 static void DirectGetterCallback(
12942     Local<String> name,
12943     const v8::PropertyCallbackInfo<v8::Value>& info) {
12944   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12945   info.GetReturnValue().Set(DoDirectGetter());
12946 }
12947
12948
12949 template<typename Accessor>
12950 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12951   LocalContext context;
12952   v8::Isolate* isolate = context->GetIsolate();
12953   v8::HandleScope scope(isolate);
12954   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12955   obj->SetAccessor(v8_str("p1"), accessor);
12956   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12957   p_getter_count = 0;
12958   v8::Handle<v8::Value> result = CompileRun(
12959       "function f() {"
12960       "  for (var i = 0; i < 30; i++) o1.p1;"
12961       "  return o1.p1"
12962       "}"
12963       "f();");
12964   CHECK_EQ(v8_str("Direct Getter Result"), result);
12965   CHECK_EQ(31, p_getter_count);
12966 }
12967
12968
12969 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12970   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12971 }
12972
12973
12974 void ThrowingDirectGetterCallback(
12975     Local<String> name,
12976     const v8::PropertyCallbackInfo<v8::Value>& info) {
12977   info.GetIsolate()->ThrowException(v8_str("g"));
12978 }
12979
12980
12981 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12982   LocalContext context;
12983   v8::Isolate* isolate = context->GetIsolate();
12984   v8::HandleScope scope(isolate);
12985   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12986   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12987   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12988   v8::Handle<Value> result = CompileRun(
12989       "var result = '';"
12990       "for (var i = 0; i < 5; i++) {"
12991       "    try { o1.p1; } catch (e) { result += e; }"
12992       "}"
12993       "result;");
12994   CHECK_EQ(v8_str("ggggg"), result);
12995 }
12996
12997
12998 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12999   int interceptor_call_count = 0;
13000   v8::Isolate* isolate = CcTest::isolate();
13001   v8::HandleScope scope(isolate);
13002   v8::Handle<v8::FunctionTemplate> fun_templ =
13003       v8::FunctionTemplate::New(isolate);
13004   v8::Handle<v8::FunctionTemplate> method_templ =
13005       v8::FunctionTemplate::New(isolate,
13006                                 FastApiCallback_TrivialSignature,
13007                                 v8_str("method_data"),
13008                                 v8::Handle<v8::Signature>());
13009   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13010   proto_templ->Set(v8_str("method"), method_templ);
13011   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13012   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13013       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13014       v8::External::New(isolate, &interceptor_call_count)));
13015   LocalContext context;
13016   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13017   GenerateSomeGarbage();
13018   context->Global()->Set(v8_str("o"), fun->NewInstance());
13019   CompileRun(
13020       "var result = 0;"
13021       "for (var i = 0; i < 100; i++) {"
13022       "  result = o.method(41);"
13023       "}");
13024   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13025   CHECK_EQ(100, interceptor_call_count);
13026 }
13027
13028
13029 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
13030   int interceptor_call_count = 0;
13031   v8::Isolate* isolate = CcTest::isolate();
13032   v8::HandleScope scope(isolate);
13033   v8::Handle<v8::FunctionTemplate> fun_templ =
13034       v8::FunctionTemplate::New(isolate);
13035   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13036       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13037       v8::Signature::New(isolate, fun_templ));
13038   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13039   proto_templ->Set(v8_str("method"), method_templ);
13040   fun_templ->SetHiddenPrototype(true);
13041   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13042   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13043       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13044       v8::External::New(isolate, &interceptor_call_count)));
13045   LocalContext context;
13046   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13047   GenerateSomeGarbage();
13048   context->Global()->Set(v8_str("o"), fun->NewInstance());
13049   CompileRun(
13050       "o.foo = 17;"
13051       "var receiver = {};"
13052       "receiver.__proto__ = o;"
13053       "var result = 0;"
13054       "for (var i = 0; i < 100; i++) {"
13055       "  result = receiver.method(41);"
13056       "}");
13057   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13058   CHECK_EQ(100, interceptor_call_count);
13059 }
13060
13061
13062 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
13063   int interceptor_call_count = 0;
13064   v8::Isolate* isolate = CcTest::isolate();
13065   v8::HandleScope scope(isolate);
13066   v8::Handle<v8::FunctionTemplate> fun_templ =
13067       v8::FunctionTemplate::New(isolate);
13068   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13069       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13070       v8::Signature::New(isolate, fun_templ));
13071   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13072   proto_templ->Set(v8_str("method"), method_templ);
13073   fun_templ->SetHiddenPrototype(true);
13074   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13075   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13076       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13077       v8::External::New(isolate, &interceptor_call_count)));
13078   LocalContext context;
13079   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13080   GenerateSomeGarbage();
13081   context->Global()->Set(v8_str("o"), fun->NewInstance());
13082   CompileRun(
13083       "o.foo = 17;"
13084       "var receiver = {};"
13085       "receiver.__proto__ = o;"
13086       "var result = 0;"
13087       "var saved_result = 0;"
13088       "for (var i = 0; i < 100; i++) {"
13089       "  result = receiver.method(41);"
13090       "  if (i == 50) {"
13091       "    saved_result = result;"
13092       "    receiver = {method: function(x) { return x - 1 }};"
13093       "  }"
13094       "}");
13095   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13096   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13097   CHECK_GE(interceptor_call_count, 50);
13098 }
13099
13100
13101 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
13102   int interceptor_call_count = 0;
13103   v8::Isolate* isolate = CcTest::isolate();
13104   v8::HandleScope scope(isolate);
13105   v8::Handle<v8::FunctionTemplate> fun_templ =
13106       v8::FunctionTemplate::New(isolate);
13107   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13108       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13109       v8::Signature::New(isolate, fun_templ));
13110   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13111   proto_templ->Set(v8_str("method"), method_templ);
13112   fun_templ->SetHiddenPrototype(true);
13113   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13114   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13115       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13116       v8::External::New(isolate, &interceptor_call_count)));
13117   LocalContext context;
13118   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13119   GenerateSomeGarbage();
13120   context->Global()->Set(v8_str("o"), fun->NewInstance());
13121   CompileRun(
13122       "o.foo = 17;"
13123       "var receiver = {};"
13124       "receiver.__proto__ = o;"
13125       "var result = 0;"
13126       "var saved_result = 0;"
13127       "for (var i = 0; i < 100; i++) {"
13128       "  result = receiver.method(41);"
13129       "  if (i == 50) {"
13130       "    saved_result = result;"
13131       "    o.method = function(x) { return x - 1 };"
13132       "  }"
13133       "}");
13134   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13135   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13136   CHECK_GE(interceptor_call_count, 50);
13137 }
13138
13139
13140 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
13141   int interceptor_call_count = 0;
13142   v8::Isolate* isolate = CcTest::isolate();
13143   v8::HandleScope scope(isolate);
13144   v8::Handle<v8::FunctionTemplate> fun_templ =
13145       v8::FunctionTemplate::New(isolate);
13146   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13147       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13148       v8::Signature::New(isolate, fun_templ));
13149   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13150   proto_templ->Set(v8_str("method"), method_templ);
13151   fun_templ->SetHiddenPrototype(true);
13152   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13153   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13154       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13155       v8::External::New(isolate, &interceptor_call_count)));
13156   LocalContext context;
13157   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13158   GenerateSomeGarbage();
13159   context->Global()->Set(v8_str("o"), fun->NewInstance());
13160   v8::TryCatch try_catch;
13161   CompileRun(
13162       "o.foo = 17;"
13163       "var receiver = {};"
13164       "receiver.__proto__ = o;"
13165       "var result = 0;"
13166       "var saved_result = 0;"
13167       "for (var i = 0; i < 100; i++) {"
13168       "  result = receiver.method(41);"
13169       "  if (i == 50) {"
13170       "    saved_result = result;"
13171       "    receiver = 333;"
13172       "  }"
13173       "}");
13174   CHECK(try_catch.HasCaught());
13175   // TODO(verwaest): Adjust message.
13176   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
13177            try_catch.Exception()->ToString(isolate));
13178   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13179   CHECK_GE(interceptor_call_count, 50);
13180 }
13181
13182
13183 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
13184   int interceptor_call_count = 0;
13185   v8::Isolate* isolate = CcTest::isolate();
13186   v8::HandleScope scope(isolate);
13187   v8::Handle<v8::FunctionTemplate> fun_templ =
13188       v8::FunctionTemplate::New(isolate);
13189   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13190       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13191       v8::Signature::New(isolate, fun_templ));
13192   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13193   proto_templ->Set(v8_str("method"), method_templ);
13194   fun_templ->SetHiddenPrototype(true);
13195   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13196   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13197       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13198       v8::External::New(isolate, &interceptor_call_count)));
13199   LocalContext context;
13200   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13201   GenerateSomeGarbage();
13202   context->Global()->Set(v8_str("o"), fun->NewInstance());
13203   v8::TryCatch try_catch;
13204   CompileRun(
13205       "o.foo = 17;"
13206       "var receiver = {};"
13207       "receiver.__proto__ = o;"
13208       "var result = 0;"
13209       "var saved_result = 0;"
13210       "for (var i = 0; i < 100; i++) {"
13211       "  result = receiver.method(41);"
13212       "  if (i == 50) {"
13213       "    saved_result = result;"
13214       "    receiver = {method: receiver.method};"
13215       "  }"
13216       "}");
13217   CHECK(try_catch.HasCaught());
13218   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
13219            try_catch.Exception()->ToString(isolate));
13220   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13221   CHECK_GE(interceptor_call_count, 50);
13222 }
13223
13224
13225 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
13226   v8::Isolate* isolate = CcTest::isolate();
13227   v8::HandleScope scope(isolate);
13228   v8::Handle<v8::FunctionTemplate> fun_templ =
13229       v8::FunctionTemplate::New(isolate);
13230   v8::Handle<v8::FunctionTemplate> method_templ =
13231       v8::FunctionTemplate::New(isolate,
13232                                 FastApiCallback_TrivialSignature,
13233                                 v8_str("method_data"),
13234                                 v8::Handle<v8::Signature>());
13235   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13236   proto_templ->Set(v8_str("method"), method_templ);
13237   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13238   USE(templ);
13239   LocalContext context;
13240   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13241   GenerateSomeGarbage();
13242   context->Global()->Set(v8_str("o"), fun->NewInstance());
13243   CompileRun(
13244       "var result = 0;"
13245       "for (var i = 0; i < 100; i++) {"
13246       "  result = o.method(41);"
13247       "}");
13248
13249   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13250 }
13251
13252
13253 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
13254   v8::Isolate* isolate = CcTest::isolate();
13255   v8::HandleScope scope(isolate);
13256   v8::Handle<v8::FunctionTemplate> fun_templ =
13257       v8::FunctionTemplate::New(isolate);
13258   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13259       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13260       v8::Signature::New(isolate, fun_templ));
13261   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13262   proto_templ->Set(v8_str("method"), method_templ);
13263   fun_templ->SetHiddenPrototype(true);
13264   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13265   CHECK(!templ.IsEmpty());
13266   LocalContext context;
13267   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13268   GenerateSomeGarbage();
13269   context->Global()->Set(v8_str("o"), fun->NewInstance());
13270   CompileRun(
13271       "o.foo = 17;"
13272       "var receiver = {};"
13273       "receiver.__proto__ = o;"
13274       "var result = 0;"
13275       "for (var i = 0; i < 100; i++) {"
13276       "  result = receiver.method(41);"
13277       "}");
13278
13279   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13280 }
13281
13282
13283 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
13284   v8::Isolate* isolate = CcTest::isolate();
13285   v8::HandleScope scope(isolate);
13286   v8::Handle<v8::FunctionTemplate> fun_templ =
13287       v8::FunctionTemplate::New(isolate);
13288   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13289       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13290       v8::Signature::New(isolate, fun_templ));
13291   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13292   proto_templ->Set(v8_str("method"), method_templ);
13293   fun_templ->SetHiddenPrototype(true);
13294   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13295   CHECK(!templ.IsEmpty());
13296   LocalContext context;
13297   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13298   GenerateSomeGarbage();
13299   context->Global()->Set(v8_str("o"), fun->NewInstance());
13300   CompileRun(
13301       "o.foo = 17;"
13302       "var receiver = {};"
13303       "receiver.__proto__ = o;"
13304       "var result = 0;"
13305       "var saved_result = 0;"
13306       "for (var i = 0; i < 100; i++) {"
13307       "  result = receiver.method(41);"
13308       "  if (i == 50) {"
13309       "    saved_result = result;"
13310       "    receiver = {method: function(x) { return x - 1 }};"
13311       "  }"
13312       "}");
13313   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13314   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13315 }
13316
13317
13318 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
13319   v8::Isolate* isolate = CcTest::isolate();
13320   v8::HandleScope scope(isolate);
13321   v8::Handle<v8::FunctionTemplate> fun_templ =
13322       v8::FunctionTemplate::New(isolate);
13323   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13324       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13325       v8::Signature::New(isolate, fun_templ));
13326   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13327   proto_templ->Set(v8_str("method"), method_templ);
13328   fun_templ->SetHiddenPrototype(true);
13329   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13330   CHECK(!templ.IsEmpty());
13331   LocalContext context;
13332   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13333   GenerateSomeGarbage();
13334   context->Global()->Set(v8_str("o"), fun->NewInstance());
13335   v8::TryCatch try_catch;
13336   CompileRun(
13337       "o.foo = 17;"
13338       "var receiver = {};"
13339       "receiver.__proto__ = o;"
13340       "var result = 0;"
13341       "var saved_result = 0;"
13342       "for (var i = 0; i < 100; i++) {"
13343       "  result = receiver.method(41);"
13344       "  if (i == 50) {"
13345       "    saved_result = result;"
13346       "    receiver = 333;"
13347       "  }"
13348       "}");
13349   CHECK(try_catch.HasCaught());
13350   // TODO(verwaest): Adjust message.
13351   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
13352            try_catch.Exception()->ToString(isolate));
13353   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13354 }
13355
13356
13357 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
13358   v8::Isolate* isolate = CcTest::isolate();
13359   v8::HandleScope scope(isolate);
13360   v8::Handle<v8::FunctionTemplate> fun_templ =
13361       v8::FunctionTemplate::New(isolate);
13362   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13363       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13364       v8::Signature::New(isolate, fun_templ));
13365   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13366   proto_templ->Set(v8_str("method"), method_templ);
13367   fun_templ->SetHiddenPrototype(true);
13368   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13369   CHECK(!templ.IsEmpty());
13370   LocalContext context;
13371   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13372   GenerateSomeGarbage();
13373   context->Global()->Set(v8_str("o"), fun->NewInstance());
13374   v8::TryCatch try_catch;
13375   CompileRun(
13376       "o.foo = 17;"
13377       "var receiver = {};"
13378       "receiver.__proto__ = o;"
13379       "var result = 0;"
13380       "var saved_result = 0;"
13381       "for (var i = 0; i < 100; i++) {"
13382       "  result = receiver.method(41);"
13383       "  if (i == 50) {"
13384       "    saved_result = result;"
13385       "    receiver = Object.create(receiver);"
13386       "  }"
13387       "}");
13388   CHECK(try_catch.HasCaught());
13389   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
13390            try_catch.Exception()->ToString(isolate));
13391   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13392 }
13393
13394
13395 v8::Handle<Value> keyed_call_ic_function;
13396
13397 static void InterceptorKeyedCallICGetter(
13398     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13399   ApiTestFuzzer::Fuzz();
13400   if (v8_str("x")->Equals(name)) {
13401     info.GetReturnValue().Set(keyed_call_ic_function);
13402   }
13403 }
13404
13405
13406 // Test the case when we stored cacheable lookup into
13407 // a stub, but the function name changed (to another cacheable function).
13408 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
13409   v8::Isolate* isolate = CcTest::isolate();
13410   v8::HandleScope scope(isolate);
13411   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13412   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13413   LocalContext context;
13414   context->Global()->Set(v8_str("o"), templ->NewInstance());
13415   CompileRun(
13416     "proto = new Object();"
13417     "proto.y = function(x) { return x + 1; };"
13418     "proto.z = function(x) { return x - 1; };"
13419     "o.__proto__ = proto;"
13420     "var result = 0;"
13421     "var method = 'y';"
13422     "for (var i = 0; i < 10; i++) {"
13423     "  if (i == 5) { method = 'z'; };"
13424     "  result += o[method](41);"
13425     "}");
13426   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13427 }
13428
13429
13430 // Test the case when we stored cacheable lookup into
13431 // a stub, but the function name changed (and the new function is present
13432 // both before and after the interceptor in the prototype chain).
13433 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
13434   v8::Isolate* isolate = CcTest::isolate();
13435   v8::HandleScope scope(isolate);
13436   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13437   templ->SetHandler(
13438       v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
13439   LocalContext context;
13440   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
13441   keyed_call_ic_function =
13442       v8_compile("function f(x) { return x - 1; }; f")->Run();
13443   CompileRun(
13444     "o = new Object();"
13445     "proto2 = new Object();"
13446     "o.y = function(x) { return x + 1; };"
13447     "proto2.y = function(x) { return x + 2; };"
13448     "o.__proto__ = proto1;"
13449     "proto1.__proto__ = proto2;"
13450     "var result = 0;"
13451     "var method = 'x';"
13452     "for (var i = 0; i < 10; i++) {"
13453     "  if (i == 5) { method = 'y'; };"
13454     "  result += o[method](41);"
13455     "}");
13456   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13457 }
13458
13459
13460 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
13461 // on the global object.
13462 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
13463   v8::Isolate* isolate = CcTest::isolate();
13464   v8::HandleScope scope(isolate);
13465   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13466   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13467   LocalContext context;
13468   context->Global()->Set(v8_str("o"), templ->NewInstance());
13469   CompileRun(
13470     "function inc(x) { return x + 1; };"
13471     "inc(1);"
13472     "function dec(x) { return x - 1; };"
13473     "dec(1);"
13474     "o.__proto__ = this;"
13475     "this.__proto__.x = inc;"
13476     "this.__proto__.y = dec;"
13477     "var result = 0;"
13478     "var method = 'x';"
13479     "for (var i = 0; i < 10; i++) {"
13480     "  if (i == 5) { method = 'y'; };"
13481     "  result += o[method](41);"
13482     "}");
13483   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13484 }
13485
13486
13487 // Test the case when actual function to call sits on global object.
13488 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
13489   v8::Isolate* isolate = CcTest::isolate();
13490   v8::HandleScope scope(isolate);
13491   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13492   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13493   LocalContext context;
13494   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13495
13496   CompileRun(
13497     "function len(x) { return x.length; };"
13498     "o.__proto__ = this;"
13499     "var m = 'parseFloat';"
13500     "var result = 0;"
13501     "for (var i = 0; i < 10; i++) {"
13502     "  if (i == 5) {"
13503     "    m = 'len';"
13504     "    saved_result = result;"
13505     "  };"
13506     "  result = o[m]('239');"
13507     "}");
13508   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
13509   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13510 }
13511
13512
13513 // Test the map transition before the interceptor.
13514 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
13515   v8::Isolate* isolate = CcTest::isolate();
13516   v8::HandleScope scope(isolate);
13517   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13518   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13519   LocalContext context;
13520   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
13521
13522   CompileRun(
13523     "var o = new Object();"
13524     "o.__proto__ = proto;"
13525     "o.method = function(x) { return x + 1; };"
13526     "var m = 'method';"
13527     "var result = 0;"
13528     "for (var i = 0; i < 10; i++) {"
13529     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
13530     "  result += o[m](41);"
13531     "}");
13532   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13533 }
13534
13535
13536 // Test the map transition after the interceptor.
13537 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
13538   v8::Isolate* isolate = CcTest::isolate();
13539   v8::HandleScope scope(isolate);
13540   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13541   templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13542   LocalContext context;
13543   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13544
13545   CompileRun(
13546     "var proto = new Object();"
13547     "o.__proto__ = proto;"
13548     "proto.method = function(x) { return x + 1; };"
13549     "var m = 'method';"
13550     "var result = 0;"
13551     "for (var i = 0; i < 10; i++) {"
13552     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
13553     "  result += o[m](41);"
13554     "}");
13555   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13556 }
13557
13558
13559 static int interceptor_call_count = 0;
13560
13561 static void InterceptorICRefErrorGetter(
13562     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13563   ApiTestFuzzer::Fuzz();
13564   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
13565     info.GetReturnValue().Set(call_ic_function2);
13566   }
13567 }
13568
13569
13570 // This test should hit load and call ICs for the interceptor case.
13571 // Once in a while, the interceptor will reply that a property was not
13572 // found in which case we should get a reference error.
13573 THREADED_TEST(InterceptorICReferenceErrors) {
13574   v8::Isolate* isolate = CcTest::isolate();
13575   v8::HandleScope scope(isolate);
13576   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13577   templ->SetHandler(
13578       v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
13579   LocalContext context(0, templ, v8::Handle<Value>());
13580   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13581   v8::Handle<Value> value = CompileRun(
13582     "function f() {"
13583     "  for (var i = 0; i < 1000; i++) {"
13584     "    try { x; } catch(e) { return true; }"
13585     "  }"
13586     "  return false;"
13587     "};"
13588     "f();");
13589   CHECK_EQ(true, value->BooleanValue());
13590   interceptor_call_count = 0;
13591   value = CompileRun(
13592     "function g() {"
13593     "  for (var i = 0; i < 1000; i++) {"
13594     "    try { x(42); } catch(e) { return true; }"
13595     "  }"
13596     "  return false;"
13597     "};"
13598     "g();");
13599   CHECK_EQ(true, value->BooleanValue());
13600 }
13601
13602
13603 static int interceptor_ic_exception_get_count = 0;
13604
13605 static void InterceptorICExceptionGetter(
13606     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13607   ApiTestFuzzer::Fuzz();
13608   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
13609     info.GetReturnValue().Set(call_ic_function3);
13610   }
13611   if (interceptor_ic_exception_get_count == 20) {
13612     info.GetIsolate()->ThrowException(v8_num(42));
13613     return;
13614   }
13615 }
13616
13617
13618 // Test interceptor load/call IC where the interceptor throws an
13619 // exception once in a while.
13620 THREADED_TEST(InterceptorICGetterExceptions) {
13621   interceptor_ic_exception_get_count = 0;
13622   v8::Isolate* isolate = CcTest::isolate();
13623   v8::HandleScope scope(isolate);
13624   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13625   templ->SetHandler(
13626       v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
13627   LocalContext context(0, templ, v8::Handle<Value>());
13628   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13629   v8::Handle<Value> value = CompileRun(
13630     "function f() {"
13631     "  for (var i = 0; i < 100; i++) {"
13632     "    try { x; } catch(e) { return true; }"
13633     "  }"
13634     "  return false;"
13635     "};"
13636     "f();");
13637   CHECK_EQ(true, value->BooleanValue());
13638   interceptor_ic_exception_get_count = 0;
13639   value = CompileRun(
13640     "function f() {"
13641     "  for (var i = 0; i < 100; i++) {"
13642     "    try { x(42); } catch(e) { return true; }"
13643     "  }"
13644     "  return false;"
13645     "};"
13646     "f();");
13647   CHECK_EQ(true, value->BooleanValue());
13648 }
13649
13650
13651 static int interceptor_ic_exception_set_count = 0;
13652
13653 static void InterceptorICExceptionSetter(
13654     Local<Name> key, Local<Value> value,
13655     const v8::PropertyCallbackInfo<v8::Value>& info) {
13656   ApiTestFuzzer::Fuzz();
13657   if (++interceptor_ic_exception_set_count > 20) {
13658     info.GetIsolate()->ThrowException(v8_num(42));
13659   }
13660 }
13661
13662
13663 // Test interceptor store IC where the interceptor throws an exception
13664 // once in a while.
13665 THREADED_TEST(InterceptorICSetterExceptions) {
13666   interceptor_ic_exception_set_count = 0;
13667   v8::Isolate* isolate = CcTest::isolate();
13668   v8::HandleScope scope(isolate);
13669   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13670   templ->SetHandler(
13671       v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
13672   LocalContext context(0, templ, v8::Handle<Value>());
13673   v8::Handle<Value> value = CompileRun(
13674     "function f() {"
13675     "  for (var i = 0; i < 100; i++) {"
13676     "    try { x = 42; } catch(e) { return true; }"
13677     "  }"
13678     "  return false;"
13679     "};"
13680     "f();");
13681   CHECK_EQ(true, value->BooleanValue());
13682 }
13683
13684
13685 // Test that we ignore null interceptors.
13686 THREADED_TEST(NullNamedInterceptor) {
13687   v8::Isolate* isolate = CcTest::isolate();
13688   v8::HandleScope scope(isolate);
13689   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13690   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13691       static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
13692   LocalContext context;
13693   templ->Set(CcTest::isolate(), "x", v8_num(42));
13694   v8::Handle<v8::Object> obj = templ->NewInstance();
13695   context->Global()->Set(v8_str("obj"), obj);
13696   v8::Handle<Value> value = CompileRun("obj.x");
13697   CHECK(value->IsInt32());
13698   CHECK_EQ(42, value->Int32Value());
13699 }
13700
13701
13702 // Test that we ignore null interceptors.
13703 THREADED_TEST(NullIndexedInterceptor) {
13704   v8::Isolate* isolate = CcTest::isolate();
13705   v8::HandleScope scope(isolate);
13706   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13707   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
13708       static_cast<v8::IndexedPropertyGetterCallback>(0)));
13709   LocalContext context;
13710   templ->Set(CcTest::isolate(), "42", v8_num(42));
13711   v8::Handle<v8::Object> obj = templ->NewInstance();
13712   context->Global()->Set(v8_str("obj"), obj);
13713   v8::Handle<Value> value = CompileRun("obj[42]");
13714   CHECK(value->IsInt32());
13715   CHECK_EQ(42, value->Int32Value());
13716 }
13717
13718
13719 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13720   v8::Isolate* isolate = CcTest::isolate();
13721   v8::HandleScope scope(isolate);
13722   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13723   templ->InstanceTemplate()->SetHandler(
13724       v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
13725   LocalContext env;
13726   env->Global()->Set(v8_str("obj"),
13727                      templ->GetFunction()->NewInstance());
13728   ExpectTrue("obj.x === 42");
13729   ExpectTrue("!obj.propertyIsEnumerable('x')");
13730 }
13731
13732
13733 static void ThrowingGetter(Local<String> name,
13734                            const v8::PropertyCallbackInfo<v8::Value>& info) {
13735   ApiTestFuzzer::Fuzz();
13736   info.GetIsolate()->ThrowException(Handle<Value>());
13737   info.GetReturnValue().SetUndefined();
13738 }
13739
13740
13741 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13742   LocalContext context;
13743   HandleScope scope(context->GetIsolate());
13744
13745   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13746   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13747   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13748
13749   Local<Object> instance = templ->GetFunction()->NewInstance();
13750
13751   Local<Object> another = Object::New(context->GetIsolate());
13752   another->SetPrototype(instance);
13753
13754   Local<Object> with_js_getter = CompileRun(
13755       "o = {};\n"
13756       "o.__defineGetter__('f', function() { throw undefined; });\n"
13757       "o\n").As<Object>();
13758   CHECK(!with_js_getter.IsEmpty());
13759
13760   TryCatch try_catch;
13761
13762   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13763   CHECK(try_catch.HasCaught());
13764   try_catch.Reset();
13765   CHECK(result.IsEmpty());
13766
13767   result = another->GetRealNamedProperty(v8_str("f"));
13768   CHECK(try_catch.HasCaught());
13769   try_catch.Reset();
13770   CHECK(result.IsEmpty());
13771
13772   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13773   CHECK(try_catch.HasCaught());
13774   try_catch.Reset();
13775   CHECK(result.IsEmpty());
13776
13777   result = another->Get(v8_str("f"));
13778   CHECK(try_catch.HasCaught());
13779   try_catch.Reset();
13780   CHECK(result.IsEmpty());
13781
13782   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13783   CHECK(try_catch.HasCaught());
13784   try_catch.Reset();
13785   CHECK(result.IsEmpty());
13786
13787   result = with_js_getter->Get(v8_str("f"));
13788   CHECK(try_catch.HasCaught());
13789   try_catch.Reset();
13790   CHECK(result.IsEmpty());
13791 }
13792
13793
13794 static void ThrowingCallbackWithTryCatch(
13795     const v8::FunctionCallbackInfo<v8::Value>& args) {
13796   TryCatch try_catch;
13797   // Verboseness is important: it triggers message delivery which can call into
13798   // external code.
13799   try_catch.SetVerbose(true);
13800   CompileRun("throw 'from JS';");
13801   CHECK(try_catch.HasCaught());
13802   CHECK(!CcTest::i_isolate()->has_pending_exception());
13803   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13804 }
13805
13806
13807 static int call_depth;
13808
13809
13810 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13811   TryCatch try_catch;
13812 }
13813
13814
13815 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13816   if (--call_depth) CompileRun("throw 'ThrowInJS';");
13817 }
13818
13819
13820 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13821   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13822 }
13823
13824
13825 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13826   Handle<String> errorMessageString = message->Get();
13827   CHECK(!errorMessageString.IsEmpty());
13828   message->GetStackTrace();
13829   message->GetScriptOrigin().ResourceName();
13830 }
13831
13832
13833 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13834   LocalContext context;
13835   v8::Isolate* isolate = context->GetIsolate();
13836   HandleScope scope(isolate);
13837
13838   Local<Function> func =
13839       FunctionTemplate::New(isolate,
13840                             ThrowingCallbackWithTryCatch)->GetFunction();
13841   context->Global()->Set(v8_str("func"), func);
13842
13843   MessageCallback callbacks[] =
13844       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13845   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13846     MessageCallback callback = callbacks[i];
13847     if (callback != NULL) {
13848       V8::AddMessageListener(callback);
13849     }
13850     // Some small number to control number of times message handler should
13851     // throw an exception.
13852     call_depth = 5;
13853     ExpectFalse(
13854         "var thrown = false;\n"
13855         "try { func(); } catch(e) { thrown = true; }\n"
13856         "thrown\n");
13857     if (callback != NULL) {
13858       V8::RemoveMessageListeners(callback);
13859     }
13860   }
13861 }
13862
13863
13864 static void ParentGetter(Local<String> name,
13865                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13866   ApiTestFuzzer::Fuzz();
13867   info.GetReturnValue().Set(v8_num(1));
13868 }
13869
13870
13871 static void ChildGetter(Local<String> name,
13872                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13873   ApiTestFuzzer::Fuzz();
13874   info.GetReturnValue().Set(v8_num(42));
13875 }
13876
13877
13878 THREADED_TEST(Overriding) {
13879   LocalContext context;
13880   v8::Isolate* isolate = context->GetIsolate();
13881   v8::HandleScope scope(isolate);
13882
13883   // Parent template.
13884   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13885   Local<ObjectTemplate> parent_instance_templ =
13886       parent_templ->InstanceTemplate();
13887   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13888
13889   // Template that inherits from the parent template.
13890   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13891   Local<ObjectTemplate> child_instance_templ =
13892       child_templ->InstanceTemplate();
13893   child_templ->Inherit(parent_templ);
13894   // Override 'f'.  The child version of 'f' should get called for child
13895   // instances.
13896   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13897   // Add 'g' twice.  The 'g' added last should get called for instances.
13898   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13899   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13900
13901   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13902   // so 'h' can be shadowed on the instance object.
13903   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13904   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13905       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13906
13907   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13908   // but the attribute does not have effect because it is duplicated with
13909   // NULL setter.
13910   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13911       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13912
13913
13914
13915   // Instantiate the child template.
13916   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13917
13918   // Check that the child function overrides the parent one.
13919   context->Global()->Set(v8_str("o"), instance);
13920   Local<Value> value = v8_compile("o.f")->Run();
13921   // Check that the 'g' that was added last is hit.
13922   CHECK_EQ(42, value->Int32Value());
13923   value = v8_compile("o.g")->Run();
13924   CHECK_EQ(42, value->Int32Value());
13925
13926   // Check that 'h' cannot be shadowed.
13927   value = v8_compile("o.h = 3; o.h")->Run();
13928   CHECK_EQ(1, value->Int32Value());
13929
13930   // Check that 'i' cannot be shadowed or changed.
13931   value = v8_compile("o.i = 3; o.i")->Run();
13932   CHECK_EQ(42, value->Int32Value());
13933 }
13934
13935
13936 static void IsConstructHandler(
13937     const v8::FunctionCallbackInfo<v8::Value>& args) {
13938   ApiTestFuzzer::Fuzz();
13939   args.GetReturnValue().Set(args.IsConstructCall());
13940 }
13941
13942
13943 THREADED_TEST(IsConstructCall) {
13944   v8::Isolate* isolate = CcTest::isolate();
13945   v8::HandleScope scope(isolate);
13946
13947   // Function template with call handler.
13948   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13949   templ->SetCallHandler(IsConstructHandler);
13950
13951   LocalContext context;
13952
13953   context->Global()->Set(v8_str("f"), templ->GetFunction());
13954   Local<Value> value = v8_compile("f()")->Run();
13955   CHECK(!value->BooleanValue());
13956   value = v8_compile("new f()")->Run();
13957   CHECK(value->BooleanValue());
13958 }
13959
13960
13961 THREADED_TEST(ObjectProtoToString) {
13962   v8::Isolate* isolate = CcTest::isolate();
13963   v8::HandleScope scope(isolate);
13964   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13965   templ->SetClassName(v8_str("MyClass"));
13966
13967   LocalContext context;
13968
13969   Local<String> customized_tostring = v8_str("customized toString");
13970
13971   // Replace Object.prototype.toString
13972   v8_compile("Object.prototype.toString = function() {"
13973                   "  return 'customized toString';"
13974                   "}")->Run();
13975
13976   // Normal ToString call should call replaced Object.prototype.toString
13977   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13978   Local<String> value = instance->ToString(isolate);
13979   CHECK(value->IsString() && value->Equals(customized_tostring));
13980
13981   // ObjectProtoToString should not call replace toString function.
13982   value = instance->ObjectProtoToString();
13983   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13984
13985   // Check global
13986   value = context->Global()->ObjectProtoToString();
13987   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13988
13989   // Check ordinary object
13990   Local<Value> object = v8_compile("new Object()")->Run();
13991   value = object.As<v8::Object>()->ObjectProtoToString();
13992   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13993 }
13994
13995
13996 TEST(ObjectProtoToStringES6) {
13997   // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
13998   i::FLAG_harmony_tostring = true;
13999   LocalContext context;
14000   v8::Isolate* isolate = CcTest::isolate();
14001   v8::HandleScope scope(isolate);
14002   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
14003   templ->SetClassName(v8_str("MyClass"));
14004
14005   Local<String> customized_tostring = v8_str("customized toString");
14006
14007   // Replace Object.prototype.toString
14008   CompileRun(
14009       "Object.prototype.toString = function() {"
14010       "  return 'customized toString';"
14011       "}");
14012
14013   // Normal ToString call should call replaced Object.prototype.toString
14014   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
14015   Local<String> value = instance->ToString(isolate);
14016   CHECK(value->IsString() && value->Equals(customized_tostring));
14017
14018   // ObjectProtoToString should not call replace toString function.
14019   value = instance->ObjectProtoToString();
14020   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
14021
14022   // Check global
14023   value = context->Global()->ObjectProtoToString();
14024   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
14025
14026   // Check ordinary object
14027   Local<Value> object = CompileRun("new Object()");
14028   value = object.As<v8::Object>()->ObjectProtoToString();
14029   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
14030
14031   // Check that ES6 semantics using @@toStringTag work
14032   Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
14033
14034 #define TEST_TOSTRINGTAG(type, tag, expected)                \
14035   do {                                                       \
14036     object = CompileRun("new " #type "()");                  \
14037     object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
14038     value = object.As<v8::Object>()->ObjectProtoToString();  \
14039     CHECK(value->IsString() &&                               \
14040           value->Equals(v8_str("[object " #expected "]")));  \
14041   } while (0)
14042
14043   TEST_TOSTRINGTAG(Array, Object, Object);
14044   TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
14045   TEST_TOSTRINGTAG(Object, Array, ~Array);
14046   TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
14047   TEST_TOSTRINGTAG(Object, Date, ~Date);
14048   TEST_TOSTRINGTAG(Object, Error, ~Error);
14049   TEST_TOSTRINGTAG(Object, Function, ~Function);
14050   TEST_TOSTRINGTAG(Object, Number, ~Number);
14051   TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
14052   TEST_TOSTRINGTAG(Object, String, ~String);
14053   TEST_TOSTRINGTAG(Object, Foo, Foo);
14054
14055 #undef TEST_TOSTRINGTAG
14056
14057   // @@toStringTag getter throws
14058   Local<Value> obj = v8::Object::New(isolate);
14059   obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
14060   {
14061     TryCatch try_catch;
14062     value = obj.As<v8::Object>()->ObjectProtoToString();
14063     CHECK(value.IsEmpty());
14064     CHECK(try_catch.HasCaught());
14065   }
14066
14067   // @@toStringTag getter does not throw
14068   obj = v8::Object::New(isolate);
14069   obj.As<v8::Object>()->SetAccessor(
14070       toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
14071   {
14072     TryCatch try_catch;
14073     value = obj.As<v8::Object>()->ObjectProtoToString();
14074     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14075     CHECK(!try_catch.HasCaught());
14076   }
14077
14078   // JS @@toStringTag value
14079   obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
14080   {
14081     TryCatch try_catch;
14082     value = obj.As<v8::Object>()->ObjectProtoToString();
14083     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14084     CHECK(!try_catch.HasCaught());
14085   }
14086
14087   // JS @@toStringTag getter throws
14088   obj = CompileRun(
14089       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
14090       "  get: function() { throw 'Test'; }"
14091       "}); obj");
14092   {
14093     TryCatch try_catch;
14094     value = obj.As<v8::Object>()->ObjectProtoToString();
14095     CHECK(value.IsEmpty());
14096     CHECK(try_catch.HasCaught());
14097   }
14098
14099   // JS @@toStringTag getter does not throw
14100   obj = CompileRun(
14101       "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
14102       "  get: function() { return 'Test'; }"
14103       "}); obj");
14104   {
14105     TryCatch try_catch;
14106     value = obj.As<v8::Object>()->ObjectProtoToString();
14107     CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14108     CHECK(!try_catch.HasCaught());
14109   }
14110 }
14111
14112
14113 THREADED_TEST(ObjectGetConstructorName) {
14114   v8::Isolate* isolate = CcTest::isolate();
14115   LocalContext context;
14116   v8::HandleScope scope(isolate);
14117   v8_compile("function Parent() {};"
14118              "function Child() {};"
14119              "Child.prototype = new Parent();"
14120              "var outer = { inner: function() { } };"
14121              "var p = new Parent();"
14122              "var c = new Child();"
14123              "var x = new outer.inner();")->Run();
14124
14125   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
14126   CHECK(p->IsObject() &&
14127         p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
14128
14129   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
14130   CHECK(c->IsObject() &&
14131         c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
14132
14133   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
14134   CHECK(x->IsObject() &&
14135         x->ToObject(isolate)->GetConstructorName()->Equals(
14136             v8_str("outer.inner")));
14137 }
14138
14139
14140 bool ApiTestFuzzer::fuzzing_ = false;
14141 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
14142 int ApiTestFuzzer::active_tests_;
14143 int ApiTestFuzzer::tests_being_run_;
14144 int ApiTestFuzzer::current_;
14145
14146
14147 // We are in a callback and want to switch to another thread (if we
14148 // are currently running the thread fuzzing test).
14149 void ApiTestFuzzer::Fuzz() {
14150   if (!fuzzing_) return;
14151   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
14152   test->ContextSwitch();
14153 }
14154
14155
14156 // Let the next thread go.  Since it is also waiting on the V8 lock it may
14157 // not start immediately.
14158 bool ApiTestFuzzer::NextThread() {
14159   int test_position = GetNextTestNumber();
14160   const char* test_name = RegisterThreadedTest::nth(current_)->name();
14161   if (test_position == current_) {
14162     if (kLogThreading)
14163       printf("Stay with %s\n", test_name);
14164     return false;
14165   }
14166   if (kLogThreading) {
14167     printf("Switch from %s to %s\n",
14168            test_name,
14169            RegisterThreadedTest::nth(test_position)->name());
14170   }
14171   current_ = test_position;
14172   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
14173   return true;
14174 }
14175
14176
14177 void ApiTestFuzzer::Run() {
14178   // When it is our turn...
14179   gate_.Wait();
14180   {
14181     // ... get the V8 lock and start running the test.
14182     v8::Locker locker(CcTest::isolate());
14183     CallTest();
14184   }
14185   // This test finished.
14186   active_ = false;
14187   active_tests_--;
14188   // If it was the last then signal that fact.
14189   if (active_tests_ == 0) {
14190     all_tests_done_.Signal();
14191   } else {
14192     // Otherwise select a new test and start that.
14193     NextThread();
14194   }
14195 }
14196
14197
14198 static unsigned linear_congruential_generator;
14199
14200
14201 void ApiTestFuzzer::SetUp(PartOfTest part) {
14202   linear_congruential_generator = i::FLAG_testing_prng_seed;
14203   fuzzing_ = true;
14204   int count = RegisterThreadedTest::count();
14205   int start =  count * part / (LAST_PART + 1);
14206   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
14207   active_tests_ = tests_being_run_ = end - start + 1;
14208   for (int i = 0; i < tests_being_run_; i++) {
14209     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
14210   }
14211   for (int i = 0; i < active_tests_; i++) {
14212     RegisterThreadedTest::nth(i)->fuzzer_->Start();
14213   }
14214 }
14215
14216
14217 static void CallTestNumber(int test_number) {
14218   (RegisterThreadedTest::nth(test_number)->callback())();
14219 }
14220
14221
14222 void ApiTestFuzzer::RunAllTests() {
14223   // Set off the first test.
14224   current_ = -1;
14225   NextThread();
14226   // Wait till they are all done.
14227   all_tests_done_.Wait();
14228 }
14229
14230
14231 int ApiTestFuzzer::GetNextTestNumber() {
14232   int next_test;
14233   do {
14234     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
14235     linear_congruential_generator *= 1664525u;
14236     linear_congruential_generator += 1013904223u;
14237   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
14238   return next_test;
14239 }
14240
14241
14242 void ApiTestFuzzer::ContextSwitch() {
14243   // If the new thread is the same as the current thread there is nothing to do.
14244   if (NextThread()) {
14245     // Now it can start.
14246     v8::Unlocker unlocker(CcTest::isolate());
14247     // Wait till someone starts us again.
14248     gate_.Wait();
14249     // And we're off.
14250   }
14251 }
14252
14253
14254 void ApiTestFuzzer::TearDown() {
14255   fuzzing_ = false;
14256   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
14257     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
14258     if (fuzzer != NULL) fuzzer->Join();
14259   }
14260 }
14261
14262
14263 // Lets not be needlessly self-referential.
14264 TEST(Threading1) {
14265   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
14266   ApiTestFuzzer::RunAllTests();
14267   ApiTestFuzzer::TearDown();
14268 }
14269
14270
14271 TEST(Threading2) {
14272   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
14273   ApiTestFuzzer::RunAllTests();
14274   ApiTestFuzzer::TearDown();
14275 }
14276
14277
14278 TEST(Threading3) {
14279   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
14280   ApiTestFuzzer::RunAllTests();
14281   ApiTestFuzzer::TearDown();
14282 }
14283
14284
14285 TEST(Threading4) {
14286   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
14287   ApiTestFuzzer::RunAllTests();
14288   ApiTestFuzzer::TearDown();
14289 }
14290
14291
14292 void ApiTestFuzzer::CallTest() {
14293   v8::Isolate::Scope scope(CcTest::isolate());
14294   if (kLogThreading)
14295     printf("Start test %d\n", test_number_);
14296   CallTestNumber(test_number_);
14297   if (kLogThreading)
14298     printf("End test %d\n", test_number_);
14299 }
14300
14301
14302 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
14303   v8::Isolate* isolate = args.GetIsolate();
14304   CHECK(v8::Locker::IsLocked(isolate));
14305   ApiTestFuzzer::Fuzz();
14306   v8::Unlocker unlocker(isolate);
14307   const char* code = "throw 7;";
14308   {
14309     v8::Locker nested_locker(isolate);
14310     v8::HandleScope scope(isolate);
14311     v8::Handle<Value> exception;
14312     { v8::TryCatch try_catch;
14313       v8::Handle<Value> value = CompileRun(code);
14314       CHECK(value.IsEmpty());
14315       CHECK(try_catch.HasCaught());
14316       // Make sure to wrap the exception in a new handle because
14317       // the handle returned from the TryCatch is destroyed
14318       // when the TryCatch is destroyed.
14319       exception = Local<Value>::New(isolate, try_catch.Exception());
14320     }
14321     args.GetIsolate()->ThrowException(exception);
14322   }
14323 }
14324
14325
14326 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
14327   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14328   ApiTestFuzzer::Fuzz();
14329   v8::Unlocker unlocker(CcTest::isolate());
14330   const char* code = "throw 7;";
14331   {
14332     v8::Locker nested_locker(CcTest::isolate());
14333     v8::HandleScope scope(args.GetIsolate());
14334     v8::Handle<Value> value = CompileRun(code);
14335     CHECK(value.IsEmpty());
14336     args.GetReturnValue().Set(v8_str("foo"));
14337   }
14338 }
14339
14340
14341 // These are locking tests that don't need to be run again
14342 // as part of the locking aggregation tests.
14343 TEST(NestedLockers) {
14344   v8::Isolate* isolate = CcTest::isolate();
14345   v8::Locker locker(isolate);
14346   CHECK(v8::Locker::IsLocked(isolate));
14347   LocalContext env;
14348   v8::HandleScope scope(env->GetIsolate());
14349   Local<v8::FunctionTemplate> fun_templ =
14350       v8::FunctionTemplate::New(isolate, ThrowInJS);
14351   Local<Function> fun = fun_templ->GetFunction();
14352   env->Global()->Set(v8_str("throw_in_js"), fun);
14353   Local<Script> script = v8_compile("(function () {"
14354                                     "  try {"
14355                                     "    throw_in_js();"
14356                                     "    return 42;"
14357                                     "  } catch (e) {"
14358                                     "    return e * 13;"
14359                                     "  }"
14360                                     "})();");
14361   CHECK_EQ(91, script->Run()->Int32Value());
14362 }
14363
14364
14365 // These are locking tests that don't need to be run again
14366 // as part of the locking aggregation tests.
14367 TEST(NestedLockersNoTryCatch) {
14368   v8::Locker locker(CcTest::isolate());
14369   LocalContext env;
14370   v8::HandleScope scope(env->GetIsolate());
14371   Local<v8::FunctionTemplate> fun_templ =
14372       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
14373   Local<Function> fun = fun_templ->GetFunction();
14374   env->Global()->Set(v8_str("throw_in_js"), fun);
14375   Local<Script> script = v8_compile("(function () {"
14376                                     "  try {"
14377                                     "    throw_in_js();"
14378                                     "    return 42;"
14379                                     "  } catch (e) {"
14380                                     "    return e * 13;"
14381                                     "  }"
14382                                     "})();");
14383   CHECK_EQ(91, script->Run()->Int32Value());
14384 }
14385
14386
14387 THREADED_TEST(RecursiveLocking) {
14388   v8::Locker locker(CcTest::isolate());
14389   {
14390     v8::Locker locker2(CcTest::isolate());
14391     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14392   }
14393 }
14394
14395
14396 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
14397   ApiTestFuzzer::Fuzz();
14398   v8::Unlocker unlocker(CcTest::isolate());
14399 }
14400
14401
14402 THREADED_TEST(LockUnlockLock) {
14403   {
14404     v8::Locker locker(CcTest::isolate());
14405     v8::HandleScope scope(CcTest::isolate());
14406     LocalContext env;
14407     Local<v8::FunctionTemplate> fun_templ =
14408         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14409     Local<Function> fun = fun_templ->GetFunction();
14410     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14411     Local<Script> script = v8_compile("(function () {"
14412                                       "  unlock_for_a_moment();"
14413                                       "  return 42;"
14414                                       "})();");
14415     CHECK_EQ(42, script->Run()->Int32Value());
14416   }
14417   {
14418     v8::Locker locker(CcTest::isolate());
14419     v8::HandleScope scope(CcTest::isolate());
14420     LocalContext env;
14421     Local<v8::FunctionTemplate> fun_templ =
14422         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14423     Local<Function> fun = fun_templ->GetFunction();
14424     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14425     Local<Script> script = v8_compile("(function () {"
14426                                       "  unlock_for_a_moment();"
14427                                       "  return 42;"
14428                                       "})();");
14429     CHECK_EQ(42, script->Run()->Int32Value());
14430   }
14431 }
14432
14433
14434 static int GetGlobalObjectsCount() {
14435   int count = 0;
14436   i::HeapIterator it(CcTest::heap());
14437   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
14438     if (object->IsJSGlobalObject()) count++;
14439   return count;
14440 }
14441
14442
14443 static void CheckSurvivingGlobalObjectsCount(int expected) {
14444   // We need to collect all garbage twice to be sure that everything
14445   // has been collected.  This is because inline caches are cleared in
14446   // the first garbage collection but some of the maps have already
14447   // been marked at that point.  Therefore some of the maps are not
14448   // collected until the second garbage collection.
14449   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14450   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
14451   int count = GetGlobalObjectsCount();
14452 #ifdef DEBUG
14453   if (count != expected) CcTest::heap()->TracePathToGlobal();
14454 #endif
14455   CHECK_EQ(expected, count);
14456 }
14457
14458
14459 TEST(DontLeakGlobalObjects) {
14460   // Regression test for issues 1139850 and 1174891.
14461
14462   i::FLAG_expose_gc = true;
14463   v8::V8::Initialize();
14464
14465   for (int i = 0; i < 5; i++) {
14466     { v8::HandleScope scope(CcTest::isolate());
14467       LocalContext context;
14468     }
14469     CcTest::isolate()->ContextDisposedNotification();
14470     CheckSurvivingGlobalObjectsCount(0);
14471
14472     { v8::HandleScope scope(CcTest::isolate());
14473       LocalContext context;
14474       v8_compile("Date")->Run();
14475     }
14476     CcTest::isolate()->ContextDisposedNotification();
14477     CheckSurvivingGlobalObjectsCount(0);
14478
14479     { v8::HandleScope scope(CcTest::isolate());
14480       LocalContext context;
14481       v8_compile("/aaa/")->Run();
14482     }
14483     CcTest::isolate()->ContextDisposedNotification();
14484     CheckSurvivingGlobalObjectsCount(0);
14485
14486     { v8::HandleScope scope(CcTest::isolate());
14487       const char* extension_list[] = { "v8/gc" };
14488       v8::ExtensionConfiguration extensions(1, extension_list);
14489       LocalContext context(&extensions);
14490       v8_compile("gc();")->Run();
14491     }
14492     CcTest::isolate()->ContextDisposedNotification();
14493     CheckSurvivingGlobalObjectsCount(0);
14494   }
14495 }
14496
14497
14498 TEST(CopyablePersistent) {
14499   LocalContext context;
14500   v8::Isolate* isolate = context->GetIsolate();
14501   i::GlobalHandles* globals =
14502       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14503   int initial_handles = globals->global_handles_count();
14504   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14505       CopyableObject;
14506   {
14507     CopyableObject handle1;
14508     {
14509       v8::HandleScope scope(isolate);
14510       handle1.Reset(isolate, v8::Object::New(isolate));
14511     }
14512     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14513     CopyableObject  handle2;
14514     handle2 = handle1;
14515     CHECK(handle1 == handle2);
14516     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14517     CopyableObject handle3(handle2);
14518     CHECK(handle1 == handle3);
14519     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14520   }
14521   // Verify autodispose
14522   CHECK_EQ(initial_handles, globals->global_handles_count());
14523 }
14524
14525
14526 static void WeakApiCallback(
14527     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
14528   Local<Value> value = data.GetValue()->Get(v8_str("key"));
14529   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
14530   data.GetParameter()->Reset();
14531   delete data.GetParameter();
14532 }
14533
14534
14535 TEST(WeakCallbackApi) {
14536   LocalContext context;
14537   v8::Isolate* isolate = context->GetIsolate();
14538   i::GlobalHandles* globals =
14539       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14540   int initial_handles = globals->global_handles_count();
14541   {
14542     v8::HandleScope scope(isolate);
14543     v8::Local<v8::Object> obj = v8::Object::New(isolate);
14544     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
14545     v8::Persistent<v8::Object>* handle =
14546         new v8::Persistent<v8::Object>(isolate, obj);
14547     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
14548                                                              WeakApiCallback);
14549   }
14550   reinterpret_cast<i::Isolate*>(isolate)->heap()->
14551       CollectAllGarbage(i::Heap::kNoGCFlags);
14552   // Verify disposed.
14553   CHECK_EQ(initial_handles, globals->global_handles_count());
14554 }
14555
14556
14557 v8::Persistent<v8::Object> some_object;
14558 v8::Persistent<v8::Object> bad_handle;
14559
14560 void NewPersistentHandleCallback(
14561     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14562   v8::HandleScope scope(data.GetIsolate());
14563   bad_handle.Reset(data.GetIsolate(), some_object);
14564   data.GetParameter()->Reset();
14565 }
14566
14567
14568 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14569   LocalContext context;
14570   v8::Isolate* isolate = context->GetIsolate();
14571
14572   v8::Persistent<v8::Object> handle1, handle2;
14573   {
14574     v8::HandleScope scope(isolate);
14575     some_object.Reset(isolate, v8::Object::New(isolate));
14576     handle1.Reset(isolate, v8::Object::New(isolate));
14577     handle2.Reset(isolate, v8::Object::New(isolate));
14578   }
14579   // Note: order is implementation dependent alas: currently
14580   // global handle nodes are processed by PostGarbageCollectionProcessing
14581   // in reverse allocation order, so if second allocated handle is deleted,
14582   // weak callback of the first handle would be able to 'reallocate' it.
14583   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
14584   handle2.Reset();
14585   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14586 }
14587
14588
14589 v8::Persistent<v8::Object> to_be_disposed;
14590
14591 void DisposeAndForceGcCallback(
14592     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14593   to_be_disposed.Reset();
14594   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14595   data.GetParameter()->Reset();
14596 }
14597
14598
14599 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14600   LocalContext context;
14601   v8::Isolate* isolate = context->GetIsolate();
14602
14603   v8::Persistent<v8::Object> handle1, handle2;
14604   {
14605     v8::HandleScope scope(isolate);
14606     handle1.Reset(isolate, v8::Object::New(isolate));
14607     handle2.Reset(isolate, v8::Object::New(isolate));
14608   }
14609   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
14610   to_be_disposed.Reset(isolate, handle2);
14611   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14612 }
14613
14614 void DisposingCallback(
14615     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14616   data.GetParameter()->Reset();
14617 }
14618
14619 void HandleCreatingCallback(
14620     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14621   v8::HandleScope scope(data.GetIsolate());
14622   v8::Persistent<v8::Object>(data.GetIsolate(),
14623                              v8::Object::New(data.GetIsolate()));
14624   data.GetParameter()->Reset();
14625 }
14626
14627
14628 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14629   LocalContext context;
14630   v8::Isolate* isolate = context->GetIsolate();
14631
14632   v8::Persistent<v8::Object> handle1, handle2, handle3;
14633   {
14634     v8::HandleScope scope(isolate);
14635     handle3.Reset(isolate, v8::Object::New(isolate));
14636     handle2.Reset(isolate, v8::Object::New(isolate));
14637     handle1.Reset(isolate, v8::Object::New(isolate));
14638   }
14639   handle2.SetWeak(&handle2, DisposingCallback);
14640   handle3.SetWeak(&handle3, HandleCreatingCallback);
14641   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14642 }
14643
14644
14645 THREADED_TEST(CheckForCrossContextObjectLiterals) {
14646   v8::V8::Initialize();
14647
14648   const int nof = 2;
14649   const char* sources[nof] = {
14650     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14651     "Object()"
14652   };
14653
14654   for (int i = 0; i < nof; i++) {
14655     const char* source = sources[i];
14656     { v8::HandleScope scope(CcTest::isolate());
14657       LocalContext context;
14658       CompileRun(source);
14659     }
14660     { v8::HandleScope scope(CcTest::isolate());
14661       LocalContext context;
14662       CompileRun(source);
14663     }
14664   }
14665 }
14666
14667
14668 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
14669   v8::EscapableHandleScope inner(env->GetIsolate());
14670   env->Enter();
14671   v8::Local<Value> three = v8_num(3);
14672   v8::Local<Value> value = inner.Escape(three);
14673   env->Exit();
14674   return value;
14675 }
14676
14677
14678 THREADED_TEST(NestedHandleScopeAndContexts) {
14679   v8::Isolate* isolate = CcTest::isolate();
14680   v8::HandleScope outer(isolate);
14681   v8::Local<Context> env = Context::New(isolate);
14682   env->Enter();
14683   v8::Handle<Value> value = NestedScope(env);
14684   v8::Handle<String> str(value->ToString(isolate));
14685   CHECK(!str.IsEmpty());
14686   env->Exit();
14687 }
14688
14689
14690 static bool MatchPointers(void* key1, void* key2) {
14691   return key1 == key2;
14692 }
14693
14694
14695 struct SymbolInfo {
14696   size_t id;
14697   size_t size;
14698   std::string name;
14699 };
14700
14701
14702 class SetFunctionEntryHookTest {
14703  public:
14704   SetFunctionEntryHookTest() {
14705     CHECK(instance_ == NULL);
14706     instance_ = this;
14707   }
14708   ~SetFunctionEntryHookTest() {
14709     CHECK(instance_ == this);
14710     instance_ = NULL;
14711   }
14712   void Reset() {
14713     symbols_.clear();
14714     symbol_locations_.clear();
14715     invocations_.clear();
14716   }
14717   void RunTest();
14718   void OnJitEvent(const v8::JitCodeEvent* event);
14719   static void JitEvent(const v8::JitCodeEvent* event) {
14720     CHECK(instance_ != NULL);
14721     instance_->OnJitEvent(event);
14722   }
14723
14724   void OnEntryHook(uintptr_t function,
14725                    uintptr_t return_addr_location);
14726   static void EntryHook(uintptr_t function,
14727                         uintptr_t return_addr_location) {
14728     CHECK(instance_ != NULL);
14729     instance_->OnEntryHook(function, return_addr_location);
14730   }
14731
14732   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14733     CHECK(instance_ != NULL);
14734     args.GetReturnValue().Set(v8_num(42));
14735   }
14736   void RunLoopInNewEnv(v8::Isolate* isolate);
14737
14738   // Records addr as location of symbol.
14739   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14740
14741   // Finds the symbol containing addr
14742   SymbolInfo* FindSymbolForAddr(i::Address addr);
14743   // Returns the number of invocations where the caller name contains
14744   // \p caller_name and the function name contains \p function_name.
14745   int CountInvocations(const char* caller_name,
14746                        const char* function_name);
14747
14748   i::Handle<i::JSFunction> foo_func_;
14749   i::Handle<i::JSFunction> bar_func_;
14750
14751   typedef std::map<size_t, SymbolInfo> SymbolMap;
14752   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14753   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14754   SymbolMap symbols_;
14755   SymbolLocationMap symbol_locations_;
14756   InvocationMap invocations_;
14757
14758   static SetFunctionEntryHookTest* instance_;
14759 };
14760 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14761
14762
14763 // Returns true if addr is in the range [start, start+len).
14764 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14765   if (start <= addr && start + len > addr)
14766     return true;
14767
14768   return false;
14769 }
14770
14771 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14772                                               SymbolInfo* symbol) {
14773   // Insert the symbol at the new location.
14774   SymbolLocationMap::iterator it =
14775       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14776   // Now erase symbols to the left and right that overlap this one.
14777   while (it != symbol_locations_.begin()) {
14778     SymbolLocationMap::iterator left = it;
14779     --left;
14780     if (!Overlaps(left->first, left->second->size, addr))
14781       break;
14782     symbol_locations_.erase(left);
14783   }
14784
14785   // Now erase symbols to the left and right that overlap this one.
14786   while (true) {
14787     SymbolLocationMap::iterator right = it;
14788     ++right;
14789     if (right == symbol_locations_.end())
14790         break;
14791     if (!Overlaps(addr, symbol->size, right->first))
14792       break;
14793     symbol_locations_.erase(right);
14794   }
14795 }
14796
14797
14798 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14799   switch (event->type) {
14800     case v8::JitCodeEvent::CODE_ADDED: {
14801         CHECK(event->code_start != NULL);
14802         CHECK_NE(0, static_cast<int>(event->code_len));
14803         CHECK(event->name.str != NULL);
14804         size_t symbol_id = symbols_.size();
14805
14806         // Record the new symbol.
14807         SymbolInfo& info = symbols_[symbol_id];
14808         info.id = symbol_id;
14809         info.size = event->code_len;
14810         info.name.assign(event->name.str, event->name.str + event->name.len);
14811
14812         // And record it's location.
14813         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14814       }
14815       break;
14816
14817     case v8::JitCodeEvent::CODE_MOVED: {
14818         // We would like to never see code move that we haven't seen before,
14819         // but the code creation event does not happen until the line endings
14820         // have been calculated (this is so that we can report the line in the
14821         // script at which the function source is found, see
14822         // Compiler::RecordFunctionCompilation) and the line endings
14823         // calculations can cause a GC, which can move the newly created code
14824         // before its existence can be logged.
14825         SymbolLocationMap::iterator it(
14826             symbol_locations_.find(
14827                 reinterpret_cast<i::Address>(event->code_start)));
14828         if (it != symbol_locations_.end()) {
14829           // Found a symbol at this location, move it.
14830           SymbolInfo* info = it->second;
14831           symbol_locations_.erase(it);
14832           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14833                          info);
14834         }
14835       }
14836     default:
14837       break;
14838   }
14839 }
14840
14841 void SetFunctionEntryHookTest::OnEntryHook(
14842     uintptr_t function, uintptr_t return_addr_location) {
14843   // Get the function's code object.
14844   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14845       reinterpret_cast<i::Address>(function));
14846   CHECK(function_code != NULL);
14847
14848   // Then try and look up the caller's code object.
14849   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14850
14851   // Count the invocation.
14852   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14853   SymbolInfo* function_symbol =
14854       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14855   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14856
14857   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14858     // Check that we have a symbol for the "bar" function at the right location.
14859     SymbolLocationMap::iterator it(
14860         symbol_locations_.find(function_code->instruction_start()));
14861     CHECK(it != symbol_locations_.end());
14862   }
14863
14864   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14865     // Check that we have a symbol for "foo" at the right location.
14866     SymbolLocationMap::iterator it(
14867         symbol_locations_.find(function_code->instruction_start()));
14868     CHECK(it != symbol_locations_.end());
14869   }
14870 }
14871
14872
14873 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14874   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14875   // Do we have a direct hit on a symbol?
14876   if (it != symbol_locations_.end()) {
14877     if (it->first == addr)
14878       return it->second;
14879   }
14880
14881   // If not a direct hit, it'll have to be the previous symbol.
14882   if (it == symbol_locations_.begin())
14883     return NULL;
14884
14885   --it;
14886   size_t offs = addr - it->first;
14887   if (offs < it->second->size)
14888     return it->second;
14889
14890   return NULL;
14891 }
14892
14893
14894 int SetFunctionEntryHookTest::CountInvocations(
14895     const char* caller_name, const char* function_name) {
14896   InvocationMap::iterator it(invocations_.begin());
14897   int invocations = 0;
14898   for (; it != invocations_.end(); ++it) {
14899     SymbolInfo* caller = it->first.first;
14900     SymbolInfo* function = it->first.second;
14901
14902     // Filter out non-matching functions.
14903     if (function_name != NULL) {
14904       if (function->name.find(function_name) == std::string::npos)
14905         continue;
14906     }
14907
14908     // Filter out non-matching callers.
14909     if (caller_name != NULL) {
14910       if (caller == NULL)
14911         continue;
14912       if (caller->name.find(caller_name) == std::string::npos)
14913         continue;
14914     }
14915
14916     // It matches add the invocation count to the tally.
14917     invocations += it->second;
14918   }
14919
14920   return invocations;
14921 }
14922
14923
14924 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14925   v8::HandleScope outer(isolate);
14926   v8::Local<Context> env = Context::New(isolate);
14927   env->Enter();
14928
14929   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14930   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14931   env->Global()->Set(v8_str("obj"), t->NewInstance());
14932
14933   const char* script =
14934       "function bar() {\n"
14935       "  var sum = 0;\n"
14936       "  for (i = 0; i < 100; ++i)\n"
14937       "    sum = foo(i);\n"
14938       "  return sum;\n"
14939       "}\n"
14940       "function foo(i) { return i * i; }\n"
14941       "// Invoke on the runtime function.\n"
14942       "obj.asdf()";
14943   CompileRun(script);
14944   bar_func_ = i::Handle<i::JSFunction>::cast(
14945           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14946   DCHECK(!bar_func_.is_null());
14947
14948   foo_func_ =
14949       i::Handle<i::JSFunction>::cast(
14950            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14951   DCHECK(!foo_func_.is_null());
14952
14953   v8::Handle<v8::Value> value = CompileRun("bar();");
14954   CHECK(value->IsNumber());
14955   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14956
14957   // Test the optimized codegen path.
14958   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14959                      "bar();");
14960   CHECK(value->IsNumber());
14961   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14962
14963   env->Exit();
14964 }
14965
14966
14967 void SetFunctionEntryHookTest::RunTest() {
14968   // Work in a new isolate throughout.
14969   v8::Isolate::CreateParams create_params;
14970   create_params.entry_hook = EntryHook;
14971   create_params.code_event_handler = JitEvent;
14972   v8::Isolate* isolate = v8::Isolate::New(create_params);
14973
14974   {
14975     v8::Isolate::Scope scope(isolate);
14976
14977     RunLoopInNewEnv(isolate);
14978
14979     // Check the exepected invocation counts.
14980     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14981     CHECK_EQ(200, CountInvocations("bar", "foo"));
14982     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14983
14984     // Verify that we have an entry hook on some specific stubs.
14985     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14986     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14987     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14988   }
14989   isolate->Dispose();
14990
14991   Reset();
14992
14993   // Make sure a second isolate is unaffected by the previous entry hook.
14994   isolate = v8::Isolate::New();
14995   {
14996     v8::Isolate::Scope scope(isolate);
14997
14998     // Reset the entry count to zero and set the entry hook.
14999     RunLoopInNewEnv(isolate);
15000
15001     // We should record no invocations in this isolate.
15002     CHECK_EQ(0, static_cast<int>(invocations_.size()));
15003   }
15004
15005   isolate->Dispose();
15006 }
15007
15008
15009 TEST(SetFunctionEntryHook) {
15010   // FunctionEntryHook does not work well with experimental natives.
15011   // Experimental natives are compiled during snapshot deserialization.
15012   // This test breaks because InstallGetter (function from snapshot that
15013   // only gets called from experimental natives) is compiled with entry hooks.
15014   i::FLAG_allow_natives_syntax = true;
15015   i::FLAG_use_inlining = false;
15016
15017   SetFunctionEntryHookTest test;
15018   test.RunTest();
15019 }
15020
15021
15022 static i::HashMap* code_map = NULL;
15023 static i::HashMap* jitcode_line_info = NULL;
15024 static int saw_bar = 0;
15025 static int move_events = 0;
15026
15027
15028 static bool FunctionNameIs(const char* expected,
15029                            const v8::JitCodeEvent* event) {
15030   // Log lines for functions are of the general form:
15031   // "LazyCompile:<type><function_name>", where the type is one of
15032   // "*", "~" or "".
15033   static const char kPreamble[] = "LazyCompile:";
15034   static size_t kPreambleLen = sizeof(kPreamble) - 1;
15035
15036   if (event->name.len < sizeof(kPreamble) - 1 ||
15037       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
15038     return false;
15039   }
15040
15041   const char* tail = event->name.str + kPreambleLen;
15042   size_t tail_len = event->name.len - kPreambleLen;
15043   size_t expected_len = strlen(expected);
15044   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
15045     --tail_len;
15046     ++tail;
15047   }
15048
15049   // Check for tails like 'bar :1'.
15050   if (tail_len > expected_len + 2 &&
15051       tail[expected_len] == ' ' &&
15052       tail[expected_len + 1] == ':' &&
15053       tail[expected_len + 2] &&
15054       !strncmp(tail, expected, expected_len)) {
15055     return true;
15056   }
15057
15058   if (tail_len != expected_len)
15059     return false;
15060
15061   return strncmp(tail, expected, expected_len) == 0;
15062 }
15063
15064
15065 static void event_handler(const v8::JitCodeEvent* event) {
15066   CHECK(event != NULL);
15067   CHECK(code_map != NULL);
15068   CHECK(jitcode_line_info != NULL);
15069
15070   class DummyJitCodeLineInfo {
15071   };
15072
15073   switch (event->type) {
15074     case v8::JitCodeEvent::CODE_ADDED: {
15075         CHECK(event->code_start != NULL);
15076         CHECK_NE(0, static_cast<int>(event->code_len));
15077         CHECK(event->name.str != NULL);
15078         i::HashMap::Entry* entry =
15079             code_map->Lookup(event->code_start,
15080                              i::ComputePointerHash(event->code_start),
15081                              true);
15082         entry->value = reinterpret_cast<void*>(event->code_len);
15083
15084         if (FunctionNameIs("bar", event)) {
15085           ++saw_bar;
15086         }
15087       }
15088       break;
15089
15090     case v8::JitCodeEvent::CODE_MOVED: {
15091         uint32_t hash = i::ComputePointerHash(event->code_start);
15092         // We would like to never see code move that we haven't seen before,
15093         // but the code creation event does not happen until the line endings
15094         // have been calculated (this is so that we can report the line in the
15095         // script at which the function source is found, see
15096         // Compiler::RecordFunctionCompilation) and the line endings
15097         // calculations can cause a GC, which can move the newly created code
15098         // before its existence can be logged.
15099         i::HashMap::Entry* entry =
15100             code_map->Lookup(event->code_start, hash, false);
15101         if (entry != NULL) {
15102           ++move_events;
15103
15104           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
15105           code_map->Remove(event->code_start, hash);
15106
15107           entry = code_map->Lookup(event->new_code_start,
15108                                    i::ComputePointerHash(event->new_code_start),
15109                                    true);
15110           CHECK(entry != NULL);
15111           entry->value = reinterpret_cast<void*>(event->code_len);
15112         }
15113       }
15114       break;
15115
15116     case v8::JitCodeEvent::CODE_REMOVED:
15117       // Object/code removal events are currently not dispatched from the GC.
15118       CHECK(false);
15119       break;
15120
15121     // For CODE_START_LINE_INFO_RECORDING event, we will create one
15122     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
15123     // record it in jitcode_line_info.
15124     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
15125         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
15126         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
15127         temp_event->user_data = line_info;
15128         i::HashMap::Entry* entry =
15129             jitcode_line_info->Lookup(line_info,
15130                                       i::ComputePointerHash(line_info),
15131                                       true);
15132         entry->value = reinterpret_cast<void*>(line_info);
15133       }
15134       break;
15135     // For these two events, we will check whether the event->user_data
15136     // data structure is created before during CODE_START_LINE_INFO_RECORDING
15137     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
15138     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
15139         CHECK(event->user_data != NULL);
15140         uint32_t hash = i::ComputePointerHash(event->user_data);
15141         i::HashMap::Entry* entry =
15142             jitcode_line_info->Lookup(event->user_data, hash, false);
15143         CHECK(entry != NULL);
15144         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
15145       }
15146       break;
15147
15148     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
15149         CHECK(event->user_data != NULL);
15150         uint32_t hash = i::ComputePointerHash(event->user_data);
15151         i::HashMap::Entry* entry =
15152             jitcode_line_info->Lookup(event->user_data, hash, false);
15153         CHECK(entry != NULL);
15154       }
15155       break;
15156
15157     default:
15158       // Impossible event.
15159       CHECK(false);
15160       break;
15161   }
15162 }
15163
15164
15165 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
15166   i::FLAG_stress_compaction = true;
15167   i::FLAG_incremental_marking = false;
15168   if (i::FLAG_never_compact) return;
15169   const char* script =
15170     "function bar() {"
15171     "  var sum = 0;"
15172     "  for (i = 0; i < 100; ++i)"
15173     "    sum = foo(i);"
15174     "  return sum;"
15175     "}"
15176     "function foo(i) { return i * i; };"
15177     "bar();";
15178
15179   // Run this test in a new isolate to make sure we don't
15180   // have remnants of state from other code.
15181   v8::Isolate* isolate = v8::Isolate::New();
15182   isolate->Enter();
15183   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
15184   i::Heap* heap = i_isolate->heap();
15185
15186   {
15187     v8::HandleScope scope(isolate);
15188     i::HashMap code(MatchPointers);
15189     code_map = &code;
15190
15191     i::HashMap lineinfo(MatchPointers);
15192     jitcode_line_info = &lineinfo;
15193
15194     saw_bar = 0;
15195     move_events = 0;
15196
15197     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
15198
15199     // Generate new code objects sparsely distributed across several
15200     // different fragmented code-space pages.
15201     const int kIterations = 10;
15202     for (int i = 0; i < kIterations; ++i) {
15203       LocalContext env(isolate);
15204       i::AlwaysAllocateScope always_allocate(i_isolate);
15205       SimulateFullSpace(heap->code_space());
15206       CompileRun(script);
15207
15208       // Keep a strong reference to the code object in the handle scope.
15209       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
15210           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
15211       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
15212           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
15213
15214       // Clear the compilation cache to get more wastage.
15215       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
15216     }
15217
15218     // Force code movement.
15219     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
15220
15221     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
15222
15223     CHECK_LE(kIterations, saw_bar);
15224     CHECK_LT(0, move_events);
15225
15226     code_map = NULL;
15227     jitcode_line_info = NULL;
15228   }
15229
15230   isolate->Exit();
15231   isolate->Dispose();
15232
15233   // Do this in a new isolate.
15234   isolate = v8::Isolate::New();
15235   isolate->Enter();
15236
15237   // Verify that we get callbacks for existing code objects when we
15238   // request enumeration of existing code.
15239   {
15240     v8::HandleScope scope(isolate);
15241     LocalContext env(isolate);
15242     CompileRun(script);
15243
15244     // Now get code through initial iteration.
15245     i::HashMap code(MatchPointers);
15246     code_map = &code;
15247
15248     i::HashMap lineinfo(MatchPointers);
15249     jitcode_line_info = &lineinfo;
15250
15251     isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
15252                                     event_handler);
15253     isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
15254
15255     jitcode_line_info = NULL;
15256     // We expect that we got some events. Note that if we could get code removal
15257     // notifications, we could compare two collections, one created by listening
15258     // from the time of creation of an isolate, and the other by subscribing
15259     // with EnumExisting.
15260     CHECK_LT(0, code.occupancy());
15261
15262     code_map = NULL;
15263   }
15264
15265   isolate->Exit();
15266   isolate->Dispose();
15267 }
15268
15269
15270 THREADED_TEST(ExternalAllocatedMemory) {
15271   v8::Isolate* isolate = CcTest::isolate();
15272   v8::HandleScope outer(isolate);
15273   v8::Local<Context> env(Context::New(isolate));
15274   CHECK(!env.IsEmpty());
15275   const int64_t kSize = 1024*1024;
15276   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
15277   CHECK_EQ(baseline + kSize,
15278            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
15279   CHECK_EQ(baseline,
15280            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
15281 }
15282
15283
15284 // Regression test for issue 54, object templates with internal fields
15285 // but no accessors or interceptors did not get their internal field
15286 // count set on instances.
15287 THREADED_TEST(Regress54) {
15288   LocalContext context;
15289   v8::Isolate* isolate = context->GetIsolate();
15290   v8::HandleScope outer(isolate);
15291   static v8::Persistent<v8::ObjectTemplate> templ;
15292   if (templ.IsEmpty()) {
15293     v8::EscapableHandleScope inner(isolate);
15294     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
15295     local->SetInternalFieldCount(1);
15296     templ.Reset(isolate, inner.Escape(local));
15297   }
15298   v8::Handle<v8::Object> result =
15299       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
15300   CHECK_EQ(1, result->InternalFieldCount());
15301 }
15302
15303
15304 // If part of the threaded tests, this test makes ThreadingTest fail
15305 // on mac.
15306 TEST(CatchStackOverflow) {
15307   LocalContext context;
15308   v8::HandleScope scope(context->GetIsolate());
15309   v8::TryCatch try_catch;
15310   v8::Handle<v8::Value> result = CompileRun(
15311     "function f() {"
15312     "  return f();"
15313     "}"
15314     ""
15315     "f();");
15316   CHECK(result.IsEmpty());
15317 }
15318
15319
15320 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
15321                                     const char* resource_name,
15322                                     int line_offset) {
15323   v8::HandleScope scope(CcTest::isolate());
15324   v8::TryCatch try_catch;
15325   v8::Handle<v8::Value> result = script->Run();
15326   CHECK(result.IsEmpty());
15327   CHECK(try_catch.HasCaught());
15328   v8::Handle<v8::Message> message = try_catch.Message();
15329   CHECK(!message.IsEmpty());
15330   CHECK_EQ(10 + line_offset, message->GetLineNumber());
15331   CHECK_EQ(91, message->GetStartPosition());
15332   CHECK_EQ(92, message->GetEndPosition());
15333   CHECK_EQ(2, message->GetStartColumn());
15334   CHECK_EQ(3, message->GetEndColumn());
15335   v8::String::Utf8Value line(message->GetSourceLine());
15336   CHECK_EQ("  throw 'nirk';", *line);
15337   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
15338   CHECK_EQ(resource_name, *name);
15339 }
15340
15341
15342 THREADED_TEST(TryCatchSourceInfo) {
15343   LocalContext context;
15344   v8::HandleScope scope(context->GetIsolate());
15345   v8::Local<v8::String> source = v8_str(
15346       "function Foo() {\n"
15347       "  return Bar();\n"
15348       "}\n"
15349       "\n"
15350       "function Bar() {\n"
15351       "  return Baz();\n"
15352       "}\n"
15353       "\n"
15354       "function Baz() {\n"
15355       "  throw 'nirk';\n"
15356       "}\n"
15357       "\n"
15358       "Foo();\n");
15359
15360   const char* resource_name;
15361   v8::Handle<v8::Script> script;
15362   resource_name = "test.js";
15363   script = CompileWithOrigin(source, resource_name);
15364   CheckTryCatchSourceInfo(script, resource_name, 0);
15365
15366   resource_name = "test1.js";
15367   v8::ScriptOrigin origin1(
15368       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
15369   script = v8::Script::Compile(source, &origin1);
15370   CheckTryCatchSourceInfo(script, resource_name, 0);
15371
15372   resource_name = "test2.js";
15373   v8::ScriptOrigin origin2(
15374       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
15375       v8::Integer::New(context->GetIsolate(), 7));
15376   script = v8::Script::Compile(source, &origin2);
15377   CheckTryCatchSourceInfo(script, resource_name, 7);
15378 }
15379
15380
15381 THREADED_TEST(CompilationCache) {
15382   LocalContext context;
15383   v8::HandleScope scope(context->GetIsolate());
15384   v8::Handle<v8::String> source0 =
15385       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15386   v8::Handle<v8::String> source1 =
15387       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15388   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
15389   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
15390   v8::Handle<v8::Script> script2 =
15391       v8::Script::Compile(source0);  // different origin
15392   CHECK_EQ(1234, script0->Run()->Int32Value());
15393   CHECK_EQ(1234, script1->Run()->Int32Value());
15394   CHECK_EQ(1234, script2->Run()->Int32Value());
15395 }
15396
15397
15398 static void FunctionNameCallback(
15399     const v8::FunctionCallbackInfo<v8::Value>& args) {
15400   ApiTestFuzzer::Fuzz();
15401   args.GetReturnValue().Set(v8_num(42));
15402 }
15403
15404
15405 THREADED_TEST(CallbackFunctionName) {
15406   LocalContext context;
15407   v8::Isolate* isolate = context->GetIsolate();
15408   v8::HandleScope scope(isolate);
15409   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15410   t->Set(v8_str("asdf"),
15411          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
15412   context->Global()->Set(v8_str("obj"), t->NewInstance());
15413   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
15414   CHECK(value->IsString());
15415   v8::String::Utf8Value name(value);
15416   CHECK_EQ("asdf", *name);
15417 }
15418
15419
15420 THREADED_TEST(DateAccess) {
15421   LocalContext context;
15422   v8::HandleScope scope(context->GetIsolate());
15423   v8::Handle<v8::Value> date =
15424       v8::Date::New(context->GetIsolate(), 1224744689038.0);
15425   CHECK(date->IsDate());
15426   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
15427 }
15428
15429
15430 void CheckProperties(v8::Isolate* isolate,
15431                      v8::Handle<v8::Value> val,
15432                      int elmc,
15433                      const char* elmv[]) {
15434   v8::Handle<v8::Object> obj = val.As<v8::Object>();
15435   v8::Handle<v8::Array> props = obj->GetPropertyNames();
15436   CHECK_EQ(elmc, props->Length());
15437   for (int i = 0; i < elmc; i++) {
15438     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15439     CHECK_EQ(elmv[i], *elm);
15440   }
15441 }
15442
15443
15444 void CheckOwnProperties(v8::Isolate* isolate,
15445                         v8::Handle<v8::Value> val,
15446                         int elmc,
15447                         const char* elmv[]) {
15448   v8::Handle<v8::Object> obj = val.As<v8::Object>();
15449   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
15450   CHECK_EQ(elmc, props->Length());
15451   for (int i = 0; i < elmc; i++) {
15452     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15453     CHECK_EQ(elmv[i], *elm);
15454   }
15455 }
15456
15457
15458 THREADED_TEST(PropertyEnumeration) {
15459   LocalContext context;
15460   v8::Isolate* isolate = context->GetIsolate();
15461   v8::HandleScope scope(isolate);
15462   v8::Handle<v8::Value> obj = CompileRun(
15463       "var result = [];"
15464       "result[0] = {};"
15465       "result[1] = {a: 1, b: 2};"
15466       "result[2] = [1, 2, 3];"
15467       "var proto = {x: 1, y: 2, z: 3};"
15468       "var x = { __proto__: proto, w: 0, z: 1 };"
15469       "result[3] = x;"
15470       "result;");
15471   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15472   CHECK_EQ(4, elms->Length());
15473   int elmc0 = 0;
15474   const char** elmv0 = NULL;
15475   CheckProperties(
15476       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15477   CheckOwnProperties(
15478       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15479   int elmc1 = 2;
15480   const char* elmv1[] = {"a", "b"};
15481   CheckProperties(
15482       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15483   CheckOwnProperties(
15484       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15485   int elmc2 = 3;
15486   const char* elmv2[] = {"0", "1", "2"};
15487   CheckProperties(
15488       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15489   CheckOwnProperties(
15490       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15491   int elmc3 = 4;
15492   const char* elmv3[] = {"w", "z", "x", "y"};
15493   CheckProperties(
15494       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
15495   int elmc4 = 2;
15496   const char* elmv4[] = {"w", "z"};
15497   CheckOwnProperties(
15498       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
15499 }
15500
15501
15502 THREADED_TEST(PropertyEnumeration2) {
15503   LocalContext context;
15504   v8::Isolate* isolate = context->GetIsolate();
15505   v8::HandleScope scope(isolate);
15506   v8::Handle<v8::Value> obj = CompileRun(
15507       "var result = [];"
15508       "result[0] = {};"
15509       "result[1] = {a: 1, b: 2};"
15510       "result[2] = [1, 2, 3];"
15511       "var proto = {x: 1, y: 2, z: 3};"
15512       "var x = { __proto__: proto, w: 0, z: 1 };"
15513       "result[3] = x;"
15514       "result;");
15515   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15516   CHECK_EQ(4, elms->Length());
15517   int elmc0 = 0;
15518   const char** elmv0 = NULL;
15519   CheckProperties(isolate,
15520                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15521
15522   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
15523   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
15524   CHECK_EQ(0, props->Length());
15525   for (uint32_t i = 0; i < props->Length(); i++) {
15526     printf("p[%u]\n", i);
15527   }
15528 }
15529
15530 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
15531                                   Local<Value> name,
15532                                   v8::AccessType type,
15533                                   Local<Value> data) {
15534   return type != v8::ACCESS_SET;
15535 }
15536
15537
15538 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
15539                                     uint32_t key,
15540                                     v8::AccessType type,
15541                                     Local<Value> data) {
15542   return type != v8::ACCESS_SET;
15543 }
15544
15545
15546 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
15547   LocalContext context;
15548   v8::Isolate* isolate = context->GetIsolate();
15549   v8::HandleScope scope(isolate);
15550   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15551   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15552                                  IndexedSetAccessBlocker);
15553   templ->Set(v8_str("x"), v8::True(isolate));
15554   Local<v8::Object> instance = templ->NewInstance();
15555   context->Global()->Set(v8_str("obj"), instance);
15556   Local<Value> value = CompileRun("obj.x");
15557   CHECK(value->BooleanValue());
15558 }
15559
15560
15561 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
15562                                   Local<Value> name,
15563                                   v8::AccessType type,
15564                                   Local<Value> data) {
15565   return false;
15566 }
15567
15568
15569 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
15570                                     uint32_t key,
15571                                     v8::AccessType type,
15572                                     Local<Value> data) {
15573   return false;
15574 }
15575
15576
15577
15578 THREADED_TEST(AccessChecksReenabledCorrectly) {
15579   LocalContext context;
15580   v8::Isolate* isolate = context->GetIsolate();
15581   v8::HandleScope scope(isolate);
15582   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15583   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15584                                  IndexedGetAccessBlocker);
15585   templ->Set(v8_str("a"), v8_str("a"));
15586   // Add more than 8 (see kMaxFastProperties) properties
15587   // so that the constructor will force copying map.
15588   // Cannot sprintf, gcc complains unsafety.
15589   char buf[4];
15590   for (char i = '0'; i <= '9' ; i++) {
15591     buf[0] = i;
15592     for (char j = '0'; j <= '9'; j++) {
15593       buf[1] = j;
15594       for (char k = '0'; k <= '9'; k++) {
15595         buf[2] = k;
15596         buf[3] = 0;
15597         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15598       }
15599     }
15600   }
15601
15602   Local<v8::Object> instance_1 = templ->NewInstance();
15603   context->Global()->Set(v8_str("obj_1"), instance_1);
15604
15605   Local<Value> value_1 = CompileRun("obj_1.a");
15606   CHECK(value_1.IsEmpty());
15607
15608   Local<v8::Object> instance_2 = templ->NewInstance();
15609   context->Global()->Set(v8_str("obj_2"), instance_2);
15610
15611   Local<Value> value_2 = CompileRun("obj_2.a");
15612   CHECK(value_2.IsEmpty());
15613 }
15614
15615
15616 // This tests that access check information remains on the global
15617 // object template when creating contexts.
15618 THREADED_TEST(AccessControlRepeatedContextCreation) {
15619   v8::Isolate* isolate = CcTest::isolate();
15620   v8::HandleScope handle_scope(isolate);
15621   v8::Handle<v8::ObjectTemplate> global_template =
15622       v8::ObjectTemplate::New(isolate);
15623   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15624                                            IndexedSetAccessBlocker);
15625   i::Handle<i::ObjectTemplateInfo> internal_template =
15626       v8::Utils::OpenHandle(*global_template);
15627   CHECK(!internal_template->constructor()->IsUndefined());
15628   i::Handle<i::FunctionTemplateInfo> constructor(
15629       i::FunctionTemplateInfo::cast(internal_template->constructor()));
15630   CHECK(!constructor->access_check_info()->IsUndefined());
15631   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
15632   CHECK(!context0.IsEmpty());
15633   CHECK(!constructor->access_check_info()->IsUndefined());
15634 }
15635
15636
15637 THREADED_TEST(TurnOnAccessCheck) {
15638   v8::Isolate* isolate = CcTest::isolate();
15639   v8::HandleScope handle_scope(isolate);
15640
15641   // Create an environment with access check to the global object disabled by
15642   // default.
15643   v8::Handle<v8::ObjectTemplate> global_template =
15644       v8::ObjectTemplate::New(isolate);
15645   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15646                                            IndexedGetAccessBlocker,
15647                                            v8::Handle<v8::Value>(),
15648                                            false);
15649   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15650   Context::Scope context_scope(context);
15651
15652   // Set up a property and a number of functions.
15653   context->Global()->Set(v8_str("a"), v8_num(1));
15654   CompileRun("function f1() {return a;}"
15655              "function f2() {return a;}"
15656              "function g1() {return h();}"
15657              "function g2() {return h();}"
15658              "function h() {return 1;}");
15659   Local<Function> f1 =
15660       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15661   Local<Function> f2 =
15662       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15663   Local<Function> g1 =
15664       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15665   Local<Function> g2 =
15666       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15667   Local<Function> h =
15668       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15669
15670   // Get the global object.
15671   v8::Handle<v8::Object> global = context->Global();
15672
15673   // Call f1 one time and f2 a number of times. This will ensure that f1 still
15674   // uses the runtime system to retreive property a whereas f2 uses global load
15675   // inline cache.
15676   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15677   for (int i = 0; i < 4; i++) {
15678     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15679   }
15680
15681   // Same for g1 and g2.
15682   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15683   for (int i = 0; i < 4; i++) {
15684     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15685   }
15686
15687   // Detach the global and turn on access check.
15688   Local<Object> hidden_global = Local<Object>::Cast(
15689       context->Global()->GetPrototype());
15690   context->DetachGlobal();
15691   hidden_global->TurnOnAccessCheck();
15692
15693   // Failing access check results in exception.
15694   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15695   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15696   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15697   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15698
15699   // No failing access check when just returning a constant.
15700   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15701 }
15702
15703
15704 static const char* kPropertyA = "a";
15705 static const char* kPropertyH = "h";
15706
15707 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15708                                        Local<Value> name,
15709                                        v8::AccessType type,
15710                                        Local<Value> data) {
15711   if (!name->IsString()) return false;
15712   i::Handle<i::String> name_handle =
15713       v8::Utils::OpenHandle(String::Cast(*name));
15714   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15715       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
15716 }
15717
15718
15719 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
15720   v8::Isolate* isolate = CcTest::isolate();
15721   v8::HandleScope handle_scope(isolate);
15722
15723   // Create an environment with access check to the global object disabled by
15724   // default. When the registered access checker will block access to properties
15725   // a and h.
15726   v8::Handle<v8::ObjectTemplate> global_template =
15727      v8::ObjectTemplate::New(isolate);
15728   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15729                                            IndexedGetAccessBlocker,
15730                                            v8::Handle<v8::Value>(),
15731                                            false);
15732   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15733   Context::Scope context_scope(context);
15734
15735   // Set up a property and a number of functions.
15736   context->Global()->Set(v8_str("a"), v8_num(1));
15737   static const char* source = "function f1() {return a;}"
15738                               "function f2() {return a;}"
15739                               "function g1() {return h();}"
15740                               "function g2() {return h();}"
15741                               "function h() {return 1;}";
15742
15743   CompileRun(source);
15744   Local<Function> f1;
15745   Local<Function> f2;
15746   Local<Function> g1;
15747   Local<Function> g2;
15748   Local<Function> h;
15749   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15750   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15751   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15752   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15753   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15754
15755   // Get the global object.
15756   v8::Handle<v8::Object> global = context->Global();
15757
15758   // Call f1 one time and f2 a number of times. This will ensure that f1 still
15759   // uses the runtime system to retreive property a whereas f2 uses global load
15760   // inline cache.
15761   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15762   for (int i = 0; i < 4; i++) {
15763     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15764   }
15765
15766   // Same for g1 and g2.
15767   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15768   for (int i = 0; i < 4; i++) {
15769     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15770   }
15771
15772   // Detach the global and turn on access check now blocking access to property
15773   // a and function h.
15774   Local<Object> hidden_global = Local<Object>::Cast(
15775       context->Global()->GetPrototype());
15776   context->DetachGlobal();
15777   hidden_global->TurnOnAccessCheck();
15778
15779   // Failing access check results in exception.
15780   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15781   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15782   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15783   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15784
15785   // No failing access check when just returning a constant.
15786   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15787
15788   // Now compile the source again. And get the newly compiled functions, except
15789   // for h for which access is blocked.
15790   CompileRun(source);
15791   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15792   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15793   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15794   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15795   CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15796
15797   // Failing access check results in exception.
15798   v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15799   CHECK(result.IsEmpty());
15800   CHECK(f1->Call(global, 0, NULL).IsEmpty());
15801   CHECK(f2->Call(global, 0, NULL).IsEmpty());
15802   CHECK(g1->Call(global, 0, NULL).IsEmpty());
15803   CHECK(g2->Call(global, 0, NULL).IsEmpty());
15804 }
15805
15806
15807 // Tests that ScriptData can be serialized and deserialized.
15808 TEST(PreCompileSerialization) {
15809   v8::V8::Initialize();
15810   LocalContext env;
15811   v8::Isolate* isolate = env->GetIsolate();
15812   HandleScope handle_scope(isolate);
15813
15814   i::FLAG_min_preparse_length = 0;
15815   const char* script = "function foo(a) { return a+1; }";
15816   v8::ScriptCompiler::Source source(v8_str(script));
15817   v8::ScriptCompiler::Compile(isolate, &source,
15818                               v8::ScriptCompiler::kProduceParserCache);
15819   // Serialize.
15820   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15821   i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15822   i::MemCopy(serialized_data, cd->data, cd->length);
15823
15824   // Deserialize.
15825   i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15826
15827   // Verify that the original is the same as the deserialized.
15828   CHECK_EQ(cd->length, deserialized->length());
15829   CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15830
15831   delete deserialized;
15832   i::DeleteArray(serialized_data);
15833 }
15834
15835
15836 // This tests that we do not allow dictionary load/call inline caches
15837 // to use functions that have not yet been compiled.  The potential
15838 // problem of loading a function that has not yet been compiled can
15839 // arise because we share code between contexts via the compilation
15840 // cache.
15841 THREADED_TEST(DictionaryICLoadedFunction) {
15842   v8::HandleScope scope(CcTest::isolate());
15843   // Test LoadIC.
15844   for (int i = 0; i < 2; i++) {
15845     LocalContext context;
15846     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15847     context->Global()->Delete(v8_str("tmp"));
15848     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15849   }
15850   // Test CallIC.
15851   for (int i = 0; i < 2; i++) {
15852     LocalContext context;
15853     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15854     context->Global()->Delete(v8_str("tmp"));
15855     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15856   }
15857 }
15858
15859
15860 // Test that cross-context new calls use the context of the callee to
15861 // create the new JavaScript object.
15862 THREADED_TEST(CrossContextNew) {
15863   v8::Isolate* isolate = CcTest::isolate();
15864   v8::HandleScope scope(isolate);
15865   v8::Local<Context> context0 = Context::New(isolate);
15866   v8::Local<Context> context1 = Context::New(isolate);
15867
15868   // Allow cross-domain access.
15869   Local<String> token = v8_str("<security token>");
15870   context0->SetSecurityToken(token);
15871   context1->SetSecurityToken(token);
15872
15873   // Set an 'x' property on the Object prototype and define a
15874   // constructor function in context0.
15875   context0->Enter();
15876   CompileRun("Object.prototype.x = 42; function C() {};");
15877   context0->Exit();
15878
15879   // Call the constructor function from context0 and check that the
15880   // result has the 'x' property.
15881   context1->Enter();
15882   context1->Global()->Set(v8_str("other"), context0->Global());
15883   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15884   CHECK(value->IsInt32());
15885   CHECK_EQ(42, value->Int32Value());
15886   context1->Exit();
15887 }
15888
15889
15890 // Verify that we can clone an object
15891 TEST(ObjectClone) {
15892   LocalContext env;
15893   v8::Isolate* isolate = env->GetIsolate();
15894   v8::HandleScope scope(isolate);
15895
15896   const char* sample =
15897     "var rv = {};"      \
15898     "rv.alpha = 'hello';" \
15899     "rv.beta = 123;"     \
15900     "rv;";
15901
15902   // Create an object, verify basics.
15903   Local<Value> val = CompileRun(sample);
15904   CHECK(val->IsObject());
15905   Local<v8::Object> obj = val.As<v8::Object>();
15906   obj->Set(v8_str("gamma"), v8_str("cloneme"));
15907
15908   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15909   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15910   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15911
15912   // Clone it.
15913   Local<v8::Object> clone = obj->Clone();
15914   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15915   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15916   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15917
15918   // Set a property on the clone, verify each object.
15919   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15920   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15921   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15922 }
15923
15924
15925 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15926  public:
15927   explicit OneByteVectorResource(i::Vector<const char> vector)
15928       : data_(vector) {}
15929   virtual ~OneByteVectorResource() {}
15930   virtual size_t length() const { return data_.length(); }
15931   virtual const char* data() const { return data_.start(); }
15932  private:
15933   i::Vector<const char> data_;
15934 };
15935
15936
15937 class UC16VectorResource : public v8::String::ExternalStringResource {
15938  public:
15939   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15940       : data_(vector) {}
15941   virtual ~UC16VectorResource() {}
15942   virtual size_t length() const { return data_.length(); }
15943   virtual const i::uc16* data() const { return data_.start(); }
15944  private:
15945   i::Vector<const i::uc16> data_;
15946 };
15947
15948
15949 static void MorphAString(i::String* string,
15950                          OneByteVectorResource* one_byte_resource,
15951                          UC16VectorResource* uc16_resource) {
15952   CHECK(i::StringShape(string).IsExternal());
15953   if (string->IsOneByteRepresentation()) {
15954     // Check old map is not internalized or long.
15955     CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15956     // Morph external string to be TwoByte string.
15957     string->set_map(CcTest::heap()->external_string_map());
15958     i::ExternalTwoByteString* morphed =
15959          i::ExternalTwoByteString::cast(string);
15960     morphed->set_resource(uc16_resource);
15961   } else {
15962     // Check old map is not internalized or long.
15963     CHECK(string->map() == CcTest::heap()->external_string_map());
15964     // Morph external string to be one-byte string.
15965     string->set_map(CcTest::heap()->external_one_byte_string_map());
15966     i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15967     morphed->set_resource(one_byte_resource);
15968   }
15969 }
15970
15971
15972 // Test that we can still flatten a string if the components it is built up
15973 // from have been turned into 16 bit strings in the mean time.
15974 THREADED_TEST(MorphCompositeStringTest) {
15975   char utf_buffer[129];
15976   const char* c_string = "Now is the time for all good men"
15977                          " to come to the aid of the party";
15978   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15979   {
15980     LocalContext env;
15981     i::Factory* factory = CcTest::i_isolate()->factory();
15982     v8::HandleScope scope(env->GetIsolate());
15983     OneByteVectorResource one_byte_resource(
15984         i::Vector<const char>(c_string, i::StrLength(c_string)));
15985     UC16VectorResource uc16_resource(
15986         i::Vector<const uint16_t>(two_byte_string,
15987                                   i::StrLength(c_string)));
15988
15989     Local<String> lhs(
15990         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15991                                         &one_byte_resource).ToHandleChecked()));
15992     Local<String> rhs(
15993         v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15994                                         &one_byte_resource).ToHandleChecked()));
15995
15996     env->Global()->Set(v8_str("lhs"), lhs);
15997     env->Global()->Set(v8_str("rhs"), rhs);
15998
15999     CompileRun(
16000         "var cons = lhs + rhs;"
16001         "var slice = lhs.substring(1, lhs.length - 1);"
16002         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
16003
16004     CHECK(lhs->IsOneByte());
16005     CHECK(rhs->IsOneByte());
16006
16007     MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
16008                  &uc16_resource);
16009     MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
16010                  &uc16_resource);
16011
16012     // This should UTF-8 without flattening, since everything is ASCII.
16013     Handle<String> cons = v8_compile("cons")->Run().As<String>();
16014     CHECK_EQ(128, cons->Utf8Length());
16015     int nchars = -1;
16016     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
16017     CHECK_EQ(128, nchars);
16018     CHECK_EQ(0, strcmp(
16019         utf_buffer,
16020         "Now is the time for all good men to come to the aid of the party"
16021         "Now is the time for all good men to come to the aid of the party"));
16022
16023     // Now do some stuff to make sure the strings are flattened, etc.
16024     CompileRun(
16025         "/[^a-z]/.test(cons);"
16026         "/[^a-z]/.test(slice);"
16027         "/[^a-z]/.test(slice_on_cons);");
16028     const char* expected_cons =
16029         "Now is the time for all good men to come to the aid of the party"
16030         "Now is the time for all good men to come to the aid of the party";
16031     const char* expected_slice =
16032         "ow is the time for all good men to come to the aid of the part";
16033     const char* expected_slice_on_cons =
16034         "ow is the time for all good men to come to the aid of the party"
16035         "Now is the time for all good men to come to the aid of the part";
16036     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
16037              env->Global()->Get(v8_str("cons")));
16038     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
16039              env->Global()->Get(v8_str("slice")));
16040     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
16041              env->Global()->Get(v8_str("slice_on_cons")));
16042   }
16043   i::DeleteArray(two_byte_string);
16044 }
16045
16046
16047 TEST(CompileExternalTwoByteSource) {
16048   LocalContext context;
16049   v8::HandleScope scope(context->GetIsolate());
16050
16051   // This is a very short list of sources, which currently is to check for a
16052   // regression caused by r2703.
16053   const char* one_byte_sources[] = {
16054       "0.5",
16055       "-0.5",   // This mainly testes PushBack in the Scanner.
16056       "--0.5",  // This mainly testes PushBack in the Scanner.
16057       NULL};
16058
16059   // Compile the sources as external two byte strings.
16060   for (int i = 0; one_byte_sources[i] != NULL; i++) {
16061     uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
16062     TestResource* uc16_resource = new TestResource(two_byte_string);
16063     v8::Local<v8::String> source =
16064         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
16065     v8::Script::Compile(source);
16066   }
16067 }
16068
16069
16070 #ifndef V8_INTERPRETED_REGEXP
16071
16072 struct RegExpInterruptionData {
16073   v8::base::Atomic32 loop_count;
16074   UC16VectorResource* string_resource;
16075   v8::Persistent<v8::String> string;
16076 } regexp_interruption_data;
16077
16078
16079 class RegExpInterruptionThread : public v8::base::Thread {
16080  public:
16081   explicit RegExpInterruptionThread(v8::Isolate* isolate)
16082       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
16083
16084   virtual void Run() {
16085     for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
16086          v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
16087          v8::base::NoBarrier_AtomicIncrement(
16088              &regexp_interruption_data.loop_count, 1)) {
16089       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
16090       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
16091     }
16092     v8::base::OS::Sleep(50);  // Wait a bit before terminating.
16093     v8::V8::TerminateExecution(isolate_);
16094   }
16095
16096  private:
16097   v8::Isolate* isolate_;
16098 };
16099
16100
16101 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
16102   if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
16103     return;
16104   }
16105   v8::HandleScope scope(CcTest::isolate());
16106   v8::Local<v8::String> string = v8::Local<v8::String>::New(
16107       CcTest::isolate(), regexp_interruption_data.string);
16108   string->MakeExternal(regexp_interruption_data.string_resource);
16109 }
16110
16111
16112 // Test that RegExp execution can be interrupted.  Specifically, we test
16113 // * interrupting with GC
16114 // * turn the subject string from one-byte internal to two-byte external string
16115 // * force termination
16116 TEST(RegExpInterruption) {
16117   v8::HandleScope scope(CcTest::isolate());
16118   LocalContext env;
16119
16120   RegExpInterruptionThread timeout_thread(CcTest::isolate());
16121
16122   v8::V8::AddGCPrologueCallback(RunBeforeGC);
16123   static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
16124   i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
16125   v8::Local<v8::String> string = v8_str(one_byte_content);
16126
16127   CcTest::global()->Set(v8_str("a"), string);
16128   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
16129   regexp_interruption_data.string_resource = new UC16VectorResource(
16130       i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
16131
16132   v8::TryCatch try_catch;
16133   timeout_thread.Start();
16134
16135   CompileRun("/((a*)*)*b/.exec(a)");
16136   CHECK(try_catch.HasTerminated());
16137
16138   timeout_thread.Join();
16139
16140   regexp_interruption_data.string.Reset();
16141   i::DeleteArray(uc16_content);
16142 }
16143
16144 #endif  // V8_INTERPRETED_REGEXP
16145
16146
16147 // Test that we cannot set a property on the global object if there
16148 // is a read-only property in the prototype chain.
16149 TEST(ReadOnlyPropertyInGlobalProto) {
16150   v8::Isolate* isolate = CcTest::isolate();
16151   v8::HandleScope scope(isolate);
16152   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16153   LocalContext context(0, templ);
16154   v8::Handle<v8::Object> global = context->Global();
16155   v8::Handle<v8::Object> global_proto =
16156       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
16157   global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
16158                          v8::ReadOnly);
16159   global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
16160                          v8::ReadOnly);
16161   // Check without 'eval' or 'with'.
16162   v8::Handle<v8::Value> res =
16163       CompileRun("function f() { x = 42; return x; }; f()");
16164   CHECK_EQ(v8::Integer::New(isolate, 0), res);
16165   // Check with 'eval'.
16166   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
16167   CHECK_EQ(v8::Integer::New(isolate, 0), res);
16168   // Check with 'with'.
16169   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
16170   CHECK_EQ(v8::Integer::New(isolate, 0), res);
16171 }
16172
16173 static int force_set_set_count = 0;
16174 static int force_set_get_count = 0;
16175 bool pass_on_get = false;
16176
16177 static void ForceSetGetter(v8::Local<v8::String> name,
16178                            const v8::PropertyCallbackInfo<v8::Value>& info) {
16179   force_set_get_count++;
16180   if (pass_on_get) {
16181     return;
16182   }
16183   info.GetReturnValue().Set(3);
16184 }
16185
16186 static void ForceSetSetter(v8::Local<v8::String> name,
16187                            v8::Local<v8::Value> value,
16188                            const v8::PropertyCallbackInfo<void>& info) {
16189   force_set_set_count++;
16190 }
16191
16192 static void ForceSetInterceptGetter(
16193     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16194   CHECK(name->IsString());
16195   ForceSetGetter(Local<String>::Cast(name), info);
16196 }
16197
16198 static void ForceSetInterceptSetter(
16199     v8::Local<v8::Name> name, v8::Local<v8::Value> value,
16200     const v8::PropertyCallbackInfo<v8::Value>& info) {
16201   force_set_set_count++;
16202   info.GetReturnValue().SetUndefined();
16203 }
16204
16205
16206 TEST(ForceSet) {
16207   force_set_get_count = 0;
16208   force_set_set_count = 0;
16209   pass_on_get = false;
16210
16211   v8::Isolate* isolate = CcTest::isolate();
16212   v8::HandleScope scope(isolate);
16213   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16214   v8::Handle<v8::String> access_property =
16215       v8::String::NewFromUtf8(isolate, "a");
16216   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
16217   LocalContext context(NULL, templ);
16218   v8::Handle<v8::Object> global = context->Global();
16219
16220   // Ordinary properties
16221   v8::Handle<v8::String> simple_property =
16222       v8::String::NewFromUtf8(isolate, "p");
16223   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
16224   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16225   // This should fail because the property is read-only
16226   global->Set(simple_property, v8::Int32::New(isolate, 5));
16227   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16228   // This should succeed even though the property is read-only
16229   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
16230   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
16231
16232   // Accessors
16233   CHECK_EQ(0, force_set_set_count);
16234   CHECK_EQ(0, force_set_get_count);
16235   CHECK_EQ(3, global->Get(access_property)->Int32Value());
16236   // CHECK_EQ the property shouldn't override it, just call the setter
16237   // which in this case does nothing.
16238   global->Set(access_property, v8::Int32::New(isolate, 7));
16239   CHECK_EQ(3, global->Get(access_property)->Int32Value());
16240   CHECK_EQ(1, force_set_set_count);
16241   CHECK_EQ(2, force_set_get_count);
16242   // Forcing the property to be set should override the accessor without
16243   // calling it
16244   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
16245   CHECK_EQ(8, global->Get(access_property)->Int32Value());
16246   CHECK_EQ(1, force_set_set_count);
16247   CHECK_EQ(2, force_set_get_count);
16248 }
16249
16250
16251 TEST(ForceSetWithInterceptor) {
16252   force_set_get_count = 0;
16253   force_set_set_count = 0;
16254   pass_on_get = false;
16255
16256   v8::Isolate* isolate = CcTest::isolate();
16257   v8::HandleScope scope(isolate);
16258   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16259   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16260       ForceSetInterceptGetter, ForceSetInterceptSetter));
16261   LocalContext context(NULL, templ);
16262   v8::Handle<v8::Object> global = context->Global();
16263
16264   v8::Handle<v8::String> some_property =
16265       v8::String::NewFromUtf8(isolate, "a");
16266   CHECK_EQ(0, force_set_set_count);
16267   CHECK_EQ(0, force_set_get_count);
16268   CHECK_EQ(3, global->Get(some_property)->Int32Value());
16269   // Setting the property shouldn't override it, just call the setter
16270   // which in this case does nothing.
16271   global->Set(some_property, v8::Int32::New(isolate, 7));
16272   CHECK_EQ(3, global->Get(some_property)->Int32Value());
16273   CHECK_EQ(1, force_set_set_count);
16274   CHECK_EQ(2, force_set_get_count);
16275   // Getting the property when the interceptor returns an empty handle
16276   // should yield undefined, since the property isn't present on the
16277   // object itself yet.
16278   pass_on_get = true;
16279   CHECK(global->Get(some_property)->IsUndefined());
16280   CHECK_EQ(1, force_set_set_count);
16281   CHECK_EQ(3, force_set_get_count);
16282   // Forcing the property to be set should cause the value to be
16283   // set locally without calling the interceptor.
16284   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
16285   CHECK_EQ(8, global->Get(some_property)->Int32Value());
16286   CHECK_EQ(1, force_set_set_count);
16287   CHECK_EQ(4, force_set_get_count);
16288   // Reenabling the interceptor should cause it to take precedence over
16289   // the property
16290   pass_on_get = false;
16291   CHECK_EQ(3, global->Get(some_property)->Int32Value());
16292   CHECK_EQ(1, force_set_set_count);
16293   CHECK_EQ(5, force_set_get_count);
16294   // The interceptor should also work for other properties
16295   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
16296                   ->Int32Value());
16297   CHECK_EQ(1, force_set_set_count);
16298   CHECK_EQ(6, force_set_get_count);
16299 }
16300
16301
16302 THREADED_TEST(ForceDelete) {
16303   v8::Isolate* isolate = CcTest::isolate();
16304   v8::HandleScope scope(isolate);
16305   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16306   LocalContext context(NULL, templ);
16307   v8::Handle<v8::Object> global = context->Global();
16308
16309   // Ordinary properties
16310   v8::Handle<v8::String> simple_property =
16311       v8::String::NewFromUtf8(isolate, "p");
16312   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
16313   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16314   // This should fail because the property is dont-delete.
16315   CHECK(!global->Delete(simple_property));
16316   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16317   // This should succeed even though the property is dont-delete.
16318   CHECK(global->ForceDelete(simple_property));
16319   CHECK(global->Get(simple_property)->IsUndefined());
16320 }
16321
16322
16323 static int force_delete_interceptor_count = 0;
16324 static bool pass_on_delete = false;
16325
16326
16327 static void ForceDeleteDeleter(
16328     v8::Local<v8::Name> name,
16329     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
16330   force_delete_interceptor_count++;
16331   if (pass_on_delete) return;
16332   info.GetReturnValue().Set(true);
16333 }
16334
16335
16336 THREADED_TEST(ForceDeleteWithInterceptor) {
16337   force_delete_interceptor_count = 0;
16338   pass_on_delete = false;
16339
16340   v8::Isolate* isolate = CcTest::isolate();
16341   v8::HandleScope scope(isolate);
16342   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16343   templ->SetHandler(
16344       v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
16345   LocalContext context(NULL, templ);
16346   v8::Handle<v8::Object> global = context->Global();
16347
16348   v8::Handle<v8::String> some_property =
16349       v8::String::NewFromUtf8(isolate, "a");
16350   global->ForceSet(some_property, v8::Integer::New(isolate, 42),
16351                    v8::DontDelete);
16352
16353   // Deleting a property should get intercepted and nothing should
16354   // happen.
16355   CHECK_EQ(0, force_delete_interceptor_count);
16356   CHECK(global->Delete(some_property));
16357   CHECK_EQ(1, force_delete_interceptor_count);
16358   CHECK_EQ(42, global->Get(some_property)->Int32Value());
16359   // Deleting the property when the interceptor returns an empty
16360   // handle should not delete the property since it is DontDelete.
16361   pass_on_delete = true;
16362   CHECK(!global->Delete(some_property));
16363   CHECK_EQ(2, force_delete_interceptor_count);
16364   CHECK_EQ(42, global->Get(some_property)->Int32Value());
16365   // Forcing the property to be deleted should delete the value
16366   // without calling the interceptor.
16367   CHECK(global->ForceDelete(some_property));
16368   CHECK(global->Get(some_property)->IsUndefined());
16369   CHECK_EQ(2, force_delete_interceptor_count);
16370 }
16371
16372
16373 // Make sure that forcing a delete invalidates any IC stubs, so we
16374 // don't read the hole value.
16375 THREADED_TEST(ForceDeleteIC) {
16376   LocalContext context;
16377   v8::HandleScope scope(context->GetIsolate());
16378   // Create a DontDelete variable on the global object.
16379   CompileRun("this.__proto__ = { foo: 'horse' };"
16380              "var foo = 'fish';"
16381              "function f() { return foo.length; }");
16382   // Initialize the IC for foo in f.
16383   CompileRun("for (var i = 0; i < 4; i++) f();");
16384   // Make sure the value of foo is correct before the deletion.
16385   CHECK_EQ(4, CompileRun("f()")->Int32Value());
16386   // Force the deletion of foo.
16387   CHECK(context->Global()->ForceDelete(v8_str("foo")));
16388   // Make sure the value for foo is read from the prototype, and that
16389   // we don't get in trouble with reading the deleted cell value
16390   // sentinel.
16391   CHECK_EQ(5, CompileRun("f()")->Int32Value());
16392 }
16393
16394
16395 TEST(InlinedFunctionAcrossContexts) {
16396   i::FLAG_allow_natives_syntax = true;
16397   v8::Isolate* isolate = CcTest::isolate();
16398   v8::HandleScope outer_scope(isolate);
16399   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
16400   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
16401   ctx1->Enter();
16402
16403   {
16404     v8::HandleScope inner_scope(CcTest::isolate());
16405     CompileRun("var G = 42; function foo() { return G; }");
16406     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
16407     ctx2->Enter();
16408     ctx2->Global()->Set(v8_str("o"), foo);
16409     v8::Local<v8::Value> res = CompileRun(
16410         "function f() { return o(); }"
16411         "for (var i = 0; i < 10; ++i) f();"
16412         "%OptimizeFunctionOnNextCall(f);"
16413         "f();");
16414     CHECK_EQ(42, res->Int32Value());
16415     ctx2->Exit();
16416     v8::Handle<v8::String> G_property =
16417         v8::String::NewFromUtf8(CcTest::isolate(), "G");
16418     CHECK(ctx1->Global()->ForceDelete(G_property));
16419     ctx2->Enter();
16420     ExpectString(
16421         "(function() {"
16422         "  try {"
16423         "    return f();"
16424         "  } catch(e) {"
16425         "    return e.toString();"
16426         "  }"
16427         " })()",
16428         "ReferenceError: G is not defined");
16429     ctx2->Exit();
16430     ctx1->Exit();
16431   }
16432 }
16433
16434
16435 static v8::Local<Context> calling_context0;
16436 static v8::Local<Context> calling_context1;
16437 static v8::Local<Context> calling_context2;
16438
16439
16440 // Check that the call to the callback is initiated in
16441 // calling_context2, the directly calling context is calling_context1
16442 // and the callback itself is in calling_context0.
16443 static void GetCallingContextCallback(
16444     const v8::FunctionCallbackInfo<v8::Value>& args) {
16445   ApiTestFuzzer::Fuzz();
16446   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
16447   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
16448   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
16449   args.GetReturnValue().Set(42);
16450 }
16451
16452
16453 THREADED_TEST(GetCurrentContextWhenNotInContext) {
16454   i::Isolate* isolate = CcTest::i_isolate();
16455   CHECK(isolate != NULL);
16456   CHECK(isolate->context() == NULL);
16457   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16458   v8::HandleScope scope(v8_isolate);
16459   // The following should not crash, but return an empty handle.
16460   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16461   CHECK(current.IsEmpty());
16462 }
16463
16464
16465 THREADED_TEST(GetCallingContext) {
16466   v8::Isolate* isolate = CcTest::isolate();
16467   v8::HandleScope scope(isolate);
16468
16469   Local<Context> calling_context0(Context::New(isolate));
16470   Local<Context> calling_context1(Context::New(isolate));
16471   Local<Context> calling_context2(Context::New(isolate));
16472   ::calling_context0 = calling_context0;
16473   ::calling_context1 = calling_context1;
16474   ::calling_context2 = calling_context2;
16475
16476   // Allow cross-domain access.
16477   Local<String> token = v8_str("<security token>");
16478   calling_context0->SetSecurityToken(token);
16479   calling_context1->SetSecurityToken(token);
16480   calling_context2->SetSecurityToken(token);
16481
16482   // Create an object with a C++ callback in context0.
16483   calling_context0->Enter();
16484   Local<v8::FunctionTemplate> callback_templ =
16485       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
16486   calling_context0->Global()->Set(v8_str("callback"),
16487                                   callback_templ->GetFunction());
16488   calling_context0->Exit();
16489
16490   // Expose context0 in context1 and set up a function that calls the
16491   // callback function.
16492   calling_context1->Enter();
16493   calling_context1->Global()->Set(v8_str("context0"),
16494                                   calling_context0->Global());
16495   CompileRun("function f() { context0.callback() }");
16496   calling_context1->Exit();
16497
16498   // Expose context1 in context2 and call the callback function in
16499   // context0 indirectly through f in context1.
16500   calling_context2->Enter();
16501   calling_context2->Global()->Set(v8_str("context1"),
16502                                   calling_context1->Global());
16503   CompileRun("context1.f()");
16504   calling_context2->Exit();
16505   ::calling_context0.Clear();
16506   ::calling_context1.Clear();
16507   ::calling_context2.Clear();
16508 }
16509
16510
16511 // Check that a variable declaration with no explicit initialization
16512 // value does shadow an existing property in the prototype chain.
16513 THREADED_TEST(InitGlobalVarInProtoChain) {
16514   LocalContext context;
16515   v8::HandleScope scope(context->GetIsolate());
16516   // Introduce a variable in the prototype chain.
16517   CompileRun("__proto__.x = 42");
16518   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
16519   CHECK(!result->IsUndefined());
16520   CHECK_EQ(43, result->Int32Value());
16521 }
16522
16523
16524 // Regression test for issue 398.
16525 // If a function is added to an object, creating a constant function
16526 // field, and the result is cloned, replacing the constant function on the
16527 // original should not affect the clone.
16528 // See http://code.google.com/p/v8/issues/detail?id=398
16529 THREADED_TEST(ReplaceConstantFunction) {
16530   LocalContext context;
16531   v8::Isolate* isolate = context->GetIsolate();
16532   v8::HandleScope scope(isolate);
16533   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16534   v8::Handle<v8::FunctionTemplate> func_templ =
16535       v8::FunctionTemplate::New(isolate);
16536   v8::Handle<v8::String> foo_string =
16537       v8::String::NewFromUtf8(isolate, "foo");
16538   obj->Set(foo_string, func_templ->GetFunction());
16539   v8::Handle<v8::Object> obj_clone = obj->Clone();
16540   obj_clone->Set(foo_string,
16541                  v8::String::NewFromUtf8(isolate, "Hello"));
16542   CHECK(!obj->Get(foo_string)->IsUndefined());
16543 }
16544
16545
16546 static void CheckElementValue(i::Isolate* isolate,
16547                               int expected,
16548                               i::Handle<i::Object> obj,
16549                               int offset) {
16550   i::Object* element =
16551       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16552   CHECK_EQ(expected, i::Smi::cast(element)->value());
16553 }
16554
16555
16556 THREADED_TEST(PixelArray) {
16557   LocalContext context;
16558   i::Isolate* isolate = CcTest::i_isolate();
16559   i::Factory* factory = isolate->factory();
16560   v8::HandleScope scope(context->GetIsolate());
16561   const int kElementCount = 260;
16562   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16563   i::Handle<i::ExternalUint8ClampedArray> pixels =
16564       i::Handle<i::ExternalUint8ClampedArray>::cast(
16565           factory->NewExternalArray(kElementCount,
16566                                     v8::kExternalUint8ClampedArray,
16567                                     pixel_data));
16568   // Force GC to trigger verification.
16569   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16570   for (int i = 0; i < kElementCount; i++) {
16571     pixels->set(i, i % 256);
16572   }
16573   // Force GC to trigger verification.
16574   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16575   for (int i = 0; i < kElementCount; i++) {
16576     CHECK_EQ(i % 256, pixels->get_scalar(i));
16577     CHECK_EQ(i % 256, pixel_data[i]);
16578   }
16579
16580   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16581   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16582   // Set the elements to be the pixels.
16583   // jsobj->set_elements(*pixels);
16584   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16585   CheckElementValue(isolate, 1, jsobj, 1);
16586   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
16587   context->Global()->Set(v8_str("pixels"), obj);
16588   v8::Handle<v8::Value> result = CompileRun("pixels.field");
16589   CHECK_EQ(1503, result->Int32Value());
16590   result = CompileRun("pixels[1]");
16591   CHECK_EQ(1, result->Int32Value());
16592
16593   result = CompileRun("var sum = 0;"
16594                       "for (var i = 0; i < 8; i++) {"
16595                       "  sum += pixels[i] = pixels[i] = -i;"
16596                       "}"
16597                       "sum;");
16598   CHECK_EQ(-28, result->Int32Value());
16599
16600   result = CompileRun("var sum = 0;"
16601                       "for (var i = 0; i < 8; i++) {"
16602                       "  sum += pixels[i] = pixels[i] = 0;"
16603                       "}"
16604                       "sum;");
16605   CHECK_EQ(0, result->Int32Value());
16606
16607   result = CompileRun("var sum = 0;"
16608                       "for (var i = 0; i < 8; i++) {"
16609                       "  sum += pixels[i] = pixels[i] = 255;"
16610                       "}"
16611                       "sum;");
16612   CHECK_EQ(8 * 255, result->Int32Value());
16613
16614   result = CompileRun("var sum = 0;"
16615                       "for (var i = 0; i < 8; i++) {"
16616                       "  sum += pixels[i] = pixels[i] = 256 + i;"
16617                       "}"
16618                       "sum;");
16619   CHECK_EQ(2076, result->Int32Value());
16620
16621   result = CompileRun("var sum = 0;"
16622                       "for (var i = 0; i < 8; i++) {"
16623                       "  sum += pixels[i] = pixels[i] = i;"
16624                       "}"
16625                       "sum;");
16626   CHECK_EQ(28, result->Int32Value());
16627
16628   result = CompileRun("var sum = 0;"
16629                       "for (var i = 0; i < 8; i++) {"
16630                       "  sum += pixels[i];"
16631                       "}"
16632                       "sum;");
16633   CHECK_EQ(28, result->Int32Value());
16634
16635   i::Handle<i::Smi> value(i::Smi::FromInt(2),
16636                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
16637   i::Handle<i::Object> no_failure;
16638   no_failure = i::JSObject::SetElement(
16639       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16640   DCHECK(!no_failure.is_null());
16641   USE(no_failure);
16642   CheckElementValue(isolate, 2, jsobj, 1);
16643   *value.location() = i::Smi::FromInt(256);
16644   no_failure = i::JSObject::SetElement(
16645       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16646   DCHECK(!no_failure.is_null());
16647   USE(no_failure);
16648   CheckElementValue(isolate, 255, jsobj, 1);
16649   *value.location() = i::Smi::FromInt(-1);
16650   no_failure = i::JSObject::SetElement(
16651       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16652   DCHECK(!no_failure.is_null());
16653   USE(no_failure);
16654   CheckElementValue(isolate, 0, jsobj, 1);
16655
16656   result = CompileRun("for (var i = 0; i < 8; i++) {"
16657                       "  pixels[i] = (i * 65) - 109;"
16658                       "}"
16659                       "pixels[1] + pixels[6];");
16660   CHECK_EQ(255, result->Int32Value());
16661   CheckElementValue(isolate, 0, jsobj, 0);
16662   CheckElementValue(isolate, 0, jsobj, 1);
16663   CheckElementValue(isolate, 21, jsobj, 2);
16664   CheckElementValue(isolate, 86, jsobj, 3);
16665   CheckElementValue(isolate, 151, jsobj, 4);
16666   CheckElementValue(isolate, 216, jsobj, 5);
16667   CheckElementValue(isolate, 255, jsobj, 6);
16668   CheckElementValue(isolate, 255, jsobj, 7);
16669   result = CompileRun("var sum = 0;"
16670                       "for (var i = 0; i < 8; i++) {"
16671                       "  sum += pixels[i];"
16672                       "}"
16673                       "sum;");
16674   CHECK_EQ(984, result->Int32Value());
16675
16676   result = CompileRun("for (var i = 0; i < 8; i++) {"
16677                       "  pixels[i] = (i * 1.1);"
16678                       "}"
16679                       "pixels[1] + pixels[6];");
16680   CHECK_EQ(8, result->Int32Value());
16681   CheckElementValue(isolate, 0, jsobj, 0);
16682   CheckElementValue(isolate, 1, jsobj, 1);
16683   CheckElementValue(isolate, 2, jsobj, 2);
16684   CheckElementValue(isolate, 3, jsobj, 3);
16685   CheckElementValue(isolate, 4, jsobj, 4);
16686   CheckElementValue(isolate, 6, jsobj, 5);
16687   CheckElementValue(isolate, 7, jsobj, 6);
16688   CheckElementValue(isolate, 8, jsobj, 7);
16689
16690   result = CompileRun("for (var i = 0; i < 8; i++) {"
16691                       "  pixels[7] = undefined;"
16692                       "}"
16693                       "pixels[7];");
16694   CHECK_EQ(0, result->Int32Value());
16695   CheckElementValue(isolate, 0, jsobj, 7);
16696
16697   result = CompileRun("for (var i = 0; i < 8; i++) {"
16698                       "  pixels[6] = '2.3';"
16699                       "}"
16700                       "pixels[6];");
16701   CHECK_EQ(2, result->Int32Value());
16702   CheckElementValue(isolate, 2, jsobj, 6);
16703
16704   result = CompileRun("for (var i = 0; i < 8; i++) {"
16705                       "  pixels[5] = NaN;"
16706                       "}"
16707                       "pixels[5];");
16708   CHECK_EQ(0, result->Int32Value());
16709   CheckElementValue(isolate, 0, jsobj, 5);
16710
16711   result = CompileRun("for (var i = 0; i < 8; i++) {"
16712                       "  pixels[8] = Infinity;"
16713                       "}"
16714                       "pixels[8];");
16715   CHECK_EQ(255, result->Int32Value());
16716   CheckElementValue(isolate, 255, jsobj, 8);
16717
16718   result = CompileRun("for (var i = 0; i < 8; i++) {"
16719                       "  pixels[9] = -Infinity;"
16720                       "}"
16721                       "pixels[9];");
16722   CHECK_EQ(0, result->Int32Value());
16723   CheckElementValue(isolate, 0, jsobj, 9);
16724
16725   result = CompileRun("pixels[3] = 33;"
16726                       "delete pixels[3];"
16727                       "pixels[3];");
16728   CHECK_EQ(33, result->Int32Value());
16729
16730   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16731                       "pixels[2] = 12; pixels[3] = 13;"
16732                       "pixels.__defineGetter__('2',"
16733                       "function() { return 120; });"
16734                       "pixels[2];");
16735   CHECK_EQ(12, result->Int32Value());
16736
16737   result = CompileRun("var js_array = new Array(40);"
16738                       "js_array[0] = 77;"
16739                       "js_array;");
16740   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16741
16742   result = CompileRun("pixels[1] = 23;"
16743                       "pixels.__proto__ = [];"
16744                       "js_array.__proto__ = pixels;"
16745                       "js_array.concat(pixels);");
16746   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16747   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16748
16749   result = CompileRun("pixels[1] = 23;");
16750   CHECK_EQ(23, result->Int32Value());
16751
16752   // Test for index greater than 255.  Regression test for:
16753   // http://code.google.com/p/chromium/issues/detail?id=26337.
16754   result = CompileRun("pixels[256] = 255;");
16755   CHECK_EQ(255, result->Int32Value());
16756   result = CompileRun("var i = 0;"
16757                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16758                       "i");
16759   CHECK_EQ(255, result->Int32Value());
16760
16761   // Make sure that pixel array ICs recognize when a non-pixel array
16762   // is passed to it.
16763   result = CompileRun("function pa_load(p) {"
16764                       "  var sum = 0;"
16765                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16766                       "  return sum;"
16767                       "}"
16768                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16769                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16770                       "just_ints = new Object();"
16771                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16772                       "for (var i = 0; i < 10; ++i) {"
16773                       "  result = pa_load(just_ints);"
16774                       "}"
16775                       "result");
16776   CHECK_EQ(32640, result->Int32Value());
16777
16778   // Make sure that pixel array ICs recognize out-of-bound accesses.
16779   result = CompileRun("function pa_load(p, start) {"
16780                       "  var sum = 0;"
16781                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16782                       "  return sum;"
16783                       "}"
16784                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16785                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16786                       "for (var i = 0; i < 10; ++i) {"
16787                       "  result = pa_load(pixels,-10);"
16788                       "}"
16789                       "result");
16790   CHECK_EQ(0, result->Int32Value());
16791
16792   // Make sure that generic ICs properly handles a pixel array.
16793   result = CompileRun("function pa_load(p) {"
16794                       "  var sum = 0;"
16795                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16796                       "  return sum;"
16797                       "}"
16798                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16799                       "just_ints = new Object();"
16800                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16801                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16802                       "for (var i = 0; i < 10; ++i) {"
16803                       "  result = pa_load(pixels);"
16804                       "}"
16805                       "result");
16806   CHECK_EQ(32640, result->Int32Value());
16807
16808   // Make sure that generic load ICs recognize out-of-bound accesses in
16809   // pixel arrays.
16810   result = CompileRun("function pa_load(p, start) {"
16811                       "  var sum = 0;"
16812                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
16813                       "  return sum;"
16814                       "}"
16815                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16816                       "just_ints = new Object();"
16817                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16818                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16819                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16820                       "for (var i = 0; i < 10; ++i) {"
16821                       "  result = pa_load(pixels,-10);"
16822                       "}"
16823                       "result");
16824   CHECK_EQ(0, result->Int32Value());
16825
16826   // Make sure that generic ICs properly handles other types than pixel
16827   // arrays (that the inlined fast pixel array test leaves the right information
16828   // in the right registers).
16829   result = CompileRun("function pa_load(p) {"
16830                       "  var sum = 0;"
16831                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
16832                       "  return sum;"
16833                       "}"
16834                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16835                       "just_ints = new Object();"
16836                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16837                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16838                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16839                       "sparse_array = new Object();"
16840                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16841                       "sparse_array[1000000] = 3;"
16842                       "for (var i = 0; i < 10; ++i) {"
16843                       "  result = pa_load(sparse_array);"
16844                       "}"
16845                       "result");
16846   CHECK_EQ(32640, result->Int32Value());
16847
16848   // Make sure that pixel array store ICs clamp values correctly.
16849   result = CompileRun("function pa_store(p) {"
16850                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16851                       "}"
16852                       "pa_store(pixels);"
16853                       "var sum = 0;"
16854                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16855                       "sum");
16856   CHECK_EQ(48896, result->Int32Value());
16857
16858   // Make sure that pixel array stores correctly handle accesses outside
16859   // of the pixel array..
16860   result = CompileRun("function pa_store(p,start) {"
16861                       "  for (var j = 0; j < 256; j++) {"
16862                       "    p[j+start] = j * 2;"
16863                       "  }"
16864                       "}"
16865                       "pa_store(pixels,0);"
16866                       "pa_store(pixels,-128);"
16867                       "var sum = 0;"
16868                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16869                       "sum");
16870   CHECK_EQ(65280, result->Int32Value());
16871
16872   // Make sure that the generic store stub correctly handle accesses outside
16873   // of the pixel array..
16874   result = CompileRun("function pa_store(p,start) {"
16875                       "  for (var j = 0; j < 256; j++) {"
16876                       "    p[j+start] = j * 2;"
16877                       "  }"
16878                       "}"
16879                       "pa_store(pixels,0);"
16880                       "just_ints = new Object();"
16881                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16882                       "pa_store(just_ints, 0);"
16883                       "pa_store(pixels,-128);"
16884                       "var sum = 0;"
16885                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16886                       "sum");
16887   CHECK_EQ(65280, result->Int32Value());
16888
16889   // Make sure that the generic keyed store stub clamps pixel array values
16890   // correctly.
16891   result = CompileRun("function pa_store(p) {"
16892                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16893                       "}"
16894                       "pa_store(pixels);"
16895                       "just_ints = new Object();"
16896                       "pa_store(just_ints);"
16897                       "pa_store(pixels);"
16898                       "var sum = 0;"
16899                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16900                       "sum");
16901   CHECK_EQ(48896, result->Int32Value());
16902
16903   // Make sure that pixel array loads are optimized by crankshaft.
16904   result = CompileRun("function pa_load(p) {"
16905                       "  var sum = 0;"
16906                       "  for (var i=0; i<256; ++i) {"
16907                       "    sum += p[i];"
16908                       "  }"
16909                       "  return sum; "
16910                       "}"
16911                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16912                       "for (var i = 0; i < 5000; ++i) {"
16913                       "  result = pa_load(pixels);"
16914                       "}"
16915                       "result");
16916   CHECK_EQ(32640, result->Int32Value());
16917
16918   // Make sure that pixel array stores are optimized by crankshaft.
16919   result = CompileRun("function pa_init(p) {"
16920                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16921                       "}"
16922                       "function pa_load(p) {"
16923                       "  var sum = 0;"
16924                       "  for (var i=0; i<256; ++i) {"
16925                       "    sum += p[i];"
16926                       "  }"
16927                       "  return sum; "
16928                       "}"
16929                       "for (var i = 0; i < 5000; ++i) {"
16930                       "  pa_init(pixels);"
16931                       "}"
16932                       "result = pa_load(pixels);"
16933                       "result");
16934   CHECK_EQ(32640, result->Int32Value());
16935
16936   free(pixel_data);
16937 }
16938
16939
16940 THREADED_TEST(PixelArrayInfo) {
16941   LocalContext context;
16942   v8::HandleScope scope(context->GetIsolate());
16943   for (int size = 0; size < 100; size += 10) {
16944     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16945     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16946     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16947     CHECK(obj->HasIndexedPropertiesInPixelData());
16948     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16949     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16950     free(pixel_data);
16951   }
16952 }
16953
16954
16955 static void NotHandledIndexedPropertyGetter(
16956     uint32_t index,
16957     const v8::PropertyCallbackInfo<v8::Value>& info) {
16958   ApiTestFuzzer::Fuzz();
16959 }
16960
16961
16962 static void NotHandledIndexedPropertySetter(
16963     uint32_t index,
16964     Local<Value> value,
16965     const v8::PropertyCallbackInfo<v8::Value>& info) {
16966   ApiTestFuzzer::Fuzz();
16967 }
16968
16969
16970 THREADED_TEST(PixelArrayWithInterceptor) {
16971   LocalContext context;
16972   i::Factory* factory = CcTest::i_isolate()->factory();
16973   v8::Isolate* isolate = context->GetIsolate();
16974   v8::HandleScope scope(isolate);
16975   const int kElementCount = 260;
16976   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16977   i::Handle<i::ExternalUint8ClampedArray> pixels =
16978       i::Handle<i::ExternalUint8ClampedArray>::cast(
16979           factory->NewExternalArray(kElementCount,
16980                                     v8::kExternalUint8ClampedArray,
16981                                     pixel_data));
16982   for (int i = 0; i < kElementCount; i++) {
16983     pixels->set(i, i % 256);
16984   }
16985   v8::Handle<v8::ObjectTemplate> templ =
16986       v8::ObjectTemplate::New(context->GetIsolate());
16987   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
16988       NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
16989   v8::Handle<v8::Object> obj = templ->NewInstance();
16990   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16991   context->Global()->Set(v8_str("pixels"), obj);
16992   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16993   CHECK_EQ(1, result->Int32Value());
16994   result = CompileRun("var sum = 0;"
16995                       "for (var i = 0; i < 8; i++) {"
16996                       "  sum += pixels[i] = pixels[i] = -i;"
16997                       "}"
16998                       "sum;");
16999   CHECK_EQ(-28, result->Int32Value());
17000   result = CompileRun("pixels.hasOwnProperty('1')");
17001   CHECK(result->BooleanValue());
17002   free(pixel_data);
17003 }
17004
17005
17006 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
17007   switch (array_type) {
17008     case v8::kExternalInt8Array:
17009     case v8::kExternalUint8Array:
17010     case v8::kExternalUint8ClampedArray:
17011       return 1;
17012       break;
17013     case v8::kExternalInt16Array:
17014     case v8::kExternalUint16Array:
17015       return 2;
17016       break;
17017     case v8::kExternalInt32Array:
17018     case v8::kExternalUint32Array:
17019     case v8::kExternalFloat32Array:
17020       return 4;
17021       break;
17022     case v8::kExternalFloat64Array:
17023       return 8;
17024       break;
17025     default:
17026       UNREACHABLE();
17027       return -1;
17028   }
17029   UNREACHABLE();
17030   return -1;
17031 }
17032
17033
17034 template <class ExternalArrayClass, class ElementType>
17035 static void ObjectWithExternalArrayTestHelper(
17036     Handle<Context> context,
17037     v8::Handle<Object> obj,
17038     int element_count,
17039     v8::ExternalArrayType array_type,
17040     int64_t low, int64_t high) {
17041   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17042   i::Isolate* isolate = jsobj->GetIsolate();
17043   obj->Set(v8_str("field"),
17044            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
17045   context->Global()->Set(v8_str("ext_array"), obj);
17046   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
17047   CHECK_EQ(1503, result->Int32Value());
17048   result = CompileRun("ext_array[1]");
17049   CHECK_EQ(1, result->Int32Value());
17050
17051   // Check assigned smis
17052   result = CompileRun("for (var i = 0; i < 8; i++) {"
17053                       "  ext_array[i] = i;"
17054                       "}"
17055                       "var sum = 0;"
17056                       "for (var i = 0; i < 8; i++) {"
17057                       "  sum += ext_array[i];"
17058                       "}"
17059                       "sum;");
17060
17061   CHECK_EQ(28, result->Int32Value());
17062   // Check pass through of assigned smis
17063   result = CompileRun("var sum = 0;"
17064                       "for (var i = 0; i < 8; i++) {"
17065                       "  sum += ext_array[i] = ext_array[i] = -i;"
17066                       "}"
17067                       "sum;");
17068   CHECK_EQ(-28, result->Int32Value());
17069
17070
17071   // Check assigned smis in reverse order
17072   result = CompileRun("for (var i = 8; --i >= 0; ) {"
17073                       "  ext_array[i] = i;"
17074                       "}"
17075                       "var sum = 0;"
17076                       "for (var i = 0; i < 8; i++) {"
17077                       "  sum += ext_array[i];"
17078                       "}"
17079                       "sum;");
17080   CHECK_EQ(28, result->Int32Value());
17081
17082   // Check pass through of assigned HeapNumbers
17083   result = CompileRun("var sum = 0;"
17084                       "for (var i = 0; i < 16; i+=2) {"
17085                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
17086                       "}"
17087                       "sum;");
17088   CHECK_EQ(-28, result->Int32Value());
17089
17090   // Check assigned HeapNumbers
17091   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
17092                       "  ext_array[i] = (i * 0.5);"
17093                       "}"
17094                       "var sum = 0;"
17095                       "for (var i = 0; i < 16; i+=2) {"
17096                       "  sum += ext_array[i];"
17097                       "}"
17098                       "sum;");
17099   CHECK_EQ(28, result->Int32Value());
17100
17101   // Check assigned HeapNumbers in reverse order
17102   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
17103                       "  ext_array[i] = (i * 0.5);"
17104                       "}"
17105                       "var sum = 0;"
17106                       "for (var i = 0; i < 16; i+=2) {"
17107                       "  sum += ext_array[i];"
17108                       "}"
17109                       "sum;");
17110   CHECK_EQ(28, result->Int32Value());
17111
17112   i::ScopedVector<char> test_buf(1024);
17113
17114   // Check legal boundary conditions.
17115   // The repeated loads and stores ensure the ICs are exercised.
17116   const char* boundary_program =
17117       "var res = 0;"
17118       "for (var i = 0; i < 16; i++) {"
17119       "  ext_array[i] = %lld;"
17120       "  if (i > 8) {"
17121       "    res = ext_array[i];"
17122       "  }"
17123       "}"
17124       "res;";
17125   i::SNPrintF(test_buf,
17126               boundary_program,
17127               low);
17128   result = CompileRun(test_buf.start());
17129   CHECK_EQ(low, result->IntegerValue());
17130
17131   i::SNPrintF(test_buf,
17132               boundary_program,
17133               high);
17134   result = CompileRun(test_buf.start());
17135   CHECK_EQ(high, result->IntegerValue());
17136
17137   // Check misprediction of type in IC.
17138   result = CompileRun("var tmp_array = ext_array;"
17139                       "var sum = 0;"
17140                       "for (var i = 0; i < 8; i++) {"
17141                       "  tmp_array[i] = i;"
17142                       "  sum += tmp_array[i];"
17143                       "  if (i == 4) {"
17144                       "    tmp_array = {};"
17145                       "  }"
17146                       "}"
17147                       "sum;");
17148   // Force GC to trigger verification.
17149   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17150   CHECK_EQ(28, result->Int32Value());
17151
17152   // Make sure out-of-range loads do not throw.
17153   i::SNPrintF(test_buf,
17154               "var caught_exception = false;"
17155               "try {"
17156               "  ext_array[%d];"
17157               "} catch (e) {"
17158               "  caught_exception = true;"
17159               "}"
17160               "caught_exception;",
17161               element_count);
17162   result = CompileRun(test_buf.start());
17163   CHECK_EQ(false, result->BooleanValue());
17164
17165   // Make sure out-of-range stores do not throw.
17166   i::SNPrintF(test_buf,
17167               "var caught_exception = false;"
17168               "try {"
17169               "  ext_array[%d] = 1;"
17170               "} catch (e) {"
17171               "  caught_exception = true;"
17172               "}"
17173               "caught_exception;",
17174               element_count);
17175   result = CompileRun(test_buf.start());
17176   CHECK_EQ(false, result->BooleanValue());
17177
17178   // Check other boundary conditions, values and operations.
17179   result = CompileRun("for (var i = 0; i < 8; i++) {"
17180                       "  ext_array[7] = undefined;"
17181                       "}"
17182                       "ext_array[7];");
17183   CHECK_EQ(0, result->Int32Value());
17184   if (array_type == v8::kExternalFloat64Array ||
17185       array_type == v8::kExternalFloat32Array) {
17186     CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
17187              static_cast<int>(
17188                  i::Object::GetElement(
17189                      isolate, jsobj, 7).ToHandleChecked()->Number()));
17190   } else {
17191     CheckElementValue(isolate, 0, jsobj, 7);
17192   }
17193
17194   result = CompileRun("for (var i = 0; i < 8; i++) {"
17195                       "  ext_array[6] = '2.3';"
17196                       "}"
17197                       "ext_array[6];");
17198   CHECK_EQ(2, result->Int32Value());
17199   CHECK_EQ(2,
17200            static_cast<int>(
17201                i::Object::GetElement(
17202                    isolate, jsobj, 6).ToHandleChecked()->Number()));
17203
17204   if (array_type != v8::kExternalFloat32Array &&
17205       array_type != v8::kExternalFloat64Array) {
17206     // Though the specification doesn't state it, be explicit about
17207     // converting NaNs and +/-Infinity to zero.
17208     result = CompileRun("for (var i = 0; i < 8; i++) {"
17209                         "  ext_array[i] = 5;"
17210                         "}"
17211                         "for (var i = 0; i < 8; i++) {"
17212                         "  ext_array[i] = NaN;"
17213                         "}"
17214                         "ext_array[5];");
17215     CHECK_EQ(0, result->Int32Value());
17216     CheckElementValue(isolate, 0, jsobj, 5);
17217
17218     result = CompileRun("for (var i = 0; i < 8; i++) {"
17219                         "  ext_array[i] = 5;"
17220                         "}"
17221                         "for (var i = 0; i < 8; i++) {"
17222                         "  ext_array[i] = Infinity;"
17223                         "}"
17224                         "ext_array[5];");
17225     int expected_value =
17226         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
17227     CHECK_EQ(expected_value, result->Int32Value());
17228     CheckElementValue(isolate, expected_value, jsobj, 5);
17229
17230     result = CompileRun("for (var i = 0; i < 8; i++) {"
17231                         "  ext_array[i] = 5;"
17232                         "}"
17233                         "for (var i = 0; i < 8; i++) {"
17234                         "  ext_array[i] = -Infinity;"
17235                         "}"
17236                         "ext_array[5];");
17237     CHECK_EQ(0, result->Int32Value());
17238     CheckElementValue(isolate, 0, jsobj, 5);
17239
17240     // Check truncation behavior of integral arrays.
17241     const char* unsigned_data =
17242         "var source_data = [0.6, 10.6];"
17243         "var expected_results = [0, 10];";
17244     const char* signed_data =
17245         "var source_data = [0.6, 10.6, -0.6, -10.6];"
17246         "var expected_results = [0, 10, 0, -10];";
17247     const char* pixel_data =
17248         "var source_data = [0.6, 10.6];"
17249         "var expected_results = [1, 11];";
17250     bool is_unsigned =
17251         (array_type == v8::kExternalUint8Array ||
17252          array_type == v8::kExternalUint16Array ||
17253          array_type == v8::kExternalUint32Array);
17254     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
17255
17256     i::SNPrintF(test_buf,
17257                 "%s"
17258                 "var all_passed = true;"
17259                 "for (var i = 0; i < source_data.length; i++) {"
17260                 "  for (var j = 0; j < 8; j++) {"
17261                 "    ext_array[j] = source_data[i];"
17262                 "  }"
17263                 "  all_passed = all_passed &&"
17264                 "               (ext_array[5] == expected_results[i]);"
17265                 "}"
17266                 "all_passed;",
17267                 (is_unsigned ?
17268                      unsigned_data :
17269                      (is_pixel_data ? pixel_data : signed_data)));
17270     result = CompileRun(test_buf.start());
17271     CHECK_EQ(true, result->BooleanValue());
17272   }
17273
17274   i::Handle<ExternalArrayClass> array(
17275       ExternalArrayClass::cast(jsobj->elements()));
17276   for (int i = 0; i < element_count; i++) {
17277     array->set(i, static_cast<ElementType>(i));
17278   }
17279
17280   // Test complex assignments
17281   result = CompileRun("function ee_op_test_complex_func(sum) {"
17282                       " for (var i = 0; i < 40; ++i) {"
17283                       "   sum += (ext_array[i] += 1);"
17284                       "   sum += (ext_array[i] -= 1);"
17285                       " } "
17286                       " return sum;"
17287                       "}"
17288                       "sum=0;"
17289                       "for (var i=0;i<10000;++i) {"
17290                       "  sum=ee_op_test_complex_func(sum);"
17291                       "}"
17292                       "sum;");
17293   CHECK_EQ(16000000, result->Int32Value());
17294
17295   // Test count operations
17296   result = CompileRun("function ee_op_test_count_func(sum) {"
17297                       " for (var i = 0; i < 40; ++i) {"
17298                       "   sum += (++ext_array[i]);"
17299                       "   sum += (--ext_array[i]);"
17300                       " } "
17301                       " return sum;"
17302                       "}"
17303                       "sum=0;"
17304                       "for (var i=0;i<10000;++i) {"
17305                       "  sum=ee_op_test_count_func(sum);"
17306                       "}"
17307                       "sum;");
17308   CHECK_EQ(16000000, result->Int32Value());
17309
17310   result = CompileRun("ext_array[3] = 33;"
17311                       "delete ext_array[3];"
17312                       "ext_array[3];");
17313   CHECK_EQ(33, result->Int32Value());
17314
17315   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
17316                       "ext_array[2] = 12; ext_array[3] = 13;"
17317                       "ext_array.__defineGetter__('2',"
17318                       "function() { return 120; });"
17319                       "ext_array[2];");
17320   CHECK_EQ(12, result->Int32Value());
17321
17322   result = CompileRun("var js_array = new Array(40);"
17323                       "js_array[0] = 77;"
17324                       "js_array;");
17325   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
17326
17327   result = CompileRun("ext_array[1] = 23;"
17328                       "ext_array.__proto__ = [];"
17329                       "js_array.__proto__ = ext_array;"
17330                       "js_array.concat(ext_array);");
17331   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
17332   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
17333
17334   result = CompileRun("ext_array[1] = 23;");
17335   CHECK_EQ(23, result->Int32Value());
17336 }
17337
17338
17339 template <class FixedTypedArrayClass,
17340           i::ElementsKind elements_kind,
17341           class ElementType>
17342 static void FixedTypedArrayTestHelper(
17343     v8::ExternalArrayType array_type,
17344     ElementType low,
17345     ElementType high) {
17346   i::FLAG_allow_natives_syntax = true;
17347   LocalContext context;
17348   i::Isolate* isolate = CcTest::i_isolate();
17349   i::Factory* factory = isolate->factory();
17350   v8::HandleScope scope(context->GetIsolate());
17351   const int kElementCount = 260;
17352   i::Handle<FixedTypedArrayClass> fixed_array =
17353     i::Handle<FixedTypedArrayClass>::cast(
17354         factory->NewFixedTypedArray(kElementCount, array_type));
17355   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
17356            fixed_array->map()->instance_type());
17357   CHECK_EQ(kElementCount, fixed_array->length());
17358   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17359   for (int i = 0; i < kElementCount; i++) {
17360     fixed_array->set(i, static_cast<ElementType>(i));
17361   }
17362   // Force GC to trigger verification.
17363   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17364   for (int i = 0; i < kElementCount; i++) {
17365     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
17366              static_cast<int64_t>(fixed_array->get_scalar(i)));
17367   }
17368   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
17369   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17370   i::Handle<i::Map> fixed_array_map =
17371       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
17372   jsobj->set_map(*fixed_array_map);
17373   jsobj->set_elements(*fixed_array);
17374
17375   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
17376       context.local(), obj, kElementCount, array_type,
17377       static_cast<int64_t>(low),
17378       static_cast<int64_t>(high));
17379 }
17380
17381
17382 THREADED_TEST(FixedUint8Array) {
17383   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
17384     v8::kExternalUint8Array,
17385     0x0, 0xFF);
17386 }
17387
17388
17389 THREADED_TEST(FixedUint8ClampedArray) {
17390   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
17391                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
17392     v8::kExternalUint8ClampedArray,
17393     0x0, 0xFF);
17394 }
17395
17396
17397 THREADED_TEST(FixedInt8Array) {
17398   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
17399     v8::kExternalInt8Array,
17400     -0x80, 0x7F);
17401 }
17402
17403
17404 THREADED_TEST(FixedUint16Array) {
17405   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
17406     v8::kExternalUint16Array,
17407     0x0, 0xFFFF);
17408 }
17409
17410
17411 THREADED_TEST(FixedInt16Array) {
17412   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
17413     v8::kExternalInt16Array,
17414     -0x8000, 0x7FFF);
17415 }
17416
17417
17418 THREADED_TEST(FixedUint32Array) {
17419   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
17420     v8::kExternalUint32Array,
17421     0x0, UINT_MAX);
17422 }
17423
17424
17425 THREADED_TEST(FixedInt32Array) {
17426   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
17427     v8::kExternalInt32Array,
17428     INT_MIN, INT_MAX);
17429 }
17430
17431
17432 THREADED_TEST(FixedFloat32Array) {
17433   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
17434     v8::kExternalFloat32Array,
17435     -500, 500);
17436 }
17437
17438
17439 THREADED_TEST(FixedFloat64Array) {
17440   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
17441     v8::kExternalFloat64Array,
17442     -500, 500);
17443 }
17444
17445
17446 template <class ExternalArrayClass, class ElementType>
17447 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
17448                                     int64_t low,
17449                                     int64_t high) {
17450   LocalContext context;
17451   i::Isolate* isolate = CcTest::i_isolate();
17452   i::Factory* factory = isolate->factory();
17453   v8::HandleScope scope(context->GetIsolate());
17454   const int kElementCount = 40;
17455   int element_size = ExternalArrayElementSize(array_type);
17456   ElementType* array_data =
17457       static_cast<ElementType*>(malloc(kElementCount * element_size));
17458   i::Handle<ExternalArrayClass> array =
17459       i::Handle<ExternalArrayClass>::cast(
17460           factory->NewExternalArray(kElementCount, array_type, array_data));
17461   // Force GC to trigger verification.
17462   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17463   for (int i = 0; i < kElementCount; i++) {
17464     array->set(i, static_cast<ElementType>(i));
17465   }
17466   // Force GC to trigger verification.
17467   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17468   for (int i = 0; i < kElementCount; i++) {
17469     CHECK_EQ(static_cast<int64_t>(i),
17470              static_cast<int64_t>(array->get_scalar(i)));
17471     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
17472   }
17473
17474   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17475   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17476   // Set the elements to be the external array.
17477   obj->SetIndexedPropertiesToExternalArrayData(array_data,
17478                                                array_type,
17479                                                kElementCount);
17480   CHECK_EQ(1,
17481            static_cast<int>(
17482                i::Object::GetElement(
17483                    isolate, jsobj, 1).ToHandleChecked()->Number()));
17484
17485   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17486       context.local(), obj, kElementCount, array_type, low, high);
17487
17488   v8::Handle<v8::Value> result;
17489
17490   // Test more complex manipulations which cause eax to contain values
17491   // that won't be completely overwritten by loads from the arrays.
17492   // This catches bugs in the instructions used for the KeyedLoadIC
17493   // for byte and word types.
17494   {
17495     const int kXSize = 300;
17496     const int kYSize = 300;
17497     const int kLargeElementCount = kXSize * kYSize * 4;
17498     ElementType* large_array_data =
17499         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
17500     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
17501     // Set the elements to be the external array.
17502     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
17503                                                        array_type,
17504                                                        kLargeElementCount);
17505     context->Global()->Set(v8_str("large_array"), large_obj);
17506     // Initialize contents of a few rows.
17507     for (int x = 0; x < 300; x++) {
17508       int row = 0;
17509       int offset = row * 300 * 4;
17510       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17511       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17512       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17513       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17514       row = 150;
17515       offset = row * 300 * 4;
17516       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17517       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17518       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17519       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17520       row = 298;
17521       offset = row * 300 * 4;
17522       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17523       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17524       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17525       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17526     }
17527     // The goal of the code below is to make "offset" large enough
17528     // that the computation of the index (which goes into eax) has
17529     // high bits set which will not be overwritten by a byte or short
17530     // load.
17531     result = CompileRun("var failed = false;"
17532                         "var offset = 0;"
17533                         "for (var i = 0; i < 300; i++) {"
17534                         "  if (large_array[4 * i] != 127 ||"
17535                         "      large_array[4 * i + 1] != 0 ||"
17536                         "      large_array[4 * i + 2] != 0 ||"
17537                         "      large_array[4 * i + 3] != 127) {"
17538                         "    failed = true;"
17539                         "  }"
17540                         "}"
17541                         "offset = 150 * 300 * 4;"
17542                         "for (var i = 0; i < 300; i++) {"
17543                         "  if (large_array[offset + 4 * i] != 127 ||"
17544                         "      large_array[offset + 4 * i + 1] != 0 ||"
17545                         "      large_array[offset + 4 * i + 2] != 0 ||"
17546                         "      large_array[offset + 4 * i + 3] != 127) {"
17547                         "    failed = true;"
17548                         "  }"
17549                         "}"
17550                         "offset = 298 * 300 * 4;"
17551                         "for (var i = 0; i < 300; i++) {"
17552                         "  if (large_array[offset + 4 * i] != 127 ||"
17553                         "      large_array[offset + 4 * i + 1] != 0 ||"
17554                         "      large_array[offset + 4 * i + 2] != 0 ||"
17555                         "      large_array[offset + 4 * i + 3] != 127) {"
17556                         "    failed = true;"
17557                         "  }"
17558                         "}"
17559                         "!failed;");
17560     CHECK_EQ(true, result->BooleanValue());
17561     free(large_array_data);
17562   }
17563
17564   // The "" property descriptor is overloaded to store information about
17565   // the external array. Ensure that setting and accessing the "" property
17566   // works (it should overwrite the information cached about the external
17567   // array in the DescriptorArray) in various situations.
17568   result = CompileRun("ext_array[''] = 23; ext_array['']");
17569   CHECK_EQ(23, result->Int32Value());
17570
17571   // Property "" set after the external array is associated with the object.
17572   {
17573     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17574     obj2->Set(v8_str("ee_test_field"),
17575               v8::Int32::New(context->GetIsolate(), 256));
17576     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17577     // Set the elements to be the external array.
17578     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17579                                                   array_type,
17580                                                   kElementCount);
17581     context->Global()->Set(v8_str("ext_array"), obj2);
17582     result = CompileRun("ext_array['']");
17583     CHECK_EQ(1503, result->Int32Value());
17584   }
17585
17586   // Property "" set after the external array is associated with the object.
17587   {
17588     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17589     obj2->Set(v8_str("ee_test_field_2"),
17590               v8::Int32::New(context->GetIsolate(), 256));
17591     // Set the elements to be the external array.
17592     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17593                                                   array_type,
17594                                                   kElementCount);
17595     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17596     context->Global()->Set(v8_str("ext_array"), obj2);
17597     result = CompileRun("ext_array['']");
17598     CHECK_EQ(1503, result->Int32Value());
17599   }
17600
17601   // Should reuse the map from previous test.
17602   {
17603     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17604     obj2->Set(v8_str("ee_test_field_2"),
17605               v8::Int32::New(context->GetIsolate(), 256));
17606     // Set the elements to be the external array. Should re-use the map
17607     // from previous test.
17608     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17609                                                   array_type,
17610                                                   kElementCount);
17611     context->Global()->Set(v8_str("ext_array"), obj2);
17612     result = CompileRun("ext_array['']");
17613   }
17614
17615   // Property "" is a constant function that shouldn't not be interfered with
17616   // when an external array is set.
17617   {
17618     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17619     // Start
17620     obj2->Set(v8_str("ee_test_field3"),
17621               v8::Int32::New(context->GetIsolate(), 256));
17622
17623     // Add a constant function to an object.
17624     context->Global()->Set(v8_str("ext_array"), obj2);
17625     result = CompileRun("ext_array[''] = function() {return 1503;};"
17626                         "ext_array['']();");
17627
17628     // Add an external array transition to the same map that
17629     // has the constant transition.
17630     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17631     obj3->Set(v8_str("ee_test_field3"),
17632               v8::Int32::New(context->GetIsolate(), 256));
17633     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17634                                                   array_type,
17635                                                   kElementCount);
17636     context->Global()->Set(v8_str("ext_array"), obj3);
17637   }
17638
17639   // If a external array transition is in the map, it should get clobbered
17640   // by a constant function.
17641   {
17642     // Add an external array transition.
17643     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17644     obj3->Set(v8_str("ee_test_field4"),
17645               v8::Int32::New(context->GetIsolate(), 256));
17646     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17647                                                   array_type,
17648                                                   kElementCount);
17649
17650     // Add a constant function to the same map that just got an external array
17651     // transition.
17652     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17653     obj2->Set(v8_str("ee_test_field4"),
17654               v8::Int32::New(context->GetIsolate(), 256));
17655     context->Global()->Set(v8_str("ext_array"), obj2);
17656     result = CompileRun("ext_array[''] = function() {return 1503;};"
17657                         "ext_array['']();");
17658   }
17659
17660   free(array_data);
17661 }
17662
17663
17664 THREADED_TEST(ExternalInt8Array) {
17665   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
17666       v8::kExternalInt8Array,
17667       -128,
17668       127);
17669 }
17670
17671
17672 THREADED_TEST(ExternalUint8Array) {
17673   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
17674       v8::kExternalUint8Array,
17675       0,
17676       255);
17677 }
17678
17679
17680 THREADED_TEST(ExternalUint8ClampedArray) {
17681   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
17682       v8::kExternalUint8ClampedArray,
17683       0,
17684       255);
17685 }
17686
17687
17688 THREADED_TEST(ExternalInt16Array) {
17689   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17690       v8::kExternalInt16Array,
17691       -32768,
17692       32767);
17693 }
17694
17695
17696 THREADED_TEST(ExternalUint16Array) {
17697   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17698       v8::kExternalUint16Array,
17699       0,
17700       65535);
17701 }
17702
17703
17704 THREADED_TEST(ExternalInt32Array) {
17705   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17706       v8::kExternalInt32Array,
17707       INT_MIN,   // -2147483648
17708       INT_MAX);  //  2147483647
17709 }
17710
17711
17712 THREADED_TEST(ExternalUint32Array) {
17713   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17714       v8::kExternalUint32Array,
17715       0,
17716       UINT_MAX);  // 4294967295
17717 }
17718
17719
17720 THREADED_TEST(ExternalFloat32Array) {
17721   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17722       v8::kExternalFloat32Array,
17723       -500,
17724       500);
17725 }
17726
17727
17728 THREADED_TEST(ExternalFloat64Array) {
17729   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17730       v8::kExternalFloat64Array,
17731       -500,
17732       500);
17733 }
17734
17735
17736 THREADED_TEST(ExternalArrays) {
17737   TestExternalInt8Array();
17738   TestExternalUint8Array();
17739   TestExternalInt16Array();
17740   TestExternalUint16Array();
17741   TestExternalInt32Array();
17742   TestExternalUint32Array();
17743   TestExternalFloat32Array();
17744 }
17745
17746
17747 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
17748   LocalContext context;
17749   v8::HandleScope scope(context->GetIsolate());
17750   for (int size = 0; size < 100; size += 10) {
17751     int element_size = ExternalArrayElementSize(array_type);
17752     void* external_data = malloc(size * element_size);
17753     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17754     obj->SetIndexedPropertiesToExternalArrayData(
17755         external_data, array_type, size);
17756     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17757     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17758     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17759     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17760     free(external_data);
17761   }
17762 }
17763
17764
17765 THREADED_TEST(ExternalArrayInfo) {
17766   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17767   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17768   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17769   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17770   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17771   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17772   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17773   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17774   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
17775 }
17776
17777
17778 void ExtArrayLimitsHelper(v8::Isolate* isolate,
17779                           v8::ExternalArrayType array_type,
17780                           int size) {
17781   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17782   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17783   last_location = last_message = NULL;
17784   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17785   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17786   CHECK_NE(NULL, last_location);
17787   CHECK_NE(NULL, last_message);
17788 }
17789
17790
17791 TEST(ExternalArrayLimits) {
17792   LocalContext context;
17793   v8::Isolate* isolate = context->GetIsolate();
17794   v8::HandleScope scope(isolate);
17795   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17796   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17797   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17798   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17799   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17800   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17801   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17802   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17803   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17804   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17805   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17806   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17807   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17808   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17809   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17810   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17811   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17812   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17813 }
17814
17815
17816 template <typename ElementType, typename TypedArray,
17817           class ExternalArrayClass>
17818 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17819                           int64_t low, int64_t high) {
17820   const int kElementCount = 50;
17821
17822   i::ScopedVector<ElementType> backing_store(kElementCount+2);
17823
17824   LocalContext env;
17825   v8::Isolate* isolate = env->GetIsolate();
17826   v8::HandleScope handle_scope(isolate);
17827
17828   Local<v8::ArrayBuffer> ab =
17829       v8::ArrayBuffer::New(isolate, backing_store.start(),
17830                            (kElementCount + 2) * sizeof(ElementType));
17831   Local<TypedArray> ta =
17832       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17833   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17834   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17835   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17836   CHECK_EQ(kElementCount*sizeof(ElementType),
17837            static_cast<int>(ta->ByteLength()));
17838   CHECK_EQ(ab, ta->Buffer());
17839
17840   ElementType* data = backing_store.start() + 2;
17841   for (int i = 0; i < kElementCount; i++) {
17842     data[i] = static_cast<ElementType>(i);
17843   }
17844
17845   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17846       env.local(), ta, kElementCount, array_type, low, high);
17847 }
17848
17849
17850 THREADED_TEST(Uint8Array) {
17851   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17852       v8::kExternalUint8Array, 0, 0xFF);
17853 }
17854
17855
17856 THREADED_TEST(Int8Array) {
17857   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17858       v8::kExternalInt8Array, -0x80, 0x7F);
17859 }
17860
17861
17862 THREADED_TEST(Uint16Array) {
17863   TypedArrayTestHelper<uint16_t,
17864                        v8::Uint16Array,
17865                        i::ExternalUint16Array>(
17866       v8::kExternalUint16Array, 0, 0xFFFF);
17867 }
17868
17869
17870 THREADED_TEST(Int16Array) {
17871   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17872       v8::kExternalInt16Array, -0x8000, 0x7FFF);
17873 }
17874
17875
17876 THREADED_TEST(Uint32Array) {
17877   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17878       v8::kExternalUint32Array, 0, UINT_MAX);
17879 }
17880
17881
17882 THREADED_TEST(Int32Array) {
17883   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17884       v8::kExternalInt32Array, INT_MIN, INT_MAX);
17885 }
17886
17887
17888 THREADED_TEST(Float32Array) {
17889   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17890       v8::kExternalFloat32Array, -500, 500);
17891 }
17892
17893
17894 THREADED_TEST(Float64Array) {
17895   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17896       v8::kExternalFloat64Array, -500, 500);
17897 }
17898
17899
17900 THREADED_TEST(Uint8ClampedArray) {
17901   TypedArrayTestHelper<uint8_t,
17902                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17903       v8::kExternalUint8ClampedArray, 0, 0xFF);
17904 }
17905
17906
17907 THREADED_TEST(DataView) {
17908   const int kSize = 50;
17909
17910   i::ScopedVector<uint8_t> backing_store(kSize+2);
17911
17912   LocalContext env;
17913   v8::Isolate* isolate = env->GetIsolate();
17914   v8::HandleScope handle_scope(isolate);
17915
17916   Local<v8::ArrayBuffer> ab =
17917       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17918   Local<v8::DataView> dv =
17919       v8::DataView::New(ab, 2, kSize);
17920   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17921   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17922   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17923   CHECK_EQ(ab, dv->Buffer());
17924 }
17925
17926
17927 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
17928   THREADED_TEST(Is##View) {                                                   \
17929     LocalContext env;                                                         \
17930     v8::Isolate* isolate = env->GetIsolate();                                 \
17931     v8::HandleScope handle_scope(isolate);                                    \
17932                                                                               \
17933     Handle<Value> result = CompileRun(                                        \
17934         "var ab = new ArrayBuffer(128);"                                      \
17935         "new " #View "(ab)");                                                 \
17936     CHECK(result->IsArrayBufferView());                                       \
17937     CHECK(result->Is##View());                                                \
17938     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17939   }
17940
17941 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17942 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17943 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17944 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17945 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17946 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17947 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17948 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17949 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17950 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17951
17952 #undef IS_ARRAY_BUFFER_VIEW_TEST
17953
17954
17955
17956 THREADED_TEST(ScriptContextDependence) {
17957   LocalContext c1;
17958   v8::HandleScope scope(c1->GetIsolate());
17959   const char *source = "foo";
17960   v8::Handle<v8::Script> dep = v8_compile(source);
17961   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17962       c1->GetIsolate(), source));
17963   v8::Handle<v8::UnboundScript> indep =
17964       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17965   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17966                     v8::Integer::New(c1->GetIsolate(), 100));
17967   CHECK_EQ(dep->Run()->Int32Value(), 100);
17968   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17969   LocalContext c2;
17970   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17971                     v8::Integer::New(c2->GetIsolate(), 101));
17972   CHECK_EQ(dep->Run()->Int32Value(), 100);
17973   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17974 }
17975
17976
17977 THREADED_TEST(StackTrace) {
17978   LocalContext context;
17979   v8::HandleScope scope(context->GetIsolate());
17980   v8::TryCatch try_catch;
17981   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17982   v8::Handle<v8::String> src =
17983       v8::String::NewFromUtf8(context->GetIsolate(), source);
17984   v8::Handle<v8::String> origin =
17985       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17986   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17987   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17988       ->BindToCurrentContext()
17989       ->Run();
17990   CHECK(try_catch.HasCaught());
17991   v8::String::Utf8Value stack(try_catch.StackTrace());
17992   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17993 }
17994
17995
17996 // Checks that a StackFrame has certain expected values.
17997 void checkStackFrame(const char* expected_script_name,
17998     const char* expected_func_name, int expected_line_number,
17999     int expected_column, bool is_eval, bool is_constructor,
18000     v8::Handle<v8::StackFrame> frame) {
18001   v8::HandleScope scope(CcTest::isolate());
18002   v8::String::Utf8Value func_name(frame->GetFunctionName());
18003   v8::String::Utf8Value script_name(frame->GetScriptName());
18004   if (*script_name == NULL) {
18005     // The situation where there is no associated script, like for evals.
18006     CHECK(expected_script_name == NULL);
18007   } else {
18008     CHECK(strstr(*script_name, expected_script_name) != NULL);
18009   }
18010   CHECK(strstr(*func_name, expected_func_name) != NULL);
18011   CHECK_EQ(expected_line_number, frame->GetLineNumber());
18012   CHECK_EQ(expected_column, frame->GetColumn());
18013   CHECK_EQ(is_eval, frame->IsEval());
18014   CHECK_EQ(is_constructor, frame->IsConstructor());
18015 }
18016
18017
18018 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
18019   v8::HandleScope scope(args.GetIsolate());
18020   const char* origin = "capture-stack-trace-test";
18021   const int kOverviewTest = 1;
18022   const int kDetailedTest = 2;
18023
18024   DCHECK(args.Length() == 1);
18025
18026   int testGroup = args[0]->Int32Value();
18027   if (testGroup == kOverviewTest) {
18028     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18029         args.GetIsolate(), 10, v8::StackTrace::kOverview);
18030     CHECK_EQ(4, stackTrace->GetFrameCount());
18031     checkStackFrame(origin, "bar", 2, 10, false, false,
18032                     stackTrace->GetFrame(0));
18033     checkStackFrame(origin, "foo", 6, 3, false, false,
18034                     stackTrace->GetFrame(1));
18035     // This is the source string inside the eval which has the call to foo.
18036     checkStackFrame(NULL, "", 1, 5, false, false,
18037                     stackTrace->GetFrame(2));
18038     // The last frame is an anonymous function which has the initial eval call.
18039     checkStackFrame(origin, "", 8, 7, false, false,
18040                     stackTrace->GetFrame(3));
18041
18042     CHECK(stackTrace->AsArray()->IsArray());
18043   } else if (testGroup == kDetailedTest) {
18044     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18045         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18046     CHECK_EQ(4, stackTrace->GetFrameCount());
18047     checkStackFrame(origin, "bat", 4, 22, false, false,
18048                     stackTrace->GetFrame(0));
18049     checkStackFrame(origin, "baz", 8, 3, false, true,
18050                     stackTrace->GetFrame(1));
18051     bool is_eval = true;
18052     // This is the source string inside the eval which has the call to baz.
18053     checkStackFrame(NULL, "", 1, 5, is_eval, false,
18054                     stackTrace->GetFrame(2));
18055     // The last frame is an anonymous function which has the initial eval call.
18056     checkStackFrame(origin, "", 10, 1, false, false,
18057                     stackTrace->GetFrame(3));
18058
18059     CHECK(stackTrace->AsArray()->IsArray());
18060   }
18061 }
18062
18063
18064 // Tests the C++ StackTrace API.
18065 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
18066 // THREADED_TEST(CaptureStackTrace) {
18067 TEST(CaptureStackTrace) {
18068   v8::Isolate* isolate = CcTest::isolate();
18069   v8::HandleScope scope(isolate);
18070   v8::Handle<v8::String> origin =
18071       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
18072   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18073   templ->Set(v8_str("AnalyzeStackInNativeCode"),
18074              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
18075   LocalContext context(0, templ);
18076
18077   // Test getting OVERVIEW information. Should ignore information that is not
18078   // script name, function name, line number, and column offset.
18079   const char *overview_source =
18080     "function bar() {\n"
18081     "  var y; AnalyzeStackInNativeCode(1);\n"
18082     "}\n"
18083     "function foo() {\n"
18084     "\n"
18085     "  bar();\n"
18086     "}\n"
18087     "var x;eval('new foo();');";
18088   v8::Handle<v8::String> overview_src =
18089       v8::String::NewFromUtf8(isolate, overview_source);
18090   v8::ScriptCompiler::Source script_source(overview_src,
18091                                            v8::ScriptOrigin(origin));
18092   v8::Handle<Value> overview_result(
18093       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
18094           ->BindToCurrentContext()
18095           ->Run());
18096   CHECK(!overview_result.IsEmpty());
18097   CHECK(overview_result->IsObject());
18098
18099   // Test getting DETAILED information.
18100   const char *detailed_source =
18101     "function bat() {AnalyzeStackInNativeCode(2);\n"
18102     "}\n"
18103     "\n"
18104     "function baz() {\n"
18105     "  bat();\n"
18106     "}\n"
18107     "eval('new baz();');";
18108   v8::Handle<v8::String> detailed_src =
18109       v8::String::NewFromUtf8(isolate, detailed_source);
18110   // Make the script using a non-zero line and column offset.
18111   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
18112   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
18113   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
18114   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
18115   v8::Handle<v8::UnboundScript> detailed_script(
18116       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
18117   v8::Handle<Value> detailed_result(
18118       detailed_script->BindToCurrentContext()->Run());
18119   CHECK(!detailed_result.IsEmpty());
18120   CHECK(detailed_result->IsObject());
18121 }
18122
18123
18124 static void StackTraceForUncaughtExceptionListener(
18125     v8::Handle<v8::Message> message,
18126     v8::Handle<Value>) {
18127   report_count++;
18128   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18129   CHECK_EQ(2, stack_trace->GetFrameCount());
18130   checkStackFrame("origin", "foo", 2, 3, false, false,
18131                   stack_trace->GetFrame(0));
18132   checkStackFrame("origin", "bar", 5, 3, false, false,
18133                   stack_trace->GetFrame(1));
18134 }
18135
18136
18137 TEST(CaptureStackTraceForUncaughtException) {
18138   report_count = 0;
18139   LocalContext env;
18140   v8::HandleScope scope(env->GetIsolate());
18141   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
18142   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18143
18144   CompileRunWithOrigin(
18145       "function foo() {\n"
18146       "  throw 1;\n"
18147       "};\n"
18148       "function bar() {\n"
18149       "  foo();\n"
18150       "};",
18151       "origin");
18152   v8::Local<v8::Object> global = env->Global();
18153   Local<Value> trouble = global->Get(v8_str("bar"));
18154   CHECK(trouble->IsFunction());
18155   Function::Cast(*trouble)->Call(global, 0, NULL);
18156   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18157   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
18158   CHECK_EQ(1, report_count);
18159 }
18160
18161
18162 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
18163   report_count = 0;
18164   LocalContext env;
18165   v8::HandleScope scope(env->GetIsolate());
18166
18167   // Create an Error object first.
18168   CompileRunWithOrigin(
18169       "function foo() {\n"
18170       "e=new Error('err');\n"
18171       "};\n"
18172       "function bar() {\n"
18173       "  foo();\n"
18174       "};\n"
18175       "var e;",
18176       "origin");
18177   v8::Local<v8::Object> global = env->Global();
18178   Local<Value> trouble = global->Get(v8_str("bar"));
18179   CHECK(trouble->IsFunction());
18180   Function::Cast(*trouble)->Call(global, 0, NULL);
18181
18182   // Enable capturing detailed stack trace late, and throw the exception.
18183   // The detailed stack trace should be extracted from the simple stack.
18184   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
18185   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18186   CompileRunWithOrigin("throw e", "origin");
18187   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18188   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
18189   CHECK_EQ(1, report_count);
18190 }
18191
18192
18193 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
18194   LocalContext env;
18195   v8::HandleScope scope(env->GetIsolate());
18196   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
18197                                                     1024,
18198                                                     v8::StackTrace::kDetailed);
18199
18200   CompileRun(
18201       "var setters = ['column', 'lineNumber', 'scriptName',\n"
18202       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
18203       "    'isConstructor'];\n"
18204       "for (var i = 0; i < setters.length; i++) {\n"
18205       "  var prop = setters[i];\n"
18206       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
18207       "}\n");
18208   CompileRun("throw 'exception';");
18209   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18210 }
18211
18212
18213 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
18214                                      v8::Handle<v8::Value> data) {
18215   // Use the frame where JavaScript is called from.
18216   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18217   CHECK(!stack_trace.IsEmpty());
18218   int frame_count = stack_trace->GetFrameCount();
18219   CHECK_EQ(3, frame_count);
18220   int line_number[] = {1, 2, 5};
18221   for (int i = 0; i < frame_count; i++) {
18222     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
18223   }
18224 }
18225
18226
18227 // Test that we only return the stack trace at the site where the exception
18228 // is first thrown (not where it is rethrown).
18229 TEST(RethrowStackTrace) {
18230   LocalContext env;
18231   v8::HandleScope scope(env->GetIsolate());
18232   // We make sure that
18233   // - the stack trace of the ReferenceError in g() is reported.
18234   // - the stack trace is not overwritten when e1 is rethrown by t().
18235   // - the stack trace of e2 does not overwrite that of e1.
18236   const char* source =
18237       "function g() { error; }          \n"
18238       "function f() { g(); }            \n"
18239       "function t(e) { throw e; }       \n"
18240       "try {                            \n"
18241       "  f();                           \n"
18242       "} catch (e1) {                   \n"
18243       "  try {                          \n"
18244       "    error;                       \n"
18245       "  } catch (e2) {                 \n"
18246       "    t(e1);                       \n"
18247       "  }                              \n"
18248       "}                                \n";
18249   v8::V8::AddMessageListener(RethrowStackTraceHandler);
18250   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18251   CompileRun(source);
18252   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18253   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
18254 }
18255
18256
18257 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
18258                                               v8::Handle<v8::Value> data) {
18259   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18260   CHECK(!stack_trace.IsEmpty());
18261   int frame_count = stack_trace->GetFrameCount();
18262   CHECK_EQ(2, frame_count);
18263   int line_number[] = {3, 7};
18264   for (int i = 0; i < frame_count; i++) {
18265     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
18266   }
18267 }
18268
18269
18270 // Test that we do not recognize identity for primitive exceptions.
18271 TEST(RethrowPrimitiveStackTrace) {
18272   LocalContext env;
18273   v8::HandleScope scope(env->GetIsolate());
18274   // We do not capture stack trace for non Error objects on creation time.
18275   // Instead, we capture the stack trace on last throw.
18276   const char* source =
18277       "function g() { throw 404; }      \n"
18278       "function f() { g(); }            \n"
18279       "function t(e) { throw e; }       \n"
18280       "try {                            \n"
18281       "  f();                           \n"
18282       "} catch (e1) {                   \n"
18283       "  t(e1)                          \n"
18284       "}                                \n";
18285   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
18286   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18287   CompileRun(source);
18288   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18289   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
18290 }
18291
18292
18293 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
18294                                               v8::Handle<v8::Value> data) {
18295   // Use the frame where JavaScript is called from.
18296   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18297   CHECK(!stack_trace.IsEmpty());
18298   CHECK_EQ(1, stack_trace->GetFrameCount());
18299   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
18300 }
18301
18302
18303 // Test that the stack trace is captured when the error object is created and
18304 // not where it is thrown.
18305 TEST(RethrowExistingStackTrace) {
18306   LocalContext env;
18307   v8::HandleScope scope(env->GetIsolate());
18308   const char* source =
18309       "var e = new Error();           \n"
18310       "throw e;                       \n";
18311   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
18312   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18313   CompileRun(source);
18314   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18315   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
18316 }
18317
18318
18319 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
18320                                                v8::Handle<v8::Value> data) {
18321   // Use the frame where JavaScript is called from.
18322   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18323   CHECK(!stack_trace.IsEmpty());
18324   CHECK_EQ(1, stack_trace->GetFrameCount());
18325   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
18326 }
18327
18328
18329 // Test that the stack trace is captured where the bogus Error object is thrown.
18330 TEST(RethrowBogusErrorStackTrace) {
18331   LocalContext env;
18332   v8::HandleScope scope(env->GetIsolate());
18333   const char* source =
18334       "var e = {__proto__: new Error()} \n"
18335       "throw e;                         \n";
18336   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
18337   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18338   CompileRun(source);
18339   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18340   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
18341 }
18342
18343
18344 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
18345 int promise_reject_counter = 0;
18346 int promise_revoke_counter = 0;
18347 int promise_reject_line_number = -1;
18348 int promise_reject_frame_count = -1;
18349
18350 void PromiseRejectCallback(v8::PromiseRejectMessage message) {
18351   if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
18352     promise_reject_counter++;
18353     CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
18354     CcTest::global()->Set(v8_str("value"), message.GetValue());
18355     v8::Handle<v8::StackTrace> stack_trace =
18356         v8::Exception::CreateMessage(message.GetValue())->GetStackTrace();
18357     if (!stack_trace.IsEmpty()) {
18358       promise_reject_frame_count = stack_trace->GetFrameCount();
18359       if (promise_reject_frame_count > 0) {
18360         CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
18361         promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
18362       } else {
18363         promise_reject_line_number = -1;
18364       }
18365     }
18366   } else {
18367     promise_revoke_counter++;
18368     CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
18369     CHECK(message.GetValue().IsEmpty());
18370   }
18371 }
18372
18373
18374 v8::Handle<v8::Promise> GetPromise(const char* name) {
18375   return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
18376 }
18377
18378
18379 v8::Handle<v8::Value> RejectValue() {
18380   return CcTest::global()->Get(v8_str("value"));
18381 }
18382
18383
18384 void ResetPromiseStates() {
18385   promise_reject_counter = 0;
18386   promise_revoke_counter = 0;
18387   promise_reject_line_number = -1;
18388   promise_reject_frame_count = -1;
18389   CcTest::global()->Set(v8_str("rejected"), v8_str(""));
18390   CcTest::global()->Set(v8_str("value"), v8_str(""));
18391   CcTest::global()->Set(v8_str("revoked"), v8_str(""));
18392 }
18393
18394
18395 TEST(PromiseRejectCallback) {
18396   LocalContext env;
18397   v8::Isolate* isolate = env->GetIsolate();
18398   v8::HandleScope scope(isolate);
18399
18400   isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18401
18402   ResetPromiseStates();
18403
18404   // Create promise p0.
18405   CompileRun(
18406       "var reject;            \n"
18407       "var p0 = new Promise(  \n"
18408       "  function(res, rej) { \n"
18409       "    reject = rej;      \n"
18410       "  }                    \n"
18411       ");                     \n");
18412   CHECK(!GetPromise("p0")->HasHandler());
18413   CHECK_EQ(0, promise_reject_counter);
18414   CHECK_EQ(0, promise_revoke_counter);
18415
18416   // Add resolve handler (and default reject handler) to p0.
18417   CompileRun("var p1 = p0.then(function(){});");
18418   CHECK(GetPromise("p0")->HasHandler());
18419   CHECK(!GetPromise("p1")->HasHandler());
18420   CHECK_EQ(0, promise_reject_counter);
18421   CHECK_EQ(0, promise_revoke_counter);
18422
18423   // Reject p0.
18424   CompileRun("reject('ppp');");
18425   CHECK(GetPromise("p0")->HasHandler());
18426   CHECK(!GetPromise("p1")->HasHandler());
18427   CHECK_EQ(1, promise_reject_counter);
18428   CHECK_EQ(0, promise_revoke_counter);
18429   CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
18430   CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
18431   CHECK(RejectValue()->Equals(v8_str("ppp")));
18432
18433   // Reject p0 again. Callback is not triggered again.
18434   CompileRun("reject();");
18435   CHECK(GetPromise("p0")->HasHandler());
18436   CHECK(!GetPromise("p1")->HasHandler());
18437   CHECK_EQ(1, promise_reject_counter);
18438   CHECK_EQ(0, promise_revoke_counter);
18439
18440   // Add resolve handler to p1.
18441   CompileRun("var p2 = p1.then(function(){});");
18442   CHECK(GetPromise("p0")->HasHandler());
18443   CHECK(GetPromise("p1")->HasHandler());
18444   CHECK(!GetPromise("p2")->HasHandler());
18445   CHECK_EQ(2, promise_reject_counter);
18446   CHECK_EQ(1, promise_revoke_counter);
18447   CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
18448   CHECK(RejectValue()->Equals(v8_str("ppp")));
18449   CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
18450
18451   ResetPromiseStates();
18452
18453   // Create promise q0.
18454   CompileRun(
18455       "var q0 = new Promise(  \n"
18456       "  function(res, rej) { \n"
18457       "    reject = rej;      \n"
18458       "  }                    \n"
18459       ");                     \n");
18460   CHECK(!GetPromise("q0")->HasHandler());
18461   CHECK_EQ(0, promise_reject_counter);
18462   CHECK_EQ(0, promise_revoke_counter);
18463
18464   // Add reject handler to q0.
18465   CompileRun("var q1 = q0.catch(function() {});");
18466   CHECK(GetPromise("q0")->HasHandler());
18467   CHECK(!GetPromise("q1")->HasHandler());
18468   CHECK_EQ(0, promise_reject_counter);
18469   CHECK_EQ(0, promise_revoke_counter);
18470
18471   // Reject q0.
18472   CompileRun("reject('qq')");
18473   CHECK(GetPromise("q0")->HasHandler());
18474   CHECK(!GetPromise("q1")->HasHandler());
18475   CHECK_EQ(0, promise_reject_counter);
18476   CHECK_EQ(0, promise_revoke_counter);
18477
18478   // Add a new reject handler, which rejects by returning Promise.reject().
18479   // The returned promise q_ triggers a reject callback at first, only to
18480   // revoke it when returning it causes q2 to be rejected.
18481   CompileRun(
18482       "var q_;"
18483       "var q2 = q0.catch(               \n"
18484       "   function() {                  \n"
18485       "     q_ = Promise.reject('qqq'); \n"
18486       "     return q_;                  \n"
18487       "   }                             \n"
18488       ");                               \n");
18489   CHECK(GetPromise("q0")->HasHandler());
18490   CHECK(!GetPromise("q1")->HasHandler());
18491   CHECK(!GetPromise("q2")->HasHandler());
18492   CHECK(GetPromise("q_")->HasHandler());
18493   CHECK_EQ(2, promise_reject_counter);
18494   CHECK_EQ(1, promise_revoke_counter);
18495   CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
18496   CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
18497   CHECK(RejectValue()->Equals(v8_str("qqq")));
18498
18499   // Add a reject handler to the resolved q1, which rejects by throwing.
18500   CompileRun(
18501       "var q3 = q1.then(  \n"
18502       "   function() {    \n"
18503       "     throw 'qqqq'; \n"
18504       "   }               \n"
18505       ");                 \n");
18506   CHECK(GetPromise("q0")->HasHandler());
18507   CHECK(GetPromise("q1")->HasHandler());
18508   CHECK(!GetPromise("q2")->HasHandler());
18509   CHECK(!GetPromise("q3")->HasHandler());
18510   CHECK_EQ(3, promise_reject_counter);
18511   CHECK_EQ(1, promise_revoke_counter);
18512   CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
18513   CHECK(RejectValue()->Equals(v8_str("qqqq")));
18514
18515   ResetPromiseStates();
18516
18517   // Create promise r0, which has three handlers, two of which handle rejects.
18518   CompileRun(
18519       "var r0 = new Promise(             \n"
18520       "  function(res, rej) {            \n"
18521       "    reject = rej;                 \n"
18522       "  }                               \n"
18523       ");                                \n"
18524       "var r1 = r0.catch(function() {}); \n"
18525       "var r2 = r0.then(function() {});  \n"
18526       "var r3 = r0.then(function() {},   \n"
18527       "                 function() {});  \n");
18528   CHECK(GetPromise("r0")->HasHandler());
18529   CHECK(!GetPromise("r1")->HasHandler());
18530   CHECK(!GetPromise("r2")->HasHandler());
18531   CHECK(!GetPromise("r3")->HasHandler());
18532   CHECK_EQ(0, promise_reject_counter);
18533   CHECK_EQ(0, promise_revoke_counter);
18534
18535   // Reject r0.
18536   CompileRun("reject('rrr')");
18537   CHECK(GetPromise("r0")->HasHandler());
18538   CHECK(!GetPromise("r1")->HasHandler());
18539   CHECK(!GetPromise("r2")->HasHandler());
18540   CHECK(!GetPromise("r3")->HasHandler());
18541   CHECK_EQ(1, promise_reject_counter);
18542   CHECK_EQ(0, promise_revoke_counter);
18543   CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
18544   CHECK(RejectValue()->Equals(v8_str("rrr")));
18545
18546   // Add reject handler to r2.
18547   CompileRun("var r4 = r2.catch(function() {});");
18548   CHECK(GetPromise("r0")->HasHandler());
18549   CHECK(!GetPromise("r1")->HasHandler());
18550   CHECK(GetPromise("r2")->HasHandler());
18551   CHECK(!GetPromise("r3")->HasHandler());
18552   CHECK(!GetPromise("r4")->HasHandler());
18553   CHECK_EQ(1, promise_reject_counter);
18554   CHECK_EQ(1, promise_revoke_counter);
18555   CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
18556   CHECK(RejectValue()->Equals(v8_str("rrr")));
18557
18558   // Add reject handlers to r4.
18559   CompileRun("var r5 = r4.then(function() {}, function() {});");
18560   CHECK(GetPromise("r0")->HasHandler());
18561   CHECK(!GetPromise("r1")->HasHandler());
18562   CHECK(GetPromise("r2")->HasHandler());
18563   CHECK(!GetPromise("r3")->HasHandler());
18564   CHECK(GetPromise("r4")->HasHandler());
18565   CHECK(!GetPromise("r5")->HasHandler());
18566   CHECK_EQ(1, promise_reject_counter);
18567   CHECK_EQ(1, promise_revoke_counter);
18568
18569   ResetPromiseStates();
18570
18571   // Create promise s0, which has three handlers, none of which handle rejects.
18572   CompileRun(
18573       "var s0 = new Promise(            \n"
18574       "  function(res, rej) {           \n"
18575       "    reject = rej;                \n"
18576       "  }                              \n"
18577       ");                               \n"
18578       "var s1 = s0.then(function() {}); \n"
18579       "var s2 = s0.then(function() {}); \n"
18580       "var s3 = s0.then(function() {}); \n");
18581   CHECK(GetPromise("s0")->HasHandler());
18582   CHECK(!GetPromise("s1")->HasHandler());
18583   CHECK(!GetPromise("s2")->HasHandler());
18584   CHECK(!GetPromise("s3")->HasHandler());
18585   CHECK_EQ(0, promise_reject_counter);
18586   CHECK_EQ(0, promise_revoke_counter);
18587
18588   // Reject s0.
18589   CompileRun("reject('sss')");
18590   CHECK(GetPromise("s0")->HasHandler());
18591   CHECK(!GetPromise("s1")->HasHandler());
18592   CHECK(!GetPromise("s2")->HasHandler());
18593   CHECK(!GetPromise("s3")->HasHandler());
18594   CHECK_EQ(3, promise_reject_counter);
18595   CHECK_EQ(0, promise_revoke_counter);
18596   CHECK(RejectValue()->Equals(v8_str("sss")));
18597
18598   // Test stack frames.
18599   V8::SetCaptureStackTraceForUncaughtExceptions(true);
18600
18601   ResetPromiseStates();
18602
18603   // Create promise t0, which is rejected in the constructor with an error.
18604   CompileRunWithOrigin(
18605       "var t0 = new Promise(  \n"
18606       "  function(res, rej) { \n"
18607       "    reference_error;   \n"
18608       "  }                    \n"
18609       ");                     \n",
18610       "pro", 0, 0);
18611   CHECK(!GetPromise("t0")->HasHandler());
18612   CHECK_EQ(1, promise_reject_counter);
18613   CHECK_EQ(0, promise_revoke_counter);
18614   CHECK_EQ(2, promise_reject_frame_count);
18615   CHECK_EQ(3, promise_reject_line_number);
18616
18617   ResetPromiseStates();
18618
18619   // Create promise u0 and chain u1 to it, which is rejected via throw.
18620   CompileRunWithOrigin(
18621       "var u0 = Promise.resolve();        \n"
18622       "var u1 = u0.then(                  \n"
18623       "           function() {            \n"
18624       "             (function() {         \n"
18625       "                throw new Error(); \n"
18626       "              })();                \n"
18627       "           }                       \n"
18628       "         );                        \n",
18629       "pro", 0, 0);
18630   CHECK(GetPromise("u0")->HasHandler());
18631   CHECK(!GetPromise("u1")->HasHandler());
18632   CHECK_EQ(1, promise_reject_counter);
18633   CHECK_EQ(0, promise_revoke_counter);
18634   CHECK_EQ(2, promise_reject_frame_count);
18635   CHECK_EQ(5, promise_reject_line_number);
18636
18637   // Throw in u3, which handles u1's rejection.
18638   CompileRunWithOrigin(
18639       "function f() {                \n"
18640       "  return (function() {        \n"
18641       "    return new Error();       \n"
18642       "  })();                       \n"
18643       "}                             \n"
18644       "var u2 = Promise.reject(f()); \n"
18645       "var u3 = u1.catch(            \n"
18646       "           function() {       \n"
18647       "             return u2;       \n"
18648       "           }                  \n"
18649       "         );                   \n",
18650       "pro", 0, 0);
18651   CHECK(GetPromise("u0")->HasHandler());
18652   CHECK(GetPromise("u1")->HasHandler());
18653   CHECK(GetPromise("u2")->HasHandler());
18654   CHECK(!GetPromise("u3")->HasHandler());
18655   CHECK_EQ(3, promise_reject_counter);
18656   CHECK_EQ(2, promise_revoke_counter);
18657   CHECK_EQ(3, promise_reject_frame_count);
18658   CHECK_EQ(3, promise_reject_line_number);
18659
18660   ResetPromiseStates();
18661
18662   // Create promise rejected promise v0, which is incorrectly handled by v1
18663   // via chaining cycle.
18664   CompileRunWithOrigin(
18665       "var v0 = Promise.reject(); \n"
18666       "var v1 = v0.catch(         \n"
18667       "           function() {    \n"
18668       "             return v1;    \n"
18669       "           }               \n"
18670       "         );                \n",
18671       "pro", 0, 0);
18672   CHECK(GetPromise("v0")->HasHandler());
18673   CHECK(!GetPromise("v1")->HasHandler());
18674   CHECK_EQ(2, promise_reject_counter);
18675   CHECK_EQ(1, promise_revoke_counter);
18676   CHECK_EQ(0, promise_reject_frame_count);
18677   CHECK_EQ(-1, promise_reject_line_number);
18678 }
18679
18680
18681 void AnalyzeStackOfEvalWithSourceURL(
18682     const v8::FunctionCallbackInfo<v8::Value>& args) {
18683   v8::HandleScope scope(args.GetIsolate());
18684   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18685       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18686   CHECK_EQ(5, stackTrace->GetFrameCount());
18687   v8::Handle<v8::String> url = v8_str("eval_url");
18688   for (int i = 0; i < 3; i++) {
18689     v8::Handle<v8::String> name =
18690         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18691     CHECK(!name.IsEmpty());
18692     CHECK_EQ(url, name);
18693   }
18694 }
18695
18696
18697 TEST(SourceURLInStackTrace) {
18698   v8::Isolate* isolate = CcTest::isolate();
18699   v8::HandleScope scope(isolate);
18700   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18701   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
18702              v8::FunctionTemplate::New(isolate,
18703                                        AnalyzeStackOfEvalWithSourceURL));
18704   LocalContext context(0, templ);
18705
18706   const char *source =
18707     "function outer() {\n"
18708     "function bar() {\n"
18709     "  AnalyzeStackOfEvalWithSourceURL();\n"
18710     "}\n"
18711     "function foo() {\n"
18712     "\n"
18713     "  bar();\n"
18714     "}\n"
18715     "foo();\n"
18716     "}\n"
18717     "eval('(' + outer +')()%s');";
18718
18719   i::ScopedVector<char> code(1024);
18720   i::SNPrintF(code, source, "//# sourceURL=eval_url");
18721   CHECK(CompileRun(code.start())->IsUndefined());
18722   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18723   CHECK(CompileRun(code.start())->IsUndefined());
18724 }
18725
18726
18727 static int scriptIdInStack[2];
18728
18729 void AnalyzeScriptIdInStack(
18730     const v8::FunctionCallbackInfo<v8::Value>& args) {
18731   v8::HandleScope scope(args.GetIsolate());
18732   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18733       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18734   CHECK_EQ(2, stackTrace->GetFrameCount());
18735   for (int i = 0; i < 2; i++) {
18736     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
18737   }
18738 }
18739
18740
18741 TEST(ScriptIdInStackTrace) {
18742   v8::Isolate* isolate = CcTest::isolate();
18743   v8::HandleScope scope(isolate);
18744   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18745   templ->Set(v8_str("AnalyzeScriptIdInStack"),
18746              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18747   LocalContext context(0, templ);
18748
18749   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18750     isolate,
18751     "function foo() {\n"
18752     "  AnalyzeScriptIdInStack();"
18753     "}\n"
18754     "foo();\n");
18755   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18756   script->Run();
18757   for (int i = 0; i < 2; i++) {
18758     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
18759     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18760   }
18761 }
18762
18763
18764 void AnalyzeStackOfInlineScriptWithSourceURL(
18765     const v8::FunctionCallbackInfo<v8::Value>& args) {
18766   v8::HandleScope scope(args.GetIsolate());
18767   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18768       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18769   CHECK_EQ(4, stackTrace->GetFrameCount());
18770   v8::Handle<v8::String> url = v8_str("url");
18771   for (int i = 0; i < 3; i++) {
18772     v8::Handle<v8::String> name =
18773         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18774     CHECK(!name.IsEmpty());
18775     CHECK_EQ(url, name);
18776   }
18777 }
18778
18779
18780 TEST(InlineScriptWithSourceURLInStackTrace) {
18781   v8::Isolate* isolate = CcTest::isolate();
18782   v8::HandleScope scope(isolate);
18783   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18784   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18785              v8::FunctionTemplate::New(
18786                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18787   LocalContext context(0, templ);
18788
18789   const char *source =
18790     "function outer() {\n"
18791     "function bar() {\n"
18792     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
18793     "}\n"
18794     "function foo() {\n"
18795     "\n"
18796     "  bar();\n"
18797     "}\n"
18798     "foo();\n"
18799     "}\n"
18800     "outer()\n%s";
18801
18802   i::ScopedVector<char> code(1024);
18803   i::SNPrintF(code, source, "//# sourceURL=source_url");
18804   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18805   i::SNPrintF(code, source, "//@ sourceURL=source_url");
18806   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18807 }
18808
18809
18810 void AnalyzeStackOfDynamicScriptWithSourceURL(
18811     const v8::FunctionCallbackInfo<v8::Value>& args) {
18812   v8::HandleScope scope(args.GetIsolate());
18813   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18814       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18815   CHECK_EQ(4, stackTrace->GetFrameCount());
18816   v8::Handle<v8::String> url = v8_str("source_url");
18817   for (int i = 0; i < 3; i++) {
18818     v8::Handle<v8::String> name =
18819         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18820     CHECK(!name.IsEmpty());
18821     CHECK_EQ(url, name);
18822   }
18823 }
18824
18825
18826 TEST(DynamicWithSourceURLInStackTrace) {
18827   v8::Isolate* isolate = CcTest::isolate();
18828   v8::HandleScope scope(isolate);
18829   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18830   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18831              v8::FunctionTemplate::New(
18832                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18833   LocalContext context(0, templ);
18834
18835   const char *source =
18836     "function outer() {\n"
18837     "function bar() {\n"
18838     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18839     "}\n"
18840     "function foo() {\n"
18841     "\n"
18842     "  bar();\n"
18843     "}\n"
18844     "foo();\n"
18845     "}\n"
18846     "outer()\n%s";
18847
18848   i::ScopedVector<char> code(1024);
18849   i::SNPrintF(code, source, "//# sourceURL=source_url");
18850   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18851   i::SNPrintF(code, source, "//@ sourceURL=source_url");
18852   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18853 }
18854
18855
18856 TEST(DynamicWithSourceURLInStackTraceString) {
18857   LocalContext context;
18858   v8::HandleScope scope(context->GetIsolate());
18859
18860   const char *source =
18861     "function outer() {\n"
18862     "  function foo() {\n"
18863     "    FAIL.FAIL;\n"
18864     "  }\n"
18865     "  foo();\n"
18866     "}\n"
18867     "outer()\n%s";
18868
18869   i::ScopedVector<char> code(1024);
18870   i::SNPrintF(code, source, "//# sourceURL=source_url");
18871   v8::TryCatch try_catch;
18872   CompileRunWithOrigin(code.start(), "", 0, 0);
18873   CHECK(try_catch.HasCaught());
18874   v8::String::Utf8Value stack(try_catch.StackTrace());
18875   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
18876 }
18877
18878
18879 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18880   LocalContext context;
18881   v8::HandleScope scope(context->GetIsolate());
18882
18883   const char *source =
18884     "function outer() {\n"
18885     "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18886     "  //# sourceURL=source_url\";\n"
18887     "  eval(scriptContents);\n"
18888     "  foo(); }\n"
18889     "outer();\n"
18890     "//# sourceURL=outer_url";
18891
18892   v8::TryCatch try_catch;
18893   CompileRun(source);
18894   CHECK(try_catch.HasCaught());
18895
18896   Local<v8::Message> message = try_catch.Message();
18897   Handle<Value> sourceURL =
18898     message->GetScriptOrigin().ResourceName();
18899   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18900 }
18901
18902
18903 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18904   LocalContext context;
18905   v8::HandleScope scope(context->GetIsolate());
18906
18907   const char *source =
18908     "function outer() {\n"
18909     "  var scriptContents = \"function boo(){ boo(); }\\\n"
18910     "  //# sourceURL=source_url\";\n"
18911     "  eval(scriptContents);\n"
18912     "  boo(); }\n"
18913     "outer();\n"
18914     "//# sourceURL=outer_url";
18915
18916   v8::TryCatch try_catch;
18917   CompileRun(source);
18918   CHECK(try_catch.HasCaught());
18919
18920   Local<v8::Message> message = try_catch.Message();
18921   Handle<Value> sourceURL =
18922     message->GetScriptOrigin().ResourceName();
18923   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18924 }
18925
18926
18927 static void CreateGarbageInOldSpace() {
18928   i::Factory* factory = CcTest::i_isolate()->factory();
18929   v8::HandleScope scope(CcTest::isolate());
18930   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18931   for (int i = 0; i < 1000; i++) {
18932     factory->NewFixedArray(1000, i::TENURED);
18933   }
18934 }
18935
18936
18937 // Test that idle notification can be handled and eventually returns true.
18938 TEST(IdleNotification) {
18939   const intptr_t MB = 1024 * 1024;
18940   const int IdlePauseInMs = 1000;
18941   LocalContext env;
18942   v8::HandleScope scope(env->GetIsolate());
18943   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18944   CreateGarbageInOldSpace();
18945   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18946   CHECK_GT(size_with_garbage, initial_size + MB);
18947   bool finished = false;
18948   for (int i = 0; i < 200 && !finished; i++) {
18949     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18950   }
18951   intptr_t final_size = CcTest::heap()->SizeOfObjects();
18952   CHECK(finished);
18953   CHECK_LT(final_size, initial_size + 1);
18954 }
18955
18956
18957 // Test that idle notification can be handled and eventually collects garbage.
18958 TEST(IdleNotificationWithSmallHint) {
18959   const intptr_t MB = 1024 * 1024;
18960   const int IdlePauseInMs = 900;
18961   LocalContext env;
18962   v8::HandleScope scope(env->GetIsolate());
18963   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18964   CreateGarbageInOldSpace();
18965   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18966   CHECK_GT(size_with_garbage, initial_size + MB);
18967   bool finished = false;
18968   for (int i = 0; i < 200 && !finished; i++) {
18969     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18970   }
18971   intptr_t final_size = CcTest::heap()->SizeOfObjects();
18972   CHECK(finished);
18973   CHECK_LT(final_size, initial_size + 1);
18974 }
18975
18976
18977 // Test that idle notification can be handled and eventually collects garbage.
18978 TEST(IdleNotificationWithLargeHint) {
18979   const intptr_t MB = 1024 * 1024;
18980   const int IdlePauseInMs = 900;
18981   LocalContext env;
18982   v8::HandleScope scope(env->GetIsolate());
18983   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18984   CreateGarbageInOldSpace();
18985   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18986   CHECK_GT(size_with_garbage, initial_size + MB);
18987   bool finished = false;
18988   for (int i = 0; i < 200 && !finished; i++) {
18989     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18990   }
18991   intptr_t final_size = CcTest::heap()->SizeOfObjects();
18992   CHECK(finished);
18993   CHECK_LT(final_size, initial_size + 1);
18994 }
18995
18996
18997 TEST(Regress2333) {
18998   LocalContext env;
18999   for (int i = 0; i < 3; i++) {
19000     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
19001   }
19002 }
19003
19004 static uint32_t* stack_limit;
19005
19006 static void GetStackLimitCallback(
19007     const v8::FunctionCallbackInfo<v8::Value>& args) {
19008   stack_limit = reinterpret_cast<uint32_t*>(
19009       CcTest::i_isolate()->stack_guard()->real_climit());
19010 }
19011
19012
19013 // Uses the address of a local variable to determine the stack top now.
19014 // Given a size, returns an address that is that far from the current
19015 // top of stack.
19016 static uint32_t* ComputeStackLimit(uint32_t size) {
19017   uint32_t* answer = &size - (size / sizeof(size));
19018   // If the size is very large and the stack is very near the bottom of
19019   // memory then the calculation above may wrap around and give an address
19020   // that is above the (downwards-growing) stack.  In that case we return
19021   // a very low address.
19022   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
19023   return answer;
19024 }
19025
19026
19027 // We need at least 165kB for an x64 debug build with clang and ASAN.
19028 static const int stack_breathing_room = 256 * i::KB;
19029
19030
19031 TEST(SetStackLimit) {
19032   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
19033
19034   // Set stack limit.
19035   CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
19036
19037   // Execute a script.
19038   LocalContext env;
19039   v8::HandleScope scope(env->GetIsolate());
19040   Local<v8::FunctionTemplate> fun_templ =
19041       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
19042   Local<Function> fun = fun_templ->GetFunction();
19043   env->Global()->Set(v8_str("get_stack_limit"), fun);
19044   CompileRun("get_stack_limit();");
19045
19046   CHECK(stack_limit == set_limit);
19047 }
19048
19049
19050 TEST(SetStackLimitInThread) {
19051   uint32_t* set_limit;
19052   {
19053     v8::Locker locker(CcTest::isolate());
19054     set_limit = ComputeStackLimit(stack_breathing_room);
19055
19056     // Set stack limit.
19057     CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
19058
19059     // Execute a script.
19060     v8::HandleScope scope(CcTest::isolate());
19061     LocalContext env;
19062     Local<v8::FunctionTemplate> fun_templ =
19063         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
19064     Local<Function> fun = fun_templ->GetFunction();
19065     env->Global()->Set(v8_str("get_stack_limit"), fun);
19066     CompileRun("get_stack_limit();");
19067
19068     CHECK(stack_limit == set_limit);
19069   }
19070   {
19071     v8::Locker locker(CcTest::isolate());
19072     CHECK(stack_limit == set_limit);
19073   }
19074 }
19075
19076
19077 THREADED_TEST(GetHeapStatistics) {
19078   LocalContext c1;
19079   v8::HandleScope scope(c1->GetIsolate());
19080   v8::HeapStatistics heap_statistics;
19081   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
19082   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
19083   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
19084   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
19085   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
19086 }
19087
19088
19089 class VisitorImpl : public v8::ExternalResourceVisitor {
19090  public:
19091   explicit VisitorImpl(TestResource** resource) {
19092     for (int i = 0; i < 4; i++) {
19093       resource_[i] = resource[i];
19094       found_resource_[i] = false;
19095     }
19096   }
19097   virtual ~VisitorImpl() {}
19098   virtual void VisitExternalString(v8::Handle<v8::String> string) {
19099     if (!string->IsExternal()) {
19100       CHECK(string->IsExternalOneByte());
19101       return;
19102     }
19103     v8::String::ExternalStringResource* resource =
19104         string->GetExternalStringResource();
19105     CHECK(resource);
19106     for (int i = 0; i < 4; i++) {
19107       if (resource_[i] == resource) {
19108         CHECK(!found_resource_[i]);
19109         found_resource_[i] = true;
19110       }
19111     }
19112   }
19113   void CheckVisitedResources() {
19114     for (int i = 0; i < 4; i++) {
19115       CHECK(found_resource_[i]);
19116     }
19117   }
19118
19119  private:
19120   v8::String::ExternalStringResource* resource_[4];
19121   bool found_resource_[4];
19122 };
19123
19124
19125 TEST(ExternalizeOldSpaceTwoByteCons) {
19126   v8::Isolate* isolate = CcTest::isolate();
19127   LocalContext env;
19128   v8::HandleScope scope(isolate);
19129   v8::Local<v8::String> cons =
19130       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
19131   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19132   CcTest::heap()->CollectAllAvailableGarbage();
19133   CHECK(CcTest::heap()->old_pointer_space()->Contains(
19134             *v8::Utils::OpenHandle(*cons)));
19135
19136   TestResource* resource = new TestResource(
19137       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
19138   cons->MakeExternal(resource);
19139
19140   CHECK(cons->IsExternal());
19141   CHECK_EQ(resource, cons->GetExternalStringResource());
19142   String::Encoding encoding;
19143   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19144   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
19145 }
19146
19147
19148 TEST(ExternalizeOldSpaceOneByteCons) {
19149   v8::Isolate* isolate = CcTest::isolate();
19150   LocalContext env;
19151   v8::HandleScope scope(isolate);
19152   v8::Local<v8::String> cons =
19153       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
19154   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19155   CcTest::heap()->CollectAllAvailableGarbage();
19156   CHECK(CcTest::heap()->old_pointer_space()->Contains(
19157             *v8::Utils::OpenHandle(*cons)));
19158
19159   TestOneByteResource* resource =
19160       new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
19161   cons->MakeExternal(resource);
19162
19163   CHECK(cons->IsExternalOneByte());
19164   CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
19165   String::Encoding encoding;
19166   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19167   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
19168 }
19169
19170
19171 TEST(VisitExternalStrings) {
19172   v8::Isolate* isolate = CcTest::isolate();
19173   LocalContext env;
19174   v8::HandleScope scope(isolate);
19175   const char* string = "Some string";
19176   uint16_t* two_byte_string = AsciiToTwoByteString(string);
19177   TestResource* resource[4];
19178   resource[0] = new TestResource(two_byte_string);
19179   v8::Local<v8::String> string0 =
19180       v8::String::NewExternal(env->GetIsolate(), resource[0]);
19181   resource[1] = new TestResource(two_byte_string, NULL, false);
19182   v8::Local<v8::String> string1 =
19183       v8::String::NewExternal(env->GetIsolate(), resource[1]);
19184
19185   // Externalized symbol.
19186   resource[2] = new TestResource(two_byte_string, NULL, false);
19187   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
19188       env->GetIsolate(), string, v8::String::kInternalizedString);
19189   CHECK(string2->MakeExternal(resource[2]));
19190
19191   // Symbolized External.
19192   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
19193   v8::Local<v8::String> string3 =
19194       v8::String::NewExternal(env->GetIsolate(), resource[3]);
19195   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
19196   // Turn into a symbol.
19197   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
19198   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
19199       string3_i).is_null());
19200   CHECK(string3_i->IsInternalizedString());
19201
19202   // We need to add usages for string* to avoid warnings in GCC 4.7
19203   CHECK(string0->IsExternal());
19204   CHECK(string1->IsExternal());
19205   CHECK(string2->IsExternal());
19206   CHECK(string3->IsExternal());
19207
19208   VisitorImpl visitor(resource);
19209   v8::V8::VisitExternalResources(&visitor);
19210   visitor.CheckVisitedResources();
19211 }
19212
19213
19214 TEST(ExternalStringCollectedAtTearDown) {
19215   int destroyed = 0;
19216   v8::Isolate* isolate = v8::Isolate::New();
19217   { v8::Isolate::Scope isolate_scope(isolate);
19218     v8::HandleScope handle_scope(isolate);
19219     const char* s = "One string to test them all, one string to find them.";
19220     TestOneByteResource* inscription =
19221         new TestOneByteResource(i::StrDup(s), &destroyed);
19222     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
19223     // Ring is still alive.  Orcs are roaming freely across our lands.
19224     CHECK_EQ(0, destroyed);
19225     USE(ring);
19226   }
19227
19228   isolate->Dispose();
19229   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
19230   CHECK_EQ(1, destroyed);
19231 }
19232
19233
19234 TEST(ExternalInternalizedStringCollectedAtTearDown) {
19235   int destroyed = 0;
19236   v8::Isolate* isolate = v8::Isolate::New();
19237   { v8::Isolate::Scope isolate_scope(isolate);
19238     LocalContext env(isolate);
19239     v8::HandleScope handle_scope(isolate);
19240     CompileRun("var ring = 'One string to test them all';");
19241     const char* s = "One string to test them all";
19242     TestOneByteResource* inscription =
19243         new TestOneByteResource(i::StrDup(s), &destroyed);
19244     v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
19245     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19246     ring->MakeExternal(inscription);
19247     // Ring is still alive.  Orcs are roaming freely across our lands.
19248     CHECK_EQ(0, destroyed);
19249     USE(ring);
19250   }
19251
19252   isolate->Dispose();
19253   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
19254   CHECK_EQ(1, destroyed);
19255 }
19256
19257
19258 TEST(ExternalInternalizedStringCollectedAtGC) {
19259   // TODO(mvstanton): vector ics need weak support.
19260   if (i::FLAG_vector_ics) return;
19261
19262   int destroyed = 0;
19263   { LocalContext env;
19264     v8::HandleScope handle_scope(env->GetIsolate());
19265     CompileRun("var ring = 'One string to test them all';");
19266     const char* s = "One string to test them all";
19267     TestOneByteResource* inscription =
19268         new TestOneByteResource(i::StrDup(s), &destroyed);
19269     v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
19270     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19271     ring->MakeExternal(inscription);
19272     // Ring is still alive.  Orcs are roaming freely across our lands.
19273     CHECK_EQ(0, destroyed);
19274     USE(ring);
19275   }
19276
19277   // Garbage collector deals swift blows to evil.
19278   CcTest::i_isolate()->compilation_cache()->Clear();
19279   CcTest::heap()->CollectAllAvailableGarbage();
19280
19281   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
19282   CHECK_EQ(1, destroyed);
19283 }
19284
19285
19286 static double DoubleFromBits(uint64_t value) {
19287   double target;
19288   i::MemCopy(&target, &value, sizeof(target));
19289   return target;
19290 }
19291
19292
19293 static uint64_t DoubleToBits(double value) {
19294   uint64_t target;
19295   i::MemCopy(&target, &value, sizeof(target));
19296   return target;
19297 }
19298
19299
19300 static double DoubleToDateTime(double input) {
19301   double date_limit = 864e13;
19302   if (std::isnan(input) || input < -date_limit || input > date_limit) {
19303     return v8::base::OS::nan_value();
19304   }
19305   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
19306 }
19307
19308
19309 // We don't have a consistent way to write 64-bit constants syntactically, so we
19310 // split them into two 32-bit constants and combine them programmatically.
19311 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
19312   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
19313 }
19314
19315
19316 THREADED_TEST(QuietSignalingNaNs) {
19317   LocalContext context;
19318   v8::Isolate* isolate = context->GetIsolate();
19319   v8::HandleScope scope(isolate);
19320   v8::TryCatch try_catch;
19321
19322   // Special double values.
19323   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
19324   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
19325   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
19326   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
19327   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
19328   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
19329   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
19330
19331   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
19332   // on either side of the epoch.
19333   double date_limit = 864e13;
19334
19335   double test_values[] = {
19336       snan,
19337       qnan,
19338       infinity,
19339       max_normal,
19340       date_limit + 1,
19341       date_limit,
19342       min_normal,
19343       max_denormal,
19344       min_denormal,
19345       0,
19346       -0,
19347       -min_denormal,
19348       -max_denormal,
19349       -min_normal,
19350       -date_limit,
19351       -date_limit - 1,
19352       -max_normal,
19353       -infinity,
19354       -qnan,
19355       -snan
19356   };
19357   int num_test_values = 20;
19358
19359   for (int i = 0; i < num_test_values; i++) {
19360     double test_value = test_values[i];
19361
19362     // Check that Number::New preserves non-NaNs and quiets SNaNs.
19363     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
19364     double stored_number = number->NumberValue();
19365     if (!std::isnan(test_value)) {
19366       CHECK_EQ(test_value, stored_number);
19367     } else {
19368       uint64_t stored_bits = DoubleToBits(stored_number);
19369       // Check if quiet nan (bits 51..62 all set).
19370 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19371     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19372       // Most significant fraction bit for quiet nan is set to 0
19373       // on MIPS architecture. Allowed by IEEE-754.
19374       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19375 #else
19376       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19377 #endif
19378     }
19379
19380     // Check that Date::New preserves non-NaNs in the date range and
19381     // quiets SNaNs.
19382     v8::Handle<v8::Value> date =
19383         v8::Date::New(isolate, test_value);
19384     double expected_stored_date = DoubleToDateTime(test_value);
19385     double stored_date = date->NumberValue();
19386     if (!std::isnan(expected_stored_date)) {
19387       CHECK_EQ(expected_stored_date, stored_date);
19388     } else {
19389       uint64_t stored_bits = DoubleToBits(stored_date);
19390       // Check if quiet nan (bits 51..62 all set).
19391 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19392     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19393       // Most significant fraction bit for quiet nan is set to 0
19394       // on MIPS architecture. Allowed by IEEE-754.
19395       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19396 #else
19397       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19398 #endif
19399     }
19400   }
19401 }
19402
19403
19404 static void SpaghettiIncident(
19405     const v8::FunctionCallbackInfo<v8::Value>& args) {
19406   v8::HandleScope scope(args.GetIsolate());
19407   v8::TryCatch tc;
19408   v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
19409   USE(str);
19410   if (tc.HasCaught())
19411     tc.ReThrow();
19412 }
19413
19414
19415 // Test that an exception can be propagated down through a spaghetti
19416 // stack using ReThrow.
19417 THREADED_TEST(SpaghettiStackReThrow) {
19418   v8::Isolate* isolate = CcTest::isolate();
19419   v8::HandleScope scope(isolate);
19420   LocalContext context;
19421   context->Global()->Set(
19422       v8::String::NewFromUtf8(isolate, "s"),
19423       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
19424   v8::TryCatch try_catch;
19425   CompileRun(
19426       "var i = 0;"
19427       "var o = {"
19428       "  toString: function () {"
19429       "    if (i == 10) {"
19430       "      throw 'Hey!';"
19431       "    } else {"
19432       "      i++;"
19433       "      return s(o);"
19434       "    }"
19435       "  }"
19436       "};"
19437       "s(o);");
19438   CHECK(try_catch.HasCaught());
19439   v8::String::Utf8Value value(try_catch.Exception());
19440   CHECK_EQ(0, strcmp(*value, "Hey!"));
19441 }
19442
19443
19444 TEST(Regress528) {
19445   v8::V8::Initialize();
19446   v8::Isolate* isolate = CcTest::isolate();
19447   v8::HandleScope scope(isolate);
19448   v8::Local<Context> other_context;
19449   int gc_count;
19450
19451   // Create a context used to keep the code from aging in the compilation
19452   // cache.
19453   other_context = Context::New(isolate);
19454
19455   // Context-dependent context data creates reference from the compilation
19456   // cache to the global object.
19457   const char* source_simple = "1";
19458   {
19459     v8::HandleScope scope(isolate);
19460     v8::Local<Context> context = Context::New(isolate);
19461
19462     context->Enter();
19463     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
19464     context->SetEmbedderData(0, obj);
19465     CompileRun(source_simple);
19466     context->Exit();
19467   }
19468   isolate->ContextDisposedNotification();
19469   for (gc_count = 1; gc_count < 10; gc_count++) {
19470     other_context->Enter();
19471     CompileRun(source_simple);
19472     other_context->Exit();
19473     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19474     if (GetGlobalObjectsCount() == 1) break;
19475   }
19476   CHECK_GE(2, gc_count);
19477   CHECK_EQ(1, GetGlobalObjectsCount());
19478
19479   // Eval in a function creates reference from the compilation cache to the
19480   // global object.
19481   const char* source_eval = "function f(){eval('1')}; f()";
19482   {
19483     v8::HandleScope scope(isolate);
19484     v8::Local<Context> context = Context::New(isolate);
19485
19486     context->Enter();
19487     CompileRun(source_eval);
19488     context->Exit();
19489   }
19490   isolate->ContextDisposedNotification();
19491   for (gc_count = 1; gc_count < 10; gc_count++) {
19492     other_context->Enter();
19493     CompileRun(source_eval);
19494     other_context->Exit();
19495     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19496     if (GetGlobalObjectsCount() == 1) break;
19497   }
19498   CHECK_GE(2, gc_count);
19499   CHECK_EQ(1, GetGlobalObjectsCount());
19500
19501   // Looking up the line number for an exception creates reference from the
19502   // compilation cache to the global object.
19503   const char* source_exception = "function f(){throw 1;} f()";
19504   {
19505     v8::HandleScope scope(isolate);
19506     v8::Local<Context> context = Context::New(isolate);
19507
19508     context->Enter();
19509     v8::TryCatch try_catch;
19510     CompileRun(source_exception);
19511     CHECK(try_catch.HasCaught());
19512     v8::Handle<v8::Message> message = try_catch.Message();
19513     CHECK(!message.IsEmpty());
19514     CHECK_EQ(1, message->GetLineNumber());
19515     context->Exit();
19516   }
19517   isolate->ContextDisposedNotification();
19518   for (gc_count = 1; gc_count < 10; gc_count++) {
19519     other_context->Enter();
19520     CompileRun(source_exception);
19521     other_context->Exit();
19522     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19523     if (GetGlobalObjectsCount() == 1) break;
19524   }
19525   CHECK_GE(2, gc_count);
19526   CHECK_EQ(1, GetGlobalObjectsCount());
19527
19528   isolate->ContextDisposedNotification();
19529 }
19530
19531
19532 THREADED_TEST(ScriptOrigin) {
19533   LocalContext env;
19534   v8::HandleScope scope(env->GetIsolate());
19535   v8::ScriptOrigin origin =
19536       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19537   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19538       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19539   v8::Script::Compile(script, &origin)->Run();
19540   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19541       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19542   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19543       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19544
19545   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
19546   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
19547   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
19548
19549   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
19550   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
19551   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
19552 }
19553
19554
19555 THREADED_TEST(FunctionGetInferredName) {
19556   LocalContext env;
19557   v8::HandleScope scope(env->GetIsolate());
19558   v8::ScriptOrigin origin =
19559       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19560   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19561       env->GetIsolate(),
19562       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19563   v8::Script::Compile(script, &origin)->Run();
19564   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19565       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19566   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
19567 }
19568
19569
19570 THREADED_TEST(FunctionGetDisplayName) {
19571   LocalContext env;
19572   v8::HandleScope scope(env->GetIsolate());
19573   const char* code = "var error = false;"
19574                      "function a() { this.x = 1; };"
19575                      "a.displayName = 'display_a';"
19576                      "var b = (function() {"
19577                      "  var f = function() { this.x = 2; };"
19578                      "  f.displayName = 'display_b';"
19579                      "  return f;"
19580                      "})();"
19581                      "var c = function() {};"
19582                      "c.__defineGetter__('displayName', function() {"
19583                      "  error = true;"
19584                      "  throw new Error();"
19585                      "});"
19586                      "function d() {};"
19587                      "d.__defineGetter__('displayName', function() {"
19588                      "  error = true;"
19589                      "  return 'wrong_display_name';"
19590                      "});"
19591                      "function e() {};"
19592                      "e.displayName = 'wrong_display_name';"
19593                      "e.__defineSetter__('displayName', function() {"
19594                      "  error = true;"
19595                      "  throw new Error();"
19596                      "});"
19597                      "function f() {};"
19598                      "f.displayName = { 'foo': 6, toString: function() {"
19599                      "  error = true;"
19600                      "  return 'wrong_display_name';"
19601                      "}};"
19602                      "var g = function() {"
19603                      "  arguments.callee.displayName = 'set_in_runtime';"
19604                      "}; g();"
19605                      ;
19606   v8::ScriptOrigin origin =
19607       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19608   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
19609       ->Run();
19610   v8::Local<v8::Value> error =
19611       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
19612   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19613       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
19614   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19615       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
19616   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19617       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
19618   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19619       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
19620   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19621       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
19622   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19623       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19624   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19625       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19626   CHECK_EQ(false, error->BooleanValue());
19627   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
19628   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
19629   CHECK(c->GetDisplayName()->IsUndefined());
19630   CHECK(d->GetDisplayName()->IsUndefined());
19631   CHECK(e->GetDisplayName()->IsUndefined());
19632   CHECK(f->GetDisplayName()->IsUndefined());
19633   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
19634 }
19635
19636
19637 THREADED_TEST(ScriptLineNumber) {
19638   LocalContext env;
19639   v8::HandleScope scope(env->GetIsolate());
19640   v8::ScriptOrigin origin =
19641       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19642   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19643       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19644   v8::Script::Compile(script, &origin)->Run();
19645   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19646       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19647   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19648       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19649   CHECK_EQ(0, f->GetScriptLineNumber());
19650   CHECK_EQ(2, g->GetScriptLineNumber());
19651 }
19652
19653
19654 THREADED_TEST(ScriptColumnNumber) {
19655   LocalContext env;
19656   v8::Isolate* isolate = env->GetIsolate();
19657   v8::HandleScope scope(isolate);
19658   v8::ScriptOrigin origin =
19659       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19660                        v8::Integer::New(isolate, 3),
19661                        v8::Integer::New(isolate, 2));
19662   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19663       isolate, "function foo() {}\n\n     function bar() {}");
19664   v8::Script::Compile(script, &origin)->Run();
19665   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19666       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19667   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19668       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19669   CHECK_EQ(14, foo->GetScriptColumnNumber());
19670   CHECK_EQ(17, bar->GetScriptColumnNumber());
19671 }
19672
19673
19674 THREADED_TEST(FunctionIsBuiltin) {
19675   LocalContext env;
19676   v8::Isolate* isolate = env->GetIsolate();
19677   v8::HandleScope scope(isolate);
19678   v8::Local<v8::Function> f;
19679   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
19680   CHECK(f->IsBuiltin());
19681   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
19682   CHECK(f->IsBuiltin());
19683   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
19684   CHECK(f->IsBuiltin());
19685   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
19686   CHECK(f->IsBuiltin());
19687   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
19688   CHECK(!f->IsBuiltin());
19689 }
19690
19691
19692 THREADED_TEST(FunctionGetScriptId) {
19693   LocalContext env;
19694   v8::Isolate* isolate = env->GetIsolate();
19695   v8::HandleScope scope(isolate);
19696   v8::ScriptOrigin origin =
19697       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19698                        v8::Integer::New(isolate, 3),
19699                        v8::Integer::New(isolate, 2));
19700   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
19701       isolate, "function foo() {}\n\n     function bar() {}");
19702   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
19703   script->Run();
19704   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19705       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19706   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19707       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19708   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19709   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19710 }
19711
19712
19713 THREADED_TEST(FunctionGetBoundFunction) {
19714   LocalContext env;
19715   v8::HandleScope scope(env->GetIsolate());
19716   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
19717       env->GetIsolate(), "test"));
19718   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19719       env->GetIsolate(),
19720       "var a = new Object();\n"
19721       "a.x = 1;\n"
19722       "function f () { return this.x };\n"
19723       "var g = f.bind(a);\n"
19724       "var b = g();");
19725   v8::Script::Compile(script, &origin)->Run();
19726   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19727       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19728   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19729       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19730   CHECK(g->GetBoundFunction()->IsFunction());
19731   Local<v8::Function> original_function = Local<v8::Function>::Cast(
19732       g->GetBoundFunction());
19733   CHECK_EQ(f->GetName(), original_function->GetName());
19734   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19735   CHECK_EQ(f->GetScriptColumnNumber(),
19736            original_function->GetScriptColumnNumber());
19737 }
19738
19739
19740 static void GetterWhichReturns42(
19741     Local<String> name,
19742     const v8::PropertyCallbackInfo<v8::Value>& info) {
19743   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19744   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19745   info.GetReturnValue().Set(v8_num(42));
19746 }
19747
19748
19749 static void SetterWhichSetsYOnThisTo23(
19750     Local<String> name,
19751     Local<Value> value,
19752     const v8::PropertyCallbackInfo<void>& info) {
19753   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19754   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19755   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19756 }
19757
19758
19759 void FooGetInterceptor(Local<Name> name,
19760                        const v8::PropertyCallbackInfo<v8::Value>& info) {
19761   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19762   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19763   if (!name->Equals(v8_str("foo"))) return;
19764   info.GetReturnValue().Set(v8_num(42));
19765 }
19766
19767
19768 void FooSetInterceptor(Local<Name> name, Local<Value> value,
19769                        const v8::PropertyCallbackInfo<v8::Value>& info) {
19770   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19771   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19772   if (!name->Equals(v8_str("foo"))) return;
19773   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19774   info.GetReturnValue().Set(v8_num(23));
19775 }
19776
19777
19778 TEST(SetterOnConstructorPrototype) {
19779   v8::Isolate* isolate = CcTest::isolate();
19780   v8::HandleScope scope(isolate);
19781   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19782   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19783                      SetterWhichSetsYOnThisTo23);
19784   LocalContext context;
19785   context->Global()->Set(v8_str("P"), templ->NewInstance());
19786   CompileRun("function C1() {"
19787              "  this.x = 23;"
19788              "};"
19789              "C1.prototype = P;"
19790              "function C2() {"
19791              "  this.x = 23"
19792              "};"
19793              "C2.prototype = { };"
19794              "C2.prototype.__proto__ = P;");
19795
19796   v8::Local<v8::Script> script;
19797   script = v8_compile("new C1();");
19798   for (int i = 0; i < 10; i++) {
19799     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19800     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19801     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19802   }
19803
19804 script = v8_compile("new C2();");
19805   for (int i = 0; i < 10; i++) {
19806     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19807     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
19808     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
19809   }
19810 }
19811
19812
19813 static void NamedPropertyGetterWhichReturns42(
19814     Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
19815   info.GetReturnValue().Set(v8_num(42));
19816 }
19817
19818
19819 static void NamedPropertySetterWhichSetsYOnThisTo23(
19820     Local<Name> name, Local<Value> value,
19821     const v8::PropertyCallbackInfo<v8::Value>& info) {
19822   if (name->Equals(v8_str("x"))) {
19823     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19824   }
19825 }
19826
19827
19828 THREADED_TEST(InterceptorOnConstructorPrototype) {
19829   v8::Isolate* isolate = CcTest::isolate();
19830   v8::HandleScope scope(isolate);
19831   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19832   templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19833       NamedPropertyGetterWhichReturns42,
19834       NamedPropertySetterWhichSetsYOnThisTo23));
19835   LocalContext context;
19836   context->Global()->Set(v8_str("P"), templ->NewInstance());
19837   CompileRun("function C1() {"
19838              "  this.x = 23;"
19839              "};"
19840              "C1.prototype = P;"
19841              "function C2() {"
19842              "  this.x = 23"
19843              "};"
19844              "C2.prototype = { };"
19845              "C2.prototype.__proto__ = P;");
19846
19847   v8::Local<v8::Script> script;
19848   script = v8_compile("new C1();");
19849   for (int i = 0; i < 10; i++) {
19850     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19851     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19852     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19853   }
19854
19855   script = v8_compile("new C2();");
19856   for (int i = 0; i < 10; i++) {
19857     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19858     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
19859     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
19860   }
19861 }
19862
19863
19864 TEST(Regress618) {
19865   const char* source = "function C1() {"
19866                        "  this.x = 23;"
19867                        "};"
19868                        "C1.prototype = P;";
19869
19870   LocalContext context;
19871   v8::Isolate* isolate = context->GetIsolate();
19872   v8::HandleScope scope(isolate);
19873   v8::Local<v8::Script> script;
19874
19875   // Use a simple object as prototype.
19876   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19877   prototype->Set(v8_str("y"), v8_num(42));
19878   context->Global()->Set(v8_str("P"), prototype);
19879
19880   // This compile will add the code to the compilation cache.
19881   CompileRun(source);
19882
19883   script = v8_compile("new C1();");
19884   // Allow enough iterations for the inobject slack tracking logic
19885   // to finalize instance size and install the fast construct stub.
19886   for (int i = 0; i < 256; i++) {
19887     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19888     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19889     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19890   }
19891
19892   // Use an API object with accessors as prototype.
19893   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19894   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19895                      SetterWhichSetsYOnThisTo23);
19896   context->Global()->Set(v8_str("P"), templ->NewInstance());
19897
19898   // This compile will get the code from the compilation cache.
19899   CompileRun(source);
19900
19901   script = v8_compile("new C1();");
19902   for (int i = 0; i < 10; i++) {
19903     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19904     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19905     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19906   }
19907 }
19908
19909 v8::Isolate* gc_callbacks_isolate = NULL;
19910 int prologue_call_count = 0;
19911 int epilogue_call_count = 0;
19912 int prologue_call_count_second = 0;
19913 int epilogue_call_count_second = 0;
19914 int prologue_call_count_alloc = 0;
19915 int epilogue_call_count_alloc = 0;
19916
19917 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19918   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19919   ++prologue_call_count;
19920 }
19921
19922
19923 void PrologueCallback(v8::Isolate* isolate,
19924                       v8::GCType,
19925                       v8::GCCallbackFlags flags) {
19926   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19927   CHECK_EQ(gc_callbacks_isolate, isolate);
19928   ++prologue_call_count;
19929 }
19930
19931
19932 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19933   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19934   ++epilogue_call_count;
19935 }
19936
19937
19938 void EpilogueCallback(v8::Isolate* isolate,
19939                       v8::GCType,
19940                       v8::GCCallbackFlags flags) {
19941   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19942   CHECK_EQ(gc_callbacks_isolate, isolate);
19943   ++epilogue_call_count;
19944 }
19945
19946
19947 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19948   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19949   ++prologue_call_count_second;
19950 }
19951
19952
19953 void PrologueCallbackSecond(v8::Isolate* isolate,
19954                             v8::GCType,
19955                             v8::GCCallbackFlags flags) {
19956   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19957   CHECK_EQ(gc_callbacks_isolate, isolate);
19958   ++prologue_call_count_second;
19959 }
19960
19961
19962 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19963   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19964   ++epilogue_call_count_second;
19965 }
19966
19967
19968 void EpilogueCallbackSecond(v8::Isolate* isolate,
19969                             v8::GCType,
19970                             v8::GCCallbackFlags flags) {
19971   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19972   CHECK_EQ(gc_callbacks_isolate, isolate);
19973   ++epilogue_call_count_second;
19974 }
19975
19976
19977 void PrologueCallbackAlloc(v8::Isolate* isolate,
19978                            v8::GCType,
19979                            v8::GCCallbackFlags flags) {
19980   v8::HandleScope scope(isolate);
19981
19982   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19983   CHECK_EQ(gc_callbacks_isolate, isolate);
19984   ++prologue_call_count_alloc;
19985
19986   // Simulate full heap to see if we will reenter this callback
19987   SimulateFullSpace(CcTest::heap()->new_space());
19988
19989   Local<Object> obj = Object::New(isolate);
19990   CHECK(!obj.IsEmpty());
19991
19992   CcTest::heap()->CollectAllGarbage(
19993       i::Heap::kAbortIncrementalMarkingMask);
19994 }
19995
19996
19997 void EpilogueCallbackAlloc(v8::Isolate* isolate,
19998                            v8::GCType,
19999                            v8::GCCallbackFlags flags) {
20000   v8::HandleScope scope(isolate);
20001
20002   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20003   CHECK_EQ(gc_callbacks_isolate, isolate);
20004   ++epilogue_call_count_alloc;
20005
20006   // Simulate full heap to see if we will reenter this callback
20007   SimulateFullSpace(CcTest::heap()->new_space());
20008
20009   Local<Object> obj = Object::New(isolate);
20010   CHECK(!obj.IsEmpty());
20011
20012   CcTest::heap()->CollectAllGarbage(
20013       i::Heap::kAbortIncrementalMarkingMask);
20014 }
20015
20016
20017 TEST(GCCallbacksOld) {
20018   LocalContext context;
20019
20020   v8::V8::AddGCPrologueCallback(PrologueCallback);
20021   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
20022   CHECK_EQ(0, prologue_call_count);
20023   CHECK_EQ(0, epilogue_call_count);
20024   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20025   CHECK_EQ(1, prologue_call_count);
20026   CHECK_EQ(1, epilogue_call_count);
20027   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
20028   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
20029   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20030   CHECK_EQ(2, prologue_call_count);
20031   CHECK_EQ(2, epilogue_call_count);
20032   CHECK_EQ(1, prologue_call_count_second);
20033   CHECK_EQ(1, epilogue_call_count_second);
20034   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
20035   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
20036   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20037   CHECK_EQ(2, prologue_call_count);
20038   CHECK_EQ(2, epilogue_call_count);
20039   CHECK_EQ(2, prologue_call_count_second);
20040   CHECK_EQ(2, epilogue_call_count_second);
20041   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
20042   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20043   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20044   CHECK_EQ(2, prologue_call_count);
20045   CHECK_EQ(2, epilogue_call_count);
20046   CHECK_EQ(2, prologue_call_count_second);
20047   CHECK_EQ(2, epilogue_call_count_second);
20048 }
20049
20050
20051 TEST(GCCallbacks) {
20052   LocalContext context;
20053   v8::Isolate* isolate = context->GetIsolate();
20054   gc_callbacks_isolate = isolate;
20055   isolate->AddGCPrologueCallback(PrologueCallback);
20056   isolate->AddGCEpilogueCallback(EpilogueCallback);
20057   CHECK_EQ(0, prologue_call_count);
20058   CHECK_EQ(0, epilogue_call_count);
20059   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20060   CHECK_EQ(1, prologue_call_count);
20061   CHECK_EQ(1, epilogue_call_count);
20062   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
20063   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
20064   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20065   CHECK_EQ(2, prologue_call_count);
20066   CHECK_EQ(2, epilogue_call_count);
20067   CHECK_EQ(1, prologue_call_count_second);
20068   CHECK_EQ(1, epilogue_call_count_second);
20069   isolate->RemoveGCPrologueCallback(PrologueCallback);
20070   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
20071   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20072   CHECK_EQ(2, prologue_call_count);
20073   CHECK_EQ(2, epilogue_call_count);
20074   CHECK_EQ(2, prologue_call_count_second);
20075   CHECK_EQ(2, epilogue_call_count_second);
20076   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
20077   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20078   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20079   CHECK_EQ(2, prologue_call_count);
20080   CHECK_EQ(2, epilogue_call_count);
20081   CHECK_EQ(2, prologue_call_count_second);
20082   CHECK_EQ(2, epilogue_call_count_second);
20083
20084   CHECK_EQ(0, prologue_call_count_alloc);
20085   CHECK_EQ(0, epilogue_call_count_alloc);
20086   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
20087   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
20088   CcTest::heap()->CollectAllGarbage(
20089       i::Heap::kAbortIncrementalMarkingMask);
20090   CHECK_EQ(1, prologue_call_count_alloc);
20091   CHECK_EQ(1, epilogue_call_count_alloc);
20092   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
20093   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
20094 }
20095
20096
20097 THREADED_TEST(AddToJSFunctionResultCache) {
20098   i::FLAG_stress_compaction = false;
20099   i::FLAG_allow_natives_syntax = true;
20100   v8::HandleScope scope(CcTest::isolate());
20101
20102   LocalContext context;
20103
20104   const char* code =
20105       "(function() {"
20106       "  var key0 = 'a';"
20107       "  var key1 = 'b';"
20108       "  var r0 = %_GetFromCache(0, key0);"
20109       "  var r1 = %_GetFromCache(0, key1);"
20110       "  var r0_ = %_GetFromCache(0, key0);"
20111       "  if (r0 !== r0_)"
20112       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
20113       "  var r1_ = %_GetFromCache(0, key1);"
20114       "  if (r1 !== r1_)"
20115       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
20116       "  return 'PASSED';"
20117       "})()";
20118   CcTest::heap()->ClearJSFunctionResultCaches();
20119   ExpectString(code, "PASSED");
20120 }
20121
20122
20123 THREADED_TEST(FillJSFunctionResultCache) {
20124   i::FLAG_allow_natives_syntax = true;
20125   LocalContext context;
20126   v8::HandleScope scope(context->GetIsolate());
20127
20128   const char* code =
20129       "(function() {"
20130       "  var k = 'a';"
20131       "  var r = %_GetFromCache(0, k);"
20132       "  for (var i = 0; i < 16; i++) {"
20133       "    %_GetFromCache(0, 'a' + i);"
20134       "  };"
20135       "  if (r === %_GetFromCache(0, k))"
20136       "    return 'FAILED: k0CacheSize is too small';"
20137       "  return 'PASSED';"
20138       "})()";
20139   CcTest::heap()->ClearJSFunctionResultCaches();
20140   ExpectString(code, "PASSED");
20141 }
20142
20143
20144 THREADED_TEST(RoundRobinGetFromCache) {
20145   i::FLAG_allow_natives_syntax = true;
20146   LocalContext context;
20147   v8::HandleScope scope(context->GetIsolate());
20148
20149   const char* code =
20150       "(function() {"
20151       "  var keys = [];"
20152       "  for (var i = 0; i < 16; i++) keys.push(i);"
20153       "  var values = [];"
20154       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
20155       "  for (var i = 0; i < 16; i++) {"
20156       "    var v = %_GetFromCache(0, keys[i]);"
20157       "    if (v.toString() !== values[i].toString())"
20158       "      return 'Wrong value for ' + "
20159       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
20160       "  };"
20161       "  return 'PASSED';"
20162       "})()";
20163   CcTest::heap()->ClearJSFunctionResultCaches();
20164   ExpectString(code, "PASSED");
20165 }
20166
20167
20168 THREADED_TEST(ReverseGetFromCache) {
20169   i::FLAG_allow_natives_syntax = true;
20170   LocalContext context;
20171   v8::HandleScope scope(context->GetIsolate());
20172
20173   const char* code =
20174       "(function() {"
20175       "  var keys = [];"
20176       "  for (var i = 0; i < 16; i++) keys.push(i);"
20177       "  var values = [];"
20178       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
20179       "  for (var i = 15; i >= 16; i--) {"
20180       "    var v = %_GetFromCache(0, keys[i]);"
20181       "    if (v !== values[i])"
20182       "      return 'Wrong value for ' + "
20183       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
20184       "  };"
20185       "  return 'PASSED';"
20186       "})()";
20187   CcTest::heap()->ClearJSFunctionResultCaches();
20188   ExpectString(code, "PASSED");
20189 }
20190
20191
20192 THREADED_TEST(TestEviction) {
20193   i::FLAG_allow_natives_syntax = true;
20194   LocalContext context;
20195   v8::HandleScope scope(context->GetIsolate());
20196
20197   const char* code =
20198       "(function() {"
20199       "  for (var i = 0; i < 2*16; i++) {"
20200       "    %_GetFromCache(0, 'a' + i);"
20201       "  };"
20202       "  return 'PASSED';"
20203       "})()";
20204   CcTest::heap()->ClearJSFunctionResultCaches();
20205   ExpectString(code, "PASSED");
20206 }
20207
20208
20209 THREADED_TEST(TwoByteStringInOneByteCons) {
20210   // See Chromium issue 47824.
20211   LocalContext context;
20212   v8::HandleScope scope(context->GetIsolate());
20213
20214   const char* init_code =
20215       "var str1 = 'abelspendabel';"
20216       "var str2 = str1 + str1 + str1;"
20217       "str2;";
20218   Local<Value> result = CompileRun(init_code);
20219
20220   Local<Value> indexof = CompileRun("str2.indexOf('els')");
20221   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
20222
20223   CHECK(result->IsString());
20224   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
20225   int length = string->length();
20226   CHECK(string->IsOneByteRepresentation());
20227
20228   i::Handle<i::String> flat_string = i::String::Flatten(string);
20229
20230   CHECK(string->IsOneByteRepresentation());
20231   CHECK(flat_string->IsOneByteRepresentation());
20232
20233   // Create external resource.
20234   uint16_t* uc16_buffer = new uint16_t[length + 1];
20235
20236   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
20237   uc16_buffer[length] = 0;
20238
20239   TestResource resource(uc16_buffer);
20240
20241   flat_string->MakeExternal(&resource);
20242
20243   CHECK(flat_string->IsTwoByteRepresentation());
20244
20245   // If the cons string has been short-circuited, skip the following checks.
20246   if (!string.is_identical_to(flat_string)) {
20247     // At this point, we should have a Cons string which is flat and one-byte,
20248     // with a first half that is a two-byte string (although it only contains
20249     // one-byte characters). This is a valid sequence of steps, and it can
20250     // happen in real pages.
20251     CHECK(string->IsOneByteRepresentation());
20252     i::ConsString* cons = i::ConsString::cast(*string);
20253     CHECK_EQ(0, cons->second()->length());
20254     CHECK(cons->first()->IsTwoByteRepresentation());
20255   }
20256
20257   // Check that some string operations work.
20258
20259   // Atom RegExp.
20260   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
20261   CHECK_EQ(6, reresult->Int32Value());
20262
20263   // Nonatom RegExp.
20264   reresult = CompileRun("str2.match(/abe./g).length;");
20265   CHECK_EQ(6, reresult->Int32Value());
20266
20267   reresult = CompileRun("str2.search(/bel/g);");
20268   CHECK_EQ(1, reresult->Int32Value());
20269
20270   reresult = CompileRun("str2.search(/be./g);");
20271   CHECK_EQ(1, reresult->Int32Value());
20272
20273   ExpectTrue("/bel/g.test(str2);");
20274
20275   ExpectTrue("/be./g.test(str2);");
20276
20277   reresult = CompileRun("/bel/g.exec(str2);");
20278   CHECK(!reresult->IsNull());
20279
20280   reresult = CompileRun("/be./g.exec(str2);");
20281   CHECK(!reresult->IsNull());
20282
20283   ExpectString("str2.substring(2, 10);", "elspenda");
20284
20285   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
20286
20287   ExpectString("str2.charAt(2);", "e");
20288
20289   ExpectObject("str2.indexOf('els');", indexof);
20290
20291   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
20292
20293   reresult = CompileRun("str2.charCodeAt(2);");
20294   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
20295 }
20296
20297
20298 TEST(ContainsOnlyOneByte) {
20299   v8::V8::Initialize();
20300   v8::Isolate* isolate = CcTest::isolate();
20301   v8::HandleScope scope(isolate);
20302   // Make a buffer long enough that it won't automatically be converted.
20303   const int length = 512;
20304   // Ensure word aligned assignment.
20305   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
20306   i::SmartArrayPointer<uintptr_t>
20307   aligned_contents(new uintptr_t[aligned_length]);
20308   uint16_t* string_contents =
20309       reinterpret_cast<uint16_t*>(aligned_contents.get());
20310   // Set to contain only one byte.
20311   for (int i = 0; i < length-1; i++) {
20312     string_contents[i] = 0x41;
20313   }
20314   string_contents[length-1] = 0;
20315   // Simple case.
20316   Handle<String> string =
20317       String::NewExternal(isolate,
20318                           new TestResource(string_contents, NULL, false));
20319   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20320   // Counter example.
20321   string = String::NewFromTwoByte(isolate, string_contents);
20322   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20323   // Test left right and balanced cons strings.
20324   Handle<String> base = String::NewFromUtf8(isolate, "a");
20325   Handle<String> left = base;
20326   Handle<String> right = base;
20327   for (int i = 0; i < 1000; i++) {
20328     left = String::Concat(base, left);
20329     right = String::Concat(right, base);
20330   }
20331   Handle<String> balanced = String::Concat(left, base);
20332   balanced = String::Concat(balanced, right);
20333   Handle<String> cons_strings[] = {left, balanced, right};
20334   Handle<String> two_byte =
20335       String::NewExternal(isolate,
20336                           new TestResource(string_contents, NULL, false));
20337   USE(two_byte); USE(cons_strings);
20338   for (size_t i = 0; i < arraysize(cons_strings); i++) {
20339     // Base assumptions.
20340     string = cons_strings[i];
20341     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20342     // Test left and right concatentation.
20343     string = String::Concat(two_byte, cons_strings[i]);
20344     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20345     string = String::Concat(cons_strings[i], two_byte);
20346     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20347   }
20348   // Set bits in different positions
20349   // for strings of different lengths and alignments.
20350   for (int alignment = 0; alignment < 7; alignment++) {
20351     for (int size = 2; alignment + size < length; size *= 2) {
20352       int zero_offset = size + alignment;
20353       string_contents[zero_offset] = 0;
20354       for (int i = 0; i < size; i++) {
20355         int shift = 8 + (i % 7);
20356         string_contents[alignment + i] = 1 << shift;
20357         string = String::NewExternal(
20358             isolate,
20359             new TestResource(string_contents + alignment, NULL, false));
20360         CHECK_EQ(size, string->Length());
20361         CHECK(!string->ContainsOnlyOneByte());
20362         string_contents[alignment + i] = 0x41;
20363       }
20364       string_contents[zero_offset] = 0x41;
20365     }
20366   }
20367 }
20368
20369
20370 // Failed access check callback that performs a GC on each invocation.
20371 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20372                                  v8::AccessType type,
20373                                  Local<v8::Value> data) {
20374   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20375 }
20376
20377
20378 TEST(GCInFailedAccessCheckCallback) {
20379   // Install a failed access check callback that performs a GC on each
20380   // invocation. Then force the callback to be called from va
20381
20382   v8::V8::Initialize();
20383   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20384
20385   v8::Isolate* isolate = CcTest::isolate();
20386   v8::HandleScope scope(isolate);
20387
20388   // Create an ObjectTemplate for global objects and install access
20389   // check callbacks that will block access.
20390   v8::Handle<v8::ObjectTemplate> global_template =
20391       v8::ObjectTemplate::New(isolate);
20392   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
20393                                            IndexedGetAccessBlocker,
20394                                            v8::Handle<v8::Value>(),
20395                                            false);
20396
20397   // Create a context and set an x property on it's global object.
20398   LocalContext context0(NULL, global_template);
20399   context0->Global()->Set(v8_str("x"), v8_num(42));
20400   v8::Handle<v8::Object> global0 = context0->Global();
20401
20402   // Create a context with a different security token so that the
20403   // failed access check callback will be called on each access.
20404   LocalContext context1(NULL, global_template);
20405   context1->Global()->Set(v8_str("other"), global0);
20406
20407   // Get property with failed access check.
20408   ExpectUndefined("other.x");
20409
20410   // Get element with failed access check.
20411   ExpectUndefined("other[0]");
20412
20413   // Set property with failed access check.
20414   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
20415   CHECK(result->IsObject());
20416
20417   // Set element with failed access check.
20418   result = CompileRun("other[0] = new Object()");
20419   CHECK(result->IsObject());
20420
20421   // Get property attribute with failed access check.
20422   ExpectFalse("\'x\' in other");
20423
20424   // Get property attribute for element with failed access check.
20425   ExpectFalse("0 in other");
20426
20427   // Delete property.
20428   ExpectFalse("delete other.x");
20429
20430   // Delete element.
20431   CHECK_EQ(false, global0->Delete(0));
20432
20433   // DefineAccessor.
20434   CHECK_EQ(false,
20435            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
20436
20437   // Define JavaScript accessor.
20438   ExpectUndefined("Object.prototype.__defineGetter__.call("
20439                   "    other, \'x\', function() { return 42; })");
20440
20441   // LookupAccessor.
20442   ExpectUndefined("Object.prototype.__lookupGetter__.call("
20443                   "    other, \'x\')");
20444
20445   // HasOwnElement.
20446   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
20447
20448   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
20449   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
20450   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
20451
20452   // Reset the failed access check callback so it does not influence
20453   // the other tests.
20454   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20455 }
20456
20457
20458 TEST(IsolateNewDispose) {
20459   v8::Isolate* current_isolate = CcTest::isolate();
20460   v8::Isolate* isolate = v8::Isolate::New();
20461   CHECK(isolate != NULL);
20462   CHECK(current_isolate != isolate);
20463   CHECK(current_isolate == CcTest::isolate());
20464
20465   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20466   last_location = last_message = NULL;
20467   isolate->Dispose();
20468   CHECK_EQ(last_location, NULL);
20469   CHECK_EQ(last_message, NULL);
20470 }
20471
20472
20473 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20474   v8::Isolate* isolate = v8::Isolate::New();
20475   {
20476     v8::Isolate::Scope i_scope(isolate);
20477     v8::HandleScope scope(isolate);
20478     LocalContext context(isolate);
20479     // Run something in this isolate.
20480     ExpectTrue("true");
20481     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20482     last_location = last_message = NULL;
20483     // Still entered, should fail.
20484     isolate->Dispose();
20485     CHECK_NE(last_location, NULL);
20486     CHECK_NE(last_message, NULL);
20487   }
20488   isolate->Dispose();
20489 }
20490
20491
20492 TEST(RunTwoIsolatesOnSingleThread) {
20493   // Run isolate 1.
20494   v8::Isolate* isolate1 = v8::Isolate::New();
20495   isolate1->Enter();
20496   v8::Persistent<v8::Context> context1;
20497   {
20498     v8::HandleScope scope(isolate1);
20499     context1.Reset(isolate1, Context::New(isolate1));
20500   }
20501
20502   {
20503     v8::HandleScope scope(isolate1);
20504     v8::Local<v8::Context> context =
20505         v8::Local<v8::Context>::New(isolate1, context1);
20506     v8::Context::Scope context_scope(context);
20507     // Run something in new isolate.
20508     CompileRun("var foo = 'isolate 1';");
20509     ExpectString("function f() { return foo; }; f()", "isolate 1");
20510   }
20511
20512   // Run isolate 2.
20513   v8::Isolate* isolate2 = v8::Isolate::New();
20514   v8::Persistent<v8::Context> context2;
20515
20516   {
20517     v8::Isolate::Scope iscope(isolate2);
20518     v8::HandleScope scope(isolate2);
20519     context2.Reset(isolate2, Context::New(isolate2));
20520     v8::Local<v8::Context> context =
20521         v8::Local<v8::Context>::New(isolate2, context2);
20522     v8::Context::Scope context_scope(context);
20523
20524     // Run something in new isolate.
20525     CompileRun("var foo = 'isolate 2';");
20526     ExpectString("function f() { return foo; }; f()", "isolate 2");
20527   }
20528
20529   {
20530     v8::HandleScope scope(isolate1);
20531     v8::Local<v8::Context> context =
20532         v8::Local<v8::Context>::New(isolate1, context1);
20533     v8::Context::Scope context_scope(context);
20534     // Now again in isolate 1
20535     ExpectString("function f() { return foo; }; f()", "isolate 1");
20536   }
20537
20538   isolate1->Exit();
20539
20540   // Run some stuff in default isolate.
20541   v8::Persistent<v8::Context> context_default;
20542   {
20543     v8::Isolate* isolate = CcTest::isolate();
20544     v8::Isolate::Scope iscope(isolate);
20545     v8::HandleScope scope(isolate);
20546     context_default.Reset(isolate, Context::New(isolate));
20547   }
20548
20549   {
20550     v8::HandleScope scope(CcTest::isolate());
20551     v8::Local<v8::Context> context =
20552         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20553     v8::Context::Scope context_scope(context);
20554     // Variables in other isolates should be not available, verify there
20555     // is an exception.
20556     ExpectTrue("function f() {"
20557                "  try {"
20558                "    foo;"
20559                "    return false;"
20560                "  } catch(e) {"
20561                "    return true;"
20562                "  }"
20563                "};"
20564                "var isDefaultIsolate = true;"
20565                "f()");
20566   }
20567
20568   isolate1->Enter();
20569
20570   {
20571     v8::Isolate::Scope iscope(isolate2);
20572     v8::HandleScope scope(isolate2);
20573     v8::Local<v8::Context> context =
20574         v8::Local<v8::Context>::New(isolate2, context2);
20575     v8::Context::Scope context_scope(context);
20576     ExpectString("function f() { return foo; }; f()", "isolate 2");
20577   }
20578
20579   {
20580     v8::HandleScope scope(v8::Isolate::GetCurrent());
20581     v8::Local<v8::Context> context =
20582         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20583     v8::Context::Scope context_scope(context);
20584     ExpectString("function f() { return foo; }; f()", "isolate 1");
20585   }
20586
20587   {
20588     v8::Isolate::Scope iscope(isolate2);
20589     context2.Reset();
20590   }
20591
20592   context1.Reset();
20593   isolate1->Exit();
20594
20595   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20596   last_location = last_message = NULL;
20597
20598   isolate1->Dispose();
20599   CHECK_EQ(last_location, NULL);
20600   CHECK_EQ(last_message, NULL);
20601
20602   isolate2->Dispose();
20603   CHECK_EQ(last_location, NULL);
20604   CHECK_EQ(last_message, NULL);
20605
20606   // Check that default isolate still runs.
20607   {
20608     v8::HandleScope scope(CcTest::isolate());
20609     v8::Local<v8::Context> context =
20610         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20611     v8::Context::Scope context_scope(context);
20612     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20613   }
20614 }
20615
20616
20617 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20618   v8::Isolate::Scope isolate_scope(isolate);
20619   v8::HandleScope scope(isolate);
20620   LocalContext context(isolate);
20621   i::ScopedVector<char> code(1024);
20622   i::SNPrintF(code, "function fib(n) {"
20623                     "  if (n <= 2) return 1;"
20624                     "  return fib(n-1) + fib(n-2);"
20625                     "}"
20626                     "fib(%d)", limit);
20627   Local<Value> value = CompileRun(code.start());
20628   CHECK(value->IsNumber());
20629   return static_cast<int>(value->NumberValue());
20630 }
20631
20632 class IsolateThread : public v8::base::Thread {
20633  public:
20634   explicit IsolateThread(int fib_limit)
20635       : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20636
20637   void Run() {
20638     v8::Isolate* isolate = v8::Isolate::New();
20639     result_ = CalcFibonacci(isolate, fib_limit_);
20640     isolate->Dispose();
20641   }
20642
20643   int result() { return result_; }
20644
20645  private:
20646   int fib_limit_;
20647   int result_;
20648 };
20649
20650
20651 TEST(MultipleIsolatesOnIndividualThreads) {
20652   IsolateThread thread1(21);
20653   IsolateThread thread2(12);
20654
20655   // Compute some fibonacci numbers on 3 threads in 3 isolates.
20656   thread1.Start();
20657   thread2.Start();
20658
20659   int result1 = CalcFibonacci(CcTest::isolate(), 21);
20660   int result2 = CalcFibonacci(CcTest::isolate(), 12);
20661
20662   thread1.Join();
20663   thread2.Join();
20664
20665   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20666   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20667   CHECK_EQ(result1, 10946);
20668   CHECK_EQ(result2, 144);
20669   CHECK_EQ(result1, thread1.result());
20670   CHECK_EQ(result2, thread2.result());
20671 }
20672
20673
20674 TEST(IsolateDifferentContexts) {
20675   v8::Isolate* isolate = v8::Isolate::New();
20676   Local<v8::Context> context;
20677   {
20678     v8::Isolate::Scope isolate_scope(isolate);
20679     v8::HandleScope handle_scope(isolate);
20680     context = v8::Context::New(isolate);
20681     v8::Context::Scope context_scope(context);
20682     Local<Value> v = CompileRun("2");
20683     CHECK(v->IsNumber());
20684     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
20685   }
20686   {
20687     v8::Isolate::Scope isolate_scope(isolate);
20688     v8::HandleScope handle_scope(isolate);
20689     context = v8::Context::New(isolate);
20690     v8::Context::Scope context_scope(context);
20691     Local<Value> v = CompileRun("22");
20692     CHECK(v->IsNumber());
20693     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
20694   }
20695   isolate->Dispose();
20696 }
20697
20698 class InitDefaultIsolateThread : public v8::base::Thread {
20699  public:
20700   enum TestCase {
20701     SetResourceConstraints,
20702     SetFatalHandler,
20703     SetCounterFunction,
20704     SetCreateHistogramFunction,
20705     SetAddHistogramSampleFunction
20706   };
20707
20708   explicit InitDefaultIsolateThread(TestCase testCase)
20709       : Thread(Options("InitDefaultIsolateThread")),
20710         testCase_(testCase),
20711         result_(false) {}
20712
20713   void Run() {
20714     v8::Isolate::CreateParams create_params;
20715     switch (testCase_) {
20716       case SetResourceConstraints: {
20717         create_params.constraints.set_max_semi_space_size(1);
20718         create_params.constraints.set_max_old_space_size(4);
20719         break;
20720       }
20721       default:
20722         break;
20723     }
20724     v8::Isolate* isolate = v8::Isolate::New(create_params);
20725     isolate->Enter();
20726     switch (testCase_) {
20727       case SetResourceConstraints:
20728         // Already handled in pre-Isolate-creation block.
20729         break;
20730
20731       case SetFatalHandler:
20732         v8::V8::SetFatalErrorHandler(NULL);
20733         break;
20734
20735       case SetCounterFunction:
20736         CcTest::isolate()->SetCounterFunction(NULL);
20737         break;
20738
20739       case SetCreateHistogramFunction:
20740         CcTest::isolate()->SetCreateHistogramFunction(NULL);
20741         break;
20742
20743       case SetAddHistogramSampleFunction:
20744         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
20745         break;
20746     }
20747     isolate->Exit();
20748     isolate->Dispose();
20749     result_ = true;
20750   }
20751
20752   bool result() { return result_; }
20753
20754  private:
20755   TestCase testCase_;
20756   bool result_;
20757 };
20758
20759
20760 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20761   InitDefaultIsolateThread thread(testCase);
20762   thread.Start();
20763   thread.Join();
20764   CHECK_EQ(thread.result(), true);
20765 }
20766
20767
20768 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
20769   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
20770 }
20771
20772
20773 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
20774   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20775 }
20776
20777
20778 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
20779   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20780 }
20781
20782
20783 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
20784   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20785 }
20786
20787
20788 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
20789   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20790 }
20791
20792
20793 TEST(StringCheckMultipleContexts) {
20794   const char* code =
20795       "(function() { return \"a\".charAt(0); })()";
20796
20797   {
20798     // Run the code twice in the first context to initialize the call IC.
20799     LocalContext context1;
20800     v8::HandleScope scope(context1->GetIsolate());
20801     ExpectString(code, "a");
20802     ExpectString(code, "a");
20803   }
20804
20805   {
20806     // Change the String.prototype in the second context and check
20807     // that the right function gets called.
20808     LocalContext context2;
20809     v8::HandleScope scope(context2->GetIsolate());
20810     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20811     ExpectString(code, "not a");
20812   }
20813 }
20814
20815
20816 TEST(NumberCheckMultipleContexts) {
20817   const char* code =
20818       "(function() { return (42).toString(); })()";
20819
20820   {
20821     // Run the code twice in the first context to initialize the call IC.
20822     LocalContext context1;
20823     v8::HandleScope scope(context1->GetIsolate());
20824     ExpectString(code, "42");
20825     ExpectString(code, "42");
20826   }
20827
20828   {
20829     // Change the Number.prototype in the second context and check
20830     // that the right function gets called.
20831     LocalContext context2;
20832     v8::HandleScope scope(context2->GetIsolate());
20833     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20834     ExpectString(code, "not 42");
20835   }
20836 }
20837
20838
20839 TEST(BooleanCheckMultipleContexts) {
20840   const char* code =
20841       "(function() { return true.toString(); })()";
20842
20843   {
20844     // Run the code twice in the first context to initialize the call IC.
20845     LocalContext context1;
20846     v8::HandleScope scope(context1->GetIsolate());
20847     ExpectString(code, "true");
20848     ExpectString(code, "true");
20849   }
20850
20851   {
20852     // Change the Boolean.prototype in the second context and check
20853     // that the right function gets called.
20854     LocalContext context2;
20855     v8::HandleScope scope(context2->GetIsolate());
20856     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20857     ExpectString(code, "");
20858   }
20859 }
20860
20861
20862 TEST(DontDeleteCellLoadIC) {
20863   const char* function_code =
20864       "function readCell() { while (true) { return cell; } }";
20865
20866   {
20867     // Run the code twice in the first context to initialize the load
20868     // IC for a don't delete cell.
20869     LocalContext context1;
20870     v8::HandleScope scope(context1->GetIsolate());
20871     CompileRun("var cell = \"first\";");
20872     ExpectBoolean("delete cell", false);
20873     CompileRun(function_code);
20874     ExpectString("readCell()", "first");
20875     ExpectString("readCell()", "first");
20876   }
20877
20878   {
20879     // Use a deletable cell in the second context.
20880     LocalContext context2;
20881     v8::HandleScope scope(context2->GetIsolate());
20882     CompileRun("cell = \"second\";");
20883     CompileRun(function_code);
20884     ExpectString("readCell()", "second");
20885     ExpectBoolean("delete cell", true);
20886     ExpectString("(function() {"
20887                  "  try {"
20888                  "    return readCell();"
20889                  "  } catch(e) {"
20890                  "    return e.toString();"
20891                  "  }"
20892                  "})()",
20893                  "ReferenceError: cell is not defined");
20894     CompileRun("cell = \"new_second\";");
20895     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20896     ExpectString("readCell()", "new_second");
20897     ExpectString("readCell()", "new_second");
20898   }
20899 }
20900
20901
20902 TEST(DontDeleteCellLoadICForceDelete) {
20903   const char* function_code =
20904       "function readCell() { while (true) { return cell; } }";
20905
20906   // Run the code twice to initialize the load IC for a don't delete
20907   // cell.
20908   LocalContext context;
20909   v8::HandleScope scope(context->GetIsolate());
20910   CompileRun("var cell = \"value\";");
20911   ExpectBoolean("delete cell", false);
20912   CompileRun(function_code);
20913   ExpectString("readCell()", "value");
20914   ExpectString("readCell()", "value");
20915
20916   // Delete the cell using the API and check the inlined code works
20917   // correctly.
20918   CHECK(context->Global()->ForceDelete(v8_str("cell")));
20919   ExpectString("(function() {"
20920                "  try {"
20921                "    return readCell();"
20922                "  } catch(e) {"
20923                "    return e.toString();"
20924                "  }"
20925                "})()",
20926                "ReferenceError: cell is not defined");
20927 }
20928
20929
20930 TEST(DontDeleteCellLoadICAPI) {
20931   const char* function_code =
20932       "function readCell() { while (true) { return cell; } }";
20933
20934   // Run the code twice to initialize the load IC for a don't delete
20935   // cell created using the API.
20936   LocalContext context;
20937   v8::HandleScope scope(context->GetIsolate());
20938   context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
20939   ExpectBoolean("delete cell", false);
20940   CompileRun(function_code);
20941   ExpectString("readCell()", "value");
20942   ExpectString("readCell()", "value");
20943
20944   // Delete the cell using the API and check the inlined code works
20945   // correctly.
20946   CHECK(context->Global()->ForceDelete(v8_str("cell")));
20947   ExpectString("(function() {"
20948                "  try {"
20949                "    return readCell();"
20950                "  } catch(e) {"
20951                "    return e.toString();"
20952                "  }"
20953                "})()",
20954                "ReferenceError: cell is not defined");
20955 }
20956
20957
20958 class Visitor42 : public v8::PersistentHandleVisitor {
20959  public:
20960   explicit Visitor42(v8::Persistent<v8::Object>* object)
20961       : counter_(0), object_(object) { }
20962
20963   virtual void VisitPersistentHandle(Persistent<Value>* value,
20964                                      uint16_t class_id) {
20965     if (class_id != 42) return;
20966     CHECK_EQ(42, value->WrapperClassId());
20967     v8::Isolate* isolate = CcTest::isolate();
20968     v8::HandleScope handle_scope(isolate);
20969     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20970     v8::Handle<v8::Value> object =
20971         v8::Local<v8::Object>::New(isolate, *object_);
20972     CHECK(handle->IsObject());
20973     CHECK_EQ(Handle<Object>::Cast(handle), object);
20974     ++counter_;
20975   }
20976
20977   int counter_;
20978   v8::Persistent<v8::Object>* object_;
20979 };
20980
20981
20982 TEST(PersistentHandleVisitor) {
20983   LocalContext context;
20984   v8::Isolate* isolate = context->GetIsolate();
20985   v8::HandleScope scope(isolate);
20986   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20987   CHECK_EQ(0, object.WrapperClassId());
20988   object.SetWrapperClassId(42);
20989   CHECK_EQ(42, object.WrapperClassId());
20990
20991   Visitor42 visitor(&object);
20992   v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
20993   CHECK_EQ(1, visitor.counter_);
20994
20995   object.Reset();
20996 }
20997
20998
20999 TEST(WrapperClassId) {
21000   LocalContext context;
21001   v8::Isolate* isolate = context->GetIsolate();
21002   v8::HandleScope scope(isolate);
21003   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
21004   CHECK_EQ(0, object.WrapperClassId());
21005   object.SetWrapperClassId(65535);
21006   CHECK_EQ(65535, object.WrapperClassId());
21007   object.Reset();
21008 }
21009
21010
21011 TEST(PersistentHandleInNewSpaceVisitor) {
21012   LocalContext context;
21013   v8::Isolate* isolate = context->GetIsolate();
21014   v8::HandleScope scope(isolate);
21015   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
21016   CHECK_EQ(0, object1.WrapperClassId());
21017   object1.SetWrapperClassId(42);
21018   CHECK_EQ(42, object1.WrapperClassId());
21019
21020   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
21021   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
21022
21023   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
21024   CHECK_EQ(0, object2.WrapperClassId());
21025   object2.SetWrapperClassId(42);
21026   CHECK_EQ(42, object2.WrapperClassId());
21027
21028   Visitor42 visitor(&object2);
21029   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
21030   CHECK_EQ(1, visitor.counter_);
21031
21032   object1.Reset();
21033   object2.Reset();
21034 }
21035
21036
21037 TEST(RegExp) {
21038   LocalContext context;
21039   v8::HandleScope scope(context->GetIsolate());
21040
21041   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
21042   CHECK(re->IsRegExp());
21043   CHECK(re->GetSource()->Equals(v8_str("foo")));
21044   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21045
21046   re = v8::RegExp::New(v8_str("bar"),
21047                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21048                                                       v8::RegExp::kGlobal));
21049   CHECK(re->IsRegExp());
21050   CHECK(re->GetSource()->Equals(v8_str("bar")));
21051   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
21052            static_cast<int>(re->GetFlags()));
21053
21054   re = v8::RegExp::New(v8_str("baz"),
21055                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21056                                                       v8::RegExp::kMultiline));
21057   CHECK(re->IsRegExp());
21058   CHECK(re->GetSource()->Equals(v8_str("baz")));
21059   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21060            static_cast<int>(re->GetFlags()));
21061
21062   re = CompileRun("/quux/").As<v8::RegExp>();
21063   CHECK(re->IsRegExp());
21064   CHECK(re->GetSource()->Equals(v8_str("quux")));
21065   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21066
21067   re = CompileRun("/quux/gm").As<v8::RegExp>();
21068   CHECK(re->IsRegExp());
21069   CHECK(re->GetSource()->Equals(v8_str("quux")));
21070   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
21071            static_cast<int>(re->GetFlags()));
21072
21073   // Override the RegExp constructor and check the API constructor
21074   // still works.
21075   CompileRun("RegExp = function() {}");
21076
21077   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
21078   CHECK(re->IsRegExp());
21079   CHECK(re->GetSource()->Equals(v8_str("foobar")));
21080   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21081
21082   re = v8::RegExp::New(v8_str("foobarbaz"),
21083                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21084                                                       v8::RegExp::kMultiline));
21085   CHECK(re->IsRegExp());
21086   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
21087   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21088            static_cast<int>(re->GetFlags()));
21089
21090   context->Global()->Set(v8_str("re"), re);
21091   ExpectTrue("re.test('FoobarbaZ')");
21092
21093   // RegExps are objects on which you can set properties.
21094   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
21095   v8::Handle<v8::Value> value(CompileRun("re.property"));
21096   CHECK_EQ(32, value->Int32Value());
21097
21098   v8::TryCatch try_catch;
21099   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
21100   CHECK(re.IsEmpty());
21101   CHECK(try_catch.HasCaught());
21102   context->Global()->Set(v8_str("ex"), try_catch.Exception());
21103   ExpectTrue("ex instanceof SyntaxError");
21104 }
21105
21106
21107 THREADED_TEST(Equals) {
21108   LocalContext localContext;
21109   v8::HandleScope handleScope(localContext->GetIsolate());
21110
21111   v8::Handle<v8::Object> globalProxy = localContext->Global();
21112   v8::Handle<Value> global = globalProxy->GetPrototype();
21113
21114   CHECK(global->StrictEquals(global));
21115   CHECK(!global->StrictEquals(globalProxy));
21116   CHECK(!globalProxy->StrictEquals(global));
21117   CHECK(globalProxy->StrictEquals(globalProxy));
21118
21119   CHECK(global->Equals(global));
21120   CHECK(!global->Equals(globalProxy));
21121   CHECK(!globalProxy->Equals(global));
21122   CHECK(globalProxy->Equals(globalProxy));
21123 }
21124
21125
21126 static void Getter(v8::Local<v8::Name> property,
21127                    const v8::PropertyCallbackInfo<v8::Value>& info) {
21128   info.GetReturnValue().Set(v8_str("42!"));
21129 }
21130
21131
21132 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
21133   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
21134   result->Set(0, v8_str("universalAnswer"));
21135   info.GetReturnValue().Set(result);
21136 }
21137
21138
21139 TEST(NamedEnumeratorAndForIn) {
21140   LocalContext context;
21141   v8::Isolate* isolate = context->GetIsolate();
21142   v8::HandleScope handle_scope(isolate);
21143   v8::Context::Scope context_scope(context.local());
21144
21145   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
21146   tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
21147                                                          NULL, Enumerator));
21148   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
21149   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
21150         "var result = []; for (var k in o) result.push(k); result"));
21151   CHECK_EQ(1, result->Length());
21152   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
21153 }
21154
21155
21156 TEST(DefinePropertyPostDetach) {
21157   LocalContext context;
21158   v8::HandleScope scope(context->GetIsolate());
21159   v8::Handle<v8::Object> proxy = context->Global();
21160   v8::Handle<v8::Function> define_property =
21161       CompileRun("(function() {"
21162                  "  Object.defineProperty("
21163                  "    this,"
21164                  "    1,"
21165                  "    { configurable: true, enumerable: true, value: 3 });"
21166                  "})").As<Function>();
21167   context->DetachGlobal();
21168   define_property->Call(proxy, 0, NULL);
21169 }
21170
21171
21172 static void InstallContextId(v8::Handle<Context> context, int id) {
21173   Context::Scope scope(context);
21174   CompileRun("Object.prototype").As<Object>()->
21175       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
21176 }
21177
21178
21179 static void CheckContextId(v8::Handle<Object> object, int expected) {
21180   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
21181 }
21182
21183
21184 THREADED_TEST(CreationContext) {
21185   v8::Isolate* isolate = CcTest::isolate();
21186   HandleScope handle_scope(isolate);
21187   Handle<Context> context1 = Context::New(isolate);
21188   InstallContextId(context1, 1);
21189   Handle<Context> context2 = Context::New(isolate);
21190   InstallContextId(context2, 2);
21191   Handle<Context> context3 = Context::New(isolate);
21192   InstallContextId(context3, 3);
21193
21194   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
21195
21196   Local<Object> object1;
21197   Local<Function> func1;
21198   {
21199     Context::Scope scope(context1);
21200     object1 = Object::New(isolate);
21201     func1 = tmpl->GetFunction();
21202   }
21203
21204   Local<Object> object2;
21205   Local<Function> func2;
21206   {
21207     Context::Scope scope(context2);
21208     object2 = Object::New(isolate);
21209     func2 = tmpl->GetFunction();
21210   }
21211
21212   Local<Object> instance1;
21213   Local<Object> instance2;
21214
21215   {
21216     Context::Scope scope(context3);
21217     instance1 = func1->NewInstance();
21218     instance2 = func2->NewInstance();
21219   }
21220
21221   CHECK(object1->CreationContext() == context1);
21222   CheckContextId(object1, 1);
21223   CHECK(func1->CreationContext() == context1);
21224   CheckContextId(func1, 1);
21225   CHECK(instance1->CreationContext() == context1);
21226   CheckContextId(instance1, 1);
21227   CHECK(object2->CreationContext() == context2);
21228   CheckContextId(object2, 2);
21229   CHECK(func2->CreationContext() == context2);
21230   CheckContextId(func2, 2);
21231   CHECK(instance2->CreationContext() == context2);
21232   CheckContextId(instance2, 2);
21233
21234   {
21235     Context::Scope scope(context1);
21236     CHECK(object1->CreationContext() == context1);
21237     CheckContextId(object1, 1);
21238     CHECK(func1->CreationContext() == context1);
21239     CheckContextId(func1, 1);
21240     CHECK(instance1->CreationContext() == context1);
21241     CheckContextId(instance1, 1);
21242     CHECK(object2->CreationContext() == context2);
21243     CheckContextId(object2, 2);
21244     CHECK(func2->CreationContext() == context2);
21245     CheckContextId(func2, 2);
21246     CHECK(instance2->CreationContext() == context2);
21247     CheckContextId(instance2, 2);
21248   }
21249
21250   {
21251     Context::Scope scope(context2);
21252     CHECK(object1->CreationContext() == context1);
21253     CheckContextId(object1, 1);
21254     CHECK(func1->CreationContext() == context1);
21255     CheckContextId(func1, 1);
21256     CHECK(instance1->CreationContext() == context1);
21257     CheckContextId(instance1, 1);
21258     CHECK(object2->CreationContext() == context2);
21259     CheckContextId(object2, 2);
21260     CHECK(func2->CreationContext() == context2);
21261     CheckContextId(func2, 2);
21262     CHECK(instance2->CreationContext() == context2);
21263     CheckContextId(instance2, 2);
21264   }
21265 }
21266
21267
21268 THREADED_TEST(CreationContextOfJsFunction) {
21269   HandleScope handle_scope(CcTest::isolate());
21270   Handle<Context> context = Context::New(CcTest::isolate());
21271   InstallContextId(context, 1);
21272
21273   Local<Object> function;
21274   {
21275     Context::Scope scope(context);
21276     function = CompileRun("function foo() {}; foo").As<Object>();
21277   }
21278
21279   CHECK(function->CreationContext() == context);
21280   CheckContextId(function, 1);
21281 }
21282
21283
21284 void HasOwnPropertyIndexedPropertyGetter(
21285     uint32_t index,
21286     const v8::PropertyCallbackInfo<v8::Value>& info) {
21287   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
21288 }
21289
21290
21291 void HasOwnPropertyNamedPropertyGetter(
21292     Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
21293   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
21294 }
21295
21296
21297 void HasOwnPropertyIndexedPropertyQuery(
21298     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21299   if (index == 42) info.GetReturnValue().Set(1);
21300 }
21301
21302
21303 void HasOwnPropertyNamedPropertyQuery(
21304     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21305   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
21306 }
21307
21308
21309 void HasOwnPropertyNamedPropertyQuery2(
21310     Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21311   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
21312 }
21313
21314
21315 void HasOwnPropertyAccessorGetter(
21316     Local<String> property,
21317     const v8::PropertyCallbackInfo<v8::Value>& info) {
21318   info.GetReturnValue().Set(v8_str("yes"));
21319 }
21320
21321
21322 TEST(HasOwnProperty) {
21323   LocalContext env;
21324   v8::Isolate* isolate = env->GetIsolate();
21325   v8::HandleScope scope(isolate);
21326   { // Check normal properties and defined getters.
21327     Handle<Value> value = CompileRun(
21328         "function Foo() {"
21329         "    this.foo = 11;"
21330         "    this.__defineGetter__('baz', function() { return 1; });"
21331         "};"
21332         "function Bar() { "
21333         "    this.bar = 13;"
21334         "    this.__defineGetter__('bla', function() { return 2; });"
21335         "};"
21336         "Bar.prototype = new Foo();"
21337         "new Bar();");
21338     CHECK(value->IsObject());
21339     Handle<Object> object = value->ToObject(isolate);
21340     CHECK(object->Has(v8_str("foo")));
21341     CHECK(!object->HasOwnProperty(v8_str("foo")));
21342     CHECK(object->HasOwnProperty(v8_str("bar")));
21343     CHECK(object->Has(v8_str("baz")));
21344     CHECK(!object->HasOwnProperty(v8_str("baz")));
21345     CHECK(object->HasOwnProperty(v8_str("bla")));
21346   }
21347   { // Check named getter interceptors.
21348     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21349     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21350         HasOwnPropertyNamedPropertyGetter));
21351     Handle<Object> instance = templ->NewInstance();
21352     CHECK(!instance->HasOwnProperty(v8_str("42")));
21353     CHECK(instance->HasOwnProperty(v8_str("foo")));
21354     CHECK(!instance->HasOwnProperty(v8_str("bar")));
21355   }
21356   { // Check indexed getter interceptors.
21357     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21358     templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21359         HasOwnPropertyIndexedPropertyGetter));
21360     Handle<Object> instance = templ->NewInstance();
21361     CHECK(instance->HasOwnProperty(v8_str("42")));
21362     CHECK(!instance->HasOwnProperty(v8_str("43")));
21363     CHECK(!instance->HasOwnProperty(v8_str("foo")));
21364   }
21365   { // Check named query interceptors.
21366     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21367     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21368         0, 0, HasOwnPropertyNamedPropertyQuery));
21369     Handle<Object> instance = templ->NewInstance();
21370     CHECK(instance->HasOwnProperty(v8_str("foo")));
21371     CHECK(!instance->HasOwnProperty(v8_str("bar")));
21372   }
21373   { // Check indexed query interceptors.
21374     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21375     templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21376         0, 0, HasOwnPropertyIndexedPropertyQuery));
21377     Handle<Object> instance = templ->NewInstance();
21378     CHECK(instance->HasOwnProperty(v8_str("42")));
21379     CHECK(!instance->HasOwnProperty(v8_str("41")));
21380   }
21381   { // Check callbacks.
21382     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21383     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21384     Handle<Object> instance = templ->NewInstance();
21385     CHECK(instance->HasOwnProperty(v8_str("foo")));
21386     CHECK(!instance->HasOwnProperty(v8_str("bar")));
21387   }
21388   { // Check that query wins on disagreement.
21389     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21390     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21391         HasOwnPropertyNamedPropertyGetter, 0,
21392         HasOwnPropertyNamedPropertyQuery2));
21393     Handle<Object> instance = templ->NewInstance();
21394     CHECK(!instance->HasOwnProperty(v8_str("foo")));
21395     CHECK(instance->HasOwnProperty(v8_str("bar")));
21396   }
21397 }
21398
21399
21400 TEST(IndexedInterceptorWithStringProto) {
21401   v8::Isolate* isolate = CcTest::isolate();
21402   v8::HandleScope scope(isolate);
21403   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21404   templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21405       NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
21406   LocalContext context;
21407   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21408   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21409   // These should be intercepted.
21410   CHECK(CompileRun("42 in obj")->BooleanValue());
21411   CHECK(CompileRun("'42' in obj")->BooleanValue());
21412   // These should fall through to the String prototype.
21413   CHECK(CompileRun("0 in obj")->BooleanValue());
21414   CHECK(CompileRun("'0' in obj")->BooleanValue());
21415   // And these should both fail.
21416   CHECK(!CompileRun("32 in obj")->BooleanValue());
21417   CHECK(!CompileRun("'32' in obj")->BooleanValue());
21418 }
21419
21420
21421 void CheckCodeGenerationAllowed() {
21422   Handle<Value> result = CompileRun("eval('42')");
21423   CHECK_EQ(42, result->Int32Value());
21424   result = CompileRun("(function(e) { return e('42'); })(eval)");
21425   CHECK_EQ(42, result->Int32Value());
21426   result = CompileRun("var f = new Function('return 42'); f()");
21427   CHECK_EQ(42, result->Int32Value());
21428 }
21429
21430
21431 void CheckCodeGenerationDisallowed() {
21432   TryCatch try_catch;
21433
21434   Handle<Value> result = CompileRun("eval('42')");
21435   CHECK(result.IsEmpty());
21436   CHECK(try_catch.HasCaught());
21437   try_catch.Reset();
21438
21439   result = CompileRun("(function(e) { return e('42'); })(eval)");
21440   CHECK(result.IsEmpty());
21441   CHECK(try_catch.HasCaught());
21442   try_catch.Reset();
21443
21444   result = CompileRun("var f = new Function('return 42'); f()");
21445   CHECK(result.IsEmpty());
21446   CHECK(try_catch.HasCaught());
21447 }
21448
21449
21450 bool CodeGenerationAllowed(Local<Context> context) {
21451   ApiTestFuzzer::Fuzz();
21452   return true;
21453 }
21454
21455
21456 bool CodeGenerationDisallowed(Local<Context> context) {
21457   ApiTestFuzzer::Fuzz();
21458   return false;
21459 }
21460
21461
21462 THREADED_TEST(AllowCodeGenFromStrings) {
21463   LocalContext context;
21464   v8::HandleScope scope(context->GetIsolate());
21465
21466   // eval and the Function constructor allowed by default.
21467   CHECK(context->IsCodeGenerationFromStringsAllowed());
21468   CheckCodeGenerationAllowed();
21469
21470   // Disallow eval and the Function constructor.
21471   context->AllowCodeGenerationFromStrings(false);
21472   CHECK(!context->IsCodeGenerationFromStringsAllowed());
21473   CheckCodeGenerationDisallowed();
21474
21475   // Allow again.
21476   context->AllowCodeGenerationFromStrings(true);
21477   CheckCodeGenerationAllowed();
21478
21479   // Disallow but setting a global callback that will allow the calls.
21480   context->AllowCodeGenerationFromStrings(false);
21481   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
21482   CHECK(!context->IsCodeGenerationFromStringsAllowed());
21483   CheckCodeGenerationAllowed();
21484
21485   // Set a callback that disallows the code generation.
21486   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21487   CHECK(!context->IsCodeGenerationFromStringsAllowed());
21488   CheckCodeGenerationDisallowed();
21489 }
21490
21491
21492 TEST(SetErrorMessageForCodeGenFromStrings) {
21493   LocalContext context;
21494   v8::HandleScope scope(context->GetIsolate());
21495   TryCatch try_catch;
21496
21497   Handle<String> message = v8_str("Message") ;
21498   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
21499   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21500   context->AllowCodeGenerationFromStrings(false);
21501   context->SetErrorMessageForCodeGenerationFromStrings(message);
21502   Handle<Value> result = CompileRun("eval('42')");
21503   CHECK(result.IsEmpty());
21504   CHECK(try_catch.HasCaught());
21505   Handle<String> actual_message = try_catch.Message()->Get();
21506   CHECK(expected_message->Equals(actual_message));
21507 }
21508
21509
21510 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21511 }
21512
21513
21514 THREADED_TEST(CallAPIFunctionOnNonObject) {
21515   LocalContext context;
21516   v8::Isolate* isolate = context->GetIsolate();
21517   v8::HandleScope scope(isolate);
21518   Handle<FunctionTemplate> templ =
21519       v8::FunctionTemplate::New(isolate, NonObjectThis);
21520   Handle<Function> function = templ->GetFunction();
21521   context->Global()->Set(v8_str("f"), function);
21522   TryCatch try_catch;
21523   CompileRun("f.call(2)");
21524 }
21525
21526
21527 // Regression test for issue 1470.
21528 THREADED_TEST(ReadOnlyIndexedProperties) {
21529   v8::Isolate* isolate = CcTest::isolate();
21530   v8::HandleScope scope(isolate);
21531   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21532
21533   LocalContext context;
21534   Local<v8::Object> obj = templ->NewInstance();
21535   context->Global()->Set(v8_str("obj"), obj);
21536   obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21537   obj->Set(v8_str("1"), v8_str("foobar"));
21538   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
21539   obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
21540   obj->Set(v8_num(2), v8_str("foobar"));
21541   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
21542
21543   // Test non-smi case.
21544   obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21545   obj->Set(v8_str("2000000000"), v8_str("foobar"));
21546   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
21547 }
21548
21549
21550 static int CountLiveMapsInMapCache(i::Context* context) {
21551   i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
21552   int length = map_cache->length();
21553   int count = 0;
21554   for (int i = 0; i < length; i++) {
21555     i::Object* value = map_cache->get(i);
21556     if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
21557   }
21558   return count;
21559 }
21560
21561
21562 THREADED_TEST(Regress1516) {
21563   LocalContext context;
21564   v8::HandleScope scope(context->GetIsolate());
21565
21566   // Object with 20 properties is not a common case, so it should be removed
21567   // from the cache after GC.
21568   { v8::HandleScope temp_scope(context->GetIsolate());
21569     CompileRun(
21570         "({"
21571         "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21572         "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21573         "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21574         "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21575         "})");
21576   }
21577
21578   int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21579   CHECK_LE(1, elements);
21580
21581   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
21582
21583   CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21584 }
21585
21586
21587 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
21588                                                 Local<Value> name,
21589                                                 v8::AccessType type,
21590                                                 Local<Value> data) {
21591   // Only block read access to __proto__.
21592   if (type == v8::ACCESS_GET && name->IsString() &&
21593       name.As<v8::String>()->Length() == 9 &&
21594       name.As<v8::String>()->Utf8Length() == 9) {
21595     char buffer[10];
21596     CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
21597     return strncmp(buffer, "__proto__", 9) != 0;
21598   }
21599
21600   return true;
21601 }
21602
21603
21604 THREADED_TEST(Regress93759) {
21605   v8::Isolate* isolate = CcTest::isolate();
21606   HandleScope scope(isolate);
21607
21608   // Template for object with security check.
21609   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
21610   // We don't do indexing, so any callback can be used for that.
21611   no_proto_template->SetAccessCheckCallbacks(
21612       BlockProtoNamedSecurityTestCallback,
21613       IndexedSecurityTestCallback);
21614
21615   // Templates for objects with hidden prototypes and possibly security check.
21616   Local<FunctionTemplate> hidden_proto_template =
21617       v8::FunctionTemplate::New(isolate);
21618   hidden_proto_template->SetHiddenPrototype(true);
21619
21620   Local<FunctionTemplate> protected_hidden_proto_template =
21621       v8::FunctionTemplate::New(isolate);
21622   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
21623       BlockProtoNamedSecurityTestCallback,
21624       IndexedSecurityTestCallback);
21625   protected_hidden_proto_template->SetHiddenPrototype(true);
21626
21627   // Context for "foreign" objects used in test.
21628   Local<Context> context = v8::Context::New(isolate);
21629   context->Enter();
21630
21631   // Plain object, no security check.
21632   Local<Object> simple_object = Object::New(isolate);
21633
21634   // Object with explicit security check.
21635   Local<Object> protected_object =
21636       no_proto_template->NewInstance();
21637
21638   // JSGlobalProxy object, always have security check.
21639   Local<Object> proxy_object =
21640       context->Global();
21641
21642   // Global object, the  prototype of proxy_object. No security checks.
21643   Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
21644
21645   // Hidden prototype without security check.
21646   Local<Object> hidden_prototype =
21647       hidden_proto_template->GetFunction()->NewInstance();
21648   Local<Object> object_with_hidden =
21649     Object::New(isolate);
21650   object_with_hidden->SetPrototype(hidden_prototype);
21651
21652   // Hidden prototype with security check on the hidden prototype.
21653   Local<Object> protected_hidden_prototype =
21654       protected_hidden_proto_template->GetFunction()->NewInstance();
21655   Local<Object> object_with_protected_hidden =
21656     Object::New(isolate);
21657   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
21658
21659   context->Exit();
21660
21661   // Template for object for second context. Values to test are put on it as
21662   // properties.
21663   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
21664   global_template->Set(v8_str("simple"), simple_object);
21665   global_template->Set(v8_str("protected"), protected_object);
21666   global_template->Set(v8_str("global"), global_object);
21667   global_template->Set(v8_str("proxy"), proxy_object);
21668   global_template->Set(v8_str("hidden"), object_with_hidden);
21669   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
21670
21671   LocalContext context2(NULL, global_template);
21672
21673   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21674   CHECK(result1->Equals(simple_object->GetPrototype()));
21675
21676   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
21677   CHECK(result2.IsEmpty());
21678
21679   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21680   CHECK(result3->Equals(global_object->GetPrototype()));
21681
21682   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
21683   CHECK(result4.IsEmpty());
21684
21685   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21686   CHECK(result5->Equals(
21687       object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
21688
21689   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
21690   CHECK(result6.IsEmpty());
21691 }
21692
21693
21694 THREADED_TEST(Regress125988) {
21695   v8::HandleScope scope(CcTest::isolate());
21696   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
21697   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
21698   LocalContext env;
21699   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
21700   CompileRun("var a = new Object();"
21701              "var b = new Intercept();"
21702              "var c = new Object();"
21703              "c.__proto__ = b;"
21704              "b.__proto__ = a;"
21705              "a.x = 23;"
21706              "for (var i = 0; i < 3; i++) c.x;");
21707   ExpectBoolean("c.hasOwnProperty('x')", false);
21708   ExpectInt32("c.x", 23);
21709   CompileRun("a.y = 42;"
21710              "for (var i = 0; i < 3; i++) c.x;");
21711   ExpectBoolean("c.hasOwnProperty('x')", false);
21712   ExpectInt32("c.x", 23);
21713   ExpectBoolean("c.hasOwnProperty('y')", false);
21714   ExpectInt32("c.y", 42);
21715 }
21716
21717
21718 static void TestReceiver(Local<Value> expected_result,
21719                          Local<Value> expected_receiver,
21720                          const char* code) {
21721   Local<Value> result = CompileRun(code);
21722   CHECK(result->IsObject());
21723   CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
21724   CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
21725 }
21726
21727
21728 THREADED_TEST(ForeignFunctionReceiver) {
21729   v8::Isolate* isolate = CcTest::isolate();
21730   HandleScope scope(isolate);
21731
21732   // Create two contexts with different "id" properties ('i' and 'o').
21733   // Call a function both from its own context and from a the foreign
21734   // context, and see what "this" is bound to (returning both "this"
21735   // and "this.id" for comparison).
21736
21737   Local<Context> foreign_context = v8::Context::New(isolate);
21738   foreign_context->Enter();
21739   Local<Value> foreign_function =
21740     CompileRun("function func() { return { 0: this.id, "
21741                "                           1: this, "
21742                "                           toString: function() { "
21743                "                               return this[0];"
21744                "                           }"
21745                "                         };"
21746                "}"
21747                "var id = 'i';"
21748                "func;");
21749   CHECK(foreign_function->IsFunction());
21750   foreign_context->Exit();
21751
21752   LocalContext context;
21753
21754   Local<String> password = v8_str("Password");
21755   // Don't get hit by security checks when accessing foreign_context's
21756   // global receiver (aka. global proxy).
21757   context->SetSecurityToken(password);
21758   foreign_context->SetSecurityToken(password);
21759
21760   Local<String> i = v8_str("i");
21761   Local<String> o = v8_str("o");
21762   Local<String> id = v8_str("id");
21763
21764   CompileRun("function ownfunc() { return { 0: this.id, "
21765              "                              1: this, "
21766              "                              toString: function() { "
21767              "                                  return this[0];"
21768              "                              }"
21769              "                             };"
21770              "}"
21771              "var id = 'o';"
21772              "ownfunc");
21773   context->Global()->Set(v8_str("func"), foreign_function);
21774
21775   // Sanity check the contexts.
21776   CHECK(i->Equals(foreign_context->Global()->Get(id)));
21777   CHECK(o->Equals(context->Global()->Get(id)));
21778
21779   // Checking local function's receiver.
21780   // Calling function using its call/apply methods.
21781   TestReceiver(o, context->Global(), "ownfunc.call()");
21782   TestReceiver(o, context->Global(), "ownfunc.apply()");
21783   // Making calls through built-in functions.
21784   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21785   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
21786   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
21787   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
21788   // Calling with environment record as base.
21789   TestReceiver(o, context->Global(), "ownfunc()");
21790   // Calling with no base.
21791   TestReceiver(o, context->Global(), "(1,ownfunc)()");
21792
21793   // Checking foreign function return value.
21794   // Calling function using its call/apply methods.
21795   TestReceiver(i, foreign_context->Global(), "func.call()");
21796   TestReceiver(i, foreign_context->Global(), "func.apply()");
21797   // Calling function using another context's call/apply methods.
21798   TestReceiver(i, foreign_context->Global(),
21799                "Function.prototype.call.call(func)");
21800   TestReceiver(i, foreign_context->Global(),
21801                "Function.prototype.call.apply(func)");
21802   TestReceiver(i, foreign_context->Global(),
21803                "Function.prototype.apply.call(func)");
21804   TestReceiver(i, foreign_context->Global(),
21805                "Function.prototype.apply.apply(func)");
21806   // Making calls through built-in functions.
21807   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21808   // ToString(func()) is func()[0], i.e., the returned this.id.
21809   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
21810   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
21811   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
21812
21813   // Calling with environment record as base.
21814   TestReceiver(i, foreign_context->Global(), "func()");
21815   // Calling with no base.
21816   TestReceiver(i, foreign_context->Global(), "(1,func)()");
21817 }
21818
21819
21820 uint8_t callback_fired = 0;
21821
21822
21823 void CallCompletedCallback1() {
21824   v8::base::OS::Print("Firing callback 1.\n");
21825   callback_fired ^= 1;  // Toggle first bit.
21826 }
21827
21828
21829 void CallCompletedCallback2() {
21830   v8::base::OS::Print("Firing callback 2.\n");
21831   callback_fired ^= 2;  // Toggle second bit.
21832 }
21833
21834
21835 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21836   int32_t level = args[0]->Int32Value();
21837   if (level < 3) {
21838     level++;
21839     v8::base::OS::Print("Entering recursion level %d.\n", level);
21840     char script[64];
21841     i::Vector<char> script_vector(script, sizeof(script));
21842     i::SNPrintF(script_vector, "recursion(%d)", level);
21843     CompileRun(script_vector.start());
21844     v8::base::OS::Print("Leaving recursion level %d.\n", level);
21845     CHECK_EQ(0, callback_fired);
21846   } else {
21847     v8::base::OS::Print("Recursion ends.\n");
21848     CHECK_EQ(0, callback_fired);
21849   }
21850 }
21851
21852
21853 TEST(CallCompletedCallback) {
21854   LocalContext env;
21855   v8::HandleScope scope(env->GetIsolate());
21856   v8::Handle<v8::FunctionTemplate> recursive_runtime =
21857       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21858   env->Global()->Set(v8_str("recursion"),
21859                      recursive_runtime->GetFunction());
21860   // Adding the same callback a second time has no effect.
21861   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21862   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21863   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21864   v8::base::OS::Print("--- Script (1) ---\n");
21865   Local<Script> script = v8::Script::Compile(
21866       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
21867   script->Run();
21868   CHECK_EQ(3, callback_fired);
21869
21870   v8::base::OS::Print("\n--- Script (2) ---\n");
21871   callback_fired = 0;
21872   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21873   script->Run();
21874   CHECK_EQ(2, callback_fired);
21875
21876   v8::base::OS::Print("\n--- Function ---\n");
21877   callback_fired = 0;
21878   Local<Function> recursive_function =
21879       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
21880   v8::Handle<Value> args[] = { v8_num(0) };
21881   recursive_function->Call(env->Global(), 1, args);
21882   CHECK_EQ(2, callback_fired);
21883 }
21884
21885
21886 void CallCompletedCallbackNoException() {
21887   v8::HandleScope scope(CcTest::isolate());
21888   CompileRun("1+1;");
21889 }
21890
21891
21892 void CallCompletedCallbackException() {
21893   v8::HandleScope scope(CcTest::isolate());
21894   CompileRun("throw 'second exception';");
21895 }
21896
21897
21898 TEST(CallCompletedCallbackOneException) {
21899   LocalContext env;
21900   v8::HandleScope scope(env->GetIsolate());
21901   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21902   CompileRun("throw 'exception';");
21903 }
21904
21905
21906 TEST(CallCompletedCallbackTwoExceptions) {
21907   LocalContext env;
21908   v8::HandleScope scope(env->GetIsolate());
21909   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21910   CompileRun("throw 'first exception';");
21911 }
21912
21913
21914 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21915   v8::HandleScope scope(info.GetIsolate());
21916   CompileRun("ext1Calls++;");
21917 }
21918
21919
21920 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21921   v8::HandleScope scope(info.GetIsolate());
21922   CompileRun("ext2Calls++;");
21923 }
21924
21925
21926 void* g_passed_to_three = NULL;
21927
21928
21929 static void MicrotaskThree(void* data) {
21930   g_passed_to_three = data;
21931 }
21932
21933
21934 TEST(EnqueueMicrotask) {
21935   LocalContext env;
21936   v8::HandleScope scope(env->GetIsolate());
21937   CompileRun(
21938       "var ext1Calls = 0;"
21939       "var ext2Calls = 0;");
21940   CompileRun("1+1;");
21941   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21942   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21943
21944   env->GetIsolate()->EnqueueMicrotask(
21945       Function::New(env->GetIsolate(), MicrotaskOne));
21946   CompileRun("1+1;");
21947   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21948   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21949
21950   env->GetIsolate()->EnqueueMicrotask(
21951       Function::New(env->GetIsolate(), MicrotaskOne));
21952   env->GetIsolate()->EnqueueMicrotask(
21953       Function::New(env->GetIsolate(), MicrotaskTwo));
21954   CompileRun("1+1;");
21955   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21956   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21957
21958   env->GetIsolate()->EnqueueMicrotask(
21959       Function::New(env->GetIsolate(), MicrotaskTwo));
21960   CompileRun("1+1;");
21961   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21962   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21963
21964   CompileRun("1+1;");
21965   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21966   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21967
21968   g_passed_to_three = NULL;
21969   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21970   CompileRun("1+1;");
21971   CHECK_EQ(NULL, g_passed_to_three);
21972   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21973   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21974
21975   int dummy;
21976   env->GetIsolate()->EnqueueMicrotask(
21977       Function::New(env->GetIsolate(), MicrotaskOne));
21978   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21979   env->GetIsolate()->EnqueueMicrotask(
21980       Function::New(env->GetIsolate(), MicrotaskTwo));
21981   CompileRun("1+1;");
21982   CHECK_EQ(&dummy, g_passed_to_three);
21983   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
21984   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21985   g_passed_to_three = NULL;
21986 }
21987
21988
21989 static void MicrotaskExceptionOne(
21990     const v8::FunctionCallbackInfo<Value>& info) {
21991   v8::HandleScope scope(info.GetIsolate());
21992   CompileRun("exception1Calls++;");
21993   info.GetIsolate()->ThrowException(
21994       v8::Exception::Error(v8_str("first")));
21995 }
21996
21997
21998 static void MicrotaskExceptionTwo(
21999     const v8::FunctionCallbackInfo<Value>& info) {
22000   v8::HandleScope scope(info.GetIsolate());
22001   CompileRun("exception2Calls++;");
22002   info.GetIsolate()->ThrowException(
22003       v8::Exception::Error(v8_str("second")));
22004 }
22005
22006
22007 TEST(RunMicrotasksIgnoresThrownExceptions) {
22008   LocalContext env;
22009   v8::Isolate* isolate = env->GetIsolate();
22010   v8::HandleScope scope(isolate);
22011   CompileRun(
22012       "var exception1Calls = 0;"
22013       "var exception2Calls = 0;");
22014   isolate->EnqueueMicrotask(
22015       Function::New(isolate, MicrotaskExceptionOne));
22016   isolate->EnqueueMicrotask(
22017       Function::New(isolate, MicrotaskExceptionTwo));
22018   TryCatch try_catch;
22019   CompileRun("1+1;");
22020   CHECK(!try_catch.HasCaught());
22021   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
22022   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
22023 }
22024
22025
22026 TEST(SetAutorunMicrotasks) {
22027   LocalContext env;
22028   v8::HandleScope scope(env->GetIsolate());
22029   CompileRun(
22030       "var ext1Calls = 0;"
22031       "var ext2Calls = 0;");
22032   CompileRun("1+1;");
22033   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
22034   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22035
22036   env->GetIsolate()->EnqueueMicrotask(
22037       Function::New(env->GetIsolate(), MicrotaskOne));
22038   CompileRun("1+1;");
22039   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22040   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22041
22042   env->GetIsolate()->SetAutorunMicrotasks(false);
22043   env->GetIsolate()->EnqueueMicrotask(
22044       Function::New(env->GetIsolate(), MicrotaskOne));
22045   env->GetIsolate()->EnqueueMicrotask(
22046       Function::New(env->GetIsolate(), MicrotaskTwo));
22047   CompileRun("1+1;");
22048   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22049   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22050
22051   env->GetIsolate()->RunMicrotasks();
22052   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22053   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
22054
22055   env->GetIsolate()->EnqueueMicrotask(
22056       Function::New(env->GetIsolate(), MicrotaskTwo));
22057   CompileRun("1+1;");
22058   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22059   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
22060
22061   env->GetIsolate()->RunMicrotasks();
22062   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22063   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
22064
22065   env->GetIsolate()->SetAutorunMicrotasks(true);
22066   env->GetIsolate()->EnqueueMicrotask(
22067       Function::New(env->GetIsolate(), MicrotaskTwo));
22068   CompileRun("1+1;");
22069   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22070   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
22071
22072   env->GetIsolate()->EnqueueMicrotask(
22073       Function::New(env->GetIsolate(), MicrotaskTwo));
22074   {
22075     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
22076     CompileRun("1+1;");
22077     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22078     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
22079   }
22080
22081   CompileRun("1+1;");
22082   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22083   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
22084 }
22085
22086
22087 TEST(RunMicrotasksWithoutEnteringContext) {
22088   v8::Isolate* isolate = CcTest::isolate();
22089   HandleScope handle_scope(isolate);
22090   isolate->SetAutorunMicrotasks(false);
22091   Handle<Context> context = Context::New(isolate);
22092   {
22093     Context::Scope context_scope(context);
22094     CompileRun("var ext1Calls = 0;");
22095     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
22096   }
22097   isolate->RunMicrotasks();
22098   {
22099     Context::Scope context_scope(context);
22100     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22101   }
22102   isolate->SetAutorunMicrotasks(true);
22103 }
22104
22105
22106 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
22107   v8::DebugEvent event = event_details.GetEvent();
22108   if (event != v8::Break) return;
22109   Handle<Object> exec_state = event_details.GetExecutionState();
22110   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
22111   CompileRun("function f(id) { new FrameDetails(id, 0); }");
22112   Handle<Function> fun =
22113       Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
22114   fun->Call(CcTest::global(), 1, &break_id);
22115 }
22116
22117
22118 TEST(Regress385349) {
22119   i::FLAG_allow_natives_syntax = true;
22120   v8::Isolate* isolate = CcTest::isolate();
22121   HandleScope handle_scope(isolate);
22122   isolate->SetAutorunMicrotasks(false);
22123   Handle<Context> context = Context::New(isolate);
22124   v8::Debug::SetDebugEventListener(DebugEventInObserver);
22125   {
22126     Context::Scope context_scope(context);
22127     CompileRun("var obj = {};"
22128                "Object.observe(obj, function(changes) { debugger; });"
22129                "obj.a = 0;");
22130   }
22131   isolate->RunMicrotasks();
22132   isolate->SetAutorunMicrotasks(true);
22133   v8::Debug::SetDebugEventListener(NULL);
22134 }
22135
22136
22137 #ifdef ENABLE_DISASSEMBLER
22138 static int probes_counter = 0;
22139 static int misses_counter = 0;
22140 static int updates_counter = 0;
22141
22142
22143 static int* LookupCounter(const char* name) {
22144   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
22145     return &probes_counter;
22146   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
22147     return &misses_counter;
22148   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
22149     return &updates_counter;
22150   }
22151   return NULL;
22152 }
22153
22154
22155 static const char* kMegamorphicTestProgram =
22156     "function ClassA() { };"
22157     "function ClassB() { };"
22158     "ClassA.prototype.foo = function() { };"
22159     "ClassB.prototype.foo = function() { };"
22160     "function fooify(obj) { obj.foo(); };"
22161     "var a = new ClassA();"
22162     "var b = new ClassB();"
22163     "for (var i = 0; i < 10000; i++) {"
22164     "  fooify(a);"
22165     "  fooify(b);"
22166     "}";
22167 #endif
22168
22169
22170 static void StubCacheHelper(bool primary) {
22171 #ifdef ENABLE_DISASSEMBLER
22172   i::FLAG_native_code_counters = true;
22173   if (primary) {
22174     i::FLAG_test_primary_stub_cache = true;
22175   } else {
22176     i::FLAG_test_secondary_stub_cache = true;
22177   }
22178   i::FLAG_crankshaft = false;
22179   LocalContext env;
22180   env->GetIsolate()->SetCounterFunction(LookupCounter);
22181   v8::HandleScope scope(env->GetIsolate());
22182   int initial_probes = probes_counter;
22183   int initial_misses = misses_counter;
22184   int initial_updates = updates_counter;
22185   CompileRun(kMegamorphicTestProgram);
22186   int probes = probes_counter - initial_probes;
22187   int misses = misses_counter - initial_misses;
22188   int updates = updates_counter - initial_updates;
22189   CHECK_LT(updates, 10);
22190   CHECK_LT(misses, 10);
22191   // TODO(verwaest): Update this test to overflow the degree of polymorphism
22192   // before megamorphism. The number of probes will only work once we teach the
22193   // serializer to embed references to counters in the stubs, given that the
22194   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
22195   CHECK_GE(probes, 0);
22196 #endif
22197 }
22198
22199
22200 TEST(SecondaryStubCache) {
22201   StubCacheHelper(true);
22202 }
22203
22204
22205 TEST(PrimaryStubCache) {
22206   StubCacheHelper(false);
22207 }
22208
22209
22210 #ifdef DEBUG
22211 static int cow_arrays_created_runtime = 0;
22212
22213
22214 static int* LookupCounterCOWArrays(const char* name) {
22215   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
22216     return &cow_arrays_created_runtime;
22217   }
22218   return NULL;
22219 }
22220 #endif
22221
22222
22223 TEST(CheckCOWArraysCreatedRuntimeCounter) {
22224 #ifdef DEBUG
22225   i::FLAG_native_code_counters = true;
22226   LocalContext env;
22227   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
22228   v8::HandleScope scope(env->GetIsolate());
22229   int initial_cow_arrays = cow_arrays_created_runtime;
22230   CompileRun("var o = [1, 2, 3];");
22231   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
22232   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
22233   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
22234   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
22235   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
22236 #endif
22237 }
22238
22239
22240 TEST(StaticGetters) {
22241   LocalContext context;
22242   i::Factory* factory = CcTest::i_isolate()->factory();
22243   v8::Isolate* isolate = CcTest::isolate();
22244   v8::HandleScope scope(isolate);
22245   i::Handle<i::Object> undefined_value = factory->undefined_value();
22246   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
22247   i::Handle<i::Object> null_value = factory->null_value();
22248   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
22249   i::Handle<i::Object> true_value = factory->true_value();
22250   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
22251   i::Handle<i::Object> false_value = factory->false_value();
22252   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
22253 }
22254
22255
22256 UNINITIALIZED_TEST(IsolateEmbedderData) {
22257   CcTest::DisableAutomaticDispose();
22258   v8::Isolate* isolate = v8::Isolate::New();
22259   isolate->Enter();
22260   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22261   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22262     CHECK_EQ(NULL, isolate->GetData(slot));
22263     CHECK_EQ(NULL, i_isolate->GetData(slot));
22264   }
22265   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22266     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22267     isolate->SetData(slot, data);
22268   }
22269   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22270     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22271     CHECK_EQ(data, isolate->GetData(slot));
22272     CHECK_EQ(data, i_isolate->GetData(slot));
22273   }
22274   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22275     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22276     isolate->SetData(slot, data);
22277   }
22278   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22279     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22280     CHECK_EQ(data, isolate->GetData(slot));
22281     CHECK_EQ(data, i_isolate->GetData(slot));
22282   }
22283   isolate->Exit();
22284   isolate->Dispose();
22285 }
22286
22287
22288 TEST(StringEmpty) {
22289   LocalContext context;
22290   i::Factory* factory = CcTest::i_isolate()->factory();
22291   v8::Isolate* isolate = CcTest::isolate();
22292   v8::HandleScope scope(isolate);
22293   i::Handle<i::Object> empty_string = factory->empty_string();
22294   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
22295 }
22296
22297
22298 static int instance_checked_getter_count = 0;
22299 static void InstanceCheckedGetter(
22300     Local<String> name,
22301     const v8::PropertyCallbackInfo<v8::Value>& info) {
22302   CHECK_EQ(name, v8_str("foo"));
22303   instance_checked_getter_count++;
22304   info.GetReturnValue().Set(v8_num(11));
22305 }
22306
22307
22308 static int instance_checked_setter_count = 0;
22309 static void InstanceCheckedSetter(Local<String> name,
22310                       Local<Value> value,
22311                       const v8::PropertyCallbackInfo<void>& info) {
22312   CHECK_EQ(name, v8_str("foo"));
22313   CHECK_EQ(value, v8_num(23));
22314   instance_checked_setter_count++;
22315 }
22316
22317
22318 static void CheckInstanceCheckedResult(int getters, int setters,
22319                                        bool expects_callbacks,
22320                                        TryCatch* try_catch) {
22321   if (expects_callbacks) {
22322     CHECK(!try_catch->HasCaught());
22323     CHECK_EQ(getters, instance_checked_getter_count);
22324     CHECK_EQ(setters, instance_checked_setter_count);
22325   } else {
22326     CHECK(try_catch->HasCaught());
22327     CHECK_EQ(0, instance_checked_getter_count);
22328     CHECK_EQ(0, instance_checked_setter_count);
22329   }
22330   try_catch->Reset();
22331 }
22332
22333
22334 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
22335   instance_checked_getter_count = 0;
22336   instance_checked_setter_count = 0;
22337   TryCatch try_catch;
22338
22339   // Test path through generic runtime code.
22340   CompileRun("obj.foo");
22341   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
22342   CompileRun("obj.foo = 23");
22343   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
22344
22345   // Test path through generated LoadIC and StoredIC.
22346   CompileRun("function test_get(o) { o.foo; }"
22347              "test_get(obj);");
22348   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
22349   CompileRun("test_get(obj);");
22350   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
22351   CompileRun("test_get(obj);");
22352   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
22353   CompileRun("function test_set(o) { o.foo = 23; }"
22354              "test_set(obj);");
22355   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
22356   CompileRun("test_set(obj);");
22357   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
22358   CompileRun("test_set(obj);");
22359   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22360
22361   // Test path through optimized code.
22362   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22363              "test_get(obj);");
22364   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22365   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22366              "test_set(obj);");
22367   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22368
22369   // Cleanup so that closures start out fresh in next check.
22370   CompileRun("%DeoptimizeFunction(test_get);"
22371              "%ClearFunctionTypeFeedback(test_get);"
22372              "%DeoptimizeFunction(test_set);"
22373              "%ClearFunctionTypeFeedback(test_set);");
22374 }
22375
22376
22377 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22378   v8::internal::FLAG_allow_natives_syntax = true;
22379   LocalContext context;
22380   v8::HandleScope scope(context->GetIsolate());
22381
22382   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22383   Local<ObjectTemplate> inst = templ->InstanceTemplate();
22384   inst->SetAccessor(v8_str("foo"),
22385                     InstanceCheckedGetter, InstanceCheckedSetter,
22386                     Handle<Value>(),
22387                     v8::DEFAULT,
22388                     v8::None,
22389                     v8::AccessorSignature::New(context->GetIsolate(), templ));
22390   context->Global()->Set(v8_str("f"), templ->GetFunction());
22391
22392   printf("Testing positive ...\n");
22393   CompileRun("var obj = new f();");
22394   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22395   CheckInstanceCheckedAccessors(true);
22396
22397   printf("Testing negative ...\n");
22398   CompileRun("var obj = {};"
22399              "obj.__proto__ = new f();");
22400   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22401   CheckInstanceCheckedAccessors(false);
22402 }
22403
22404
22405 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22406   v8::internal::FLAG_allow_natives_syntax = true;
22407   LocalContext context;
22408   v8::HandleScope scope(context->GetIsolate());
22409
22410   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22411   Local<ObjectTemplate> inst = templ->InstanceTemplate();
22412   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22413   inst->SetAccessor(v8_str("foo"),
22414                     InstanceCheckedGetter, InstanceCheckedSetter,
22415                     Handle<Value>(),
22416                     v8::DEFAULT,
22417                     v8::None,
22418                     v8::AccessorSignature::New(context->GetIsolate(), templ));
22419   context->Global()->Set(v8_str("f"), templ->GetFunction());
22420
22421   printf("Testing positive ...\n");
22422   CompileRun("var obj = new f();");
22423   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22424   CheckInstanceCheckedAccessors(true);
22425
22426   printf("Testing negative ...\n");
22427   CompileRun("var obj = {};"
22428              "obj.__proto__ = new f();");
22429   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22430   CheckInstanceCheckedAccessors(false);
22431 }
22432
22433
22434 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22435   v8::internal::FLAG_allow_natives_syntax = true;
22436   LocalContext context;
22437   v8::HandleScope scope(context->GetIsolate());
22438
22439   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22440   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22441   proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22442                      InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
22443                      v8::None,
22444                      v8::AccessorSignature::New(context->GetIsolate(), templ));
22445   context->Global()->Set(v8_str("f"), templ->GetFunction());
22446
22447   printf("Testing positive ...\n");
22448   CompileRun("var obj = new f();");
22449   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22450   CheckInstanceCheckedAccessors(true);
22451
22452   printf("Testing negative ...\n");
22453   CompileRun("var obj = {};"
22454              "obj.__proto__ = new f();");
22455   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22456   CheckInstanceCheckedAccessors(false);
22457
22458   printf("Testing positive with modified prototype chain ...\n");
22459   CompileRun("var obj = new f();"
22460              "var pro = {};"
22461              "pro.__proto__ = obj.__proto__;"
22462              "obj.__proto__ = pro;");
22463   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22464   CheckInstanceCheckedAccessors(true);
22465 }
22466
22467
22468 TEST(TryFinallyMessage) {
22469   LocalContext context;
22470   v8::HandleScope scope(context->GetIsolate());
22471   {
22472     // Test that the original error message is not lost if there is a
22473     // recursive call into Javascript is done in the finally block, e.g. to
22474     // initialize an IC. (crbug.com/129171)
22475     TryCatch try_catch;
22476     const char* trigger_ic =
22477         "try {                      \n"
22478         "  throw new Error('test'); \n"
22479         "} finally {                \n"
22480         "  var x = 0;               \n"
22481         "  x++;                     \n"  // Trigger an IC initialization here.
22482         "}                          \n";
22483     CompileRun(trigger_ic);
22484     CHECK(try_catch.HasCaught());
22485     Local<Message> message = try_catch.Message();
22486     CHECK(!message.IsEmpty());
22487     CHECK_EQ(2, message->GetLineNumber());
22488   }
22489
22490   {
22491     // Test that the original exception message is indeed overwritten if
22492     // a new error is thrown in the finally block.
22493     TryCatch try_catch;
22494     const char* throw_again =
22495         "try {                       \n"
22496         "  throw new Error('test');  \n"
22497         "} finally {                 \n"
22498         "  var x = 0;                \n"
22499         "  x++;                      \n"
22500         "  throw new Error('again'); \n"  // This is the new uncaught error.
22501         "}                           \n";
22502     CompileRun(throw_again);
22503     CHECK(try_catch.HasCaught());
22504     Local<Message> message = try_catch.Message();
22505     CHECK(!message.IsEmpty());
22506     CHECK_EQ(6, message->GetLineNumber());
22507   }
22508 }
22509
22510
22511 static void Helper137002(bool do_store,
22512                          bool polymorphic,
22513                          bool remove_accessor,
22514                          bool interceptor) {
22515   LocalContext context;
22516   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22517   if (interceptor) {
22518     templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22519                                                             FooSetInterceptor));
22520   } else {
22521     templ->SetAccessor(v8_str("foo"),
22522                        GetterWhichReturns42,
22523                        SetterWhichSetsYOnThisTo23);
22524   }
22525   context->Global()->Set(v8_str("obj"), templ->NewInstance());
22526
22527   // Turn monomorphic on slow object with native accessor, then turn
22528   // polymorphic, finally optimize to create negative lookup and fail.
22529   CompileRun(do_store ?
22530              "function f(x) { x.foo = void 0; }" :
22531              "function f(x) { return x.foo; }");
22532   CompileRun("obj.y = void 0;");
22533   if (!interceptor) {
22534     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22535   }
22536   CompileRun("obj.__proto__ = null;"
22537              "f(obj); f(obj); f(obj);");
22538   if (polymorphic) {
22539     CompileRun("f({});");
22540   }
22541   CompileRun("obj.y = void 0;"
22542              "%OptimizeFunctionOnNextCall(f);");
22543   if (remove_accessor) {
22544     CompileRun("delete obj.foo;");
22545   }
22546   CompileRun("var result = f(obj);");
22547   if (do_store) {
22548     CompileRun("result = obj.y;");
22549   }
22550   if (remove_accessor && !interceptor) {
22551     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
22552   } else {
22553     CHECK_EQ(do_store ? 23 : 42,
22554              context->Global()->Get(v8_str("result"))->Int32Value());
22555   }
22556 }
22557
22558
22559 THREADED_TEST(Regress137002a) {
22560   i::FLAG_allow_natives_syntax = true;
22561   i::FLAG_compilation_cache = false;
22562   v8::HandleScope scope(CcTest::isolate());
22563   for (int i = 0; i < 16; i++) {
22564     Helper137002(i & 8, i & 4, i & 2, i & 1);
22565   }
22566 }
22567
22568
22569 THREADED_TEST(Regress137002b) {
22570   i::FLAG_allow_natives_syntax = true;
22571   LocalContext context;
22572   v8::Isolate* isolate = context->GetIsolate();
22573   v8::HandleScope scope(isolate);
22574   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22575   templ->SetAccessor(v8_str("foo"),
22576                      GetterWhichReturns42,
22577                      SetterWhichSetsYOnThisTo23);
22578   context->Global()->Set(v8_str("obj"), templ->NewInstance());
22579
22580   // Turn monomorphic on slow object with native accessor, then just
22581   // delete the property and fail.
22582   CompileRun("function load(x) { return x.foo; }"
22583              "function store(x) { x.foo = void 0; }"
22584              "function keyed_load(x, key) { return x[key]; }"
22585              // Second version of function has a different source (add void 0)
22586              // so that it does not share code with the first version.  This
22587              // ensures that the ICs are monomorphic.
22588              "function load2(x) { void 0; return x.foo; }"
22589              "function store2(x) { void 0; x.foo = void 0; }"
22590              "function keyed_load2(x, key) { void 0; return x[key]; }"
22591
22592              "obj.y = void 0;"
22593              "obj.__proto__ = null;"
22594              "var subobj = {};"
22595              "subobj.y = void 0;"
22596              "subobj.__proto__ = obj;"
22597              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22598
22599              // Make the ICs monomorphic.
22600              "load(obj); load(obj);"
22601              "load2(subobj); load2(subobj);"
22602              "store(obj); store(obj);"
22603              "store2(subobj); store2(subobj);"
22604              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22605              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22606
22607              // Actually test the shiny new ICs and better not crash. This
22608              // serves as a regression test for issue 142088 as well.
22609              "load(obj);"
22610              "load2(subobj);"
22611              "store(obj);"
22612              "store2(subobj);"
22613              "keyed_load(obj, 'foo');"
22614              "keyed_load2(subobj, 'foo');"
22615
22616              // Delete the accessor.  It better not be called any more now.
22617              "delete obj.foo;"
22618              "obj.y = void 0;"
22619              "subobj.y = void 0;"
22620
22621              "var load_result = load(obj);"
22622              "var load_result2 = load2(subobj);"
22623              "var keyed_load_result = keyed_load(obj, 'foo');"
22624              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22625              "store(obj);"
22626              "store2(subobj);"
22627              "var y_from_obj = obj.y;"
22628              "var y_from_subobj = subobj.y;");
22629   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
22630   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
22631   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
22632   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
22633   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
22634   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
22635 }
22636
22637
22638 THREADED_TEST(Regress142088) {
22639   i::FLAG_allow_natives_syntax = true;
22640   LocalContext context;
22641   v8::Isolate* isolate = context->GetIsolate();
22642   v8::HandleScope scope(isolate);
22643   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22644   templ->SetAccessor(v8_str("foo"),
22645                      GetterWhichReturns42,
22646                      SetterWhichSetsYOnThisTo23);
22647   context->Global()->Set(v8_str("obj"), templ->NewInstance());
22648
22649   CompileRun("function load(x) { return x.foo; }"
22650              "var o = Object.create(obj);"
22651              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22652              "load(o); load(o); load(o); load(o);");
22653 }
22654
22655
22656 THREADED_TEST(Regress3337) {
22657   LocalContext context;
22658   v8::Isolate* isolate = context->GetIsolate();
22659   v8::HandleScope scope(isolate);
22660   Local<v8::Object> o1 = Object::New(isolate);
22661   Local<v8::Object> o2 = Object::New(isolate);
22662   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
22663   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
22664   CHECK(io1->map() == io2->map());
22665   o1->SetIndexedPropertiesToExternalArrayData(
22666       NULL, v8::kExternalUint32Array, 0);
22667   o2->SetIndexedPropertiesToExternalArrayData(
22668       NULL, v8::kExternalUint32Array, 0);
22669   CHECK(io1->map() == io2->map());
22670 }
22671
22672
22673 THREADED_TEST(Regress137496) {
22674   i::FLAG_expose_gc = true;
22675   LocalContext context;
22676   v8::HandleScope scope(context->GetIsolate());
22677
22678   // Compile a try-finally clause where the finally block causes a GC
22679   // while there still is a message pending for external reporting.
22680   TryCatch try_catch;
22681   try_catch.SetVerbose(true);
22682   CompileRun("try { throw new Error(); } finally { gc(); }");
22683   CHECK(try_catch.HasCaught());
22684 }
22685
22686
22687 THREADED_TEST(Regress149912) {
22688   LocalContext context;
22689   v8::HandleScope scope(context->GetIsolate());
22690   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22691   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22692   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22693   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
22694 }
22695
22696
22697 THREADED_TEST(Regress157124) {
22698   LocalContext context;
22699   v8::Isolate* isolate = context->GetIsolate();
22700   v8::HandleScope scope(isolate);
22701   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22702   Local<Object> obj = templ->NewInstance();
22703   obj->GetIdentityHash();
22704   obj->DeleteHiddenValue(v8_str("Bug"));
22705 }
22706
22707
22708 THREADED_TEST(Regress2535) {
22709   LocalContext context;
22710   v8::HandleScope scope(context->GetIsolate());
22711   Local<Value> set_value = CompileRun("new Set();");
22712   Local<Object> set_object(Local<Object>::Cast(set_value));
22713   CHECK_EQ(0, set_object->InternalFieldCount());
22714   Local<Value> map_value = CompileRun("new Map();");
22715   Local<Object> map_object(Local<Object>::Cast(map_value));
22716   CHECK_EQ(0, map_object->InternalFieldCount());
22717 }
22718
22719
22720 THREADED_TEST(Regress2746) {
22721   LocalContext context;
22722   v8::Isolate* isolate = context->GetIsolate();
22723   v8::HandleScope scope(isolate);
22724   Local<Object> obj = Object::New(isolate);
22725   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
22726   obj->SetHiddenValue(key, v8::Undefined(isolate));
22727   Local<Value> value = obj->GetHiddenValue(key);
22728   CHECK(!value.IsEmpty());
22729   CHECK(value->IsUndefined());
22730 }
22731
22732
22733 THREADED_TEST(Regress260106) {
22734   LocalContext context;
22735   v8::Isolate* isolate = context->GetIsolate();
22736   v8::HandleScope scope(isolate);
22737   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22738                                                         DummyCallHandler);
22739   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22740   Local<Function> function = templ->GetFunction();
22741   CHECK(!function.IsEmpty());
22742   CHECK(function->IsFunction());
22743 }
22744
22745
22746 THREADED_TEST(JSONParseObject) {
22747   LocalContext context;
22748   HandleScope scope(context->GetIsolate());
22749   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
22750   Handle<Object> global = context->Global();
22751   global->Set(v8_str("obj"), obj);
22752   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22753 }
22754
22755
22756 THREADED_TEST(JSONParseNumber) {
22757   LocalContext context;
22758   HandleScope scope(context->GetIsolate());
22759   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
22760   Handle<Object> global = context->Global();
22761   global->Set(v8_str("obj"), obj);
22762   ExpectString("JSON.stringify(obj)", "42");
22763 }
22764
22765
22766 #if V8_OS_POSIX && !V8_OS_NACL
22767 class ThreadInterruptTest {
22768  public:
22769   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22770   ~ThreadInterruptTest() {}
22771
22772   void RunTest() {
22773     InterruptThread i_thread(this);
22774     i_thread.Start();
22775
22776     sem_.Wait();
22777     CHECK_EQ(kExpectedValue, sem_value_);
22778   }
22779
22780  private:
22781   static const int kExpectedValue = 1;
22782
22783   class InterruptThread : public v8::base::Thread {
22784    public:
22785     explicit InterruptThread(ThreadInterruptTest* test)
22786         : Thread(Options("InterruptThread")), test_(test) {}
22787
22788     virtual void Run() {
22789       struct sigaction action;
22790
22791       // Ensure that we'll enter waiting condition
22792       v8::base::OS::Sleep(100);
22793
22794       // Setup signal handler
22795       memset(&action, 0, sizeof(action));
22796       action.sa_handler = SignalHandler;
22797       sigaction(SIGCHLD, &action, NULL);
22798
22799       // Send signal
22800       kill(getpid(), SIGCHLD);
22801
22802       // Ensure that if wait has returned because of error
22803       v8::base::OS::Sleep(100);
22804
22805       // Set value and signal semaphore
22806       test_->sem_value_ = 1;
22807       test_->sem_.Signal();
22808     }
22809
22810     static void SignalHandler(int signal) {
22811     }
22812
22813    private:
22814      ThreadInterruptTest* test_;
22815   };
22816
22817   v8::base::Semaphore sem_;
22818   volatile int sem_value_;
22819 };
22820
22821
22822 THREADED_TEST(SemaphoreInterruption) {
22823   ThreadInterruptTest().RunTest();
22824 }
22825
22826
22827 #endif  // V8_OS_POSIX
22828
22829
22830 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
22831                                      Local<Value> name,
22832                                      v8::AccessType type,
22833                                      Local<Value> data) {
22834   i::PrintF("Named access blocked.\n");
22835   return false;
22836 }
22837
22838
22839 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
22840                                      uint32_t key,
22841                                      v8::AccessType type,
22842                                      Local<Value> data) {
22843   i::PrintF("Indexed access blocked.\n");
22844   return false;
22845 }
22846
22847
22848 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22849   CHECK(false);
22850 }
22851
22852
22853 TEST(JSONStringifyAccessCheck) {
22854   v8::V8::Initialize();
22855   v8::Isolate* isolate = CcTest::isolate();
22856   v8::HandleScope scope(isolate);
22857
22858   // Create an ObjectTemplate for global objects and install access
22859   // check callbacks that will block access.
22860   v8::Handle<v8::ObjectTemplate> global_template =
22861       v8::ObjectTemplate::New(isolate);
22862   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22863                                            IndexAccessAlwaysBlocked);
22864
22865   // Create a context and set an x property on it's global object.
22866   LocalContext context0(NULL, global_template);
22867   v8::Handle<v8::Object> global0 = context0->Global();
22868   global0->Set(v8_str("x"), v8_num(42));
22869   ExpectString("JSON.stringify(this)", "{\"x\":42}");
22870
22871   for (int i = 0; i < 2; i++) {
22872     if (i == 1) {
22873       // Install a toJSON function on the second run.
22874       v8::Handle<v8::FunctionTemplate> toJSON =
22875           v8::FunctionTemplate::New(isolate, UnreachableCallback);
22876
22877       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
22878     }
22879     // Create a context with a different security token so that the
22880     // failed access check callback will be called on each access.
22881     LocalContext context1(NULL, global_template);
22882     context1->Global()->Set(v8_str("other"), global0);
22883
22884     CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22885     CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22886     CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22887
22888     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
22889     array->Set(0, v8_str("a"));
22890     array->Set(1, v8_str("b"));
22891     context1->Global()->Set(v8_str("array"), array);
22892     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
22893     array->TurnOnAccessCheck();
22894     CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
22895     CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
22896     CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
22897   }
22898 }
22899
22900
22901 bool access_check_fail_thrown = false;
22902 bool catch_callback_called = false;
22903
22904
22905 // Failed access check callback that performs a GC on each invocation.
22906 void FailedAccessCheckThrows(Local<v8::Object> target,
22907                              v8::AccessType type,
22908                              Local<v8::Value> data) {
22909   access_check_fail_thrown = true;
22910   i::PrintF("Access check failed. Error thrown.\n");
22911   CcTest::isolate()->ThrowException(
22912       v8::Exception::Error(v8_str("cross context")));
22913 }
22914
22915
22916 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22917   for (int i = 0; i < args.Length(); i++) {
22918     i::PrintF("%s\n", *String::Utf8Value(args[i]));
22919   }
22920   catch_callback_called = true;
22921 }
22922
22923
22924 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22925   args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
22926       args[1]->ToString(args.GetIsolate()));
22927 }
22928
22929
22930 void CheckCorrectThrow(const char* script) {
22931   // Test that the script, when wrapped into a try-catch, triggers the catch
22932   // clause due to failed access check throwing an exception.
22933   // The subsequent try-catch should run without any exception.
22934   access_check_fail_thrown = false;
22935   catch_callback_called = false;
22936   i::ScopedVector<char> source(1024);
22937   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22938   CompileRun(source.start());
22939   CHECK(access_check_fail_thrown);
22940   CHECK(catch_callback_called);
22941
22942   access_check_fail_thrown = false;
22943   catch_callback_called = false;
22944   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22945   CHECK(!access_check_fail_thrown);
22946   CHECK(!catch_callback_called);
22947 }
22948
22949
22950 TEST(AccessCheckThrows) {
22951   i::FLAG_allow_natives_syntax = true;
22952   v8::V8::Initialize();
22953   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22954   v8::Isolate* isolate = CcTest::isolate();
22955   v8::HandleScope scope(isolate);
22956
22957   // Create an ObjectTemplate for global objects and install access
22958   // check callbacks that will block access.
22959   v8::Handle<v8::ObjectTemplate> global_template =
22960       v8::ObjectTemplate::New(isolate);
22961   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22962                                            IndexAccessAlwaysBlocked);
22963
22964   // Create a context and set an x property on it's global object.
22965   LocalContext context0(NULL, global_template);
22966   v8::Handle<v8::Object> global0 = context0->Global();
22967
22968   // Create a context with a different security token so that the
22969   // failed access check callback will be called on each access.
22970   LocalContext context1(NULL, global_template);
22971   context1->Global()->Set(v8_str("other"), global0);
22972
22973   v8::Handle<v8::FunctionTemplate> catcher_fun =
22974       v8::FunctionTemplate::New(isolate, CatcherCallback);
22975   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
22976
22977   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
22978       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22979   context1->Global()->Set(v8_str("has_own_property"),
22980                           has_own_property_fun->GetFunction());
22981
22982   { v8::TryCatch try_catch;
22983     access_check_fail_thrown = false;
22984     CompileRun("other.x;");
22985     CHECK(access_check_fail_thrown);
22986     CHECK(try_catch.HasCaught());
22987   }
22988
22989   CheckCorrectThrow("other.x");
22990   CheckCorrectThrow("other[1]");
22991   CheckCorrectThrow("JSON.stringify(other)");
22992   CheckCorrectThrow("has_own_property(other, 'x')");
22993   CheckCorrectThrow("%GetProperty(other, 'x')");
22994   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
22995   CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
22996   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
22997   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22998   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
22999   CheckCorrectThrow("%HasProperty(other, 'x')");
23000   CheckCorrectThrow("%HasElement(other, 1)");
23001   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
23002   CheckCorrectThrow("%GetPropertyNames(other)");
23003   // PROPERTY_ATTRIBUTES_NONE = 0
23004   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
23005   CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
23006                         "other, 'x', null, null, 1)");
23007
23008   // Reset the failed access check callback so it does not influence
23009   // the other tests.
23010   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
23011 }
23012
23013
23014 THREADED_TEST(Regress256330) {
23015   i::FLAG_allow_natives_syntax = true;
23016   LocalContext context;
23017   v8::HandleScope scope(context->GetIsolate());
23018   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
23019   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
23020   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
23021   CompileRun("\"use strict\"; var o = new Bug;"
23022              "function f(o) { o.x = 10; };"
23023              "f(o); f(o); f(o);"
23024              "%OptimizeFunctionOnNextCall(f);"
23025              "f(o);");
23026   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
23027 }
23028
23029
23030 THREADED_TEST(CrankshaftInterceptorSetter) {
23031   i::FLAG_allow_natives_syntax = true;
23032   v8::HandleScope scope(CcTest::isolate());
23033   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23034   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23035   LocalContext env;
23036   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23037   CompileRun("var obj = new Obj;"
23038              // Initialize fields to avoid transitions later.
23039              "obj.age = 0;"
23040              "obj.accessor_age = 42;"
23041              "function setter(i) { this.accessor_age = i; };"
23042              "function getter() { return this.accessor_age; };"
23043              "function setAge(i) { obj.age = i; };"
23044              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
23045              "setAge(1);"
23046              "setAge(2);"
23047              "setAge(3);"
23048              "%OptimizeFunctionOnNextCall(setAge);"
23049              "setAge(4);");
23050   // All stores went through the interceptor.
23051   ExpectInt32("obj.interceptor_age", 4);
23052   ExpectInt32("obj.accessor_age", 42);
23053 }
23054
23055
23056 THREADED_TEST(CrankshaftInterceptorGetter) {
23057   i::FLAG_allow_natives_syntax = true;
23058   v8::HandleScope scope(CcTest::isolate());
23059   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23060   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23061   LocalContext env;
23062   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23063   CompileRun("var obj = new Obj;"
23064              // Initialize fields to avoid transitions later.
23065              "obj.age = 1;"
23066              "obj.accessor_age = 42;"
23067              "function getter() { return this.accessor_age; };"
23068              "function getAge() { return obj.interceptor_age; };"
23069              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
23070              "getAge();"
23071              "getAge();"
23072              "getAge();"
23073              "%OptimizeFunctionOnNextCall(getAge);");
23074   // Access through interceptor.
23075   ExpectInt32("getAge()", 1);
23076 }
23077
23078
23079 THREADED_TEST(CrankshaftInterceptorFieldRead) {
23080   i::FLAG_allow_natives_syntax = true;
23081   v8::HandleScope scope(CcTest::isolate());
23082   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23083   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23084   LocalContext env;
23085   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23086   CompileRun("var obj = new Obj;"
23087              "obj.__proto__.interceptor_age = 42;"
23088              "obj.age = 100;"
23089              "function getAge() { return obj.interceptor_age; };");
23090   ExpectInt32("getAge();", 100);
23091   ExpectInt32("getAge();", 100);
23092   ExpectInt32("getAge();", 100);
23093   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
23094   // Access through interceptor.
23095   ExpectInt32("getAge();", 100);
23096 }
23097
23098
23099 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
23100   i::FLAG_allow_natives_syntax = true;
23101   v8::HandleScope scope(CcTest::isolate());
23102   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23103   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23104   LocalContext env;
23105   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23106   CompileRun("var obj = new Obj;"
23107              "obj.age = 100000;"
23108              "function setAge(i) { obj.age = i };"
23109              "setAge(100);"
23110              "setAge(101);"
23111              "setAge(102);"
23112              "%OptimizeFunctionOnNextCall(setAge);"
23113              "setAge(103);");
23114   ExpectInt32("obj.age", 100000);
23115   ExpectInt32("obj.interceptor_age", 103);
23116 }
23117
23118
23119 class RequestInterruptTestBase {
23120  public:
23121   RequestInterruptTestBase()
23122       : env_(),
23123         isolate_(env_->GetIsolate()),
23124         sem_(0),
23125         warmup_(20000),
23126         should_continue_(true) {
23127   }
23128
23129   virtual ~RequestInterruptTestBase() { }
23130
23131   virtual void StartInterruptThread() = 0;
23132
23133   virtual void TestBody() = 0;
23134
23135   void RunTest() {
23136     StartInterruptThread();
23137
23138     v8::HandleScope handle_scope(isolate_);
23139
23140     TestBody();
23141
23142     // Verify we arrived here because interruptor was called
23143     // not due to a bug causing us to exit the loop too early.
23144     CHECK(!should_continue());
23145   }
23146
23147   void WakeUpInterruptor() {
23148     sem_.Signal();
23149   }
23150
23151   bool should_continue() const { return should_continue_; }
23152
23153   bool ShouldContinue() {
23154     if (warmup_ > 0) {
23155       if (--warmup_ == 0) {
23156         WakeUpInterruptor();
23157       }
23158     }
23159
23160     return should_continue_;
23161   }
23162
23163   static void ShouldContinueCallback(
23164       const v8::FunctionCallbackInfo<Value>& info) {
23165     RequestInterruptTestBase* test =
23166         reinterpret_cast<RequestInterruptTestBase*>(
23167             info.Data().As<v8::External>()->Value());
23168     info.GetReturnValue().Set(test->ShouldContinue());
23169   }
23170
23171   LocalContext env_;
23172   v8::Isolate* isolate_;
23173   v8::base::Semaphore sem_;
23174   int warmup_;
23175   bool should_continue_;
23176 };
23177
23178
23179 class RequestInterruptTestBaseWithSimpleInterrupt
23180     : public RequestInterruptTestBase {
23181  public:
23182   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
23183
23184   virtual void StartInterruptThread() {
23185     i_thread.Start();
23186   }
23187
23188  private:
23189   class InterruptThread : public v8::base::Thread {
23190    public:
23191     explicit InterruptThread(RequestInterruptTestBase* test)
23192         : Thread(Options("RequestInterruptTest")), test_(test) {}
23193
23194     virtual void Run() {
23195       test_->sem_.Wait();
23196       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23197     }
23198
23199     static void OnInterrupt(v8::Isolate* isolate, void* data) {
23200       reinterpret_cast<RequestInterruptTestBase*>(data)->
23201           should_continue_ = false;
23202     }
23203
23204    private:
23205      RequestInterruptTestBase* test_;
23206   };
23207
23208   InterruptThread i_thread;
23209 };
23210
23211
23212 class RequestInterruptTestWithFunctionCall
23213     : public RequestInterruptTestBaseWithSimpleInterrupt {
23214  public:
23215   virtual void TestBody() {
23216     Local<Function> func = Function::New(
23217         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23218     env_->Global()->Set(v8_str("ShouldContinue"), func);
23219
23220     CompileRun("while (ShouldContinue()) { }");
23221   }
23222 };
23223
23224
23225 class RequestInterruptTestWithMethodCall
23226     : public RequestInterruptTestBaseWithSimpleInterrupt {
23227  public:
23228   virtual void TestBody() {
23229     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23230     v8::Local<v8::Template> proto = t->PrototypeTemplate();
23231     proto->Set(v8_str("shouldContinue"), Function::New(
23232         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23233     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23234
23235     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23236   }
23237 };
23238
23239
23240 class RequestInterruptTestWithAccessor
23241     : public RequestInterruptTestBaseWithSimpleInterrupt {
23242  public:
23243   virtual void TestBody() {
23244     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23245     v8::Local<v8::Template> proto = t->PrototypeTemplate();
23246     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23247         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23248     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23249
23250     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23251   }
23252 };
23253
23254
23255 class RequestInterruptTestWithNativeAccessor
23256     : public RequestInterruptTestBaseWithSimpleInterrupt {
23257  public:
23258   virtual void TestBody() {
23259     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23260     t->InstanceTemplate()->SetNativeDataProperty(
23261         v8_str("shouldContinue"),
23262         &ShouldContinueNativeGetter,
23263         NULL,
23264         v8::External::New(isolate_, this));
23265     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23266
23267     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23268   }
23269
23270  private:
23271   static void ShouldContinueNativeGetter(
23272       Local<String> property,
23273       const v8::PropertyCallbackInfo<v8::Value>& info) {
23274     RequestInterruptTestBase* test =
23275         reinterpret_cast<RequestInterruptTestBase*>(
23276             info.Data().As<v8::External>()->Value());
23277     info.GetReturnValue().Set(test->ShouldContinue());
23278   }
23279 };
23280
23281
23282 class RequestInterruptTestWithMethodCallAndInterceptor
23283     : public RequestInterruptTestBaseWithSimpleInterrupt {
23284  public:
23285   virtual void TestBody() {
23286     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23287     v8::Local<v8::Template> proto = t->PrototypeTemplate();
23288     proto->Set(v8_str("shouldContinue"), Function::New(
23289         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23290     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23291     instance_template->SetHandler(
23292         v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23293
23294     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23295
23296     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23297   }
23298
23299  private:
23300   static void EmptyInterceptor(
23301       Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23302 };
23303
23304
23305 class RequestInterruptTestWithMathAbs
23306     : public RequestInterruptTestBaseWithSimpleInterrupt {
23307  public:
23308   virtual void TestBody() {
23309     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
23310         isolate_,
23311         WakeUpInterruptorCallback,
23312         v8::External::New(isolate_, this)));
23313
23314     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
23315         isolate_,
23316         ShouldContinueCallback,
23317         v8::External::New(isolate_, this)));
23318
23319     i::FLAG_allow_natives_syntax = true;
23320     CompileRun("function loopish(o) {"
23321                "  var pre = 10;"
23322                "  while (o.abs(1) > 0) {"
23323                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23324                "    if (pre > 0) {"
23325                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
23326                "    }"
23327                "  }"
23328                "}"
23329                "var i = 50;"
23330                "var obj = {abs: function () { return i-- }, x: null};"
23331                "delete obj.x;"
23332                "loopish(obj);"
23333                "%OptimizeFunctionOnNextCall(loopish);"
23334                "loopish(Math);");
23335
23336     i::FLAG_allow_natives_syntax = false;
23337   }
23338
23339  private:
23340   static void WakeUpInterruptorCallback(
23341       const v8::FunctionCallbackInfo<Value>& info) {
23342     if (!info[0]->BooleanValue()) return;
23343
23344     RequestInterruptTestBase* test =
23345         reinterpret_cast<RequestInterruptTestBase*>(
23346             info.Data().As<v8::External>()->Value());
23347     test->WakeUpInterruptor();
23348   }
23349
23350   static void ShouldContinueCallback(
23351       const v8::FunctionCallbackInfo<Value>& info) {
23352     RequestInterruptTestBase* test =
23353         reinterpret_cast<RequestInterruptTestBase*>(
23354             info.Data().As<v8::External>()->Value());
23355     info.GetReturnValue().Set(test->should_continue());
23356   }
23357 };
23358
23359
23360 TEST(RequestInterruptTestWithFunctionCall) {
23361   RequestInterruptTestWithFunctionCall().RunTest();
23362 }
23363
23364
23365 TEST(RequestInterruptTestWithMethodCall) {
23366   RequestInterruptTestWithMethodCall().RunTest();
23367 }
23368
23369
23370 TEST(RequestInterruptTestWithAccessor) {
23371   RequestInterruptTestWithAccessor().RunTest();
23372 }
23373
23374
23375 TEST(RequestInterruptTestWithNativeAccessor) {
23376   RequestInterruptTestWithNativeAccessor().RunTest();
23377 }
23378
23379
23380 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23381   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23382 }
23383
23384
23385 TEST(RequestInterruptTestWithMathAbs) {
23386   RequestInterruptTestWithMathAbs().RunTest();
23387 }
23388
23389
23390 class RequestMultipleInterrupts : public RequestInterruptTestBase {
23391  public:
23392   RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23393
23394   virtual void StartInterruptThread() {
23395     i_thread.Start();
23396   }
23397
23398   virtual void TestBody() {
23399     Local<Function> func = Function::New(
23400         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23401     env_->Global()->Set(v8_str("ShouldContinue"), func);
23402
23403     CompileRun("while (ShouldContinue()) { }");
23404   }
23405
23406  private:
23407   class InterruptThread : public v8::base::Thread {
23408    public:
23409     enum { NUM_INTERRUPTS = 10 };
23410     explicit InterruptThread(RequestMultipleInterrupts* test)
23411         : Thread(Options("RequestInterruptTest")), test_(test) {}
23412
23413     virtual void Run() {
23414       test_->sem_.Wait();
23415       for (int i = 0; i < NUM_INTERRUPTS; i++) {
23416         test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23417       }
23418     }
23419
23420     static void OnInterrupt(v8::Isolate* isolate, void* data) {
23421       RequestMultipleInterrupts* test =
23422           reinterpret_cast<RequestMultipleInterrupts*>(data);
23423       test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23424     }
23425
23426    private:
23427     RequestMultipleInterrupts* test_;
23428   };
23429
23430   InterruptThread i_thread;
23431   int counter_;
23432 };
23433
23434
23435 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23436
23437
23438 static Local<Value> function_new_expected_env;
23439 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23440   CHECK_EQ(function_new_expected_env, info.Data());
23441   info.GetReturnValue().Set(17);
23442 }
23443
23444
23445 THREADED_TEST(FunctionNew) {
23446   LocalContext env;
23447   v8::Isolate* isolate = env->GetIsolate();
23448   v8::HandleScope scope(isolate);
23449   Local<Object> data = v8::Object::New(isolate);
23450   function_new_expected_env = data;
23451   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
23452   env->Global()->Set(v8_str("func"), func);
23453   Local<Value> result = CompileRun("func();");
23454   CHECK_EQ(v8::Integer::New(isolate, 17), result);
23455   // Verify function not cached
23456   int serial_number =
23457       i::Smi::cast(v8::Utils::OpenHandle(*func)
23458           ->shared()->get_api_func_data()->serial_number())->value();
23459   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23460   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
23461   i::Handle<i::Object> elm =
23462       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
23463   CHECK(elm->IsUndefined());
23464   // Verify that each Function::New creates a new function instance
23465   Local<Object> data2 = v8::Object::New(isolate);
23466   function_new_expected_env = data2;
23467   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
23468   CHECK(!func2->IsNull());
23469   CHECK_NE(func, func2);
23470   env->Global()->Set(v8_str("func2"), func2);
23471   Local<Value> result2 = CompileRun("func2();");
23472   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
23473 }
23474
23475
23476 TEST(EscapeableHandleScope) {
23477   HandleScope outer_scope(CcTest::isolate());
23478   LocalContext context;
23479   const int runs = 10;
23480   Local<String> values[runs];
23481   for (int i = 0; i < runs; i++) {
23482     v8::EscapableHandleScope inner_scope(CcTest::isolate());
23483     Local<String> value;
23484     if (i != 0) value = v8_str("escape value");
23485     values[i] = inner_scope.Escape(value);
23486   }
23487   for (int i = 0; i < runs; i++) {
23488     Local<String> expected;
23489     if (i != 0) {
23490       CHECK_EQ(v8_str("escape value"), values[i]);
23491     } else {
23492       CHECK(values[i].IsEmpty());
23493     }
23494   }
23495 }
23496
23497
23498 static void SetterWhichExpectsThisAndHolderToDiffer(
23499     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23500   CHECK(info.Holder() != info.This());
23501 }
23502
23503
23504 TEST(Regress239669) {
23505   LocalContext context;
23506   v8::Isolate* isolate = context->GetIsolate();
23507   v8::HandleScope scope(isolate);
23508   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23509   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
23510   context->Global()->Set(v8_str("P"), templ->NewInstance());
23511   CompileRun(
23512       "function C1() {"
23513       "  this.x = 23;"
23514       "};"
23515       "C1.prototype = P;"
23516       "for (var i = 0; i < 4; i++ ) {"
23517       "  new C1();"
23518       "}");
23519 }
23520
23521
23522 class ApiCallOptimizationChecker {
23523  private:
23524   static Local<Object> data;
23525   static Local<Object> receiver;
23526   static Local<Object> holder;
23527   static Local<Object> callee;
23528   static int count;
23529
23530   static void OptimizationCallback(
23531       const v8::FunctionCallbackInfo<v8::Value>& info) {
23532     CHECK(callee == info.Callee());
23533     CHECK(data == info.Data());
23534     CHECK(receiver == info.This());
23535     if (info.Length() == 1) {
23536       CHECK_EQ(v8_num(1), info[0]);
23537     }
23538     CHECK(holder == info.Holder());
23539     count++;
23540     info.GetReturnValue().Set(v8_str("returned"));
23541   }
23542
23543  public:
23544   enum SignatureType {
23545     kNoSignature,
23546     kSignatureOnReceiver,
23547     kSignatureOnPrototype
23548   };
23549
23550   void RunAll() {
23551     SignatureType signature_types[] =
23552       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23553     for (unsigned i = 0; i < arraysize(signature_types); i++) {
23554       SignatureType signature_type = signature_types[i];
23555       for (int j = 0; j < 2; j++) {
23556         bool global = j == 0;
23557         int key = signature_type +
23558             arraysize(signature_types) * (global ? 1 : 0);
23559         Run(signature_type, global, key);
23560       }
23561     }
23562   }
23563
23564   void Run(SignatureType signature_type, bool global, int key) {
23565     v8::Isolate* isolate = CcTest::isolate();
23566     v8::HandleScope scope(isolate);
23567     // Build a template for signature checks.
23568     Local<v8::ObjectTemplate> signature_template;
23569     Local<v8::Signature> signature;
23570     {
23571       Local<v8::FunctionTemplate> parent_template =
23572         FunctionTemplate::New(isolate);
23573       parent_template->SetHiddenPrototype(true);
23574       Local<v8::FunctionTemplate> function_template
23575           = FunctionTemplate::New(isolate);
23576       function_template->Inherit(parent_template);
23577       switch (signature_type) {
23578         case kNoSignature:
23579           break;
23580         case kSignatureOnReceiver:
23581           signature = v8::Signature::New(isolate, function_template);
23582           break;
23583         case kSignatureOnPrototype:
23584           signature = v8::Signature::New(isolate, parent_template);
23585           break;
23586       }
23587       signature_template = function_template->InstanceTemplate();
23588     }
23589     // Global object must pass checks.
23590     Local<v8::Context> context =
23591         v8::Context::New(isolate, NULL, signature_template);
23592     v8::Context::Scope context_scope(context);
23593     // Install regular object that can pass signature checks.
23594     Local<Object> function_receiver = signature_template->NewInstance();
23595     context->Global()->Set(v8_str("function_receiver"), function_receiver);
23596     // Get the holder objects.
23597     Local<Object> inner_global =
23598         Local<Object>::Cast(context->Global()->GetPrototype());
23599     // Install functions on hidden prototype object if there is one.
23600     data = Object::New(isolate);
23601     Local<FunctionTemplate> function_template = FunctionTemplate::New(
23602         isolate, OptimizationCallback, data, signature);
23603     Local<Function> function = function_template->GetFunction();
23604     Local<Object> global_holder = inner_global;
23605     Local<Object> function_holder = function_receiver;
23606     if (signature_type == kSignatureOnPrototype) {
23607       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23608       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23609     }
23610     global_holder->Set(v8_str("g_f"), function);
23611     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23612     function_holder->Set(v8_str("f"), function);
23613     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23614     // Initialize expected values.
23615     callee = function;
23616     count = 0;
23617     if (global) {
23618       receiver = context->Global();
23619       holder = inner_global;
23620     } else {
23621       holder = function_receiver;
23622       // If not using a signature, add something else to the prototype chain
23623       // to test the case that holder != receiver
23624       if (signature_type == kNoSignature) {
23625         receiver = Local<Object>::Cast(CompileRun(
23626             "var receiver_subclass = {};\n"
23627             "receiver_subclass.__proto__ = function_receiver;\n"
23628             "receiver_subclass"));
23629       } else {
23630         receiver = Local<Object>::Cast(CompileRun(
23631           "var receiver_subclass = function_receiver;\n"
23632           "receiver_subclass"));
23633       }
23634     }
23635     // With no signature, the holder is not set.
23636     if (signature_type == kNoSignature) holder = receiver;
23637     // build wrap_function
23638     i::ScopedVector<char> wrap_function(200);
23639     if (global) {
23640       i::SNPrintF(
23641           wrap_function,
23642           "function wrap_f_%d() { var f = g_f; return f(); }\n"
23643           "function wrap_get_%d() { return this.g_acc; }\n"
23644           "function wrap_set_%d() { return this.g_acc = 1; }\n",
23645           key, key, key);
23646     } else {
23647       i::SNPrintF(
23648           wrap_function,
23649           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23650           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23651           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23652           key, key, key);
23653     }
23654     // build source string
23655     i::ScopedVector<char> source(1000);
23656     i::SNPrintF(
23657         source,
23658         "%s\n"  // wrap functions
23659         "function wrap_f() { return wrap_f_%d(); }\n"
23660         "function wrap_get() { return wrap_get_%d(); }\n"
23661         "function wrap_set() { return wrap_set_%d(); }\n"
23662         "check = function(returned) {\n"
23663         "  if (returned !== 'returned') { throw returned; }\n"
23664         "}\n"
23665         "\n"
23666         "check(wrap_f());\n"
23667         "check(wrap_f());\n"
23668         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23669         "check(wrap_f());\n"
23670         "\n"
23671         "check(wrap_get());\n"
23672         "check(wrap_get());\n"
23673         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23674         "check(wrap_get());\n"
23675         "\n"
23676         "check = function(returned) {\n"
23677         "  if (returned !== 1) { throw returned; }\n"
23678         "}\n"
23679         "check(wrap_set());\n"
23680         "check(wrap_set());\n"
23681         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23682         "check(wrap_set());\n",
23683         wrap_function.start(), key, key, key, key, key, key);
23684     v8::TryCatch try_catch;
23685     CompileRun(source.start());
23686     DCHECK(!try_catch.HasCaught());
23687     CHECK_EQ(9, count);
23688   }
23689 };
23690
23691
23692 Local<Object> ApiCallOptimizationChecker::data;
23693 Local<Object> ApiCallOptimizationChecker::receiver;
23694 Local<Object> ApiCallOptimizationChecker::holder;
23695 Local<Object> ApiCallOptimizationChecker::callee;
23696 int ApiCallOptimizationChecker::count = 0;
23697
23698
23699 TEST(TestFunctionCallOptimization) {
23700   i::FLAG_allow_natives_syntax = true;
23701   ApiCallOptimizationChecker checker;
23702   checker.RunAll();
23703 }
23704
23705
23706 static const char* last_event_message;
23707 static int last_event_status;
23708 void StoringEventLoggerCallback(const char* message, int status) {
23709     last_event_message = message;
23710     last_event_status = status;
23711 }
23712
23713
23714 TEST(EventLogging) {
23715   v8::Isolate* isolate = CcTest::isolate();
23716   isolate->SetEventLogger(StoringEventLoggerCallback);
23717   v8::internal::HistogramTimer histogramTimer(
23718       "V8.Test", 0, 10000, 50,
23719       reinterpret_cast<v8::internal::Isolate*>(isolate));
23720   histogramTimer.Start();
23721   CHECK_EQ("V8.Test", last_event_message);
23722   CHECK_EQ(0, last_event_status);
23723   histogramTimer.Stop();
23724   CHECK_EQ("V8.Test", last_event_message);
23725   CHECK_EQ(1, last_event_status);
23726 }
23727
23728
23729 TEST(Promises) {
23730   LocalContext context;
23731   v8::Isolate* isolate = context->GetIsolate();
23732   v8::HandleScope scope(isolate);
23733   Handle<Object> global = context->Global();
23734
23735   // Creation.
23736   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23737   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
23738   Handle<v8::Promise> p = pr->GetPromise();
23739   Handle<v8::Promise> r = rr->GetPromise();
23740   CHECK_EQ(isolate, p->GetIsolate());
23741
23742   // IsPromise predicate.
23743   CHECK(p->IsPromise());
23744   CHECK(r->IsPromise());
23745   Handle<Value> o = v8::Object::New(isolate);
23746   CHECK(!o->IsPromise());
23747
23748   // Resolution and rejection.
23749   pr->Resolve(v8::Integer::New(isolate, 1));
23750   CHECK(p->IsPromise());
23751   rr->Reject(v8::Integer::New(isolate, 2));
23752   CHECK(r->IsPromise());
23753
23754   // Chaining non-pending promises.
23755   CompileRun(
23756       "var x1 = 0;\n"
23757       "var x2 = 0;\n"
23758       "function f1(x) { x1 = x; return x+1 };\n"
23759       "function f2(x) { x2 = x; return x+1 };\n");
23760   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23761   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23762
23763   p->Chain(f1);
23764   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23765   isolate->RunMicrotasks();
23766   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23767
23768   p->Catch(f2);
23769   isolate->RunMicrotasks();
23770   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23771
23772   r->Catch(f2);
23773   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23774   isolate->RunMicrotasks();
23775   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23776
23777   r->Chain(f1);
23778   isolate->RunMicrotasks();
23779   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23780
23781   // Chaining pending promises.
23782   CompileRun("x1 = x2 = 0;");
23783   pr = v8::Promise::Resolver::New(isolate);
23784   rr = v8::Promise::Resolver::New(isolate);
23785
23786   pr->GetPromise()->Chain(f1);
23787   rr->GetPromise()->Catch(f2);
23788   isolate->RunMicrotasks();
23789   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23790   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23791
23792   pr->Resolve(v8::Integer::New(isolate, 1));
23793   rr->Reject(v8::Integer::New(isolate, 2));
23794   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23795   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23796
23797   isolate->RunMicrotasks();
23798   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23799   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23800
23801   // Multi-chaining.
23802   CompileRun("x1 = x2 = 0;");
23803   pr = v8::Promise::Resolver::New(isolate);
23804   pr->GetPromise()->Chain(f1)->Chain(f2);
23805   pr->Resolve(v8::Integer::New(isolate, 3));
23806   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23807   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23808   isolate->RunMicrotasks();
23809   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23810   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23811
23812   CompileRun("x1 = x2 = 0;");
23813   rr = v8::Promise::Resolver::New(isolate);
23814   rr->GetPromise()->Catch(f1)->Chain(f2);
23815   rr->Reject(v8::Integer::New(isolate, 3));
23816   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23817   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23818   isolate->RunMicrotasks();
23819   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23820   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23821 }
23822
23823
23824 TEST(PromiseThen) {
23825   LocalContext context;
23826   v8::Isolate* isolate = context->GetIsolate();
23827   v8::HandleScope scope(isolate);
23828   Handle<Object> global = context->Global();
23829
23830   // Creation.
23831   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23832   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
23833   Handle<v8::Promise> p = pr->GetPromise();
23834   Handle<v8::Promise> q = qr->GetPromise();
23835
23836   CHECK(p->IsPromise());
23837   CHECK(q->IsPromise());
23838
23839   pr->Resolve(v8::Integer::New(isolate, 1));
23840   qr->Resolve(p);
23841
23842   // Chaining non-pending promises.
23843   CompileRun(
23844       "var x1 = 0;\n"
23845       "var x2 = 0;\n"
23846       "function f1(x) { x1 = x; return x+1 };\n"
23847       "function f2(x) { x2 = x; return x+1 };\n");
23848   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23849   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23850
23851   // Chain
23852   q->Chain(f1);
23853   CHECK(global->Get(v8_str("x1"))->IsNumber());
23854   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23855   isolate->RunMicrotasks();
23856   CHECK(!global->Get(v8_str("x1"))->IsNumber());
23857   CHECK_EQ(p, global->Get(v8_str("x1")));
23858
23859   // Then
23860   CompileRun("x1 = x2 = 0;");
23861   q->Then(f1);
23862   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23863   isolate->RunMicrotasks();
23864   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23865
23866   // Then
23867   CompileRun("x1 = x2 = 0;");
23868   pr = v8::Promise::Resolver::New(isolate);
23869   qr = v8::Promise::Resolver::New(isolate);
23870
23871   qr->Resolve(pr);
23872   qr->GetPromise()->Then(f1)->Then(f2);
23873
23874   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23875   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23876   isolate->RunMicrotasks();
23877   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23878   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23879
23880   pr->Resolve(v8::Integer::New(isolate, 3));
23881
23882   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23883   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23884   isolate->RunMicrotasks();
23885   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23886   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23887 }
23888
23889
23890 TEST(DisallowJavascriptExecutionScope) {
23891   LocalContext context;
23892   v8::Isolate* isolate = context->GetIsolate();
23893   v8::HandleScope scope(isolate);
23894   v8::Isolate::DisallowJavascriptExecutionScope no_js(
23895       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23896   CompileRun("2+2");
23897 }
23898
23899
23900 TEST(AllowJavascriptExecutionScope) {
23901   LocalContext context;
23902   v8::Isolate* isolate = context->GetIsolate();
23903   v8::HandleScope scope(isolate);
23904   v8::Isolate::DisallowJavascriptExecutionScope no_js(
23905       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23906   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23907       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23908   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
23909     CompileRun("1+1");
23910   }
23911 }
23912
23913
23914 TEST(ThrowOnJavascriptExecution) {
23915   LocalContext context;
23916   v8::Isolate* isolate = context->GetIsolate();
23917   v8::HandleScope scope(isolate);
23918   v8::TryCatch try_catch;
23919   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23920       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23921   CompileRun("1+1");
23922   CHECK(try_catch.HasCaught());
23923 }
23924
23925
23926 TEST(Regress354123) {
23927   LocalContext current;
23928   v8::Isolate* isolate = current->GetIsolate();
23929   v8::HandleScope scope(isolate);
23930
23931   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
23932   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
23933   current->Global()->Set(v8_str("friend"), templ->NewInstance());
23934
23935   // Test access using __proto__ from the prototype chain.
23936   named_access_count = 0;
23937   CompileRun("friend.__proto__ = {};");
23938   CHECK_EQ(2, named_access_count);
23939   CompileRun("friend.__proto__;");
23940   CHECK_EQ(4, named_access_count);
23941
23942   // Test access using __proto__ as a hijacked function (A).
23943   named_access_count = 0;
23944   CompileRun("var p = Object.prototype;"
23945              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
23946              "f.call(friend, {});");
23947   CHECK_EQ(1, named_access_count);
23948   CompileRun("var p = Object.prototype;"
23949              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
23950              "f.call(friend);");
23951   CHECK_EQ(2, named_access_count);
23952
23953   // Test access using __proto__ as a hijacked function (B).
23954   named_access_count = 0;
23955   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
23956              "f.call(friend, {});");
23957   CHECK_EQ(1, named_access_count);
23958   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
23959              "f.call(friend);");
23960   CHECK_EQ(2, named_access_count);
23961
23962   // Test access using Object.setPrototypeOf reflective method.
23963   named_access_count = 0;
23964   CompileRun("Object.setPrototypeOf(friend, {});");
23965   CHECK_EQ(1, named_access_count);
23966   CompileRun("Object.getPrototypeOf(friend);");
23967   CHECK_EQ(2, named_access_count);
23968 }
23969
23970
23971 TEST(CaptureStackTraceForStackOverflow) {
23972   v8::internal::FLAG_stack_size = 150;
23973   LocalContext current;
23974   v8::Isolate* isolate = current->GetIsolate();
23975   v8::HandleScope scope(isolate);
23976   V8::SetCaptureStackTraceForUncaughtExceptions(
23977       true, 10, v8::StackTrace::kDetailed);
23978   v8::TryCatch try_catch;
23979   CompileRun("(function f(x) { f(x+1); })(0)");
23980   CHECK(try_catch.HasCaught());
23981 }
23982
23983
23984 TEST(ScriptNameAndLineNumber) {
23985   LocalContext env;
23986   v8::Isolate* isolate = env->GetIsolate();
23987   v8::HandleScope scope(isolate);
23988   const char* url = "http://www.foo.com/foo.js";
23989   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23990   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
23991   Local<Script> script = v8::ScriptCompiler::Compile(
23992       isolate, &script_source);
23993   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
23994   CHECK(!script_name.IsEmpty());
23995   CHECK(script_name->IsString());
23996   String::Utf8Value utf8_name(script_name);
23997   CHECK_EQ(url, *utf8_name);
23998   int line_number = script->GetUnboundScript()->GetLineNumber(0);
23999   CHECK_EQ(13, line_number);
24000 }
24001
24002
24003 void SourceURLHelper(const char* source, const char* expected_source_url,
24004                      const char* expected_source_mapping_url) {
24005   Local<Script> script = v8_compile(source);
24006   if (expected_source_url != NULL) {
24007     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
24008     CHECK_EQ(expected_source_url, *url);
24009   } else {
24010     CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24011   }
24012   if (expected_source_mapping_url != NULL) {
24013     v8::String::Utf8Value url(
24014         script->GetUnboundScript()->GetSourceMappingURL());
24015     CHECK_EQ(expected_source_mapping_url, *url);
24016   } else {
24017     CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24018   }
24019 }
24020
24021
24022 TEST(ScriptSourceURLAndSourceMappingURL) {
24023   LocalContext env;
24024   v8::Isolate* isolate = env->GetIsolate();
24025   v8::HandleScope scope(isolate);
24026   SourceURLHelper("function foo() {}\n"
24027                   "//# sourceURL=bar1.js\n", "bar1.js", NULL);
24028   SourceURLHelper("function foo() {}\n"
24029                   "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
24030
24031   // Both sourceURL and sourceMappingURL.
24032   SourceURLHelper("function foo() {}\n"
24033                   "//# sourceURL=bar3.js\n"
24034                   "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
24035
24036   // Two source URLs; the first one is ignored.
24037   SourceURLHelper("function foo() {}\n"
24038                   "//# sourceURL=ignoreme.js\n"
24039                   "//# sourceURL=bar5.js\n", "bar5.js", NULL);
24040   SourceURLHelper("function foo() {}\n"
24041                   "//# sourceMappingURL=ignoreme.js\n"
24042                   "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
24043
24044   // SourceURL or sourceMappingURL in the middle of the script.
24045   SourceURLHelper("function foo() {}\n"
24046                   "//# sourceURL=bar7.js\n"
24047                   "function baz() {}\n", "bar7.js", NULL);
24048   SourceURLHelper("function foo() {}\n"
24049                   "//# sourceMappingURL=bar8.js\n"
24050                   "function baz() {}\n", NULL, "bar8.js");
24051
24052   // Too much whitespace.
24053   SourceURLHelper("function foo() {}\n"
24054                   "//#  sourceURL=bar9.js\n"
24055                   "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
24056   SourceURLHelper("function foo() {}\n"
24057                   "//# sourceURL =bar11.js\n"
24058                   "//# sourceMappingURL =bar12.js\n", NULL, NULL);
24059
24060   // Disallowed characters in value.
24061   SourceURLHelper("function foo() {}\n"
24062                   "//# sourceURL=bar13 .js   \n"
24063                   "//# sourceMappingURL=bar14 .js \n",
24064                   NULL, NULL);
24065   SourceURLHelper("function foo() {}\n"
24066                   "//# sourceURL=bar15\t.js   \n"
24067                   "//# sourceMappingURL=bar16\t.js \n",
24068                   NULL, NULL);
24069   SourceURLHelper("function foo() {}\n"
24070                   "//# sourceURL=bar17'.js   \n"
24071                   "//# sourceMappingURL=bar18'.js \n",
24072                   NULL, NULL);
24073   SourceURLHelper("function foo() {}\n"
24074                   "//# sourceURL=bar19\".js   \n"
24075                   "//# sourceMappingURL=bar20\".js \n",
24076                   NULL, NULL);
24077
24078   // Not too much whitespace.
24079   SourceURLHelper("function foo() {}\n"
24080                   "//# sourceURL=  bar21.js   \n"
24081                   "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
24082 }
24083
24084
24085 TEST(GetOwnPropertyDescriptor) {
24086   LocalContext env;
24087   v8::Isolate* isolate = env->GetIsolate();
24088   v8::HandleScope scope(isolate);
24089   CompileRun(
24090     "var x = { value : 13};"
24091     "Object.defineProperty(x, 'p0', {value : 12});"
24092     "Object.defineProperty(x, 'p1', {"
24093     "  set : function(value) { this.value = value; },"
24094     "  get : function() { return this.value; },"
24095     "});");
24096   Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
24097   Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
24098   CHECK(desc->IsUndefined());
24099   desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
24100   CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
24101   desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
24102   Local<Function> set =
24103     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
24104   Local<Function> get =
24105     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
24106   CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
24107   Handle<Value> args[] = { v8_num(14) };
24108   set->Call(x, 1, args);
24109   CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
24110 }
24111
24112
24113 TEST(Regress411877) {
24114   v8::Isolate* isolate = CcTest::isolate();
24115   v8::HandleScope handle_scope(isolate);
24116   v8::Handle<v8::ObjectTemplate> object_template =
24117       v8::ObjectTemplate::New(isolate);
24118   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24119                                            IndexedAccessCounter);
24120
24121   v8::Handle<Context> context = Context::New(isolate);
24122   v8::Context::Scope context_scope(context);
24123
24124   context->Global()->Set(v8_str("o"), object_template->NewInstance());
24125   CompileRun("Object.getOwnPropertyNames(o)");
24126 }
24127
24128
24129 TEST(GetHiddenPropertyTableAfterAccessCheck) {
24130   v8::Isolate* isolate = CcTest::isolate();
24131   v8::HandleScope handle_scope(isolate);
24132   v8::Handle<v8::ObjectTemplate> object_template =
24133       v8::ObjectTemplate::New(isolate);
24134   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24135                                            IndexedAccessCounter);
24136
24137   v8::Handle<Context> context = Context::New(isolate);
24138   v8::Context::Scope context_scope(context);
24139
24140   v8::Handle<v8::Object> obj = object_template->NewInstance();
24141   obj->Set(v8_str("key"), v8_str("value"));
24142   obj->Delete(v8_str("key"));
24143
24144   obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
24145 }
24146
24147
24148 TEST(Regress411793) {
24149   v8::Isolate* isolate = CcTest::isolate();
24150   v8::HandleScope handle_scope(isolate);
24151   v8::Handle<v8::ObjectTemplate> object_template =
24152       v8::ObjectTemplate::New(isolate);
24153   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24154                                            IndexedAccessCounter);
24155
24156   v8::Handle<Context> context = Context::New(isolate);
24157   v8::Context::Scope context_scope(context);
24158
24159   context->Global()->Set(v8_str("o"), object_template->NewInstance());
24160   CompileRun(
24161       "Object.defineProperty(o, 'key', "
24162       "    { get: function() {}, set: function() {} });");
24163 }
24164
24165 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24166  public:
24167   explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24168
24169   virtual size_t GetMoreData(const uint8_t** src) {
24170     // Unlike in real use cases, this function will never block.
24171     if (chunks_[index_] == NULL) {
24172       return 0;
24173     }
24174     // Copy the data, since the caller takes ownership of it.
24175     size_t len = strlen(chunks_[index_]);
24176     // We don't need to zero-terminate since we return the length.
24177     uint8_t* copy = new uint8_t[len];
24178     memcpy(copy, chunks_[index_], len);
24179     *src = copy;
24180     ++index_;
24181     return len;
24182   }
24183
24184   // Helper for constructing a string from chunks (the compilation needs it
24185   // too).
24186   static char* FullSourceString(const char** chunks) {
24187     size_t total_len = 0;
24188     for (size_t i = 0; chunks[i] != NULL; ++i) {
24189       total_len += strlen(chunks[i]);
24190     }
24191     char* full_string = new char[total_len + 1];
24192     size_t offset = 0;
24193     for (size_t i = 0; chunks[i] != NULL; ++i) {
24194       size_t len = strlen(chunks[i]);
24195       memcpy(full_string + offset, chunks[i], len);
24196       offset += len;
24197     }
24198     full_string[total_len] = 0;
24199     return full_string;
24200   }
24201
24202  private:
24203   const char** chunks_;
24204   unsigned index_;
24205 };
24206
24207
24208 // Helper function for running streaming tests.
24209 void RunStreamingTest(const char** chunks,
24210                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
24211                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24212                       bool expected_success = true) {
24213   LocalContext env;
24214   v8::Isolate* isolate = env->GetIsolate();
24215   v8::HandleScope scope(isolate);
24216   v8::TryCatch try_catch;
24217
24218   v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
24219                                             encoding);
24220   v8::ScriptCompiler::ScriptStreamingTask* task =
24221       v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24222
24223   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24224   // task here in the main thread.
24225   task->Run();
24226   delete task;
24227
24228   v8::ScriptOrigin origin(v8_str("http://foo.com"));
24229   char* full_source = TestSourceStream::FullSourceString(chunks);
24230
24231   // The possible errors are only produced while compiling.
24232   CHECK_EQ(false, try_catch.HasCaught());
24233
24234   v8::Handle<Script> script = v8::ScriptCompiler::Compile(
24235       isolate, &source, v8_str(full_source), origin);
24236   if (expected_success) {
24237     CHECK(!script.IsEmpty());
24238     v8::Handle<Value> result(script->Run());
24239     // All scripts are supposed to return the fixed value 13 when ran.
24240     CHECK_EQ(13, result->Int32Value());
24241   } else {
24242     CHECK(script.IsEmpty());
24243     CHECK(try_catch.HasCaught());
24244   }
24245   delete[] full_source;
24246 }
24247
24248
24249 TEST(StreamingSimpleScript) {
24250   // This script is unrealistically small, since no one chunk is enough to fill
24251   // the backing buffer of Scanner, let alone overflow it.
24252   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24253                           NULL};
24254   RunStreamingTest(chunks);
24255 }
24256
24257
24258 TEST(StreamingBiggerScript) {
24259   const char* chunk1 =
24260       "function foo() {\n"
24261       "  // Make this chunk sufficiently long so that it will overflow the\n"
24262       "  // backing buffer of the Scanner.\n"
24263       "  var i = 0;\n"
24264       "  var result = 0;\n"
24265       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24266       "  result = 0;\n"
24267       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24268       "  result = 0;\n"
24269       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24270       "  result = 0;\n"
24271       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24272       "  return result;\n"
24273       "}\n";
24274   const char* chunks[] = {chunk1, "foo(); ", NULL};
24275   RunStreamingTest(chunks);
24276 }
24277
24278
24279 TEST(StreamingScriptWithParseError) {
24280   // Test that parse errors from streamed scripts are propagated correctly.
24281   {
24282     char chunk1[] =
24283         "  // This will result in a parse error.\n"
24284         "  var if else then foo";
24285     char chunk2[] = "  13\n";
24286     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24287
24288     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24289                      false);
24290   }
24291   // Test that the next script succeeds normally.
24292   {
24293     char chunk1[] =
24294         "  // This will be parsed successfully.\n"
24295         "  function foo() { return ";
24296     char chunk2[] = "  13; }\n";
24297     const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24298
24299     RunStreamingTest(chunks);
24300   }
24301 }
24302
24303
24304 TEST(StreamingUtf8Script) {
24305   // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
24306   // don't like it.
24307   const char* chunk1 =
24308       "function foo() {\n"
24309       "  // This function will contain an UTF-8 character which is not in\n"
24310       "  // ASCII.\n"
24311       "  var foob\xec\x92\x81r = 13;\n"
24312       "  return foob\xec\x92\x81r;\n"
24313       "}\n";
24314   const char* chunks[] = {chunk1, "foo(); ", NULL};
24315   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24316 }
24317
24318
24319 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
24320   // A sanity check to prove that the approach of splitting UTF-8
24321   // characters is correct. Here is an UTF-8 character which will take three
24322   // bytes.
24323   const char* reference = "\xec\x92\x81";
24324   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
24325
24326   char chunk1[] =
24327       "function foo() {\n"
24328       "  // This function will contain an UTF-8 character which is not in\n"
24329       "  // ASCII.\n"
24330       "  var foob";
24331   char chunk2[] =
24332       "XXXr = 13;\n"
24333       "  return foob\xec\x92\x81r;\n"
24334       "}\n";
24335   for (int i = 0; i < 3; ++i) {
24336     chunk2[i] = reference[i];
24337   }
24338   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24339   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24340 }
24341
24342
24343 TEST(StreamingUtf8ScriptWithSplitCharacters) {
24344   // Stream data where a multi-byte UTF-8 character is split between two data
24345   // chunks.
24346   const char* reference = "\xec\x92\x81";
24347   char chunk1[] =
24348       "function foo() {\n"
24349       "  // This function will contain an UTF-8 character which is not in\n"
24350       "  // ASCII.\n"
24351       "  var foobX";
24352   char chunk2[] =
24353       "XXr = 13;\n"
24354       "  return foob\xec\x92\x81r;\n"
24355       "}\n";
24356   chunk1[strlen(chunk1) - 1] = reference[0];
24357   chunk2[0] = reference[1];
24358   chunk2[1] = reference[2];
24359   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24360   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24361 }
24362
24363
24364 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24365   // Tests edge cases which should still be decoded correctly.
24366
24367   // Case 1: a chunk contains only bytes for a split character (and no other
24368   // data). This kind of a chunk would be exceptionally small, but we should
24369   // still decode it correctly.
24370   const char* reference = "\xec\x92\x81";
24371   // The small chunk is at the beginning of the split character
24372   {
24373     char chunk1[] =
24374         "function foo() {\n"
24375         "  // This function will contain an UTF-8 character which is not in\n"
24376         "  // ASCII.\n"
24377         "  var foob";
24378     char chunk2[] = "XX";
24379     char chunk3[] =
24380         "Xr = 13;\n"
24381         "  return foob\xec\x92\x81r;\n"
24382         "}\n";
24383     chunk2[0] = reference[0];
24384     chunk2[1] = reference[1];
24385     chunk3[0] = reference[2];
24386     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24387     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24388   }
24389   // The small chunk is at the end of a character
24390   {
24391     char chunk1[] =
24392         "function foo() {\n"
24393         "  // This function will contain an UTF-8 character which is not in\n"
24394         "  // ASCII.\n"
24395         "  var foobX";
24396     char chunk2[] = "XX";
24397     char chunk3[] =
24398         "r = 13;\n"
24399         "  return foob\xec\x92\x81r;\n"
24400         "}\n";
24401     chunk1[strlen(chunk1) - 1] = reference[0];
24402     chunk2[0] = reference[1];
24403     chunk2[1] = reference[2];
24404     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24405     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24406   }
24407   // Case 2: the script ends with a multi-byte character. Make sure that it's
24408   // decoded correctly and not just ignored.
24409   {
24410     char chunk1[] =
24411         "var foob\xec\x92\x81 = 13;\n"
24412         "foob\xec\x92\x81";
24413     const char* chunks[] = {chunk1, NULL};
24414     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24415   }
24416 }
24417
24418
24419 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
24420   // Test cases where a UTF-8 character is split over several chunks. Those
24421   // cases are not supported (the embedder should give the data in big enough
24422   // chunks), but we shouldn't crash, just produce a parse error.
24423   const char* reference = "\xec\x92\x81";
24424   char chunk1[] =
24425       "function foo() {\n"
24426       "  // This function will contain an UTF-8 character which is not in\n"
24427       "  // ASCII.\n"
24428       "  var foobX";
24429   char chunk2[] = "X";
24430   char chunk3[] =
24431       "Xr = 13;\n"
24432       "  return foob\xec\x92\x81r;\n"
24433       "}\n";
24434   chunk1[strlen(chunk1) - 1] = reference[0];
24435   chunk2[0] = reference[1];
24436   chunk3[0] = reference[2];
24437   const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24438
24439   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24440 }
24441
24442
24443 TEST(StreamingProducesParserCache) {
24444   i::FLAG_min_preparse_length = 0;
24445   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24446                           NULL};
24447
24448   LocalContext env;
24449   v8::Isolate* isolate = env->GetIsolate();
24450   v8::HandleScope scope(isolate);
24451
24452   v8::ScriptCompiler::StreamedSource source(
24453       new TestSourceStream(chunks),
24454       v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24455   v8::ScriptCompiler::ScriptStreamingTask* task =
24456       v8::ScriptCompiler::StartStreamingScript(
24457           isolate, &source, v8::ScriptCompiler::kProduceParserCache);
24458
24459   // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24460   // task here in the main thread.
24461   task->Run();
24462   delete task;
24463
24464   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
24465   CHECK(cached_data != NULL);
24466   CHECK(cached_data->data != NULL);
24467   CHECK(!cached_data->rejected);
24468   CHECK_GT(cached_data->length, 0);
24469 }
24470
24471
24472 TEST(StreamingScriptWithInvalidUtf8) {
24473   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
24474   // chunk don't produce a crash.
24475   const char* reference = "\xec\x92\x81\x80\x80";
24476   char chunk1[] =
24477       "function foo() {\n"
24478       "  // This function will contain an UTF-8 character which is not in\n"
24479       "  // ASCII.\n"
24480       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
24481   char chunk2[] =
24482       "r = 13;\n"
24483       "  return foob\xec\x92\x81\x80\x80r;\n"
24484       "}\n";
24485   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
24486
24487   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24488   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24489 }
24490
24491
24492 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
24493   // Regression test: Stream data where there are several multi-byte UTF-8
24494   // characters in a sequence and one of them is split between two data chunks.
24495   const char* reference = "\xec\x92\x81";
24496   char chunk1[] =
24497       "function foo() {\n"
24498       "  // This function will contain an UTF-8 character which is not in\n"
24499       "  // ASCII.\n"
24500       "  var foob\xec\x92\x81X";
24501   char chunk2[] =
24502       "XXr = 13;\n"
24503       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
24504       "}\n";
24505   chunk1[strlen(chunk1) - 1] = reference[0];
24506   chunk2[0] = reference[1];
24507   chunk2[1] = reference[2];
24508   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24509   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24510 }
24511
24512
24513 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
24514   // Another regression test, similar to the previous one. The difference is
24515   // that the split character is not the last one in the sequence.
24516   const char* reference = "\xec\x92\x81";
24517   char chunk1[] =
24518       "function foo() {\n"
24519       "  // This function will contain an UTF-8 character which is not in\n"
24520       "  // ASCII.\n"
24521       "  var foobX";
24522   char chunk2[] =
24523       "XX\xec\x92\x81r = 13;\n"
24524       "  return foob\xec\x92\x81\xec\x92\x81r;\n"
24525       "}\n";
24526   chunk1[strlen(chunk1) - 1] = reference[0];
24527   chunk2[0] = reference[1];
24528   chunk2[1] = reference[2];
24529   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24530   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24531 }
24532
24533
24534 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
24535   const char* garbage = "garbage garbage garbage garbage.";
24536   const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
24537   int length = 16;
24538   v8::ScriptCompiler::CachedData* cached_data =
24539       new v8::ScriptCompiler::CachedData(data, length);
24540   DCHECK(!cached_data->rejected);
24541   v8::ScriptOrigin origin(v8_str("origin"));
24542   v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
24543   v8::Handle<v8::Script> script =
24544       v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
24545   CHECK(cached_data->rejected);
24546   CHECK_EQ(42, script->Run()->Int32Value());
24547 }
24548
24549
24550 TEST(InvalidCacheData) {
24551   v8::V8::Initialize();
24552   v8::HandleScope scope(CcTest::isolate());
24553   LocalContext context;
24554   TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
24555   TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
24556 }
24557
24558
24559 TEST(ParserCacheRejectedGracefully) {
24560   i::FLAG_min_preparse_length = 0;
24561   v8::V8::Initialize();
24562   v8::HandleScope scope(CcTest::isolate());
24563   LocalContext context;
24564   // Produce valid cached data.
24565   v8::ScriptOrigin origin(v8_str("origin"));
24566   v8::Local<v8::String> source_str = v8_str("function foo() {}");
24567   v8::ScriptCompiler::Source source(source_str, origin);
24568   v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
24569       CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
24570   CHECK(!script.IsEmpty());
24571   const v8::ScriptCompiler::CachedData* original_cached_data =
24572       source.GetCachedData();
24573   CHECK(original_cached_data != NULL);
24574   CHECK(original_cached_data->data != NULL);
24575   CHECK(!original_cached_data->rejected);
24576   CHECK_GT(original_cached_data->length, 0);
24577   // Recompiling the same script with it won't reject the data.
24578   {
24579     v8::ScriptCompiler::Source source_with_cached_data(
24580         source_str, origin,
24581         new v8::ScriptCompiler::CachedData(original_cached_data->data,
24582                                            original_cached_data->length));
24583     v8::Handle<v8::Script> script =
24584         v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
24585                                     v8::ScriptCompiler::kConsumeParserCache);
24586     CHECK(!script.IsEmpty());
24587     const v8::ScriptCompiler::CachedData* new_cached_data =
24588         source_with_cached_data.GetCachedData();
24589     CHECK(new_cached_data != NULL);
24590     CHECK(!new_cached_data->rejected);
24591   }
24592   // Compile an incompatible script with the cached data. The new script doesn't
24593   // have the same starting position for the function as the old one, so the old
24594   // cached data will be incompatible with it and will be rejected.
24595   {
24596     v8::Local<v8::String> incompatible_source_str =
24597         v8_str("   function foo() {}");
24598     v8::ScriptCompiler::Source source_with_cached_data(
24599         incompatible_source_str, origin,
24600         new v8::ScriptCompiler::CachedData(original_cached_data->data,
24601                                            original_cached_data->length));
24602     v8::Handle<v8::Script> script =
24603         v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
24604                                     v8::ScriptCompiler::kConsumeParserCache);
24605     CHECK(!script.IsEmpty());
24606     const v8::ScriptCompiler::CachedData* new_cached_data =
24607         source_with_cached_data.GetCachedData();
24608     CHECK(new_cached_data != NULL);
24609     CHECK(new_cached_data->rejected);
24610   }
24611 }
24612
24613
24614 TEST(StringConcatOverflow) {
24615   v8::V8::Initialize();
24616   v8::HandleScope scope(CcTest::isolate());
24617   RandomLengthOneByteResource* r =
24618       new RandomLengthOneByteResource(i::String::kMaxLength);
24619   v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
24620   CHECK(!str.IsEmpty());
24621   v8::TryCatch try_catch;
24622   v8::Local<v8::String> result = v8::String::Concat(str, str);
24623   CHECK(result.IsEmpty());
24624   CHECK(!try_catch.HasCaught());
24625 }
24626
24627
24628 TEST(TurboAsmDisablesNeuter) {
24629   v8::V8::Initialize();
24630   v8::HandleScope scope(CcTest::isolate());
24631   LocalContext context;
24632 #if V8_TURBOFAN_TARGET
24633   bool should_be_neuterable = !i::FLAG_turbo_asm;
24634 #else
24635   bool should_be_neuterable = true;
24636 #endif
24637   const char* load =
24638       "function Module(stdlib, foreign, heap) {"
24639       "  'use asm';"
24640       "  var MEM32 = new stdlib.Int32Array(heap);"
24641       "  function load() { return MEM32[0]; }"
24642       "  return { load: load };"
24643       "}"
24644       "var buffer = new ArrayBuffer(4);"
24645       "Module(this, {}, buffer).load();"
24646       "buffer";
24647
24648   v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
24649   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24650
24651   const char* store =
24652       "function Module(stdlib, foreign, heap) {"
24653       "  'use asm';"
24654       "  var MEM32 = new stdlib.Int32Array(heap);"
24655       "  function store() { MEM32[0] = 0; }"
24656       "  return { store: store };"
24657       "}"
24658       "var buffer = new ArrayBuffer(4);"
24659       "Module(this, {}, buffer).store();"
24660       "buffer";
24661
24662   result = CompileRun(store).As<v8::ArrayBuffer>();
24663   CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24664 }
24665
24666
24667 TEST(GetPrototypeAccessControl) {
24668   i::FLAG_allow_natives_syntax = true;
24669   v8::Isolate* isolate = CcTest::isolate();
24670   v8::HandleScope handle_scope(isolate);
24671   LocalContext env;
24672
24673   v8::Handle<v8::ObjectTemplate> obj_template =
24674       v8::ObjectTemplate::New(isolate);
24675   obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
24676                                         BlockEverythingIndexed);
24677
24678   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
24679
24680   {
24681     v8::TryCatch try_catch;
24682     CompileRun(
24683         "function f() { %_GetPrototype(prohibited); }"
24684         "%OptimizeFunctionOnNextCall(f);"
24685         "f();");
24686     CHECK(try_catch.HasCaught());
24687   }
24688 }
24689
24690
24691 TEST(GetPrototypeHidden) {
24692   i::FLAG_allow_natives_syntax = true;
24693   v8::Isolate* isolate = CcTest::isolate();
24694   v8::HandleScope handle_scope(isolate);
24695   LocalContext env;
24696
24697   Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
24698   t->SetHiddenPrototype(true);
24699   Handle<Object> proto = t->GetFunction()->NewInstance();
24700   Handle<Object> object = Object::New(isolate);
24701   Handle<Object> proto2 = Object::New(isolate);
24702   object->SetPrototype(proto);
24703   proto->SetPrototype(proto2);
24704
24705   env->Global()->Set(v8_str("object"), object);
24706   env->Global()->Set(v8_str("proto"), proto);
24707   env->Global()->Set(v8_str("proto2"), proto2);
24708
24709   v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
24710   CHECK(result->Equals(proto2));
24711
24712   result = CompileRun(
24713       "function f() { return %_GetPrototype(object); }"
24714       "%OptimizeFunctionOnNextCall(f);"
24715       "f()");
24716   CHECK(result->Equals(proto2));
24717 }
24718
24719
24720 TEST(ClassPrototypeCreationContext) {
24721   i::FLAG_harmony_classes = true;
24722   v8::Isolate* isolate = CcTest::isolate();
24723   v8::HandleScope handle_scope(isolate);
24724   LocalContext env;
24725
24726   Handle<Object> result = Handle<Object>::Cast(
24727       CompileRun("'use strict'; class Example { }; Example.prototype"));
24728   CHECK(env.local() == result->CreationContext());
24729 }