Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-api.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <climits>
29 #include <csignal>
30 #include <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::Message;
67 using ::v8::MessageCallback;
68 using ::v8::Object;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
71 using ::v8::Script;
72 using ::v8::StackTrace;
73 using ::v8::String;
74 using ::v8::TryCatch;
75 using ::v8::Undefined;
76 using ::v8::UniqueId;
77 using ::v8::V8;
78 using ::v8::Value;
79
80
81 #define THREADED_PROFILED_TEST(Name)                                 \
82   static void Test##Name();                                          \
83   TEST(Name##WithProfiler) {                                         \
84     RunWithProfiler(&Test##Name);                                    \
85   }                                                                  \
86   THREADED_TEST(Name)
87
88
89 void RunWithProfiler(void (*test)()) {
90   LocalContext env;
91   v8::HandleScope scope(env->GetIsolate());
92   v8::Local<v8::String> profile_name =
93       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
95
96   cpu_profiler->StartProfiling(profile_name);
97   (*test)();
98   reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
99 }
100
101
102 static int signature_callback_count;
103 static Local<Value> signature_expected_receiver;
104 static void IncrementingSignatureCallback(
105     const v8::FunctionCallbackInfo<v8::Value>& args) {
106   ApiTestFuzzer::Fuzz();
107   signature_callback_count++;
108   CHECK_EQ(signature_expected_receiver, args.Holder());
109   CHECK_EQ(signature_expected_receiver, args.This());
110   v8::Handle<v8::Array> result =
111       v8::Array::New(args.GetIsolate(), args.Length());
112   for (int i = 0; i < args.Length(); i++)
113     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
114   args.GetReturnValue().Set(result);
115 }
116
117
118 static void SignatureCallback(
119     const v8::FunctionCallbackInfo<v8::Value>& args) {
120   ApiTestFuzzer::Fuzz();
121   v8::Handle<v8::Array> result =
122       v8::Array::New(args.GetIsolate(), args.Length());
123   for (int i = 0; i < args.Length(); i++) {
124     result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
125   }
126   args.GetReturnValue().Set(result);
127 }
128
129
130 // Tests that call v8::V8::Dispose() cannot be threaded.
131 TEST(InitializeAndDisposeOnce) {
132   CHECK(v8::V8::Initialize());
133   CHECK(v8::V8::Dispose());
134 }
135
136
137 // Tests that call v8::V8::Dispose() cannot be threaded.
138 TEST(InitializeAndDisposeMultiple) {
139   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
140   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
141   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142   // TODO(mstarzinger): This should fail gracefully instead of asserting.
143   // for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
144   for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
145 }
146
147
148 THREADED_TEST(Handles) {
149   v8::HandleScope scope(CcTest::isolate());
150   Local<Context> local_env;
151   {
152     LocalContext env;
153     local_env = env.local();
154   }
155
156   // Local context should still be live.
157   CHECK(!local_env.IsEmpty());
158   local_env->Enter();
159
160   v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
161   CHECK(!undef.IsEmpty());
162   CHECK(undef->IsUndefined());
163
164   const char* source = "1 + 2 + 3";
165   Local<Script> script = v8_compile(source);
166   CHECK_EQ(6, script->Run()->Int32Value());
167
168   local_env->Exit();
169 }
170
171
172 THREADED_TEST(IsolateOfContext) {
173   v8::HandleScope scope(CcTest::isolate());
174   v8::Handle<Context> env = Context::New(CcTest::isolate());
175
176   CHECK(!env->GetIsolate()->InContext());
177   CHECK(env->GetIsolate() == CcTest::isolate());
178   env->Enter();
179   CHECK(env->GetIsolate()->InContext());
180   CHECK(env->GetIsolate() == CcTest::isolate());
181   env->Exit();
182   CHECK(!env->GetIsolate()->InContext());
183   CHECK(env->GetIsolate() == CcTest::isolate());
184 }
185
186
187 static void TestSignature(const char* loop_js, Local<Value> receiver) {
188   i::ScopedVector<char> source(200);
189   i::SNPrintF(source,
190               "for (var i = 0; i < 10; i++) {"
191               "  %s"
192               "}",
193               loop_js);
194   signature_callback_count = 0;
195   signature_expected_receiver = receiver;
196   bool expected_to_throw = receiver.IsEmpty();
197   v8::TryCatch try_catch;
198   CompileRun(source.start());
199   CHECK_EQ(expected_to_throw, try_catch.HasCaught());
200   if (!expected_to_throw) {
201     CHECK_EQ(10, signature_callback_count);
202   } else {
203     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
204              try_catch.Exception()->ToString());
205   }
206 }
207
208
209 THREADED_TEST(ReceiverSignature) {
210   LocalContext env;
211   v8::Isolate* isolate = env->GetIsolate();
212   v8::HandleScope scope(isolate);
213   // Setup templates.
214   v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
215   v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
216   v8::Handle<v8::FunctionTemplate> callback_sig =
217       v8::FunctionTemplate::New(
218           isolate, IncrementingSignatureCallback, Local<Value>(), sig);
219   v8::Handle<v8::FunctionTemplate> callback =
220       v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
221   v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
222   sub_fun->Inherit(fun);
223   v8::Handle<v8::FunctionTemplate> unrel_fun =
224       v8::FunctionTemplate::New(isolate);
225   // Install properties.
226   v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
227   fun_proto->Set(v8_str("prop_sig"), callback_sig);
228   fun_proto->Set(v8_str("prop"), callback);
229   fun_proto->SetAccessorProperty(
230       v8_str("accessor_sig"), callback_sig, callback_sig);
231   fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
232   // Instantiate templates.
233   Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
234   Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
235   // Setup global variables.
236   env->Global()->Set(v8_str("Fun"), fun->GetFunction());
237   env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
238   env->Global()->Set(v8_str("fun_instance"), fun_instance);
239   env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
240   CompileRun(
241       "var accessor_sig_key = 'accessor_sig';"
242       "var accessor_key = 'accessor';"
243       "var prop_sig_key = 'prop_sig';"
244       "var prop_key = 'prop';"
245       ""
246       "function copy_props(obj) {"
247       "  var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
248       "  var source = Fun.prototype;"
249       "  for (var i in keys) {"
250       "    var key = keys[i];"
251       "    var desc = Object.getOwnPropertyDescriptor(source, key);"
252       "    Object.defineProperty(obj, key, desc);"
253       "  }"
254       "}"
255       ""
256       "var obj = {};"
257       "copy_props(obj);"
258       "var unrel = new UnrelFun();"
259       "copy_props(unrel);");
260   // Test with and without ICs
261   const char* test_objects[] = {
262       "fun_instance", "sub_fun_instance", "obj", "unrel" };
263   unsigned bad_signature_start_offset = 2;
264   for (unsigned i = 0; i < ARRAY_SIZE(test_objects); i++) {
265     i::ScopedVector<char> source(200);
266     i::SNPrintF(
267         source, "var test_object = %s; test_object", test_objects[i]);
268     Local<Value> test_object = CompileRun(source.start());
269     TestSignature("test_object.prop();", test_object);
270     TestSignature("test_object.accessor;", test_object);
271     TestSignature("test_object[accessor_key];", test_object);
272     TestSignature("test_object.accessor = 1;", test_object);
273     TestSignature("test_object[accessor_key] = 1;", test_object);
274     if (i >= bad_signature_start_offset) test_object = Local<Value>();
275     TestSignature("test_object.prop_sig();", test_object);
276     TestSignature("test_object.accessor_sig;", test_object);
277     TestSignature("test_object[accessor_sig_key];", test_object);
278     TestSignature("test_object.accessor_sig = 1;", test_object);
279     TestSignature("test_object[accessor_sig_key] = 1;", test_object);
280   }
281 }
282
283
284 THREADED_TEST(ArgumentSignature) {
285   LocalContext env;
286   v8::Isolate* isolate = env->GetIsolate();
287   v8::HandleScope scope(isolate);
288   v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
289   cons->SetClassName(v8_str("Cons"));
290   v8::Handle<v8::Signature> sig = v8::Signature::New(
291       isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
292   v8::Handle<v8::FunctionTemplate> fun =
293       v8::FunctionTemplate::New(isolate,
294                                 SignatureCallback,
295                                 v8::Handle<Value>(),
296                                 sig);
297   env->Global()->Set(v8_str("Cons"), cons->GetFunction());
298   env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
299
300   v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
301   CHECK(value1->IsTrue());
302
303   v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
304   CHECK(value2->IsTrue());
305
306   v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
307   CHECK(value3->IsTrue());
308
309   v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
310   cons1->SetClassName(v8_str("Cons1"));
311   v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
312   cons2->SetClassName(v8_str("Cons2"));
313   v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
314   cons3->SetClassName(v8_str("Cons3"));
315
316   v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
317   v8::Handle<v8::Signature> wsig = v8::Signature::New(
318       isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
319   v8::Handle<v8::FunctionTemplate> fun2 =
320       v8::FunctionTemplate::New(isolate,
321                                 SignatureCallback,
322                                 v8::Handle<Value>(),
323                                 wsig);
324
325   env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
326   env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
327   env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
328   env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
329   v8::Handle<Value> value4 = CompileRun(
330       "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
331       "'[object Cons1],[object Cons2],[object Cons3]'");
332   CHECK(value4->IsTrue());
333
334   v8::Handle<Value> value5 = CompileRun(
335       "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
336   CHECK(value5->IsTrue());
337
338   v8::Handle<Value> value6 = CompileRun(
339       "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
340   CHECK(value6->IsTrue());
341
342   v8::Handle<Value> value7 = CompileRun(
343       "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
344       "'[object Cons1],[object Cons2],[object Cons3],d';");
345   CHECK(value7->IsTrue());
346
347   v8::Handle<Value> value8 = CompileRun(
348       "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
349   CHECK(value8->IsTrue());
350 }
351
352
353 THREADED_TEST(HulIgennem) {
354   LocalContext env;
355   v8::Isolate* isolate = env->GetIsolate();
356   v8::HandleScope scope(isolate);
357   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
358   Local<String> undef_str = undef->ToString();
359   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
360   undef_str->WriteUtf8(value);
361   CHECK_EQ(0, strcmp(value, "undefined"));
362   i::DeleteArray(value);
363 }
364
365
366 THREADED_TEST(Access) {
367   LocalContext env;
368   v8::Isolate* isolate = env->GetIsolate();
369   v8::HandleScope scope(isolate);
370   Local<v8::Object> obj = v8::Object::New(isolate);
371   Local<Value> foo_before = obj->Get(v8_str("foo"));
372   CHECK(foo_before->IsUndefined());
373   Local<String> bar_str = v8_str("bar");
374   obj->Set(v8_str("foo"), bar_str);
375   Local<Value> foo_after = obj->Get(v8_str("foo"));
376   CHECK(!foo_after->IsUndefined());
377   CHECK(foo_after->IsString());
378   CHECK_EQ(bar_str, foo_after);
379 }
380
381
382 THREADED_TEST(AccessElement) {
383   LocalContext env;
384   v8::HandleScope scope(env->GetIsolate());
385   Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
386   Local<Value> before = obj->Get(1);
387   CHECK(before->IsUndefined());
388   Local<String> bar_str = v8_str("bar");
389   obj->Set(1, bar_str);
390   Local<Value> after = obj->Get(1);
391   CHECK(!after->IsUndefined());
392   CHECK(after->IsString());
393   CHECK_EQ(bar_str, after);
394
395   Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
396   CHECK_EQ(v8_str("a"), value->Get(0));
397   CHECK_EQ(v8_str("b"), value->Get(1));
398 }
399
400
401 THREADED_TEST(Script) {
402   LocalContext env;
403   v8::HandleScope scope(env->GetIsolate());
404   const char* source = "1 + 2 + 3";
405   Local<Script> script = v8_compile(source);
406   CHECK_EQ(6, script->Run()->Int32Value());
407 }
408
409
410 class TestResource: public String::ExternalStringResource {
411  public:
412   explicit TestResource(uint16_t* data, int* counter = NULL,
413                         bool owning_data = true)
414       : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
415     while (data[length_]) ++length_;
416   }
417
418   ~TestResource() {
419     if (owning_data_) i::DeleteArray(data_);
420     if (counter_ != NULL) ++*counter_;
421   }
422
423   const uint16_t* data() const {
424     return data_;
425   }
426
427   size_t length() const {
428     return length_;
429   }
430
431  private:
432   uint16_t* data_;
433   size_t length_;
434   int* counter_;
435   bool owning_data_;
436 };
437
438
439 class TestAsciiResource: public String::ExternalAsciiStringResource {
440  public:
441   explicit TestAsciiResource(const char* data, int* counter = NULL,
442                              size_t offset = 0)
443       : orig_data_(data),
444         data_(data + offset),
445         length_(strlen(data) - offset),
446         counter_(counter) {}
447
448   ~TestAsciiResource() {
449     i::DeleteArray(orig_data_);
450     if (counter_ != NULL) ++*counter_;
451   }
452
453   const char* data() const {
454     return data_;
455   }
456
457   size_t length() const {
458     return length_;
459   }
460
461  private:
462   const char* orig_data_;
463   const char* data_;
464   size_t length_;
465   int* counter_;
466 };
467
468
469 THREADED_TEST(ScriptUsingStringResource) {
470   int dispose_count = 0;
471   const char* c_source = "1 + 2 * 3";
472   uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
473   {
474     LocalContext env;
475     v8::HandleScope scope(env->GetIsolate());
476     TestResource* resource = new TestResource(two_byte_source, &dispose_count);
477     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
478     Local<Script> script = v8_compile(source);
479     Local<Value> value = script->Run();
480     CHECK(value->IsNumber());
481     CHECK_EQ(7, value->Int32Value());
482     CHECK(source->IsExternal());
483     CHECK_EQ(resource,
484              static_cast<TestResource*>(source->GetExternalStringResource()));
485     String::Encoding encoding = String::UNKNOWN_ENCODING;
486     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
487              source->GetExternalStringResourceBase(&encoding));
488     CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
489     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
490     CHECK_EQ(0, dispose_count);
491   }
492   CcTest::i_isolate()->compilation_cache()->Clear();
493   CcTest::heap()->CollectAllAvailableGarbage();
494   CHECK_EQ(1, dispose_count);
495 }
496
497
498 THREADED_TEST(ScriptUsingAsciiStringResource) {
499   int dispose_count = 0;
500   const char* c_source = "1 + 2 * 3";
501   {
502     LocalContext env;
503     v8::HandleScope scope(env->GetIsolate());
504     TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
505                                                         &dispose_count);
506     Local<String> source = String::NewExternal(env->GetIsolate(), resource);
507     CHECK(source->IsExternalAscii());
508     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
509              source->GetExternalAsciiStringResource());
510     String::Encoding encoding = String::UNKNOWN_ENCODING;
511     CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
512              source->GetExternalStringResourceBase(&encoding));
513     CHECK_EQ(String::ASCII_ENCODING, encoding);
514     Local<Script> script = v8_compile(source);
515     Local<Value> value = script->Run();
516     CHECK(value->IsNumber());
517     CHECK_EQ(7, value->Int32Value());
518     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
519     CHECK_EQ(0, dispose_count);
520   }
521   CcTest::i_isolate()->compilation_cache()->Clear();
522   CcTest::heap()->CollectAllAvailableGarbage();
523   CHECK_EQ(1, dispose_count);
524 }
525
526
527 THREADED_TEST(ScriptMakingExternalString) {
528   int dispose_count = 0;
529   uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
530   {
531     LocalContext env;
532     v8::HandleScope scope(env->GetIsolate());
533     Local<String> source =
534         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
535     // Trigger GCs so that the newly allocated string moves to old gen.
536     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
537     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
538     CHECK_EQ(source->IsExternal(), false);
539     CHECK_EQ(source->IsExternalAscii(), false);
540     String::Encoding encoding = String::UNKNOWN_ENCODING;
541     CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
542     CHECK_EQ(String::ASCII_ENCODING, encoding);
543     bool success = source->MakeExternal(new TestResource(two_byte_source,
544                                                          &dispose_count));
545     CHECK(success);
546     Local<Script> script = v8_compile(source);
547     Local<Value> value = script->Run();
548     CHECK(value->IsNumber());
549     CHECK_EQ(7, value->Int32Value());
550     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
551     CHECK_EQ(0, dispose_count);
552   }
553   CcTest::i_isolate()->compilation_cache()->Clear();
554   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
555   CHECK_EQ(1, dispose_count);
556 }
557
558
559 THREADED_TEST(ScriptMakingExternalAsciiString) {
560   int dispose_count = 0;
561   const char* c_source = "1 + 2 * 3";
562   {
563     LocalContext env;
564     v8::HandleScope scope(env->GetIsolate());
565     Local<String> source = v8_str(c_source);
566     // Trigger GCs so that the newly allocated string moves to old gen.
567     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
568     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
569     bool success = source->MakeExternal(
570         new TestAsciiResource(i::StrDup(c_source), &dispose_count));
571     CHECK(success);
572     Local<Script> script = v8_compile(source);
573     Local<Value> value = script->Run();
574     CHECK(value->IsNumber());
575     CHECK_EQ(7, value->Int32Value());
576     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
577     CHECK_EQ(0, dispose_count);
578   }
579   CcTest::i_isolate()->compilation_cache()->Clear();
580   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
581   CHECK_EQ(1, dispose_count);
582 }
583
584
585 TEST(MakingExternalStringConditions) {
586   LocalContext env;
587   v8::HandleScope scope(env->GetIsolate());
588
589   // Free some space in the new space so that we can check freshness.
590   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
591   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592
593   uint16_t* two_byte_string = AsciiToTwoByteString("s1");
594   Local<String> small_string =
595       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
596   i::DeleteArray(two_byte_string);
597
598   // We should refuse to externalize newly created small string.
599   CHECK(!small_string->CanMakeExternal());
600   // Trigger GCs so that the newly allocated string moves to old gen.
601   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
602   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
603   // Old space strings should be accepted.
604   CHECK(small_string->CanMakeExternal());
605
606   two_byte_string = AsciiToTwoByteString("small string 2");
607   small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
608   i::DeleteArray(two_byte_string);
609
610   // We should refuse externalizing newly created small string.
611   CHECK(!small_string->CanMakeExternal());
612   for (int i = 0; i < 100; i++) {
613     String::Value value(small_string);
614   }
615   // Frequently used strings should be accepted.
616   CHECK(small_string->CanMakeExternal());
617
618   const int buf_size = 10 * 1024;
619   char* buf = i::NewArray<char>(buf_size);
620   memset(buf, 'a', buf_size);
621   buf[buf_size - 1] = '\0';
622
623   two_byte_string = AsciiToTwoByteString(buf);
624   Local<String> large_string =
625       String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
626   i::DeleteArray(buf);
627   i::DeleteArray(two_byte_string);
628   // Large strings should be immediately accepted.
629   CHECK(large_string->CanMakeExternal());
630 }
631
632
633 TEST(MakingExternalAsciiStringConditions) {
634   LocalContext env;
635   v8::HandleScope scope(env->GetIsolate());
636
637   // Free some space in the new space so that we can check freshness.
638   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
639   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640
641   Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
642   // We should refuse to externalize newly created small string.
643   CHECK(!small_string->CanMakeExternal());
644   // Trigger GCs so that the newly allocated string moves to old gen.
645   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
646   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
647   // Old space strings should be accepted.
648   CHECK(small_string->CanMakeExternal());
649
650   small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
651   // We should refuse externalizing newly created small string.
652   CHECK(!small_string->CanMakeExternal());
653   for (int i = 0; i < 100; i++) {
654     String::Value value(small_string);
655   }
656   // Frequently used strings should be accepted.
657   CHECK(small_string->CanMakeExternal());
658
659   const int buf_size = 10 * 1024;
660   char* buf = i::NewArray<char>(buf_size);
661   memset(buf, 'a', buf_size);
662   buf[buf_size - 1] = '\0';
663   Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
664   i::DeleteArray(buf);
665   // Large strings should be immediately accepted.
666   CHECK(large_string->CanMakeExternal());
667 }
668
669
670 TEST(MakingExternalUnalignedAsciiString) {
671   LocalContext env;
672   v8::HandleScope scope(env->GetIsolate());
673
674   CompileRun("function cons(a, b) { return a + b; }"
675              "function slice(a) { return a.substring(1); }");
676   // Create a cons string that will land in old pointer space.
677   Local<String> cons = Local<String>::Cast(CompileRun(
678       "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
679   // Create a sliced string that will land in old pointer space.
680   Local<String> slice = Local<String>::Cast(CompileRun(
681       "slice('abcdefghijklmnopqrstuvwxyz');"));
682
683   // Trigger GCs so that the newly allocated string moves to old gen.
684   SimulateFullSpace(CcTest::heap()->old_pointer_space());
685   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
686   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
687
688   // Turn into external string with unaligned resource data.
689   const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
690   bool success = cons->MakeExternal(
691       new TestAsciiResource(i::StrDup(c_cons), NULL, 1));
692   CHECK(success);
693   const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
694   success = slice->MakeExternal(
695       new TestAsciiResource(i::StrDup(c_slice), NULL, 1));
696   CHECK(success);
697
698   // Trigger GCs and force evacuation.
699   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
700   CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
701 }
702
703
704 THREADED_TEST(UsingExternalString) {
705   i::Factory* factory = CcTest::i_isolate()->factory();
706   {
707     v8::HandleScope scope(CcTest::isolate());
708     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
709     Local<String> string = String::NewExternal(
710         CcTest::isolate(), new TestResource(two_byte_string));
711     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
712     // Trigger GCs so that the newly allocated string moves to old gen.
713     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
714     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
715     i::Handle<i::String> isymbol =
716         factory->InternalizeString(istring);
717     CHECK(isymbol->IsInternalizedString());
718   }
719   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
720   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721 }
722
723
724 THREADED_TEST(UsingExternalAsciiString) {
725   i::Factory* factory = CcTest::i_isolate()->factory();
726   {
727     v8::HandleScope scope(CcTest::isolate());
728     const char* one_byte_string = "test string";
729     Local<String> string = String::NewExternal(
730         CcTest::isolate(), new TestAsciiResource(i::StrDup(one_byte_string)));
731     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
732     // Trigger GCs so that the newly allocated string moves to old gen.
733     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
734     CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
735     i::Handle<i::String> isymbol =
736         factory->InternalizeString(istring);
737     CHECK(isymbol->IsInternalizedString());
738   }
739   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
740   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
741 }
742
743
744 THREADED_TEST(ScavengeExternalString) {
745   i::FLAG_stress_compaction = false;
746   i::FLAG_gc_global = false;
747   int dispose_count = 0;
748   bool in_new_space = false;
749   {
750     v8::HandleScope scope(CcTest::isolate());
751     uint16_t* two_byte_string = AsciiToTwoByteString("test string");
752     Local<String> string = String::NewExternal(
753         CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
754     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
755     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
756     in_new_space = CcTest::heap()->InNewSpace(*istring);
757     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
758     CHECK_EQ(0, dispose_count);
759   }
760   CcTest::heap()->CollectGarbage(
761       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
762   CHECK_EQ(1, dispose_count);
763 }
764
765
766 THREADED_TEST(ScavengeExternalAsciiString) {
767   i::FLAG_stress_compaction = false;
768   i::FLAG_gc_global = false;
769   int dispose_count = 0;
770   bool in_new_space = false;
771   {
772     v8::HandleScope scope(CcTest::isolate());
773     const char* one_byte_string = "test string";
774     Local<String> string = String::NewExternal(
775         CcTest::isolate(),
776         new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
777     i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
778     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
779     in_new_space = CcTest::heap()->InNewSpace(*istring);
780     CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
781     CHECK_EQ(0, dispose_count);
782   }
783   CcTest::heap()->CollectGarbage(
784       in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
785   CHECK_EQ(1, dispose_count);
786 }
787
788
789 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
790  public:
791   // Only used by non-threaded tests, so it can use static fields.
792   static int dispose_calls;
793   static int dispose_count;
794
795   TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
796       : TestAsciiResource(data, &dispose_count),
797         dispose_(dispose) { }
798
799   void Dispose() {
800     ++dispose_calls;
801     if (dispose_) delete this;
802   }
803  private:
804   bool dispose_;
805 };
806
807
808 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
809 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
810
811
812 TEST(ExternalStringWithDisposeHandling) {
813   const char* c_source = "1 + 2 * 3";
814
815   // Use a stack allocated external string resource allocated object.
816   TestAsciiResourceWithDisposeControl::dispose_count = 0;
817   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
818   TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
819   {
820     LocalContext env;
821     v8::HandleScope scope(env->GetIsolate());
822     Local<String> source =  String::NewExternal(env->GetIsolate(), &res_stack);
823     Local<Script> script = v8_compile(source);
824     Local<Value> value = script->Run();
825     CHECK(value->IsNumber());
826     CHECK_EQ(7, value->Int32Value());
827     CcTest::heap()->CollectAllAvailableGarbage();
828     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
829   }
830   CcTest::i_isolate()->compilation_cache()->Clear();
831   CcTest::heap()->CollectAllAvailableGarbage();
832   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
833   CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
834
835   // Use a heap allocated external string resource allocated object.
836   TestAsciiResourceWithDisposeControl::dispose_count = 0;
837   TestAsciiResourceWithDisposeControl::dispose_calls = 0;
838   TestAsciiResource* res_heap =
839       new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
840   {
841     LocalContext env;
842     v8::HandleScope scope(env->GetIsolate());
843     Local<String> source =  String::NewExternal(env->GetIsolate(), res_heap);
844     Local<Script> script = v8_compile(source);
845     Local<Value> value = script->Run();
846     CHECK(value->IsNumber());
847     CHECK_EQ(7, value->Int32Value());
848     CcTest::heap()->CollectAllAvailableGarbage();
849     CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
850   }
851   CcTest::i_isolate()->compilation_cache()->Clear();
852   CcTest::heap()->CollectAllAvailableGarbage();
853   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
854   CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
855 }
856
857
858 THREADED_TEST(StringConcat) {
859   {
860     LocalContext env;
861     v8::HandleScope scope(env->GetIsolate());
862     const char* one_byte_string_1 = "function a_times_t";
863     const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
864     const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
865     const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
866     const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
867     const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
868     const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
869     Local<String> left = v8_str(one_byte_string_1);
870
871     uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
872     Local<String> right =
873         String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
874     i::DeleteArray(two_byte_source);
875
876     Local<String> source = String::Concat(left, right);
877     right = String::NewExternal(
878         env->GetIsolate(), new TestAsciiResource(i::StrDup(one_byte_extern_1)));
879     source = String::Concat(source, right);
880     right = String::NewExternal(
881         env->GetIsolate(),
882         new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
883     source = String::Concat(source, right);
884     right = v8_str(one_byte_string_2);
885     source = String::Concat(source, right);
886
887     two_byte_source = AsciiToTwoByteString(two_byte_string_2);
888     right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
889     i::DeleteArray(two_byte_source);
890
891     source = String::Concat(source, right);
892     right = String::NewExternal(
893         env->GetIsolate(),
894         new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
895     source = String::Concat(source, right);
896     Local<Script> script = v8_compile(source);
897     Local<Value> value = script->Run();
898     CHECK(value->IsNumber());
899     CHECK_EQ(68, value->Int32Value());
900   }
901   CcTest::i_isolate()->compilation_cache()->Clear();
902   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
903   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
904 }
905
906
907 THREADED_TEST(GlobalProperties) {
908   LocalContext env;
909   v8::HandleScope scope(env->GetIsolate());
910   v8::Handle<v8::Object> global = env->Global();
911   global->Set(v8_str("pi"), v8_num(3.1415926));
912   Local<Value> pi = global->Get(v8_str("pi"));
913   CHECK_EQ(3.1415926, pi->NumberValue());
914 }
915
916
917 template<typename T>
918 static void CheckReturnValue(const T& t, i::Address callback) {
919   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
920   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
921   CHECK_EQ(CcTest::isolate(), t.GetIsolate());
922   CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
923   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
924   // Verify reset
925   bool is_runtime = (*o)->IsTheHole();
926   rv.Set(true);
927   CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
928   rv.Set(v8::Handle<v8::Object>());
929   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
930   CHECK_EQ(is_runtime, (*o)->IsTheHole());
931
932   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
933   // If CPU profiler is active check that when API callback is invoked
934   // VMState is set to EXTERNAL.
935   if (isolate->cpu_profiler()->is_profiling()) {
936     CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
937     CHECK(isolate->external_callback_scope());
938     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
939   }
940 }
941
942
943 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
944                                  i::Address callback) {
945   ApiTestFuzzer::Fuzz();
946   CheckReturnValue(info, callback);
947   info.GetReturnValue().Set(v8_str("bad value"));
948   info.GetReturnValue().Set(v8_num(102));
949 }
950
951
952 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
953   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
954 }
955
956
957 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
958   return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
959 }
960
961 static void construct_callback(
962     const v8::FunctionCallbackInfo<Value>& info) {
963   ApiTestFuzzer::Fuzz();
964   CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
965   info.This()->Set(v8_str("x"), v8_num(1));
966   info.This()->Set(v8_str("y"), v8_num(2));
967   info.GetReturnValue().Set(v8_str("bad value"));
968   info.GetReturnValue().Set(info.This());
969 }
970
971
972 static void Return239Callback(
973     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
974   ApiTestFuzzer::Fuzz();
975   CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
976   info.GetReturnValue().Set(v8_str("bad value"));
977   info.GetReturnValue().Set(v8_num(239));
978 }
979
980
981 template<typename Handler>
982 static void TestFunctionTemplateInitializer(Handler handler,
983                                             Handler handler_2) {
984   // Test constructor calls.
985   {
986     LocalContext env;
987     v8::Isolate* isolate = env->GetIsolate();
988     v8::HandleScope scope(isolate);
989
990     Local<v8::FunctionTemplate> fun_templ =
991         v8::FunctionTemplate::New(isolate, handler);
992     Local<Function> fun = fun_templ->GetFunction();
993     env->Global()->Set(v8_str("obj"), fun);
994     Local<Script> script = v8_compile("obj()");
995     for (int i = 0; i < 30; i++) {
996       CHECK_EQ(102, script->Run()->Int32Value());
997     }
998   }
999   // Use SetCallHandler to initialize a function template, should work like
1000   // the previous one.
1001   {
1002     LocalContext env;
1003     v8::Isolate* isolate = env->GetIsolate();
1004     v8::HandleScope scope(isolate);
1005
1006     Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1007     fun_templ->SetCallHandler(handler_2);
1008     Local<Function> fun = fun_templ->GetFunction();
1009     env->Global()->Set(v8_str("obj"), fun);
1010     Local<Script> script = v8_compile("obj()");
1011     for (int i = 0; i < 30; i++) {
1012       CHECK_EQ(102, script->Run()->Int32Value());
1013     }
1014   }
1015 }
1016
1017
1018 template<typename Constructor, typename Accessor>
1019 static void TestFunctionTemplateAccessor(Constructor constructor,
1020                                          Accessor accessor) {
1021   LocalContext env;
1022   v8::HandleScope scope(env->GetIsolate());
1023
1024   Local<v8::FunctionTemplate> fun_templ =
1025       v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1026   fun_templ->SetClassName(v8_str("funky"));
1027   fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1028   Local<Function> fun = fun_templ->GetFunction();
1029   env->Global()->Set(v8_str("obj"), fun);
1030   Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1031   CHECK_EQ(v8_str("[object funky]"), result);
1032   CompileRun("var obj_instance = new obj();");
1033   Local<Script> script;
1034   script = v8_compile("obj_instance.x");
1035   for (int i = 0; i < 30; i++) {
1036     CHECK_EQ(1, script->Run()->Int32Value());
1037   }
1038   script = v8_compile("obj_instance.m");
1039   for (int i = 0; i < 30; i++) {
1040     CHECK_EQ(239, script->Run()->Int32Value());
1041   }
1042 }
1043
1044
1045 THREADED_PROFILED_TEST(FunctionTemplate) {
1046   TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1047   TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1048 }
1049
1050
1051 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1052   ApiTestFuzzer::Fuzz();
1053   CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1054   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1055 }
1056
1057
1058 template<typename Callback>
1059 static void TestSimpleCallback(Callback callback) {
1060   LocalContext env;
1061   v8::Isolate* isolate = env->GetIsolate();
1062   v8::HandleScope scope(isolate);
1063
1064   v8::Handle<v8::ObjectTemplate> object_template =
1065       v8::ObjectTemplate::New(isolate);
1066   object_template->Set(isolate, "callback",
1067                        v8::FunctionTemplate::New(isolate, callback));
1068   v8::Local<v8::Object> object = object_template->NewInstance();
1069   (*env)->Global()->Set(v8_str("callback_object"), object);
1070   v8::Handle<v8::Script> script;
1071   script = v8_compile("callback_object.callback(17)");
1072   for (int i = 0; i < 30; i++) {
1073     CHECK_EQ(51424, script->Run()->Int32Value());
1074   }
1075   script = v8_compile("callback_object.callback(17, 24)");
1076   for (int i = 0; i < 30; i++) {
1077     CHECK_EQ(51425, script->Run()->Int32Value());
1078   }
1079 }
1080
1081
1082 THREADED_PROFILED_TEST(SimpleCallback) {
1083   TestSimpleCallback(SimpleCallback);
1084 }
1085
1086
1087 template<typename T>
1088 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1089
1090 // constant return values
1091 static int32_t fast_return_value_int32 = 471;
1092 static uint32_t fast_return_value_uint32 = 571;
1093 static const double kFastReturnValueDouble = 2.7;
1094 // variable return values
1095 static bool fast_return_value_bool = false;
1096 enum ReturnValueOddball {
1097   kNullReturnValue,
1098   kUndefinedReturnValue,
1099   kEmptyStringReturnValue
1100 };
1101 static ReturnValueOddball fast_return_value_void;
1102 static bool fast_return_value_object_is_empty = false;
1103
1104 // Helper function to avoid compiler error: insufficient contextual information
1105 // to determine type when applying FUNCTION_ADDR to a template function.
1106 static i::Address address_of(v8::FunctionCallback callback) {
1107   return FUNCTION_ADDR(callback);
1108 }
1109
1110 template<>
1111 void FastReturnValueCallback<int32_t>(
1112     const v8::FunctionCallbackInfo<v8::Value>& info) {
1113   CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1114   info.GetReturnValue().Set(fast_return_value_int32);
1115 }
1116
1117 template<>
1118 void FastReturnValueCallback<uint32_t>(
1119     const v8::FunctionCallbackInfo<v8::Value>& info) {
1120   CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1121   info.GetReturnValue().Set(fast_return_value_uint32);
1122 }
1123
1124 template<>
1125 void FastReturnValueCallback<double>(
1126     const v8::FunctionCallbackInfo<v8::Value>& info) {
1127   CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1128   info.GetReturnValue().Set(kFastReturnValueDouble);
1129 }
1130
1131 template<>
1132 void FastReturnValueCallback<bool>(
1133     const v8::FunctionCallbackInfo<v8::Value>& info) {
1134   CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1135   info.GetReturnValue().Set(fast_return_value_bool);
1136 }
1137
1138 template<>
1139 void FastReturnValueCallback<void>(
1140     const v8::FunctionCallbackInfo<v8::Value>& info) {
1141   CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1142   switch (fast_return_value_void) {
1143     case kNullReturnValue:
1144       info.GetReturnValue().SetNull();
1145       break;
1146     case kUndefinedReturnValue:
1147       info.GetReturnValue().SetUndefined();
1148       break;
1149     case kEmptyStringReturnValue:
1150       info.GetReturnValue().SetEmptyString();
1151       break;
1152   }
1153 }
1154
1155 template<>
1156 void FastReturnValueCallback<Object>(
1157     const v8::FunctionCallbackInfo<v8::Value>& info) {
1158   v8::Handle<v8::Object> object;
1159   if (!fast_return_value_object_is_empty) {
1160     object = Object::New(info.GetIsolate());
1161   }
1162   info.GetReturnValue().Set(object);
1163 }
1164
1165 template<typename T>
1166 Handle<Value> TestFastReturnValues() {
1167   LocalContext env;
1168   v8::Isolate* isolate = env->GetIsolate();
1169   v8::EscapableHandleScope scope(isolate);
1170   v8::Handle<v8::ObjectTemplate> object_template =
1171       v8::ObjectTemplate::New(isolate);
1172   v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1173   object_template->Set(isolate, "callback",
1174                        v8::FunctionTemplate::New(isolate, callback));
1175   v8::Local<v8::Object> object = object_template->NewInstance();
1176   (*env)->Global()->Set(v8_str("callback_object"), object);
1177   return scope.Escape(CompileRun("callback_object.callback()"));
1178 }
1179
1180
1181 THREADED_PROFILED_TEST(FastReturnValues) {
1182   LocalContext env;
1183   v8::HandleScope scope(CcTest::isolate());
1184   v8::Handle<v8::Value> value;
1185   // check int32_t and uint32_t
1186   int32_t int_values[] = {
1187       0, 234, -723,
1188       i::Smi::kMinValue, i::Smi::kMaxValue
1189   };
1190   for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1191     for (int modifier = -1; modifier <= 1; modifier++) {
1192       int int_value = int_values[i] + modifier;
1193       // check int32_t
1194       fast_return_value_int32 = int_value;
1195       value = TestFastReturnValues<int32_t>();
1196       CHECK(value->IsInt32());
1197       CHECK(fast_return_value_int32 == value->Int32Value());
1198       // check uint32_t
1199       fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1200       value = TestFastReturnValues<uint32_t>();
1201       CHECK(value->IsUint32());
1202       CHECK(fast_return_value_uint32 == value->Uint32Value());
1203     }
1204   }
1205   // check double
1206   value = TestFastReturnValues<double>();
1207   CHECK(value->IsNumber());
1208   CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1209   // check bool values
1210   for (int i = 0; i < 2; i++) {
1211     fast_return_value_bool = i == 0;
1212     value = TestFastReturnValues<bool>();
1213     CHECK(value->IsBoolean());
1214     CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1215   }
1216   // check oddballs
1217   ReturnValueOddball oddballs[] = {
1218       kNullReturnValue,
1219       kUndefinedReturnValue,
1220       kEmptyStringReturnValue
1221   };
1222   for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1223     fast_return_value_void = oddballs[i];
1224     value = TestFastReturnValues<void>();
1225     switch (fast_return_value_void) {
1226       case kNullReturnValue:
1227         CHECK(value->IsNull());
1228         break;
1229       case kUndefinedReturnValue:
1230         CHECK(value->IsUndefined());
1231         break;
1232       case kEmptyStringReturnValue:
1233         CHECK(value->IsString());
1234         CHECK_EQ(0, v8::String::Cast(*value)->Length());
1235         break;
1236     }
1237   }
1238   // check handles
1239   fast_return_value_object_is_empty = false;
1240   value = TestFastReturnValues<Object>();
1241   CHECK(value->IsObject());
1242   fast_return_value_object_is_empty = true;
1243   value = TestFastReturnValues<Object>();
1244   CHECK(value->IsUndefined());
1245 }
1246
1247
1248 THREADED_TEST(FunctionTemplateSetLength) {
1249   LocalContext env;
1250   v8::Isolate* isolate = env->GetIsolate();
1251   v8::HandleScope scope(isolate);
1252   {
1253     Local<v8::FunctionTemplate> fun_templ =
1254         v8::FunctionTemplate::New(isolate,
1255                                   handle_callback,
1256                                   Handle<v8::Value>(),
1257                                   Handle<v8::Signature>(),
1258                                   23);
1259     Local<Function> fun = fun_templ->GetFunction();
1260     env->Global()->Set(v8_str("obj"), fun);
1261     Local<Script> script = v8_compile("obj.length");
1262     CHECK_EQ(23, script->Run()->Int32Value());
1263   }
1264   {
1265     Local<v8::FunctionTemplate> fun_templ =
1266         v8::FunctionTemplate::New(isolate, handle_callback);
1267     fun_templ->SetLength(22);
1268     Local<Function> fun = fun_templ->GetFunction();
1269     env->Global()->Set(v8_str("obj"), fun);
1270     Local<Script> script = v8_compile("obj.length");
1271     CHECK_EQ(22, script->Run()->Int32Value());
1272   }
1273   {
1274     // Without setting length it defaults to 0.
1275     Local<v8::FunctionTemplate> fun_templ =
1276         v8::FunctionTemplate::New(isolate, handle_callback);
1277     Local<Function> fun = fun_templ->GetFunction();
1278     env->Global()->Set(v8_str("obj"), fun);
1279     Local<Script> script = v8_compile("obj.length");
1280     CHECK_EQ(0, script->Run()->Int32Value());
1281   }
1282 }
1283
1284
1285 static void* expected_ptr;
1286 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1287   void* ptr = v8::External::Cast(*args.Data())->Value();
1288   CHECK_EQ(expected_ptr, ptr);
1289   args.GetReturnValue().Set(true);
1290 }
1291
1292
1293 static void TestExternalPointerWrapping() {
1294   LocalContext env;
1295   v8::Isolate* isolate = env->GetIsolate();
1296   v8::HandleScope scope(isolate);
1297
1298   v8::Handle<v8::Value> data =
1299       v8::External::New(isolate, expected_ptr);
1300
1301   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1302   obj->Set(v8_str("func"),
1303            v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1304   env->Global()->Set(v8_str("obj"), obj);
1305
1306   CHECK(CompileRun(
1307         "function foo() {\n"
1308         "  for (var i = 0; i < 13; i++) obj.func();\n"
1309         "}\n"
1310         "foo(), true")->BooleanValue());
1311 }
1312
1313
1314 THREADED_TEST(ExternalWrap) {
1315   // Check heap allocated object.
1316   int* ptr = new int;
1317   expected_ptr = ptr;
1318   TestExternalPointerWrapping();
1319   delete ptr;
1320
1321   // Check stack allocated object.
1322   int foo;
1323   expected_ptr = &foo;
1324   TestExternalPointerWrapping();
1325
1326   // Check not aligned addresses.
1327   const int n = 100;
1328   char* s = new char[n];
1329   for (int i = 0; i < n; i++) {
1330     expected_ptr = s + i;
1331     TestExternalPointerWrapping();
1332   }
1333
1334   delete[] s;
1335
1336   // Check several invalid addresses.
1337   expected_ptr = reinterpret_cast<void*>(1);
1338   TestExternalPointerWrapping();
1339
1340   expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1341   TestExternalPointerWrapping();
1342
1343   expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1344   TestExternalPointerWrapping();
1345
1346 #if defined(V8_HOST_ARCH_X64)
1347   // Check a value with a leading 1 bit in x64 Smi encoding.
1348   expected_ptr = reinterpret_cast<void*>(0x400000000);
1349   TestExternalPointerWrapping();
1350
1351   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1352   TestExternalPointerWrapping();
1353
1354   expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1355   TestExternalPointerWrapping();
1356 #endif
1357 }
1358
1359
1360 THREADED_TEST(FindInstanceInPrototypeChain) {
1361   LocalContext env;
1362   v8::Isolate* isolate = env->GetIsolate();
1363   v8::HandleScope scope(isolate);
1364
1365   Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1366   Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1367   Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1368   derived->Inherit(base);
1369
1370   Local<v8::Function> base_function = base->GetFunction();
1371   Local<v8::Function> derived_function = derived->GetFunction();
1372   Local<v8::Function> other_function = other->GetFunction();
1373
1374   Local<v8::Object> base_instance = base_function->NewInstance();
1375   Local<v8::Object> derived_instance = derived_function->NewInstance();
1376   Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1377   Local<v8::Object> other_instance = other_function->NewInstance();
1378   derived_instance2->Set(v8_str("__proto__"), derived_instance);
1379   other_instance->Set(v8_str("__proto__"), derived_instance2);
1380
1381   // base_instance is only an instance of base.
1382   CHECK_EQ(base_instance,
1383            base_instance->FindInstanceInPrototypeChain(base));
1384   CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1385   CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1386
1387   // derived_instance is an instance of base and derived.
1388   CHECK_EQ(derived_instance,
1389            derived_instance->FindInstanceInPrototypeChain(base));
1390   CHECK_EQ(derived_instance,
1391            derived_instance->FindInstanceInPrototypeChain(derived));
1392   CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1393
1394   // other_instance is an instance of other and its immediate
1395   // prototype derived_instance2 is an instance of base and derived.
1396   // Note, derived_instance is an instance of base and derived too,
1397   // but it comes after derived_instance2 in the prototype chain of
1398   // other_instance.
1399   CHECK_EQ(derived_instance2,
1400            other_instance->FindInstanceInPrototypeChain(base));
1401   CHECK_EQ(derived_instance2,
1402            other_instance->FindInstanceInPrototypeChain(derived));
1403   CHECK_EQ(other_instance,
1404            other_instance->FindInstanceInPrototypeChain(other));
1405 }
1406
1407
1408 THREADED_TEST(TinyInteger) {
1409   LocalContext env;
1410   v8::Isolate* isolate = env->GetIsolate();
1411   v8::HandleScope scope(isolate);
1412
1413   int32_t value = 239;
1414   Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1415   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1416
1417   value_obj = v8::Integer::New(isolate, value);
1418   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1419 }
1420
1421
1422 THREADED_TEST(BigSmiInteger) {
1423   LocalContext env;
1424   v8::HandleScope scope(env->GetIsolate());
1425   v8::Isolate* isolate = CcTest::isolate();
1426
1427   int32_t value = i::Smi::kMaxValue;
1428   // We cannot add one to a Smi::kMaxValue without wrapping.
1429   if (i::SmiValuesAre31Bits()) {
1430     CHECK(i::Smi::IsValid(value));
1431     CHECK(!i::Smi::IsValid(value + 1));
1432
1433     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1434     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1435
1436     value_obj = v8::Integer::New(isolate, value);
1437     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1438   }
1439 }
1440
1441
1442 THREADED_TEST(BigInteger) {
1443   LocalContext env;
1444   v8::HandleScope scope(env->GetIsolate());
1445   v8::Isolate* isolate = CcTest::isolate();
1446
1447   // We cannot add one to a Smi::kMaxValue without wrapping.
1448   if (i::SmiValuesAre31Bits()) {
1449     // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1450     // The code will not be run in that case, due to the "if" guard.
1451     int32_t value =
1452         static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1453     CHECK(value > i::Smi::kMaxValue);
1454     CHECK(!i::Smi::IsValid(value));
1455
1456     Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1457     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1458
1459     value_obj = v8::Integer::New(isolate, value);
1460     CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1461   }
1462 }
1463
1464
1465 THREADED_TEST(TinyUnsignedInteger) {
1466   LocalContext env;
1467   v8::HandleScope scope(env->GetIsolate());
1468   v8::Isolate* isolate = CcTest::isolate();
1469
1470   uint32_t value = 239;
1471
1472   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1473   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1474
1475   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1476   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1477 }
1478
1479
1480 THREADED_TEST(BigUnsignedSmiInteger) {
1481   LocalContext env;
1482   v8::HandleScope scope(env->GetIsolate());
1483   v8::Isolate* isolate = CcTest::isolate();
1484
1485   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1486   CHECK(i::Smi::IsValid(value));
1487   CHECK(!i::Smi::IsValid(value + 1));
1488
1489   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1490   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1491
1492   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1493   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1494 }
1495
1496
1497 THREADED_TEST(BigUnsignedInteger) {
1498   LocalContext env;
1499   v8::HandleScope scope(env->GetIsolate());
1500   v8::Isolate* isolate = CcTest::isolate();
1501
1502   uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1503   CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1504   CHECK(!i::Smi::IsValid(value));
1505
1506   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1507   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1508
1509   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1510   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1511 }
1512
1513
1514 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1515   LocalContext env;
1516   v8::HandleScope scope(env->GetIsolate());
1517   v8::Isolate* isolate = CcTest::isolate();
1518
1519   uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1520   uint32_t value = INT32_MAX_AS_UINT + 1;
1521   CHECK(value > INT32_MAX_AS_UINT);  // No overflow.
1522
1523   Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1525
1526   value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1527   CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1528 }
1529
1530
1531 THREADED_TEST(IsNativeError) {
1532   LocalContext env;
1533   v8::HandleScope scope(env->GetIsolate());
1534   v8::Handle<Value> syntax_error = CompileRun(
1535       "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1536   CHECK(syntax_error->IsNativeError());
1537   v8::Handle<Value> not_error = CompileRun("{a:42}");
1538   CHECK(!not_error->IsNativeError());
1539   v8::Handle<Value> not_object = CompileRun("42");
1540   CHECK(!not_object->IsNativeError());
1541 }
1542
1543
1544 THREADED_TEST(StringObject) {
1545   LocalContext env;
1546   v8::HandleScope scope(env->GetIsolate());
1547   v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1548   CHECK(boxed_string->IsStringObject());
1549   v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1550   CHECK(!unboxed_string->IsStringObject());
1551   v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1552   CHECK(!boxed_not_string->IsStringObject());
1553   v8::Handle<Value> not_object = CompileRun("0");
1554   CHECK(!not_object->IsStringObject());
1555   v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1556   CHECK(!as_boxed.IsEmpty());
1557   Local<v8::String> the_string = as_boxed->ValueOf();
1558   CHECK(!the_string.IsEmpty());
1559   ExpectObject("\"test\"", the_string);
1560   v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1561   CHECK(new_boxed_string->IsStringObject());
1562   as_boxed = new_boxed_string.As<v8::StringObject>();
1563   the_string = as_boxed->ValueOf();
1564   CHECK(!the_string.IsEmpty());
1565   ExpectObject("\"test\"", the_string);
1566 }
1567
1568
1569 THREADED_TEST(NumberObject) {
1570   LocalContext env;
1571   v8::HandleScope scope(env->GetIsolate());
1572   v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1573   CHECK(boxed_number->IsNumberObject());
1574   v8::Handle<Value> unboxed_number = CompileRun("42");
1575   CHECK(!unboxed_number->IsNumberObject());
1576   v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1577   CHECK(!boxed_not_number->IsNumberObject());
1578   v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1579   CHECK(!as_boxed.IsEmpty());
1580   double the_number = as_boxed->ValueOf();
1581   CHECK_EQ(42.0, the_number);
1582   v8::Handle<v8::Value> new_boxed_number =
1583       v8::NumberObject::New(env->GetIsolate(), 43);
1584   CHECK(new_boxed_number->IsNumberObject());
1585   as_boxed = new_boxed_number.As<v8::NumberObject>();
1586   the_number = as_boxed->ValueOf();
1587   CHECK_EQ(43.0, the_number);
1588 }
1589
1590
1591 THREADED_TEST(BooleanObject) {
1592   LocalContext env;
1593   v8::HandleScope scope(env->GetIsolate());
1594   v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1595   CHECK(boxed_boolean->IsBooleanObject());
1596   v8::Handle<Value> unboxed_boolean = CompileRun("true");
1597   CHECK(!unboxed_boolean->IsBooleanObject());
1598   v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1599   CHECK(!boxed_not_boolean->IsBooleanObject());
1600   v8::Handle<v8::BooleanObject> as_boxed =
1601       boxed_boolean.As<v8::BooleanObject>();
1602   CHECK(!as_boxed.IsEmpty());
1603   bool the_boolean = as_boxed->ValueOf();
1604   CHECK_EQ(true, the_boolean);
1605   v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1606   v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1607   CHECK(boxed_true->IsBooleanObject());
1608   CHECK(boxed_false->IsBooleanObject());
1609   as_boxed = boxed_true.As<v8::BooleanObject>();
1610   CHECK_EQ(true, as_boxed->ValueOf());
1611   as_boxed = boxed_false.As<v8::BooleanObject>();
1612   CHECK_EQ(false, as_boxed->ValueOf());
1613 }
1614
1615
1616 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1617   LocalContext env;
1618   v8::HandleScope scope(env->GetIsolate());
1619
1620   Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1621   CHECK(primitive_false->IsBoolean());
1622   CHECK(!primitive_false->IsBooleanObject());
1623   CHECK(!primitive_false->BooleanValue());
1624   CHECK(!primitive_false->IsTrue());
1625   CHECK(primitive_false->IsFalse());
1626
1627   Local<Value> false_value = BooleanObject::New(false);
1628   CHECK(!false_value->IsBoolean());
1629   CHECK(false_value->IsBooleanObject());
1630   CHECK(false_value->BooleanValue());
1631   CHECK(!false_value->IsTrue());
1632   CHECK(!false_value->IsFalse());
1633
1634   Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1635   CHECK(!false_boolean_object->IsBoolean());
1636   CHECK(false_boolean_object->IsBooleanObject());
1637   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1638   // CHECK(false_boolean_object->BooleanValue());
1639   CHECK(!false_boolean_object->ValueOf());
1640   CHECK(!false_boolean_object->IsTrue());
1641   CHECK(!false_boolean_object->IsFalse());
1642
1643   Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1644   CHECK(primitive_true->IsBoolean());
1645   CHECK(!primitive_true->IsBooleanObject());
1646   CHECK(primitive_true->BooleanValue());
1647   CHECK(primitive_true->IsTrue());
1648   CHECK(!primitive_true->IsFalse());
1649
1650   Local<Value> true_value = BooleanObject::New(true);
1651   CHECK(!true_value->IsBoolean());
1652   CHECK(true_value->IsBooleanObject());
1653   CHECK(true_value->BooleanValue());
1654   CHECK(!true_value->IsTrue());
1655   CHECK(!true_value->IsFalse());
1656
1657   Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1658   CHECK(!true_boolean_object->IsBoolean());
1659   CHECK(true_boolean_object->IsBooleanObject());
1660   // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1661   // CHECK(true_boolean_object->BooleanValue());
1662   CHECK(true_boolean_object->ValueOf());
1663   CHECK(!true_boolean_object->IsTrue());
1664   CHECK(!true_boolean_object->IsFalse());
1665 }
1666
1667
1668 THREADED_TEST(Number) {
1669   LocalContext env;
1670   v8::HandleScope scope(env->GetIsolate());
1671   double PI = 3.1415926;
1672   Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1673   CHECK_EQ(PI, pi_obj->NumberValue());
1674 }
1675
1676
1677 THREADED_TEST(ToNumber) {
1678   LocalContext env;
1679   v8::Isolate* isolate = CcTest::isolate();
1680   v8::HandleScope scope(isolate);
1681   Local<String> str = v8_str("3.1415926");
1682   CHECK_EQ(3.1415926, str->NumberValue());
1683   v8::Handle<v8::Boolean> t = v8::True(isolate);
1684   CHECK_EQ(1.0, t->NumberValue());
1685   v8::Handle<v8::Boolean> f = v8::False(isolate);
1686   CHECK_EQ(0.0, f->NumberValue());
1687 }
1688
1689
1690 THREADED_TEST(Date) {
1691   LocalContext env;
1692   v8::HandleScope scope(env->GetIsolate());
1693   double PI = 3.1415926;
1694   Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1695   CHECK_EQ(3.0, date->NumberValue());
1696   date.As<v8::Date>()->Set(v8_str("property"),
1697                            v8::Integer::New(env->GetIsolate(), 42));
1698   CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1699 }
1700
1701
1702 THREADED_TEST(Boolean) {
1703   LocalContext env;
1704   v8::Isolate* isolate = env->GetIsolate();
1705   v8::HandleScope scope(isolate);
1706   v8::Handle<v8::Boolean> t = v8::True(isolate);
1707   CHECK(t->Value());
1708   v8::Handle<v8::Boolean> f = v8::False(isolate);
1709   CHECK(!f->Value());
1710   v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1711   CHECK(!u->BooleanValue());
1712   v8::Handle<v8::Primitive> n = v8::Null(isolate);
1713   CHECK(!n->BooleanValue());
1714   v8::Handle<String> str1 = v8_str("");
1715   CHECK(!str1->BooleanValue());
1716   v8::Handle<String> str2 = v8_str("x");
1717   CHECK(str2->BooleanValue());
1718   CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1719   CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1720   CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1721   CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1722   CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1723 }
1724
1725
1726 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1727   ApiTestFuzzer::Fuzz();
1728   args.GetReturnValue().Set(v8_num(13.4));
1729 }
1730
1731
1732 static void GetM(Local<String> name,
1733                  const v8::PropertyCallbackInfo<v8::Value>& info) {
1734   ApiTestFuzzer::Fuzz();
1735   info.GetReturnValue().Set(v8_num(876));
1736 }
1737
1738
1739 THREADED_TEST(GlobalPrototype) {
1740   v8::Isolate* isolate = CcTest::isolate();
1741   v8::HandleScope scope(isolate);
1742   v8::Handle<v8::FunctionTemplate> func_templ =
1743       v8::FunctionTemplate::New(isolate);
1744   func_templ->PrototypeTemplate()->Set(
1745       isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1746   v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1747   templ->Set(isolate, "x", v8_num(200));
1748   templ->SetAccessor(v8_str("m"), GetM);
1749   LocalContext env(0, templ);
1750   v8::Handle<Script> script(v8_compile("dummy()"));
1751   v8::Handle<Value> result(script->Run());
1752   CHECK_EQ(13.4, result->NumberValue());
1753   CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1754   CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1755 }
1756
1757
1758 THREADED_TEST(ObjectTemplate) {
1759   v8::Isolate* isolate = CcTest::isolate();
1760   v8::HandleScope scope(isolate);
1761   Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1762   templ1->Set(isolate, "x", v8_num(10));
1763   templ1->Set(isolate, "y", v8_num(13));
1764   LocalContext env;
1765   Local<v8::Object> instance1 = templ1->NewInstance();
1766   env->Global()->Set(v8_str("p"), instance1);
1767   CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1768   CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1769   Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1770   fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1771   Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1772   templ2->Set(isolate, "a", v8_num(12));
1773   templ2->Set(isolate, "b", templ1);
1774   Local<v8::Object> instance2 = templ2->NewInstance();
1775   env->Global()->Set(v8_str("q"), instance2);
1776   CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1777   CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1778   CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1779   CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1780 }
1781
1782
1783 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1784   ApiTestFuzzer::Fuzz();
1785   args.GetReturnValue().Set(v8_num(17.2));
1786 }
1787
1788
1789 static void GetKnurd(Local<String> property,
1790                      const v8::PropertyCallbackInfo<v8::Value>& info) {
1791   ApiTestFuzzer::Fuzz();
1792   info.GetReturnValue().Set(v8_num(15.2));
1793 }
1794
1795
1796 THREADED_TEST(DescriptorInheritance) {
1797   v8::Isolate* isolate = CcTest::isolate();
1798   v8::HandleScope scope(isolate);
1799   v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1800   super->PrototypeTemplate()->Set(isolate, "flabby",
1801                                   v8::FunctionTemplate::New(isolate,
1802                                                             GetFlabby));
1803   super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1804
1805   super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1806
1807   v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1808   base1->Inherit(super);
1809   base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1810
1811   v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1812   base2->Inherit(super);
1813   base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1814
1815   LocalContext env;
1816
1817   env->Global()->Set(v8_str("s"), super->GetFunction());
1818   env->Global()->Set(v8_str("base1"), base1->GetFunction());
1819   env->Global()->Set(v8_str("base2"), base2->GetFunction());
1820
1821   // Checks right __proto__ chain.
1822   CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1823   CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1824
1825   CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1826
1827   // Instance accessor should not be visible on function object or its prototype
1828   CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1829   CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1830   CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1831
1832   env->Global()->Set(v8_str("obj"),
1833                      base1->GetFunction()->NewInstance());
1834   CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1835   CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1836   CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1837   CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1838   CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1839
1840   env->Global()->Set(v8_str("obj2"),
1841                      base2->GetFunction()->NewInstance());
1842   CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1843   CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1844   CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1845   CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1846   CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1847
1848   // base1 and base2 cannot cross reference to each's prototype
1849   CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1850   CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1851 }
1852
1853
1854 int echo_named_call_count;
1855
1856
1857 static void EchoNamedProperty(Local<String> name,
1858                               const v8::PropertyCallbackInfo<v8::Value>& info) {
1859   ApiTestFuzzer::Fuzz();
1860   CHECK_EQ(v8_str("data"), info.Data());
1861   echo_named_call_count++;
1862   info.GetReturnValue().Set(name);
1863 }
1864
1865
1866 // Helper functions for Interceptor/Accessor interaction tests
1867
1868 void SimpleAccessorGetter(Local<String> name,
1869                           const v8::PropertyCallbackInfo<v8::Value>& info) {
1870   Handle<Object> self = Handle<Object>::Cast(info.This());
1871   info.GetReturnValue().Set(
1872       self->Get(String::Concat(v8_str("accessor_"), name)));
1873 }
1874
1875 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1876                           const v8::PropertyCallbackInfo<void>& info) {
1877   Handle<Object> self = Handle<Object>::Cast(info.This());
1878   self->Set(String::Concat(v8_str("accessor_"), name), value);
1879 }
1880
1881 void EmptyInterceptorGetter(Local<String> name,
1882                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1883 }
1884
1885 void EmptyInterceptorSetter(Local<String> name,
1886                             Local<Value> value,
1887                             const v8::PropertyCallbackInfo<v8::Value>& info) {
1888 }
1889
1890 void InterceptorGetter(Local<String> name,
1891                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1892   // Intercept names that start with 'interceptor_'.
1893   String::Utf8Value utf8(name);
1894   char* name_str = *utf8;
1895   char prefix[] = "interceptor_";
1896   int i;
1897   for (i = 0; name_str[i] && prefix[i]; ++i) {
1898     if (name_str[i] != prefix[i]) return;
1899   }
1900   Handle<Object> self = Handle<Object>::Cast(info.This());
1901   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1902 }
1903
1904 void InterceptorSetter(Local<String> name,
1905                        Local<Value> value,
1906                        const v8::PropertyCallbackInfo<v8::Value>& info) {
1907   // Intercept accesses that set certain integer values, for which the name does
1908   // not start with 'accessor_'.
1909   String::Utf8Value utf8(name);
1910   char* name_str = *utf8;
1911   char prefix[] = "accessor_";
1912   int i;
1913   for (i = 0; name_str[i] && prefix[i]; ++i) {
1914     if (name_str[i] != prefix[i]) break;
1915   }
1916   if (!prefix[i]) return;
1917
1918   if (value->IsInt32() && value->Int32Value() < 10000) {
1919     Handle<Object> self = Handle<Object>::Cast(info.This());
1920     self->SetHiddenValue(name, value);
1921     info.GetReturnValue().Set(value);
1922   }
1923 }
1924
1925 void AddAccessor(Handle<FunctionTemplate> templ,
1926                  Handle<String> name,
1927                  v8::AccessorGetterCallback getter,
1928                  v8::AccessorSetterCallback setter) {
1929   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1930 }
1931
1932 void AddInterceptor(Handle<FunctionTemplate> templ,
1933                     v8::NamedPropertyGetterCallback getter,
1934                     v8::NamedPropertySetterCallback setter) {
1935   templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1936 }
1937
1938
1939 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1940   v8::HandleScope scope(CcTest::isolate());
1941   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
1942   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
1943   child->Inherit(parent);
1944   AddAccessor(parent, v8_str("age"),
1945               SimpleAccessorGetter, SimpleAccessorSetter);
1946   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1947   LocalContext env;
1948   env->Global()->Set(v8_str("Child"), child->GetFunction());
1949   CompileRun("var child = new Child;"
1950              "child.age = 10;");
1951   ExpectBoolean("child.hasOwnProperty('age')", false);
1952   ExpectInt32("child.age", 10);
1953   ExpectInt32("child.accessor_age", 10);
1954 }
1955
1956
1957 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1958   v8::Isolate* isolate = CcTest::isolate();
1959   v8::HandleScope scope(isolate);
1960   LocalContext env;
1961   v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1962   i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1963   CHECK(a->map()->instance_descriptors()->IsFixedArray());
1964   CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1965   CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1966   CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1967   // But we should still have an ExecutableAccessorInfo.
1968   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
1969   i::LookupResult lookup(i_isolate);
1970   i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1971   a->LookupOwnRealNamedProperty(name, &lookup);
1972   CHECK(lookup.IsPropertyCallbacks());
1973   i::Handle<i::Object> callback(lookup.GetCallbackObject(), i_isolate);
1974   CHECK(callback->IsExecutableAccessorInfo());
1975 }
1976
1977
1978 THREADED_TEST(EmptyInterceptorBreakTransitions) {
1979   v8::HandleScope scope(CcTest::isolate());
1980   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
1981   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
1982   LocalContext env;
1983   env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
1984   CompileRun("var o1 = new Constructor;"
1985              "o1.a = 1;"  // Ensure a and x share the descriptor array.
1986              "Object.defineProperty(o1, 'x', {value: 10});");
1987   CompileRun("var o2 = new Constructor;"
1988              "o2.a = 1;"
1989              "Object.defineProperty(o2, 'x', {value: 10});");
1990 }
1991
1992
1993 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1994   v8::Isolate* isolate = CcTest::isolate();
1995   v8::HandleScope scope(isolate);
1996   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
1997   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
1998   child->Inherit(parent);
1999   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2000   LocalContext env;
2001   env->Global()->Set(v8_str("Child"), child->GetFunction());
2002   CompileRun("var child = new Child;"
2003              "var parent = child.__proto__;"
2004              "Object.defineProperty(parent, 'age', "
2005              "  {get: function(){ return this.accessor_age; }, "
2006              "   set: function(v){ this.accessor_age = v; }, "
2007              "   enumerable: true, configurable: true});"
2008              "child.age = 10;");
2009   ExpectBoolean("child.hasOwnProperty('age')", false);
2010   ExpectInt32("child.age", 10);
2011   ExpectInt32("child.accessor_age", 10);
2012 }
2013
2014
2015 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2016   v8::Isolate* isolate = CcTest::isolate();
2017   v8::HandleScope scope(isolate);
2018   Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2019   Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2020   child->Inherit(parent);
2021   AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2022   LocalContext env;
2023   env->Global()->Set(v8_str("Child"), child->GetFunction());
2024   CompileRun("var child = new Child;"
2025              "var parent = child.__proto__;"
2026              "parent.name = 'Alice';");
2027   ExpectBoolean("child.hasOwnProperty('name')", false);
2028   ExpectString("child.name", "Alice");
2029   CompileRun("child.name = 'Bob';");
2030   ExpectString("child.name", "Bob");
2031   ExpectBoolean("child.hasOwnProperty('name')", true);
2032   ExpectString("parent.name", "Alice");
2033 }
2034
2035
2036 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2037   v8::HandleScope scope(CcTest::isolate());
2038   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2039   AddAccessor(templ, v8_str("age"),
2040               SimpleAccessorGetter, SimpleAccessorSetter);
2041   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2042   LocalContext env;
2043   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2044   CompileRun("var obj = new Obj;"
2045              "function setAge(i){ obj.age = i; };"
2046              "for(var i = 0; i <= 10000; i++) setAge(i);");
2047   // All i < 10000 go to the interceptor.
2048   ExpectInt32("obj.interceptor_age", 9999);
2049   // The last i goes to the accessor.
2050   ExpectInt32("obj.accessor_age", 10000);
2051 }
2052
2053
2054 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2055   v8::HandleScope scope(CcTest::isolate());
2056   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2057   AddAccessor(templ, v8_str("age"),
2058               SimpleAccessorGetter, SimpleAccessorSetter);
2059   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2060   LocalContext env;
2061   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2062   CompileRun("var obj = new Obj;"
2063              "function setAge(i){ obj.age = i; };"
2064              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2065   // All i >= 10000 go to the accessor.
2066   ExpectInt32("obj.accessor_age", 10000);
2067   // The last i goes to the interceptor.
2068   ExpectInt32("obj.interceptor_age", 9999);
2069 }
2070
2071
2072 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2073   v8::HandleScope scope(CcTest::isolate());
2074   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2075   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2076   child->Inherit(parent);
2077   AddAccessor(parent, v8_str("age"),
2078               SimpleAccessorGetter, SimpleAccessorSetter);
2079   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2080   LocalContext env;
2081   env->Global()->Set(v8_str("Child"), child->GetFunction());
2082   CompileRun("var child = new Child;"
2083              "function setAge(i){ child.age = i; };"
2084              "for(var i = 0; i <= 10000; i++) setAge(i);");
2085   // All i < 10000 go to the interceptor.
2086   ExpectInt32("child.interceptor_age", 9999);
2087   // The last i goes to the accessor.
2088   ExpectInt32("child.accessor_age", 10000);
2089 }
2090
2091
2092 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2093   v8::HandleScope scope(CcTest::isolate());
2094   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2095   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2096   child->Inherit(parent);
2097   AddAccessor(parent, v8_str("age"),
2098               SimpleAccessorGetter, SimpleAccessorSetter);
2099   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2100   LocalContext env;
2101   env->Global()->Set(v8_str("Child"), child->GetFunction());
2102   CompileRun("var child = new Child;"
2103              "function setAge(i){ child.age = i; };"
2104              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2105   // All i >= 10000 go to the accessor.
2106   ExpectInt32("child.accessor_age", 10000);
2107   // The last i goes to the interceptor.
2108   ExpectInt32("child.interceptor_age", 9999);
2109 }
2110
2111
2112 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2113   v8::HandleScope scope(CcTest::isolate());
2114   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2115   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2116   LocalContext env;
2117   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2118   CompileRun("var obj = new Obj;"
2119              "function setter(i) { this.accessor_age = i; };"
2120              "function getter() { return this.accessor_age; };"
2121              "function setAge(i) { obj.age = i; };"
2122              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2123              "for(var i = 0; i <= 10000; i++) setAge(i);");
2124   // All i < 10000 go to the interceptor.
2125   ExpectInt32("obj.interceptor_age", 9999);
2126   // The last i goes to the JavaScript accessor.
2127   ExpectInt32("obj.accessor_age", 10000);
2128   // The installed JavaScript getter is still intact.
2129   // This last part is a regression test for issue 1651 and relies on the fact
2130   // that both interceptor and accessor are being installed on the same object.
2131   ExpectInt32("obj.age", 10000);
2132   ExpectBoolean("obj.hasOwnProperty('age')", true);
2133   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2134 }
2135
2136
2137 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2138   v8::HandleScope scope(CcTest::isolate());
2139   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2140   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2141   LocalContext env;
2142   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2143   CompileRun("var obj = new Obj;"
2144              "function setter(i) { this.accessor_age = i; };"
2145              "function getter() { return this.accessor_age; };"
2146              "function setAge(i) { obj.age = i; };"
2147              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2148              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2149   // All i >= 10000 go to the accessor.
2150   ExpectInt32("obj.accessor_age", 10000);
2151   // The last i goes to the interceptor.
2152   ExpectInt32("obj.interceptor_age", 9999);
2153   // The installed JavaScript getter is still intact.
2154   // This last part is a regression test for issue 1651 and relies on the fact
2155   // that both interceptor and accessor are being installed on the same object.
2156   ExpectInt32("obj.age", 10000);
2157   ExpectBoolean("obj.hasOwnProperty('age')", true);
2158   ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2159 }
2160
2161
2162 THREADED_TEST(SwitchFromInterceptorToProperty) {
2163   v8::HandleScope scope(CcTest::isolate());
2164   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2165   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2166   child->Inherit(parent);
2167   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2168   LocalContext env;
2169   env->Global()->Set(v8_str("Child"), child->GetFunction());
2170   CompileRun("var child = new Child;"
2171              "function setAge(i){ child.age = i; };"
2172              "for(var i = 0; i <= 10000; i++) setAge(i);");
2173   // All i < 10000 go to the interceptor.
2174   ExpectInt32("child.interceptor_age", 9999);
2175   // The last i goes to child's own property.
2176   ExpectInt32("child.age", 10000);
2177 }
2178
2179
2180 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2181   v8::HandleScope scope(CcTest::isolate());
2182   Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2183   Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2184   child->Inherit(parent);
2185   AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2186   LocalContext env;
2187   env->Global()->Set(v8_str("Child"), child->GetFunction());
2188   CompileRun("var child = new Child;"
2189              "function setAge(i){ child.age = i; };"
2190              "for(var i = 20000; i >= 9999; i--) setAge(i);");
2191   // All i >= 10000 go to child's own property.
2192   ExpectInt32("child.age", 10000);
2193   // The last i goes to the interceptor.
2194   ExpectInt32("child.interceptor_age", 9999);
2195 }
2196
2197
2198 THREADED_TEST(NamedPropertyHandlerGetter) {
2199   echo_named_call_count = 0;
2200   v8::HandleScope scope(CcTest::isolate());
2201   v8::Handle<v8::FunctionTemplate> templ =
2202       v8::FunctionTemplate::New(CcTest::isolate());
2203   templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2204                                                      0, 0, 0, 0,
2205                                                      v8_str("data"));
2206   LocalContext env;
2207   env->Global()->Set(v8_str("obj"),
2208                      templ->GetFunction()->NewInstance());
2209   CHECK_EQ(echo_named_call_count, 0);
2210   v8_compile("obj.x")->Run();
2211   CHECK_EQ(echo_named_call_count, 1);
2212   const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2213   v8::Handle<Value> str = CompileRun(code);
2214   String::Utf8Value value(str);
2215   CHECK_EQ(*value, "oddlepoddle");
2216   // Check default behavior
2217   CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2218   CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2219   CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2220 }
2221
2222
2223 int echo_indexed_call_count = 0;
2224
2225
2226 static void EchoIndexedProperty(
2227     uint32_t index,
2228     const v8::PropertyCallbackInfo<v8::Value>& info) {
2229   ApiTestFuzzer::Fuzz();
2230   CHECK_EQ(v8_num(637), info.Data());
2231   echo_indexed_call_count++;
2232   info.GetReturnValue().Set(v8_num(index));
2233 }
2234
2235
2236 THREADED_TEST(IndexedPropertyHandlerGetter) {
2237   v8::Isolate* isolate = CcTest::isolate();
2238   v8::HandleScope scope(isolate);
2239   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2240   templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2241                                                        0, 0, 0, 0,
2242                                                        v8_num(637));
2243   LocalContext env;
2244   env->Global()->Set(v8_str("obj"),
2245                      templ->GetFunction()->NewInstance());
2246   Local<Script> script = v8_compile("obj[900]");
2247   CHECK_EQ(script->Run()->Int32Value(), 900);
2248 }
2249
2250
2251 v8::Handle<v8::Object> bottom;
2252
2253 static void CheckThisIndexedPropertyHandler(
2254     uint32_t index,
2255     const v8::PropertyCallbackInfo<v8::Value>& info) {
2256   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2257   ApiTestFuzzer::Fuzz();
2258   CHECK(info.This()->Equals(bottom));
2259 }
2260
2261 static void CheckThisNamedPropertyHandler(
2262     Local<String> name,
2263     const v8::PropertyCallbackInfo<v8::Value>& info) {
2264   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2265   ApiTestFuzzer::Fuzz();
2266   CHECK(info.This()->Equals(bottom));
2267 }
2268
2269 void CheckThisIndexedPropertySetter(
2270     uint32_t index,
2271     Local<Value> value,
2272     const v8::PropertyCallbackInfo<v8::Value>& info) {
2273   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2274   ApiTestFuzzer::Fuzz();
2275   CHECK(info.This()->Equals(bottom));
2276 }
2277
2278
2279 void CheckThisNamedPropertySetter(
2280     Local<String> property,
2281     Local<Value> value,
2282     const v8::PropertyCallbackInfo<v8::Value>& info) {
2283   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2284   ApiTestFuzzer::Fuzz();
2285   CHECK(info.This()->Equals(bottom));
2286 }
2287
2288 void CheckThisIndexedPropertyQuery(
2289     uint32_t index,
2290     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2291   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2292   ApiTestFuzzer::Fuzz();
2293   CHECK(info.This()->Equals(bottom));
2294 }
2295
2296
2297 void CheckThisNamedPropertyQuery(
2298     Local<String> property,
2299     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2300   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2301   ApiTestFuzzer::Fuzz();
2302   CHECK(info.This()->Equals(bottom));
2303 }
2304
2305
2306 void CheckThisIndexedPropertyDeleter(
2307     uint32_t index,
2308     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2309   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2310   ApiTestFuzzer::Fuzz();
2311   CHECK(info.This()->Equals(bottom));
2312 }
2313
2314
2315 void CheckThisNamedPropertyDeleter(
2316     Local<String> property,
2317     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2318   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2319   ApiTestFuzzer::Fuzz();
2320   CHECK(info.This()->Equals(bottom));
2321 }
2322
2323
2324 void CheckThisIndexedPropertyEnumerator(
2325     const v8::PropertyCallbackInfo<v8::Array>& info) {
2326   CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2327   ApiTestFuzzer::Fuzz();
2328   CHECK(info.This()->Equals(bottom));
2329 }
2330
2331
2332 void CheckThisNamedPropertyEnumerator(
2333     const v8::PropertyCallbackInfo<v8::Array>& info) {
2334   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2335   ApiTestFuzzer::Fuzz();
2336   CHECK(info.This()->Equals(bottom));
2337 }
2338
2339
2340 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2341   LocalContext env;
2342   v8::Isolate* isolate = env->GetIsolate();
2343   v8::HandleScope scope(isolate);
2344
2345   // Set up a prototype chain with three interceptors.
2346   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2347   templ->InstanceTemplate()->SetIndexedPropertyHandler(
2348       CheckThisIndexedPropertyHandler,
2349       CheckThisIndexedPropertySetter,
2350       CheckThisIndexedPropertyQuery,
2351       CheckThisIndexedPropertyDeleter,
2352       CheckThisIndexedPropertyEnumerator);
2353
2354   templ->InstanceTemplate()->SetNamedPropertyHandler(
2355       CheckThisNamedPropertyHandler,
2356       CheckThisNamedPropertySetter,
2357       CheckThisNamedPropertyQuery,
2358       CheckThisNamedPropertyDeleter,
2359       CheckThisNamedPropertyEnumerator);
2360
2361   bottom = templ->GetFunction()->NewInstance();
2362   Local<v8::Object> top = templ->GetFunction()->NewInstance();
2363   Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2364
2365   bottom->SetPrototype(middle);
2366   middle->SetPrototype(top);
2367   env->Global()->Set(v8_str("obj"), bottom);
2368
2369   // Indexed and named get.
2370   CompileRun("obj[0]");
2371   CompileRun("obj.x");
2372
2373   // Indexed and named set.
2374   CompileRun("obj[1] = 42");
2375   CompileRun("obj.y = 42");
2376
2377   // Indexed and named query.
2378   CompileRun("0 in obj");
2379   CompileRun("'x' in obj");
2380
2381   // Indexed and named deleter.
2382   CompileRun("delete obj[0]");
2383   CompileRun("delete obj.x");
2384
2385   // Enumerators.
2386   CompileRun("for (var p in obj) ;");
2387 }
2388
2389
2390 static void PrePropertyHandlerGet(
2391     Local<String> key,
2392     const v8::PropertyCallbackInfo<v8::Value>& info) {
2393   ApiTestFuzzer::Fuzz();
2394   if (v8_str("pre")->Equals(key)) {
2395     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2396   }
2397 }
2398
2399
2400 static void PrePropertyHandlerQuery(
2401     Local<String> key,
2402     const v8::PropertyCallbackInfo<v8::Integer>& info) {
2403   if (v8_str("pre")->Equals(key)) {
2404     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2405   }
2406 }
2407
2408
2409 THREADED_TEST(PrePropertyHandler) {
2410   v8::Isolate* isolate = CcTest::isolate();
2411   v8::HandleScope scope(isolate);
2412   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2413   desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2414                                                     0,
2415                                                     PrePropertyHandlerQuery);
2416   LocalContext env(NULL, desc->InstanceTemplate());
2417   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2418   v8::Handle<Value> result_pre = CompileRun("pre");
2419   CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2420   v8::Handle<Value> result_on = CompileRun("on");
2421   CHECK_EQ(v8_str("Object: on"), result_on);
2422   v8::Handle<Value> result_post = CompileRun("post");
2423   CHECK(result_post.IsEmpty());
2424 }
2425
2426
2427 THREADED_TEST(UndefinedIsNotEnumerable) {
2428   LocalContext env;
2429   v8::HandleScope scope(env->GetIsolate());
2430   v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2431   CHECK(result->IsFalse());
2432 }
2433
2434
2435 v8::Handle<Script> call_recursively_script;
2436 static const int kTargetRecursionDepth = 200;  // near maximum
2437
2438
2439 static void CallScriptRecursivelyCall(
2440     const v8::FunctionCallbackInfo<v8::Value>& args) {
2441   ApiTestFuzzer::Fuzz();
2442   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2443   if (depth == kTargetRecursionDepth) return;
2444   args.This()->Set(v8_str("depth"),
2445                    v8::Integer::New(args.GetIsolate(), depth + 1));
2446   args.GetReturnValue().Set(call_recursively_script->Run());
2447 }
2448
2449
2450 static void CallFunctionRecursivelyCall(
2451     const v8::FunctionCallbackInfo<v8::Value>& args) {
2452   ApiTestFuzzer::Fuzz();
2453   int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2454   if (depth == kTargetRecursionDepth) {
2455     printf("[depth = %d]\n", depth);
2456     return;
2457   }
2458   args.This()->Set(v8_str("depth"),
2459                    v8::Integer::New(args.GetIsolate(), depth + 1));
2460   v8::Handle<Value> function =
2461       args.This()->Get(v8_str("callFunctionRecursively"));
2462   args.GetReturnValue().Set(
2463       function.As<Function>()->Call(args.This(), 0, NULL));
2464 }
2465
2466
2467 THREADED_TEST(DeepCrossLanguageRecursion) {
2468   v8::Isolate* isolate = CcTest::isolate();
2469   v8::HandleScope scope(isolate);
2470   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2471   global->Set(v8_str("callScriptRecursively"),
2472               v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2473   global->Set(v8_str("callFunctionRecursively"),
2474               v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2475   LocalContext env(NULL, global);
2476
2477   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2478   call_recursively_script = v8_compile("callScriptRecursively()");
2479   call_recursively_script->Run();
2480   call_recursively_script = v8::Handle<Script>();
2481
2482   env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2483   CompileRun("callFunctionRecursively()");
2484 }
2485
2486
2487 static void ThrowingPropertyHandlerGet(
2488     Local<String> key,
2489     const v8::PropertyCallbackInfo<v8::Value>& info) {
2490   ApiTestFuzzer::Fuzz();
2491   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2492 }
2493
2494
2495 static void ThrowingPropertyHandlerSet(
2496     Local<String> key,
2497     Local<Value>,
2498     const v8::PropertyCallbackInfo<v8::Value>& info) {
2499   info.GetIsolate()->ThrowException(key);
2500   info.GetReturnValue().SetUndefined();  // not the same as empty handle
2501 }
2502
2503
2504 THREADED_TEST(CallbackExceptionRegression) {
2505   v8::Isolate* isolate = CcTest::isolate();
2506   v8::HandleScope scope(isolate);
2507   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2508   obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2509                                ThrowingPropertyHandlerSet);
2510   LocalContext env;
2511   env->Global()->Set(v8_str("obj"), obj->NewInstance());
2512   v8::Handle<Value> otto = CompileRun(
2513       "try { with (obj) { otto; } } catch (e) { e; }");
2514   CHECK_EQ(v8_str("otto"), otto);
2515   v8::Handle<Value> netto = CompileRun(
2516       "try { with (obj) { netto = 4; } } catch (e) { e; }");
2517   CHECK_EQ(v8_str("netto"), netto);
2518 }
2519
2520
2521 THREADED_TEST(FunctionPrototype) {
2522   v8::Isolate* isolate = CcTest::isolate();
2523   v8::HandleScope scope(isolate);
2524   Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2525   Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2526   LocalContext env;
2527   env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2528   Local<Script> script = v8_compile("Foo.prototype.plak");
2529   CHECK_EQ(script->Run()->Int32Value(), 321);
2530 }
2531
2532
2533 THREADED_TEST(InternalFields) {
2534   LocalContext env;
2535   v8::Isolate* isolate = env->GetIsolate();
2536   v8::HandleScope scope(isolate);
2537
2538   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2539   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2540   instance_templ->SetInternalFieldCount(1);
2541   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2542   CHECK_EQ(1, obj->InternalFieldCount());
2543   CHECK(obj->GetInternalField(0)->IsUndefined());
2544   obj->SetInternalField(0, v8_num(17));
2545   CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2546 }
2547
2548
2549 THREADED_TEST(GlobalObjectInternalFields) {
2550   v8::Isolate* isolate = CcTest::isolate();
2551   v8::HandleScope scope(isolate);
2552   Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2553   global_template->SetInternalFieldCount(1);
2554   LocalContext env(NULL, global_template);
2555   v8::Handle<v8::Object> global_proxy = env->Global();
2556   v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2557   CHECK_EQ(1, global->InternalFieldCount());
2558   CHECK(global->GetInternalField(0)->IsUndefined());
2559   global->SetInternalField(0, v8_num(17));
2560   CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2561 }
2562
2563
2564 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2565   LocalContext env;
2566   v8::HandleScope scope(CcTest::isolate());
2567
2568   v8::Local<v8::Object> global = env->Global();
2569   global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2570   CHECK(global->HasRealIndexedProperty(0));
2571 }
2572
2573
2574 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2575                                                void* value) {
2576   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2577   obj->SetAlignedPointerInInternalField(0, value);
2578   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2579   CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2580 }
2581
2582
2583 THREADED_TEST(InternalFieldsAlignedPointers) {
2584   LocalContext env;
2585   v8::Isolate* isolate = env->GetIsolate();
2586   v8::HandleScope scope(isolate);
2587
2588   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2589   Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2590   instance_templ->SetInternalFieldCount(1);
2591   Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2592   CHECK_EQ(1, obj->InternalFieldCount());
2593
2594   CheckAlignedPointerInInternalField(obj, NULL);
2595
2596   int* heap_allocated = new int[100];
2597   CheckAlignedPointerInInternalField(obj, heap_allocated);
2598   delete[] heap_allocated;
2599
2600   int stack_allocated[100];
2601   CheckAlignedPointerInInternalField(obj, stack_allocated);
2602
2603   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2604   CheckAlignedPointerInInternalField(obj, huge);
2605
2606   v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2607   CHECK_EQ(1, Object::InternalFieldCount(persistent));
2608   CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2609 }
2610
2611
2612 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2613                                               int index,
2614                                               void* value) {
2615   CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2616   (*env)->SetAlignedPointerInEmbedderData(index, value);
2617   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2618   CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2619 }
2620
2621
2622 static void* AlignedTestPointer(int i) {
2623   return reinterpret_cast<void*>(i * 1234);
2624 }
2625
2626
2627 THREADED_TEST(EmbedderDataAlignedPointers) {
2628   LocalContext env;
2629   v8::HandleScope scope(env->GetIsolate());
2630
2631   CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2632
2633   int* heap_allocated = new int[100];
2634   CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2635   delete[] heap_allocated;
2636
2637   int stack_allocated[100];
2638   CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2639
2640   void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2641   CheckAlignedPointerInEmbedderData(&env, 3, huge);
2642
2643   // Test growing of the embedder data's backing store.
2644   for (int i = 0; i < 100; i++) {
2645     env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2646   }
2647   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2648   for (int i = 0; i < 100; i++) {
2649     CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2650   }
2651 }
2652
2653
2654 static void CheckEmbedderData(LocalContext* env,
2655                               int index,
2656                               v8::Handle<Value> data) {
2657   (*env)->SetEmbedderData(index, data);
2658   CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2659 }
2660
2661
2662 THREADED_TEST(EmbedderData) {
2663   LocalContext env;
2664   v8::Isolate* isolate = env->GetIsolate();
2665   v8::HandleScope scope(isolate);
2666
2667   CheckEmbedderData(
2668       &env, 3,
2669       v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2670   CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2671                                                      "over the lazy dog."));
2672   CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2673   CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2674 }
2675
2676
2677 THREADED_TEST(IdentityHash) {
2678   LocalContext env;
2679   v8::Isolate* isolate = env->GetIsolate();
2680   v8::HandleScope scope(isolate);
2681
2682   // Ensure that the test starts with an fresh heap to test whether the hash
2683   // code is based on the address.
2684   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2685   Local<v8::Object> obj = v8::Object::New(isolate);
2686   int hash = obj->GetIdentityHash();
2687   int hash1 = obj->GetIdentityHash();
2688   CHECK_EQ(hash, hash1);
2689   int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2690   // Since the identity hash is essentially a random number two consecutive
2691   // objects should not be assigned the same hash code. If the test below fails
2692   // the random number generator should be evaluated.
2693   CHECK_NE(hash, hash2);
2694   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2695   int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2696   // Make sure that the identity hash is not based on the initial address of
2697   // the object alone. If the test below fails the random number generator
2698   // should be evaluated.
2699   CHECK_NE(hash, hash3);
2700   int hash4 = obj->GetIdentityHash();
2701   CHECK_EQ(hash, hash4);
2702
2703   // Check identity hashes behaviour in the presence of JS accessors.
2704   // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2705   {
2706     CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2707     Local<v8::Object> o1 = v8::Object::New(isolate);
2708     Local<v8::Object> o2 = v8::Object::New(isolate);
2709     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2710   }
2711   {
2712     CompileRun(
2713         "function cnst() { return 42; };\n"
2714         "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2715     Local<v8::Object> o1 = v8::Object::New(isolate);
2716     Local<v8::Object> o2 = v8::Object::New(isolate);
2717     CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2718   }
2719 }
2720
2721
2722 THREADED_TEST(GlobalProxyIdentityHash) {
2723   LocalContext env;
2724   v8::Isolate* isolate = env->GetIsolate();
2725   v8::HandleScope scope(isolate);
2726   Handle<Object> global_proxy = env->Global();
2727   int hash1 = global_proxy->GetIdentityHash();
2728   // Hash should be retained after being detached.
2729   env->DetachGlobal();
2730   int hash2 = global_proxy->GetIdentityHash();
2731   CHECK_EQ(hash1, hash2);
2732   {
2733     // Re-attach global proxy to a new context, hash should stay the same.
2734     LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2735     int hash3 = global_proxy->GetIdentityHash();
2736     CHECK_EQ(hash1, hash3);
2737   }
2738 }
2739
2740
2741 THREADED_TEST(SymbolProperties) {
2742   LocalContext env;
2743   v8::Isolate* isolate = env->GetIsolate();
2744   v8::HandleScope scope(isolate);
2745
2746   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2747   v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2748   v8::Local<v8::Symbol> sym2 =
2749       v8::Symbol::New(isolate, v8_str("my-symbol"));
2750
2751   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2752
2753   // Check basic symbol functionality.
2754   CHECK(sym1->IsSymbol());
2755   CHECK(sym2->IsSymbol());
2756   CHECK(!obj->IsSymbol());
2757
2758   CHECK(sym1->Equals(sym1));
2759   CHECK(sym2->Equals(sym2));
2760   CHECK(!sym1->Equals(sym2));
2761   CHECK(!sym2->Equals(sym1));
2762   CHECK(sym1->StrictEquals(sym1));
2763   CHECK(sym2->StrictEquals(sym2));
2764   CHECK(!sym1->StrictEquals(sym2));
2765   CHECK(!sym2->StrictEquals(sym1));
2766
2767   CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2768
2769   v8::Local<v8::Value> sym_val = sym2;
2770   CHECK(sym_val->IsSymbol());
2771   CHECK(sym_val->Equals(sym2));
2772   CHECK(sym_val->StrictEquals(sym2));
2773   CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2774
2775   v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2776   CHECK(sym_obj->IsSymbolObject());
2777   CHECK(!sym2->IsSymbolObject());
2778   CHECK(!obj->IsSymbolObject());
2779   CHECK(!sym_obj->Equals(sym2));
2780   CHECK(!sym_obj->StrictEquals(sym2));
2781   CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2782   CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2783
2784   // Make sure delete of a non-existent symbol property works.
2785   CHECK(obj->Delete(sym1));
2786   CHECK(!obj->Has(sym1));
2787
2788   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2789   CHECK(obj->Has(sym1));
2790   CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2791   CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2792   CHECK(obj->Has(sym1));
2793   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2794   CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2795
2796   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2797   int num_props = obj->GetPropertyNames()->Length();
2798   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2799                  v8::Integer::New(isolate, 20)));
2800   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2801   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2802
2803   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2804
2805   // Add another property and delete it afterwards to force the object in
2806   // slow case.
2807   CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2808   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2809   CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2810   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2811   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2812
2813   CHECK(obj->Has(sym1));
2814   CHECK(obj->Has(sym2));
2815   CHECK(obj->Delete(sym2));
2816   CHECK(obj->Has(sym1));
2817   CHECK(!obj->Has(sym2));
2818   CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2819   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2820
2821   // Symbol properties are inherited.
2822   v8::Local<v8::Object> child = v8::Object::New(isolate);
2823   child->SetPrototype(obj);
2824   CHECK(child->Has(sym1));
2825   CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2826   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2827 }
2828
2829
2830 THREADED_TEST(PrivateProperties) {
2831   LocalContext env;
2832   v8::Isolate* isolate = env->GetIsolate();
2833   v8::HandleScope scope(isolate);
2834
2835   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2836   v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2837   v8::Local<v8::Private> priv2 =
2838       v8::Private::New(isolate, v8_str("my-private"));
2839
2840   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2841
2842   CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2843
2844   // Make sure delete of a non-existent private symbol property works.
2845   CHECK(obj->DeletePrivate(priv1));
2846   CHECK(!obj->HasPrivate(priv1));
2847
2848   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2849   CHECK(obj->HasPrivate(priv1));
2850   CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2851   CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2852   CHECK(obj->HasPrivate(priv1));
2853   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2854
2855   CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2856   int num_props = obj->GetPropertyNames()->Length();
2857   CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2858                  v8::Integer::New(isolate, 20)));
2859   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2860   CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2861
2862   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2863
2864   // Add another property and delete it afterwards to force the object in
2865   // slow case.
2866   CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2867   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2868   CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2869   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2870   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2871
2872   CHECK(obj->HasPrivate(priv1));
2873   CHECK(obj->HasPrivate(priv2));
2874   CHECK(obj->DeletePrivate(priv2));
2875   CHECK(obj->HasPrivate(priv1));
2876   CHECK(!obj->HasPrivate(priv2));
2877   CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2878   CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2879
2880   // Private properties are inherited (for the time being).
2881   v8::Local<v8::Object> child = v8::Object::New(isolate);
2882   child->SetPrototype(obj);
2883   CHECK(child->HasPrivate(priv1));
2884   CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2885   CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
2886 }
2887
2888
2889 THREADED_TEST(GlobalSymbols) {
2890   LocalContext env;
2891   v8::Isolate* isolate = env->GetIsolate();
2892   v8::HandleScope scope(isolate);
2893
2894   v8::Local<String> name = v8_str("my-symbol");
2895   v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2896   v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2897   CHECK(glob2->SameValue(glob));
2898
2899   v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2900   v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2901   CHECK(glob_api2->SameValue(glob_api));
2902   CHECK(!glob_api->SameValue(glob));
2903
2904   v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2905   CHECK(!sym->SameValue(glob));
2906
2907   CompileRun("var sym2 = Symbol.for('my-symbol')");
2908   v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2909   CHECK(sym2->SameValue(glob));
2910   CHECK(!sym2->SameValue(glob_api));
2911 }
2912
2913
2914 THREADED_TEST(GlobalPrivates) {
2915   LocalContext env;
2916   v8::Isolate* isolate = env->GetIsolate();
2917   v8::HandleScope scope(isolate);
2918
2919   v8::Local<String> name = v8_str("my-private");
2920   v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2921   v8::Local<v8::Object> obj = v8::Object::New(isolate);
2922   CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2923
2924   v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2925   CHECK(obj->HasPrivate(glob2));
2926
2927   v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2928   CHECK(!obj->HasPrivate(priv));
2929
2930   CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2931   v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2932   CHECK(!obj->Has(intern));
2933 }
2934
2935
2936 class ScopedArrayBufferContents {
2937  public:
2938   explicit ScopedArrayBufferContents(
2939       const v8::ArrayBuffer::Contents& contents)
2940     : contents_(contents) {}
2941   ~ScopedArrayBufferContents() { free(contents_.Data()); }
2942   void* Data() const { return contents_.Data(); }
2943   size_t ByteLength() const { return contents_.ByteLength(); }
2944  private:
2945   const v8::ArrayBuffer::Contents contents_;
2946 };
2947
2948 template <typename T>
2949 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2950   CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2951   for (int i = 0; i < value->InternalFieldCount(); i++) {
2952     CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2953   }
2954 }
2955
2956
2957 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2958   LocalContext env;
2959   v8::Isolate* isolate = env->GetIsolate();
2960   v8::HandleScope handle_scope(isolate);
2961
2962   Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2963   CheckInternalFieldsAreZero(ab);
2964   CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2965   CHECK(!ab->IsExternal());
2966   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2967
2968   ScopedArrayBufferContents ab_contents(ab->Externalize());
2969   CHECK(ab->IsExternal());
2970
2971   CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2972   uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2973   DCHECK(data != NULL);
2974   env->Global()->Set(v8_str("ab"), ab);
2975
2976   v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2977   CHECK_EQ(1024, result->Int32Value());
2978
2979   result = CompileRun("var u8 = new Uint8Array(ab);"
2980                       "u8[0] = 0xFF;"
2981                       "u8[1] = 0xAA;"
2982                       "u8.length");
2983   CHECK_EQ(1024, result->Int32Value());
2984   CHECK_EQ(0xFF, data[0]);
2985   CHECK_EQ(0xAA, data[1]);
2986   data[0] = 0xCC;
2987   data[1] = 0x11;
2988   result = CompileRun("u8[0] + u8[1]");
2989   CHECK_EQ(0xDD, result->Int32Value());
2990 }
2991
2992
2993 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2994   LocalContext env;
2995   v8::Isolate* isolate = env->GetIsolate();
2996   v8::HandleScope handle_scope(isolate);
2997
2998
2999   v8::Local<v8::Value> result =
3000       CompileRun("var ab1 = new ArrayBuffer(2);"
3001                  "var u8_a = new Uint8Array(ab1);"
3002                  "u8_a[0] = 0xAA;"
3003                  "u8_a[1] = 0xFF; u8_a.buffer");
3004   Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3005   CheckInternalFieldsAreZero(ab1);
3006   CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3007   CHECK(!ab1->IsExternal());
3008   ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3009   CHECK(ab1->IsExternal());
3010
3011   result = CompileRun("ab1.byteLength");
3012   CHECK_EQ(2, result->Int32Value());
3013   result = CompileRun("u8_a[0]");
3014   CHECK_EQ(0xAA, result->Int32Value());
3015   result = CompileRun("u8_a[1]");
3016   CHECK_EQ(0xFF, result->Int32Value());
3017   result = CompileRun("var u8_b = new Uint8Array(ab1);"
3018                       "u8_b[0] = 0xBB;"
3019                       "u8_a[0]");
3020   CHECK_EQ(0xBB, result->Int32Value());
3021   result = CompileRun("u8_b[1]");
3022   CHECK_EQ(0xFF, result->Int32Value());
3023
3024   CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3025   uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3026   CHECK_EQ(0xBB, ab1_data[0]);
3027   CHECK_EQ(0xFF, ab1_data[1]);
3028   ab1_data[0] = 0xCC;
3029   ab1_data[1] = 0x11;
3030   result = CompileRun("u8_a[0] + u8_a[1]");
3031   CHECK_EQ(0xDD, result->Int32Value());
3032 }
3033
3034
3035 THREADED_TEST(ArrayBuffer_External) {
3036   LocalContext env;
3037   v8::Isolate* isolate = env->GetIsolate();
3038   v8::HandleScope handle_scope(isolate);
3039
3040   i::ScopedVector<uint8_t> my_data(100);
3041   memset(my_data.start(), 0, 100);
3042   Local<v8::ArrayBuffer> ab3 =
3043       v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3044   CheckInternalFieldsAreZero(ab3);
3045   CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3046   CHECK(ab3->IsExternal());
3047
3048   env->Global()->Set(v8_str("ab3"), ab3);
3049
3050   v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3051   CHECK_EQ(100, result->Int32Value());
3052
3053   result = CompileRun("var u8_b = new Uint8Array(ab3);"
3054                       "u8_b[0] = 0xBB;"
3055                       "u8_b[1] = 0xCC;"
3056                       "u8_b.length");
3057   CHECK_EQ(100, result->Int32Value());
3058   CHECK_EQ(0xBB, my_data[0]);
3059   CHECK_EQ(0xCC, my_data[1]);
3060   my_data[0] = 0xCC;
3061   my_data[1] = 0x11;
3062   result = CompileRun("u8_b[0] + u8_b[1]");
3063   CHECK_EQ(0xDD, result->Int32Value());
3064 }
3065
3066
3067 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3068   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3069   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3070 }
3071
3072
3073 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3074   CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3075   CHECK_EQ(0, static_cast<int>(ta->Length()));
3076   CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3077 }
3078
3079
3080 static void CheckIsTypedArrayVarNeutered(const char* name) {
3081   i::ScopedVector<char> source(1024);
3082   i::SNPrintF(source,
3083       "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3084       name, name, name);
3085   CHECK(CompileRun(source.start())->IsTrue());
3086   v8::Handle<v8::TypedArray> ta =
3087     v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3088   CheckIsNeutered(ta);
3089 }
3090
3091
3092 template <typename TypedArray, int kElementSize>
3093 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3094                                          int byteOffset,
3095                                          int length) {
3096   v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3097   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3098   CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3099   CHECK_EQ(length, static_cast<int>(ta->Length()));
3100   CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3101   return ta;
3102 }
3103
3104
3105 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3106   LocalContext env;
3107   v8::Isolate* isolate = env->GetIsolate();
3108   v8::HandleScope handle_scope(isolate);
3109
3110   v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3111
3112   v8::Handle<v8::Uint8Array> u8a =
3113     CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3114   v8::Handle<v8::Uint8ClampedArray> u8c =
3115     CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3116   v8::Handle<v8::Int8Array> i8a =
3117     CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3118
3119   v8::Handle<v8::Uint16Array> u16a =
3120     CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3121   v8::Handle<v8::Int16Array> i16a =
3122     CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3123
3124   v8::Handle<v8::Uint32Array> u32a =
3125     CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3126   v8::Handle<v8::Int32Array> i32a =
3127     CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3128
3129   v8::Handle<v8::Float32Array> f32a =
3130     CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3131   v8::Handle<v8::Float64Array> f64a =
3132     CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3133
3134   v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3135   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3136   CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3137   CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3138
3139   ScopedArrayBufferContents contents(buffer->Externalize());
3140   buffer->Neuter();
3141   CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3142   CheckIsNeutered(u8a);
3143   CheckIsNeutered(u8c);
3144   CheckIsNeutered(i8a);
3145   CheckIsNeutered(u16a);
3146   CheckIsNeutered(i16a);
3147   CheckIsNeutered(u32a);
3148   CheckIsNeutered(i32a);
3149   CheckIsNeutered(f32a);
3150   CheckIsNeutered(f64a);
3151   CheckDataViewIsNeutered(dv);
3152 }
3153
3154
3155 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3156   LocalContext env;
3157   v8::Isolate* isolate = env->GetIsolate();
3158   v8::HandleScope handle_scope(isolate);
3159
3160   CompileRun(
3161       "var ab = new ArrayBuffer(1024);"
3162       "var u8a = new Uint8Array(ab, 1, 1023);"
3163       "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3164       "var i8a = new Int8Array(ab, 1, 1023);"
3165       "var u16a = new Uint16Array(ab, 2, 511);"
3166       "var i16a = new Int16Array(ab, 2, 511);"
3167       "var u32a = new Uint32Array(ab, 4, 255);"
3168       "var i32a = new Int32Array(ab, 4, 255);"
3169       "var f32a = new Float32Array(ab, 4, 255);"
3170       "var f64a = new Float64Array(ab, 8, 127);"
3171       "var dv = new DataView(ab, 1, 1023);");
3172
3173   v8::Handle<v8::ArrayBuffer> ab =
3174       Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3175
3176   v8::Handle<v8::DataView> dv =
3177     v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3178
3179   ScopedArrayBufferContents contents(ab->Externalize());
3180   ab->Neuter();
3181   CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3182   CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3183
3184   CheckIsTypedArrayVarNeutered("u8a");
3185   CheckIsTypedArrayVarNeutered("u8c");
3186   CheckIsTypedArrayVarNeutered("i8a");
3187   CheckIsTypedArrayVarNeutered("u16a");
3188   CheckIsTypedArrayVarNeutered("i16a");
3189   CheckIsTypedArrayVarNeutered("u32a");
3190   CheckIsTypedArrayVarNeutered("i32a");
3191   CheckIsTypedArrayVarNeutered("f32a");
3192   CheckIsTypedArrayVarNeutered("f64a");
3193
3194   CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3195   CheckDataViewIsNeutered(dv);
3196 }
3197
3198
3199
3200 THREADED_TEST(HiddenProperties) {
3201   LocalContext env;
3202   v8::Isolate* isolate = env->GetIsolate();
3203   v8::HandleScope scope(isolate);
3204
3205   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3206   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3207   v8::Local<v8::String> empty = v8_str("");
3208   v8::Local<v8::String> prop_name = v8_str("prop_name");
3209
3210   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3211
3212   // Make sure delete of a non-existent hidden value works
3213   CHECK(obj->DeleteHiddenValue(key));
3214
3215   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3216   CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3217   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3218   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3219
3220   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3221
3222   // Make sure we do not find the hidden property.
3223   CHECK(!obj->Has(empty));
3224   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3225   CHECK(obj->Get(empty)->IsUndefined());
3226   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3227   CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3228   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3229   CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3230
3231   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3232
3233   // Add another property and delete it afterwards to force the object in
3234   // slow case.
3235   CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3236   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3237   CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3238   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3239   CHECK(obj->Delete(prop_name));
3240   CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3241
3242   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3243
3244   CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3245   CHECK(obj->GetHiddenValue(key).IsEmpty());
3246
3247   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3248   CHECK(obj->DeleteHiddenValue(key));
3249   CHECK(obj->GetHiddenValue(key).IsEmpty());
3250 }
3251
3252
3253 THREADED_TEST(Regress97784) {
3254   // Regression test for crbug.com/97784
3255   // Messing with the Object.prototype should not have effect on
3256   // hidden properties.
3257   LocalContext env;
3258   v8::HandleScope scope(env->GetIsolate());
3259
3260   v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3261   v8::Local<v8::String> key = v8_str("hidden");
3262
3263   CompileRun(
3264       "set_called = false;"
3265       "Object.defineProperty("
3266       "    Object.prototype,"
3267       "    'hidden',"
3268       "    {get: function() { return 45; },"
3269       "     set: function() { set_called = true; }})");
3270
3271   CHECK(obj->GetHiddenValue(key).IsEmpty());
3272   // Make sure that the getter and setter from Object.prototype is not invoked.
3273   // If it did we would have full access to the hidden properties in
3274   // the accessor.
3275   CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3276   ExpectFalse("set_called");
3277   CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3278 }
3279
3280
3281 static bool interceptor_for_hidden_properties_called;
3282 static void InterceptorForHiddenProperties(
3283     Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3284   interceptor_for_hidden_properties_called = true;
3285 }
3286
3287
3288 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3289   LocalContext context;
3290   v8::Isolate* isolate = context->GetIsolate();
3291   v8::HandleScope scope(isolate);
3292
3293   interceptor_for_hidden_properties_called = false;
3294
3295   v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3296
3297   // Associate an interceptor with an object and start setting hidden values.
3298   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3299   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3300   instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3301   Local<v8::Function> function = fun_templ->GetFunction();
3302   Local<v8::Object> obj = function->NewInstance();
3303   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3304   CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3305   CHECK(!interceptor_for_hidden_properties_called);
3306 }
3307
3308
3309 THREADED_TEST(External) {
3310   v8::HandleScope scope(CcTest::isolate());
3311   int x = 3;
3312   Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3313   LocalContext env;
3314   env->Global()->Set(v8_str("ext"), ext);
3315   Local<Value> reext_obj = CompileRun("this.ext");
3316   v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3317   int* ptr = static_cast<int*>(reext->Value());
3318   CHECK_EQ(x, 3);
3319   *ptr = 10;
3320   CHECK_EQ(x, 10);
3321
3322   // Make sure unaligned pointers are wrapped properly.
3323   char* data = i::StrDup("0123456789");
3324   Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3325   Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3326   Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3327   Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3328
3329   char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3330   CHECK_EQ('0', *char_ptr);
3331   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3332   CHECK_EQ('1', *char_ptr);
3333   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3334   CHECK_EQ('2', *char_ptr);
3335   char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3336   CHECK_EQ('3', *char_ptr);
3337   i::DeleteArray(data);
3338 }
3339
3340
3341 THREADED_TEST(GlobalHandle) {
3342   v8::Isolate* isolate = CcTest::isolate();
3343   v8::Persistent<String> global;
3344   {
3345     v8::HandleScope scope(isolate);
3346     global.Reset(isolate, v8_str("str"));
3347   }
3348   {
3349     v8::HandleScope scope(isolate);
3350     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3351   }
3352   global.Reset();
3353   {
3354     v8::HandleScope scope(isolate);
3355     global.Reset(isolate, v8_str("str"));
3356   }
3357   {
3358     v8::HandleScope scope(isolate);
3359     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3360   }
3361   global.Reset();
3362 }
3363
3364
3365 THREADED_TEST(ResettingGlobalHandle) {
3366   v8::Isolate* isolate = CcTest::isolate();
3367   v8::Persistent<String> global;
3368   {
3369     v8::HandleScope scope(isolate);
3370     global.Reset(isolate, v8_str("str"));
3371   }
3372   v8::internal::GlobalHandles* global_handles =
3373       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3374   int initial_handle_count = global_handles->global_handles_count();
3375   {
3376     v8::HandleScope scope(isolate);
3377     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3378   }
3379   {
3380     v8::HandleScope scope(isolate);
3381     global.Reset(isolate, v8_str("longer"));
3382   }
3383   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3384   {
3385     v8::HandleScope scope(isolate);
3386     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3387   }
3388   global.Reset();
3389   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3390 }
3391
3392
3393 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3394   v8::Isolate* isolate = CcTest::isolate();
3395   v8::Persistent<String> global;
3396   {
3397     v8::HandleScope scope(isolate);
3398     global.Reset(isolate, v8_str("str"));
3399   }
3400   v8::internal::GlobalHandles* global_handles =
3401       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3402   int initial_handle_count = global_handles->global_handles_count();
3403   {
3404     v8::HandleScope scope(isolate);
3405     CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3406   }
3407   {
3408     v8::HandleScope scope(isolate);
3409     Local<String> empty;
3410     global.Reset(isolate, empty);
3411   }
3412   CHECK(global.IsEmpty());
3413   CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3414 }
3415
3416
3417 template<class T>
3418 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3419   return unique.Pass();
3420 }
3421
3422
3423 template<class T>
3424 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3425                                             const v8::Persistent<T> & global) {
3426   v8::UniquePersistent<String> unique(isolate, global);
3427   return unique.Pass();
3428 }
3429
3430
3431 THREADED_TEST(UniquePersistent) {
3432   v8::Isolate* isolate = CcTest::isolate();
3433   v8::Persistent<String> global;
3434   {
3435     v8::HandleScope scope(isolate);
3436     global.Reset(isolate, v8_str("str"));
3437   }
3438   v8::internal::GlobalHandles* global_handles =
3439       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3440   int initial_handle_count = global_handles->global_handles_count();
3441   {
3442     v8::UniquePersistent<String> unique(isolate, global);
3443     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3444     // Test assignment via Pass
3445     {
3446       v8::UniquePersistent<String> copy = unique.Pass();
3447       CHECK(unique.IsEmpty());
3448       CHECK(copy == global);
3449       CHECK_EQ(initial_handle_count + 1,
3450                global_handles->global_handles_count());
3451       unique = copy.Pass();
3452     }
3453     // Test ctor via Pass
3454     {
3455       v8::UniquePersistent<String> copy(unique.Pass());
3456       CHECK(unique.IsEmpty());
3457       CHECK(copy == global);
3458       CHECK_EQ(initial_handle_count + 1,
3459                global_handles->global_handles_count());
3460       unique = copy.Pass();
3461     }
3462     // Test pass through function call
3463     {
3464       v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3465       CHECK(unique.IsEmpty());
3466       CHECK(copy == global);
3467       CHECK_EQ(initial_handle_count + 1,
3468                global_handles->global_handles_count());
3469       unique = copy.Pass();
3470     }
3471     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3472   }
3473   // Test pass from function call
3474   {
3475     v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3476     CHECK(unique == global);
3477     CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3478   }
3479   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3480   global.Reset();
3481 }
3482
3483
3484 template<typename K, typename V>
3485 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3486  public:
3487   typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3488       MapType;
3489   static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3490   struct WeakCallbackDataType {
3491     MapType* map;
3492     K key;
3493   };
3494   static WeakCallbackDataType* WeakCallbackParameter(
3495       MapType* map, const K& key, Local<V> value) {
3496     WeakCallbackDataType* data = new WeakCallbackDataType;
3497     data->map = map;
3498     data->key = key;
3499     return data;
3500   }
3501   static MapType* MapFromWeakCallbackData(
3502       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3503     return data.GetParameter()->map;
3504   }
3505   static K KeyFromWeakCallbackData(
3506       const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3507     return data.GetParameter()->key;
3508   }
3509   static void DisposeCallbackData(WeakCallbackDataType* data) {
3510     delete data;
3511   }
3512   static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3513       K key) { }
3514 };
3515
3516
3517 template<typename Map>
3518 static void TestPersistentValueMap() {
3519   LocalContext env;
3520   v8::Isolate* isolate = env->GetIsolate();
3521   Map map(isolate);
3522   v8::internal::GlobalHandles* global_handles =
3523       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3524   int initial_handle_count = global_handles->global_handles_count();
3525   CHECK_EQ(0, static_cast<int>(map.Size()));
3526   {
3527     HandleScope scope(isolate);
3528     Local<v8::Object> obj = map.Get(7);
3529     CHECK(obj.IsEmpty());
3530     Local<v8::Object> expected = v8::Object::New(isolate);
3531     map.Set(7, expected);
3532     CHECK_EQ(1, static_cast<int>(map.Size()));
3533     obj = map.Get(7);
3534     CHECK_EQ(expected, obj);
3535     {
3536       typename Map::PersistentValueReference ref = map.GetReference(7);
3537       CHECK_EQ(expected, ref.NewLocal(isolate));
3538     }
3539     v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3540     CHECK_EQ(0, static_cast<int>(map.Size()));
3541     CHECK(expected == removed);
3542     removed = map.Remove(7);
3543     CHECK(removed.IsEmpty());
3544     map.Set(8, expected);
3545     CHECK_EQ(1, static_cast<int>(map.Size()));
3546     map.Set(8, expected);
3547     CHECK_EQ(1, static_cast<int>(map.Size()));
3548     {
3549       typename Map::PersistentValueReference ref;
3550       Local<v8::Object> expected2 = v8::Object::New(isolate);
3551       removed = map.Set(8,
3552           v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3553       CHECK_EQ(1, static_cast<int>(map.Size()));
3554       CHECK(expected == removed);
3555       CHECK_EQ(expected2, ref.NewLocal(isolate));
3556     }
3557   }
3558   CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3559   if (map.IsWeak()) {
3560     reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3561         CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3562   } else {
3563     map.Clear();
3564   }
3565   CHECK_EQ(0, static_cast<int>(map.Size()));
3566   CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3567 }
3568
3569
3570 TEST(PersistentValueMap) {
3571   // Default case, w/o weak callbacks:
3572   TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3573
3574   // Custom traits with weak callbacks:
3575   typedef v8::PersistentValueMap<int, v8::Object,
3576       WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3577   TestPersistentValueMap<WeakPersistentValueMap>();
3578 }
3579
3580
3581 TEST(PersistentValueVector) {
3582   LocalContext env;
3583   v8::Isolate* isolate = env->GetIsolate();
3584   v8::internal::GlobalHandles* global_handles =
3585       reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3586   int handle_count = global_handles->global_handles_count();
3587   HandleScope scope(isolate);
3588
3589   v8::PersistentValueVector<v8::Object> vector(isolate);
3590
3591   Local<v8::Object> obj1 = v8::Object::New(isolate);
3592   Local<v8::Object> obj2 = v8::Object::New(isolate);
3593   v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3594
3595   CHECK(vector.IsEmpty());
3596   CHECK_EQ(0, static_cast<int>(vector.Size()));
3597
3598   vector.ReserveCapacity(3);
3599   CHECK(vector.IsEmpty());
3600
3601   vector.Append(obj1);
3602   vector.Append(obj2);
3603   vector.Append(obj1);
3604   vector.Append(obj3.Pass());
3605   vector.Append(obj1);
3606
3607   CHECK(!vector.IsEmpty());
3608   CHECK_EQ(5, static_cast<int>(vector.Size()));
3609   CHECK(obj3.IsEmpty());
3610   CHECK_EQ(obj1, vector.Get(0));
3611   CHECK_EQ(obj1, vector.Get(2));
3612   CHECK_EQ(obj1, vector.Get(4));
3613   CHECK_EQ(obj2, vector.Get(1));
3614
3615   CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3616
3617   vector.Clear();
3618   CHECK(vector.IsEmpty());
3619   CHECK_EQ(0, static_cast<int>(vector.Size()));
3620   CHECK_EQ(handle_count, global_handles->global_handles_count());
3621 }
3622
3623
3624 THREADED_TEST(GlobalHandleUpcast) {
3625   v8::Isolate* isolate = CcTest::isolate();
3626   v8::HandleScope scope(isolate);
3627   v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3628   v8::Persistent<String> global_string(isolate, local);
3629   v8::Persistent<Value>& global_value =
3630       v8::Persistent<Value>::Cast(global_string);
3631   CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3632   CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3633   global_string.Reset();
3634 }
3635
3636
3637 THREADED_TEST(HandleEquality) {
3638   v8::Isolate* isolate = CcTest::isolate();
3639   v8::Persistent<String> global1;
3640   v8::Persistent<String> global2;
3641   {
3642     v8::HandleScope scope(isolate);
3643     global1.Reset(isolate, v8_str("str"));
3644     global2.Reset(isolate, v8_str("str2"));
3645   }
3646   CHECK_EQ(global1 == global1, true);
3647   CHECK_EQ(global1 != global1, false);
3648   {
3649     v8::HandleScope scope(isolate);
3650     Local<String> local1 = Local<String>::New(isolate, global1);
3651     Local<String> local2 = Local<String>::New(isolate, global2);
3652
3653     CHECK_EQ(global1 == local1, true);
3654     CHECK_EQ(global1 != local1, false);
3655     CHECK_EQ(local1 == global1, true);
3656     CHECK_EQ(local1 != global1, false);
3657
3658     CHECK_EQ(global1 == local2, false);
3659     CHECK_EQ(global1 != local2, true);
3660     CHECK_EQ(local2 == global1, false);
3661     CHECK_EQ(local2 != global1, true);
3662
3663     CHECK_EQ(local1 == local2, false);
3664     CHECK_EQ(local1 != local2, true);
3665
3666     Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3667     CHECK_EQ(local1 == anotherLocal1, true);
3668     CHECK_EQ(local1 != anotherLocal1, false);
3669   }
3670   global1.Reset();
3671   global2.Reset();
3672 }
3673
3674
3675 THREADED_TEST(LocalHandle) {
3676   v8::HandleScope scope(CcTest::isolate());
3677   v8::Local<String> local =
3678       v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3679   CHECK_EQ(local->Length(), 3);
3680 }
3681
3682
3683 class WeakCallCounter {
3684  public:
3685   explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3686   int id() { return id_; }
3687   void increment() { number_of_weak_calls_++; }
3688   int NumberOfWeakCalls() { return number_of_weak_calls_; }
3689  private:
3690   int id_;
3691   int number_of_weak_calls_;
3692 };
3693
3694
3695 template<typename T>
3696 struct WeakCallCounterAndPersistent {
3697   explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3698       : counter(counter) {}
3699   WeakCallCounter* counter;
3700   v8::Persistent<T> handle;
3701 };
3702
3703
3704 template <typename T>
3705 static void WeakPointerCallback(
3706     const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3707   CHECK_EQ(1234, data.GetParameter()->counter->id());
3708   data.GetParameter()->counter->increment();
3709   data.GetParameter()->handle.Reset();
3710 }
3711
3712
3713 template<typename T>
3714 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3715   return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3716 }
3717
3718
3719 THREADED_TEST(ApiObjectGroups) {
3720   LocalContext env;
3721   v8::Isolate* iso = env->GetIsolate();
3722   HandleScope scope(iso);
3723
3724   WeakCallCounter counter(1234);
3725
3726   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3727   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3728   WeakCallCounterAndPersistent<Value> g1c1(&counter);
3729   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3730   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3731   WeakCallCounterAndPersistent<Value> g2c1(&counter);
3732
3733   {
3734     HandleScope scope(iso);
3735     g1s1.handle.Reset(iso, Object::New(iso));
3736     g1s2.handle.Reset(iso, Object::New(iso));
3737     g1c1.handle.Reset(iso, Object::New(iso));
3738     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3739     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3740     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3741
3742     g2s1.handle.Reset(iso, Object::New(iso));
3743     g2s2.handle.Reset(iso, Object::New(iso));
3744     g2c1.handle.Reset(iso, Object::New(iso));
3745     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3746     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3747     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3748   }
3749
3750   WeakCallCounterAndPersistent<Value> root(&counter);
3751   root.handle.Reset(iso, g1s1.handle);  // make a root.
3752
3753   // Connect group 1 and 2, make a cycle.
3754   {
3755     HandleScope scope(iso);
3756     CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
3757             Set(0, Local<Value>::New(iso, g2s2.handle)));
3758     CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
3759             Set(0, Local<Value>::New(iso, g1s1.handle)));
3760   }
3761
3762   {
3763     UniqueId id1 = MakeUniqueId(g1s1.handle);
3764     UniqueId id2 = MakeUniqueId(g2s2.handle);
3765     iso->SetObjectGroupId(g1s1.handle, id1);
3766     iso->SetObjectGroupId(g1s2.handle, id1);
3767     iso->SetReferenceFromGroup(id1, g1c1.handle);
3768     iso->SetObjectGroupId(g2s1.handle, id2);
3769     iso->SetObjectGroupId(g2s2.handle, id2);
3770     iso->SetReferenceFromGroup(id2, g2c1.handle);
3771   }
3772   // Do a single full GC, ensure incremental marking is stopped.
3773   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3774       iso)->heap();
3775   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3776
3777   // All object should be alive.
3778   CHECK_EQ(0, counter.NumberOfWeakCalls());
3779
3780   // Weaken the root.
3781   root.handle.SetWeak(&root, &WeakPointerCallback);
3782   // But make children strong roots---all the objects (except for children)
3783   // should be collectable now.
3784   g1c1.handle.ClearWeak();
3785   g2c1.handle.ClearWeak();
3786
3787   // Groups are deleted, rebuild groups.
3788   {
3789     UniqueId id1 = MakeUniqueId(g1s1.handle);
3790     UniqueId id2 = MakeUniqueId(g2s2.handle);
3791     iso->SetObjectGroupId(g1s1.handle, id1);
3792     iso->SetObjectGroupId(g1s2.handle, id1);
3793     iso->SetReferenceFromGroup(id1, g1c1.handle);
3794     iso->SetObjectGroupId(g2s1.handle, id2);
3795     iso->SetObjectGroupId(g2s2.handle, id2);
3796     iso->SetReferenceFromGroup(id2, g2c1.handle);
3797   }
3798
3799   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3800
3801   // All objects should be gone. 5 global handles in total.
3802   CHECK_EQ(5, counter.NumberOfWeakCalls());
3803
3804   // And now make children weak again and collect them.
3805   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3806   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3807
3808   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3809   CHECK_EQ(7, counter.NumberOfWeakCalls());
3810 }
3811
3812
3813 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3814   LocalContext env;
3815   v8::Isolate* iso = env->GetIsolate();
3816   HandleScope scope(iso);
3817
3818   WeakCallCounter counter(1234);
3819
3820   WeakCallCounterAndPersistent<Object> g1s1(&counter);
3821   WeakCallCounterAndPersistent<String> g1s2(&counter);
3822   WeakCallCounterAndPersistent<String> g1c1(&counter);
3823   WeakCallCounterAndPersistent<Object> g2s1(&counter);
3824   WeakCallCounterAndPersistent<String> g2s2(&counter);
3825   WeakCallCounterAndPersistent<String> g2c1(&counter);
3826
3827   {
3828     HandleScope scope(iso);
3829     g1s1.handle.Reset(iso, Object::New(iso));
3830     g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3831     g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3832     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3833     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3834     g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3835
3836     g2s1.handle.Reset(iso, Object::New(iso));
3837     g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3838     g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3839     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3840     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3841     g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3842   }
3843
3844   WeakCallCounterAndPersistent<Value> root(&counter);
3845   root.handle.Reset(iso, g1s1.handle);  // make a root.
3846
3847   // Connect group 1 and 2, make a cycle.
3848   {
3849     HandleScope scope(iso);
3850     CHECK(Local<Object>::New(iso, g1s1.handle)
3851               ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3852     CHECK(Local<Object>::New(iso, g2s1.handle)
3853               ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3854   }
3855
3856   {
3857     UniqueId id1 = MakeUniqueId(g1s1.handle);
3858     UniqueId id2 = MakeUniqueId(g2s2.handle);
3859     iso->SetObjectGroupId(g1s1.handle, id1);
3860     iso->SetObjectGroupId(g1s2.handle, id1);
3861     iso->SetReference(g1s1.handle, g1c1.handle);
3862     iso->SetObjectGroupId(g2s1.handle, id2);
3863     iso->SetObjectGroupId(g2s2.handle, id2);
3864     iso->SetReferenceFromGroup(id2, g2c1.handle);
3865   }
3866   // Do a single full GC, ensure incremental marking is stopped.
3867   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3868       iso)->heap();
3869   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3870
3871   // All object should be alive.
3872   CHECK_EQ(0, counter.NumberOfWeakCalls());
3873
3874   // Weaken the root.
3875   root.handle.SetWeak(&root, &WeakPointerCallback);
3876   // But make children strong roots---all the objects (except for children)
3877   // should be collectable now.
3878   g1c1.handle.ClearWeak();
3879   g2c1.handle.ClearWeak();
3880
3881   // Groups are deleted, rebuild groups.
3882   {
3883     UniqueId id1 = MakeUniqueId(g1s1.handle);
3884     UniqueId id2 = MakeUniqueId(g2s2.handle);
3885     iso->SetObjectGroupId(g1s1.handle, id1);
3886     iso->SetObjectGroupId(g1s2.handle, id1);
3887     iso->SetReference(g1s1.handle, g1c1.handle);
3888     iso->SetObjectGroupId(g2s1.handle, id2);
3889     iso->SetObjectGroupId(g2s2.handle, id2);
3890     iso->SetReferenceFromGroup(id2, g2c1.handle);
3891   }
3892
3893   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3894
3895   // All objects should be gone. 5 global handles in total.
3896   CHECK_EQ(5, counter.NumberOfWeakCalls());
3897
3898   // And now make children weak again and collect them.
3899   g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3900   g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3901
3902   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3903   CHECK_EQ(7, counter.NumberOfWeakCalls());
3904 }
3905
3906
3907 THREADED_TEST(ApiObjectGroupsCycle) {
3908   LocalContext env;
3909   v8::Isolate* iso = env->GetIsolate();
3910   HandleScope scope(iso);
3911
3912   WeakCallCounter counter(1234);
3913
3914   WeakCallCounterAndPersistent<Value> g1s1(&counter);
3915   WeakCallCounterAndPersistent<Value> g1s2(&counter);
3916   WeakCallCounterAndPersistent<Value> g2s1(&counter);
3917   WeakCallCounterAndPersistent<Value> g2s2(&counter);
3918   WeakCallCounterAndPersistent<Value> g3s1(&counter);
3919   WeakCallCounterAndPersistent<Value> g3s2(&counter);
3920   WeakCallCounterAndPersistent<Value> g4s1(&counter);
3921   WeakCallCounterAndPersistent<Value> g4s2(&counter);
3922
3923   {
3924     HandleScope scope(iso);
3925     g1s1.handle.Reset(iso, Object::New(iso));
3926     g1s2.handle.Reset(iso, Object::New(iso));
3927     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3928     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3929     CHECK(g1s1.handle.IsWeak());
3930     CHECK(g1s2.handle.IsWeak());
3931
3932     g2s1.handle.Reset(iso, Object::New(iso));
3933     g2s2.handle.Reset(iso, Object::New(iso));
3934     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3935     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3936     CHECK(g2s1.handle.IsWeak());
3937     CHECK(g2s2.handle.IsWeak());
3938
3939     g3s1.handle.Reset(iso, Object::New(iso));
3940     g3s2.handle.Reset(iso, Object::New(iso));
3941     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3942     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3943     CHECK(g3s1.handle.IsWeak());
3944     CHECK(g3s2.handle.IsWeak());
3945
3946     g4s1.handle.Reset(iso, Object::New(iso));
3947     g4s2.handle.Reset(iso, Object::New(iso));
3948     g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3949     g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3950     CHECK(g4s1.handle.IsWeak());
3951     CHECK(g4s2.handle.IsWeak());
3952   }
3953
3954   WeakCallCounterAndPersistent<Value> root(&counter);
3955   root.handle.Reset(iso, g1s1.handle);  // make a root.
3956
3957   // Connect groups.  We're building the following cycle:
3958   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3959   // groups.
3960   {
3961     UniqueId id1 = MakeUniqueId(g1s1.handle);
3962     UniqueId id2 = MakeUniqueId(g2s1.handle);
3963     UniqueId id3 = MakeUniqueId(g3s1.handle);
3964     UniqueId id4 = MakeUniqueId(g4s1.handle);
3965     iso->SetObjectGroupId(g1s1.handle, id1);
3966     iso->SetObjectGroupId(g1s2.handle, id1);
3967     iso->SetReferenceFromGroup(id1, g2s1.handle);
3968     iso->SetObjectGroupId(g2s1.handle, id2);
3969     iso->SetObjectGroupId(g2s2.handle, id2);
3970     iso->SetReferenceFromGroup(id2, g3s1.handle);
3971     iso->SetObjectGroupId(g3s1.handle, id3);
3972     iso->SetObjectGroupId(g3s2.handle, id3);
3973     iso->SetReferenceFromGroup(id3, g4s1.handle);
3974     iso->SetObjectGroupId(g4s1.handle, id4);
3975     iso->SetObjectGroupId(g4s2.handle, id4);
3976     iso->SetReferenceFromGroup(id4, g1s1.handle);
3977   }
3978   // Do a single full GC
3979   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3980       iso)->heap();
3981   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3982
3983   // All object should be alive.
3984   CHECK_EQ(0, counter.NumberOfWeakCalls());
3985
3986   // Weaken the root.
3987   root.handle.SetWeak(&root, &WeakPointerCallback);
3988
3989   // Groups are deleted, rebuild groups.
3990   {
3991     UniqueId id1 = MakeUniqueId(g1s1.handle);
3992     UniqueId id2 = MakeUniqueId(g2s1.handle);
3993     UniqueId id3 = MakeUniqueId(g3s1.handle);
3994     UniqueId id4 = MakeUniqueId(g4s1.handle);
3995     iso->SetObjectGroupId(g1s1.handle, id1);
3996     iso->SetObjectGroupId(g1s2.handle, id1);
3997     iso->SetReferenceFromGroup(id1, g2s1.handle);
3998     iso->SetObjectGroupId(g2s1.handle, id2);
3999     iso->SetObjectGroupId(g2s2.handle, id2);
4000     iso->SetReferenceFromGroup(id2, g3s1.handle);
4001     iso->SetObjectGroupId(g3s1.handle, id3);
4002     iso->SetObjectGroupId(g3s2.handle, id3);
4003     iso->SetReferenceFromGroup(id3, g4s1.handle);
4004     iso->SetObjectGroupId(g4s1.handle, id4);
4005     iso->SetObjectGroupId(g4s2.handle, id4);
4006     iso->SetReferenceFromGroup(id4, g1s1.handle);
4007   }
4008
4009   heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4010
4011   // All objects should be gone. 9 global handles in total.
4012   CHECK_EQ(9, counter.NumberOfWeakCalls());
4013 }
4014
4015
4016 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4017 // on the buildbots, so was made non-threaded for the time being.
4018 TEST(ApiObjectGroupsCycleForScavenger) {
4019   i::FLAG_stress_compaction = false;
4020   i::FLAG_gc_global = false;
4021   LocalContext env;
4022   v8::Isolate* iso = env->GetIsolate();
4023   HandleScope scope(iso);
4024
4025   WeakCallCounter counter(1234);
4026
4027   WeakCallCounterAndPersistent<Value> g1s1(&counter);
4028   WeakCallCounterAndPersistent<Value> g1s2(&counter);
4029   WeakCallCounterAndPersistent<Value> g2s1(&counter);
4030   WeakCallCounterAndPersistent<Value> g2s2(&counter);
4031   WeakCallCounterAndPersistent<Value> g3s1(&counter);
4032   WeakCallCounterAndPersistent<Value> g3s2(&counter);
4033
4034   {
4035     HandleScope scope(iso);
4036     g1s1.handle.Reset(iso, Object::New(iso));
4037     g1s2.handle.Reset(iso, Object::New(iso));
4038     g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4039     g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4040
4041     g2s1.handle.Reset(iso, Object::New(iso));
4042     g2s2.handle.Reset(iso, Object::New(iso));
4043     g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4044     g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4045
4046     g3s1.handle.Reset(iso, Object::New(iso));
4047     g3s2.handle.Reset(iso, Object::New(iso));
4048     g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4049     g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4050   }
4051
4052   // Make a root.
4053   WeakCallCounterAndPersistent<Value> root(&counter);
4054   root.handle.Reset(iso, g1s1.handle);
4055   root.handle.MarkPartiallyDependent();
4056
4057   // Connect groups.  We're building the following cycle:
4058   // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4059   // groups.
4060   {
4061     HandleScope handle_scope(iso);
4062     g1s1.handle.MarkPartiallyDependent();
4063     g1s2.handle.MarkPartiallyDependent();
4064     g2s1.handle.MarkPartiallyDependent();
4065     g2s2.handle.MarkPartiallyDependent();
4066     g3s1.handle.MarkPartiallyDependent();
4067     g3s2.handle.MarkPartiallyDependent();
4068     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4069     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4070     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4071         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4072     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4073     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4074     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4075         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4076     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4077     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4078     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4079         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4080   }
4081
4082   v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4083       iso)->heap();
4084   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4085
4086   // All objects should be alive.
4087   CHECK_EQ(0, counter.NumberOfWeakCalls());
4088
4089   // Weaken the root.
4090   root.handle.SetWeak(&root, &WeakPointerCallback);
4091   root.handle.MarkPartiallyDependent();
4092
4093   // Groups are deleted, rebuild groups.
4094   {
4095     HandleScope handle_scope(iso);
4096     g1s1.handle.MarkPartiallyDependent();
4097     g1s2.handle.MarkPartiallyDependent();
4098     g2s1.handle.MarkPartiallyDependent();
4099     g2s2.handle.MarkPartiallyDependent();
4100     g3s1.handle.MarkPartiallyDependent();
4101     g3s2.handle.MarkPartiallyDependent();
4102     iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4103     iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4104     Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4105         v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4106     iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4107     iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4108     Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4109         v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4110     iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4111     iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4112     Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4113         v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4114   }
4115
4116   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4117
4118   // All objects should be gone. 7 global handles in total.
4119   CHECK_EQ(7, counter.NumberOfWeakCalls());
4120 }
4121
4122
4123 THREADED_TEST(ScriptException) {
4124   LocalContext env;
4125   v8::HandleScope scope(env->GetIsolate());
4126   Local<Script> script = v8_compile("throw 'panama!';");
4127   v8::TryCatch try_catch;
4128   Local<Value> result = script->Run();
4129   CHECK(result.IsEmpty());
4130   CHECK(try_catch.HasCaught());
4131   String::Utf8Value exception_value(try_catch.Exception());
4132   CHECK_EQ(*exception_value, "panama!");
4133 }
4134
4135
4136 TEST(TryCatchCustomException) {
4137   LocalContext env;
4138   v8::HandleScope scope(env->GetIsolate());
4139   v8::TryCatch try_catch;
4140   CompileRun("function CustomError() { this.a = 'b'; }"
4141              "(function f() { throw new CustomError(); })();");
4142   CHECK(try_catch.HasCaught());
4143   CHECK(try_catch.Exception()->ToObject()->
4144             Get(v8_str("a"))->Equals(v8_str("b")));
4145 }
4146
4147
4148 bool message_received;
4149
4150
4151 static void check_message_0(v8::Handle<v8::Message> message,
4152                             v8::Handle<Value> data) {
4153   CHECK_EQ(5.76, data->NumberValue());
4154   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4155   CHECK(!message->IsSharedCrossOrigin());
4156   message_received = true;
4157 }
4158
4159
4160 THREADED_TEST(MessageHandler0) {
4161   message_received = false;
4162   v8::HandleScope scope(CcTest::isolate());
4163   CHECK(!message_received);
4164   LocalContext context;
4165   v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4166   v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4167   script->Run();
4168   CHECK(message_received);
4169   // clear out the message listener
4170   v8::V8::RemoveMessageListeners(check_message_0);
4171 }
4172
4173
4174 static void check_message_1(v8::Handle<v8::Message> message,
4175                             v8::Handle<Value> data) {
4176   CHECK(data->IsNumber());
4177   CHECK_EQ(1337, data->Int32Value());
4178   CHECK(!message->IsSharedCrossOrigin());
4179   message_received = true;
4180 }
4181
4182
4183 TEST(MessageHandler1) {
4184   message_received = false;
4185   v8::HandleScope scope(CcTest::isolate());
4186   CHECK(!message_received);
4187   v8::V8::AddMessageListener(check_message_1);
4188   LocalContext context;
4189   CompileRun("throw 1337;");
4190   CHECK(message_received);
4191   // clear out the message listener
4192   v8::V8::RemoveMessageListeners(check_message_1);
4193 }
4194
4195
4196 static void check_message_2(v8::Handle<v8::Message> message,
4197                             v8::Handle<Value> data) {
4198   LocalContext context;
4199   CHECK(data->IsObject());
4200   v8::Local<v8::Value> hidden_property =
4201       v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4202   CHECK(v8_str("hidden value")->Equals(hidden_property));
4203   CHECK(!message->IsSharedCrossOrigin());
4204   message_received = true;
4205 }
4206
4207
4208 TEST(MessageHandler2) {
4209   message_received = false;
4210   v8::HandleScope scope(CcTest::isolate());
4211   CHECK(!message_received);
4212   v8::V8::AddMessageListener(check_message_2);
4213   LocalContext context;
4214   v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4215   v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4216                                            v8_str("hidden value"));
4217   context->Global()->Set(v8_str("error"), error);
4218   CompileRun("throw error;");
4219   CHECK(message_received);
4220   // clear out the message listener
4221   v8::V8::RemoveMessageListeners(check_message_2);
4222 }
4223
4224
4225 static void check_message_3(v8::Handle<v8::Message> message,
4226                             v8::Handle<Value> data) {
4227   CHECK(message->IsSharedCrossOrigin());
4228   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4229   message_received = true;
4230 }
4231
4232
4233 TEST(MessageHandler3) {
4234   message_received = false;
4235   v8::Isolate* isolate = CcTest::isolate();
4236   v8::HandleScope scope(isolate);
4237   CHECK(!message_received);
4238   v8::V8::AddMessageListener(check_message_3);
4239   LocalContext context;
4240   v8::ScriptOrigin origin =
4241       v8::ScriptOrigin(v8_str("6.75"),
4242                        v8::Integer::New(isolate, 1),
4243                        v8::Integer::New(isolate, 2),
4244                        v8::True(isolate));
4245   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4246                                                   &origin);
4247   script->Run();
4248   CHECK(message_received);
4249   // clear out the message listener
4250   v8::V8::RemoveMessageListeners(check_message_3);
4251 }
4252
4253
4254 static void check_message_4(v8::Handle<v8::Message> message,
4255                             v8::Handle<Value> data) {
4256   CHECK(!message->IsSharedCrossOrigin());
4257   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4258   message_received = true;
4259 }
4260
4261
4262 TEST(MessageHandler4) {
4263   message_received = false;
4264   v8::Isolate* isolate = CcTest::isolate();
4265   v8::HandleScope scope(isolate);
4266   CHECK(!message_received);
4267   v8::V8::AddMessageListener(check_message_4);
4268   LocalContext context;
4269   v8::ScriptOrigin origin =
4270       v8::ScriptOrigin(v8_str("6.75"),
4271                        v8::Integer::New(isolate, 1),
4272                        v8::Integer::New(isolate, 2),
4273                        v8::False(isolate));
4274   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4275                                                   &origin);
4276   script->Run();
4277   CHECK(message_received);
4278   // clear out the message listener
4279   v8::V8::RemoveMessageListeners(check_message_4);
4280 }
4281
4282
4283 static void check_message_5a(v8::Handle<v8::Message> message,
4284                             v8::Handle<Value> data) {
4285   CHECK(message->IsSharedCrossOrigin());
4286   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4287   message_received = true;
4288 }
4289
4290
4291 static void check_message_5b(v8::Handle<v8::Message> message,
4292                             v8::Handle<Value> data) {
4293   CHECK(!message->IsSharedCrossOrigin());
4294   CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4295   message_received = true;
4296 }
4297
4298
4299 TEST(MessageHandler5) {
4300   message_received = false;
4301   v8::Isolate* isolate = CcTest::isolate();
4302   v8::HandleScope scope(isolate);
4303   CHECK(!message_received);
4304   v8::V8::AddMessageListener(check_message_5a);
4305   LocalContext context;
4306   v8::ScriptOrigin origin =
4307       v8::ScriptOrigin(v8_str("6.75"),
4308                        v8::Integer::New(isolate, 1),
4309                        v8::Integer::New(isolate, 2),
4310                        v8::True(isolate));
4311   v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4312                                                   &origin);
4313   script->Run();
4314   CHECK(message_received);
4315   // clear out the message listener
4316   v8::V8::RemoveMessageListeners(check_message_5a);
4317
4318   message_received = false;
4319   v8::V8::AddMessageListener(check_message_5b);
4320   origin =
4321       v8::ScriptOrigin(v8_str("6.75"),
4322                        v8::Integer::New(isolate, 1),
4323                        v8::Integer::New(isolate, 2),
4324                        v8::False(isolate));
4325   script = Script::Compile(v8_str("throw 'error'"),
4326                            &origin);
4327   script->Run();
4328   CHECK(message_received);
4329   // clear out the message listener
4330   v8::V8::RemoveMessageListeners(check_message_5b);
4331 }
4332
4333
4334 THREADED_TEST(GetSetProperty) {
4335   LocalContext context;
4336   v8::Isolate* isolate = context->GetIsolate();
4337   v8::HandleScope scope(isolate);
4338   context->Global()->Set(v8_str("foo"), v8_num(14));
4339   context->Global()->Set(v8_str("12"), v8_num(92));
4340   context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4341   context->Global()->Set(v8_num(13), v8_num(56));
4342   Local<Value> foo = CompileRun("this.foo");
4343   CHECK_EQ(14, foo->Int32Value());
4344   Local<Value> twelve = CompileRun("this[12]");
4345   CHECK_EQ(92, twelve->Int32Value());
4346   Local<Value> sixteen = CompileRun("this[16]");
4347   CHECK_EQ(32, sixteen->Int32Value());
4348   Local<Value> thirteen = CompileRun("this[13]");
4349   CHECK_EQ(56, thirteen->Int32Value());
4350   CHECK_EQ(92,
4351            context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4352   CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4353   CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4354   CHECK_EQ(32,
4355            context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4356   CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4357   CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4358   CHECK_EQ(56,
4359            context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4360   CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4361   CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4362 }
4363
4364
4365 THREADED_TEST(PropertyAttributes) {
4366   LocalContext context;
4367   v8::HandleScope scope(context->GetIsolate());
4368   // none
4369   Local<String> prop = v8_str("none");
4370   context->Global()->Set(prop, v8_num(7));
4371   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4372   // read-only
4373   prop = v8_str("read_only");
4374   context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4375   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4376   CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4377   CompileRun("read_only = 9");
4378   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4379   context->Global()->Set(prop, v8_num(10));
4380   CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4381   // dont-delete
4382   prop = v8_str("dont_delete");
4383   context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4384   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4385   CompileRun("delete dont_delete");
4386   CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4387   CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4388   // dont-enum
4389   prop = v8_str("dont_enum");
4390   context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4391   CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4392   // absent
4393   prop = v8_str("absent");
4394   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4395   Local<Value> fake_prop = v8_num(1);
4396   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4397   // exception
4398   TryCatch try_catch;
4399   Local<Value> exception =
4400       CompileRun("({ toString: function() { throw 'exception';} })");
4401   CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4402   CHECK(try_catch.HasCaught());
4403   String::Utf8Value exception_value(try_catch.Exception());
4404   CHECK_EQ("exception", *exception_value);
4405   try_catch.Reset();
4406 }
4407
4408
4409 THREADED_TEST(Array) {
4410   LocalContext context;
4411   v8::HandleScope scope(context->GetIsolate());
4412   Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4413   CHECK_EQ(0, array->Length());
4414   CHECK(array->Get(0)->IsUndefined());
4415   CHECK(!array->Has(0));
4416   CHECK(array->Get(100)->IsUndefined());
4417   CHECK(!array->Has(100));
4418   array->Set(2, v8_num(7));
4419   CHECK_EQ(3, array->Length());
4420   CHECK(!array->Has(0));
4421   CHECK(!array->Has(1));
4422   CHECK(array->Has(2));
4423   CHECK_EQ(7, array->Get(2)->Int32Value());
4424   Local<Value> obj = CompileRun("[1, 2, 3]");
4425   Local<v8::Array> arr = obj.As<v8::Array>();
4426   CHECK_EQ(3, arr->Length());
4427   CHECK_EQ(1, arr->Get(0)->Int32Value());
4428   CHECK_EQ(2, arr->Get(1)->Int32Value());
4429   CHECK_EQ(3, arr->Get(2)->Int32Value());
4430   array = v8::Array::New(context->GetIsolate(), 27);
4431   CHECK_EQ(27, array->Length());
4432   array = v8::Array::New(context->GetIsolate(), -27);
4433   CHECK_EQ(0, array->Length());
4434 }
4435
4436
4437 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4438   v8::EscapableHandleScope scope(args.GetIsolate());
4439   ApiTestFuzzer::Fuzz();
4440   Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4441   for (int i = 0; i < args.Length(); i++)
4442     result->Set(i, args[i]);
4443   args.GetReturnValue().Set(scope.Escape(result));
4444 }
4445
4446
4447 THREADED_TEST(Vector) {
4448   v8::Isolate* isolate = CcTest::isolate();
4449   v8::HandleScope scope(isolate);
4450   Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4451   global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4452   LocalContext context(0, global);
4453
4454   const char* fun = "f()";
4455   Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4456   CHECK_EQ(0, a0->Length());
4457
4458   const char* fun2 = "f(11)";
4459   Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4460   CHECK_EQ(1, a1->Length());
4461   CHECK_EQ(11, a1->Get(0)->Int32Value());
4462
4463   const char* fun3 = "f(12, 13)";
4464   Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4465   CHECK_EQ(2, a2->Length());
4466   CHECK_EQ(12, a2->Get(0)->Int32Value());
4467   CHECK_EQ(13, a2->Get(1)->Int32Value());
4468
4469   const char* fun4 = "f(14, 15, 16)";
4470   Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4471   CHECK_EQ(3, a3->Length());
4472   CHECK_EQ(14, a3->Get(0)->Int32Value());
4473   CHECK_EQ(15, a3->Get(1)->Int32Value());
4474   CHECK_EQ(16, a3->Get(2)->Int32Value());
4475
4476   const char* fun5 = "f(17, 18, 19, 20)";
4477   Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4478   CHECK_EQ(4, a4->Length());
4479   CHECK_EQ(17, a4->Get(0)->Int32Value());
4480   CHECK_EQ(18, a4->Get(1)->Int32Value());
4481   CHECK_EQ(19, a4->Get(2)->Int32Value());
4482   CHECK_EQ(20, a4->Get(3)->Int32Value());
4483 }
4484
4485
4486 THREADED_TEST(FunctionCall) {
4487   LocalContext context;
4488   v8::Isolate* isolate = context->GetIsolate();
4489   v8::HandleScope scope(isolate);
4490   CompileRun(
4491     "function Foo() {"
4492     "  var result = [];"
4493     "  for (var i = 0; i < arguments.length; i++) {"
4494     "    result.push(arguments[i]);"
4495     "  }"
4496     "  return result;"
4497     "}"
4498     "function ReturnThisSloppy() {"
4499     "  return this;"
4500     "}"
4501     "function ReturnThisStrict() {"
4502     "  'use strict';"
4503     "  return this;"
4504     "}");
4505   Local<Function> Foo =
4506       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4507   Local<Function> ReturnThisSloppy =
4508       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4509   Local<Function> ReturnThisStrict =
4510       Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4511
4512   v8::Handle<Value>* args0 = NULL;
4513   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4514   CHECK_EQ(0, a0->Length());
4515
4516   v8::Handle<Value> args1[] = { v8_num(1.1) };
4517   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4518   CHECK_EQ(1, a1->Length());
4519   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4520
4521   v8::Handle<Value> args2[] = { v8_num(2.2),
4522                                 v8_num(3.3) };
4523   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4524   CHECK_EQ(2, a2->Length());
4525   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4526   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4527
4528   v8::Handle<Value> args3[] = { v8_num(4.4),
4529                                 v8_num(5.5),
4530                                 v8_num(6.6) };
4531   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4532   CHECK_EQ(3, a3->Length());
4533   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4534   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4535   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4536
4537   v8::Handle<Value> args4[] = { v8_num(7.7),
4538                                 v8_num(8.8),
4539                                 v8_num(9.9),
4540                                 v8_num(10.11) };
4541   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4542   CHECK_EQ(4, a4->Length());
4543   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4544   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4545   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4546   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4547
4548   Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4549   CHECK(r1->StrictEquals(context->Global()));
4550   Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4551   CHECK(r2->StrictEquals(context->Global()));
4552   Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4553   CHECK(r3->IsNumberObject());
4554   CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4555   Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4556   CHECK(r4->IsStringObject());
4557   CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4558   Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4559   CHECK(r5->IsBooleanObject());
4560   CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4561
4562   Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4563   CHECK(r6->IsUndefined());
4564   Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4565   CHECK(r7->IsNull());
4566   Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4567   CHECK(r8->StrictEquals(v8_num(42)));
4568   Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4569   CHECK(r9->StrictEquals(v8_str("hello")));
4570   Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4571   CHECK(r10->StrictEquals(v8::True(isolate)));
4572 }
4573
4574
4575 THREADED_TEST(ConstructCall) {
4576   LocalContext context;
4577   v8::Isolate* isolate = context->GetIsolate();
4578   v8::HandleScope scope(isolate);
4579   CompileRun(
4580     "function Foo() {"
4581     "  var result = [];"
4582     "  for (var i = 0; i < arguments.length; i++) {"
4583     "    result.push(arguments[i]);"
4584     "  }"
4585     "  return result;"
4586     "}");
4587   Local<Function> Foo =
4588       Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4589
4590   v8::Handle<Value>* args0 = NULL;
4591   Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4592   CHECK_EQ(0, a0->Length());
4593
4594   v8::Handle<Value> args1[] = { v8_num(1.1) };
4595   Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4596   CHECK_EQ(1, a1->Length());
4597   CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4598
4599   v8::Handle<Value> args2[] = { v8_num(2.2),
4600                                 v8_num(3.3) };
4601   Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4602   CHECK_EQ(2, a2->Length());
4603   CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4604   CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4605
4606   v8::Handle<Value> args3[] = { v8_num(4.4),
4607                                 v8_num(5.5),
4608                                 v8_num(6.6) };
4609   Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4610   CHECK_EQ(3, a3->Length());
4611   CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4612   CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4613   CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4614
4615   v8::Handle<Value> args4[] = { v8_num(7.7),
4616                                 v8_num(8.8),
4617                                 v8_num(9.9),
4618                                 v8_num(10.11) };
4619   Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4620   CHECK_EQ(4, a4->Length());
4621   CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4622   CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4623   CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4624   CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4625 }
4626
4627
4628 static void CheckUncle(v8::TryCatch* try_catch) {
4629   CHECK(try_catch->HasCaught());
4630   String::Utf8Value str_value(try_catch->Exception());
4631   CHECK_EQ(*str_value, "uncle?");
4632   try_catch->Reset();
4633 }
4634
4635
4636 THREADED_TEST(ConversionNumber) {
4637   LocalContext env;
4638   v8::HandleScope scope(env->GetIsolate());
4639   // Very large number.
4640   CompileRun("var obj = Math.pow(2,32) * 1237;");
4641   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4642   CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4643   CHECK_EQ(0, obj->ToInt32()->Value());
4644   CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
4645   // Large number.
4646   CompileRun("var obj = -1234567890123;");
4647   obj = env->Global()->Get(v8_str("obj"));
4648   CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4649   CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4650   CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
4651   // Small positive integer.
4652   CompileRun("var obj = 42;");
4653   obj = env->Global()->Get(v8_str("obj"));
4654   CHECK_EQ(42.0, obj->ToNumber()->Value());
4655   CHECK_EQ(42, obj->ToInt32()->Value());
4656   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4657   // Negative integer.
4658   CompileRun("var obj = -37;");
4659   obj = env->Global()->Get(v8_str("obj"));
4660   CHECK_EQ(-37.0, obj->ToNumber()->Value());
4661   CHECK_EQ(-37, obj->ToInt32()->Value());
4662   CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
4663   // Positive non-int32 integer.
4664   CompileRun("var obj = 0x81234567;");
4665   obj = env->Global()->Get(v8_str("obj"));
4666   CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4667   CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4668   CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
4669   // Fraction.
4670   CompileRun("var obj = 42.3;");
4671   obj = env->Global()->Get(v8_str("obj"));
4672   CHECK_EQ(42.3, obj->ToNumber()->Value());
4673   CHECK_EQ(42, obj->ToInt32()->Value());
4674   CHECK(42u == obj->ToUint32()->Value());  // NOLINT
4675   // Large negative fraction.
4676   CompileRun("var obj = -5726623061.75;");
4677   obj = env->Global()->Get(v8_str("obj"));
4678   CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4679   CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4680   CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
4681 }
4682
4683
4684 THREADED_TEST(isNumberType) {
4685   LocalContext env;
4686   v8::HandleScope scope(env->GetIsolate());
4687   // Very large number.
4688   CompileRun("var obj = Math.pow(2,32) * 1237;");
4689   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4690   CHECK(!obj->IsInt32());
4691   CHECK(!obj->IsUint32());
4692   // Large negative number.
4693   CompileRun("var obj = -1234567890123;");
4694   obj = env->Global()->Get(v8_str("obj"));
4695   CHECK(!obj->IsInt32());
4696   CHECK(!obj->IsUint32());
4697   // Small positive integer.
4698   CompileRun("var obj = 42;");
4699   obj = env->Global()->Get(v8_str("obj"));
4700   CHECK(obj->IsInt32());
4701   CHECK(obj->IsUint32());
4702   // Negative integer.
4703   CompileRun("var obj = -37;");
4704   obj = env->Global()->Get(v8_str("obj"));
4705   CHECK(obj->IsInt32());
4706   CHECK(!obj->IsUint32());
4707   // Positive non-int32 integer.
4708   CompileRun("var obj = 0x81234567;");
4709   obj = env->Global()->Get(v8_str("obj"));
4710   CHECK(!obj->IsInt32());
4711   CHECK(obj->IsUint32());
4712   // Fraction.
4713   CompileRun("var obj = 42.3;");
4714   obj = env->Global()->Get(v8_str("obj"));
4715   CHECK(!obj->IsInt32());
4716   CHECK(!obj->IsUint32());
4717   // Large negative fraction.
4718   CompileRun("var obj = -5726623061.75;");
4719   obj = env->Global()->Get(v8_str("obj"));
4720   CHECK(!obj->IsInt32());
4721   CHECK(!obj->IsUint32());
4722   // Positive zero
4723   CompileRun("var obj = 0.0;");
4724   obj = env->Global()->Get(v8_str("obj"));
4725   CHECK(obj->IsInt32());
4726   CHECK(obj->IsUint32());
4727   // Positive zero
4728   CompileRun("var obj = -0.0;");
4729   obj = env->Global()->Get(v8_str("obj"));
4730   CHECK(!obj->IsInt32());
4731   CHECK(!obj->IsUint32());
4732 }
4733
4734
4735 THREADED_TEST(ConversionException) {
4736   LocalContext env;
4737   v8::Isolate* isolate = env->GetIsolate();
4738   v8::HandleScope scope(isolate);
4739   CompileRun(
4740     "function TestClass() { };"
4741     "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4742     "var obj = new TestClass();");
4743   Local<Value> obj = env->Global()->Get(v8_str("obj"));
4744
4745   v8::TryCatch try_catch;
4746
4747   Local<Value> to_string_result = obj->ToString();
4748   CHECK(to_string_result.IsEmpty());
4749   CheckUncle(&try_catch);
4750
4751   Local<Value> to_number_result = obj->ToNumber();
4752   CHECK(to_number_result.IsEmpty());
4753   CheckUncle(&try_catch);
4754
4755   Local<Value> to_integer_result = obj->ToInteger();
4756   CHECK(to_integer_result.IsEmpty());
4757   CheckUncle(&try_catch);
4758
4759   Local<Value> to_uint32_result = obj->ToUint32();
4760   CHECK(to_uint32_result.IsEmpty());
4761   CheckUncle(&try_catch);
4762
4763   Local<Value> to_int32_result = obj->ToInt32();
4764   CHECK(to_int32_result.IsEmpty());
4765   CheckUncle(&try_catch);
4766
4767   Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
4768   CHECK(to_object_result.IsEmpty());
4769   CHECK(try_catch.HasCaught());
4770   try_catch.Reset();
4771
4772   int32_t int32_value = obj->Int32Value();
4773   CHECK_EQ(0, int32_value);
4774   CheckUncle(&try_catch);
4775
4776   uint32_t uint32_value = obj->Uint32Value();
4777   CHECK_EQ(0, uint32_value);
4778   CheckUncle(&try_catch);
4779
4780   double number_value = obj->NumberValue();
4781   CHECK_NE(0, std::isnan(number_value));
4782   CheckUncle(&try_catch);
4783
4784   int64_t integer_value = obj->IntegerValue();
4785   CHECK_EQ(0.0, static_cast<double>(integer_value));
4786   CheckUncle(&try_catch);
4787 }
4788
4789
4790 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4791   ApiTestFuzzer::Fuzz();
4792   args.GetIsolate()->ThrowException(v8_str("konto"));
4793 }
4794
4795
4796 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4797   if (args.Length() < 1) {
4798     args.GetReturnValue().Set(false);
4799     return;
4800   }
4801   v8::HandleScope scope(args.GetIsolate());
4802   v8::TryCatch try_catch;
4803   Local<Value> result = CompileRun(args[0]->ToString());
4804   CHECK(!try_catch.HasCaught() || result.IsEmpty());
4805   args.GetReturnValue().Set(try_catch.HasCaught());
4806 }
4807
4808
4809 THREADED_TEST(APICatch) {
4810   v8::Isolate* isolate = CcTest::isolate();
4811   v8::HandleScope scope(isolate);
4812   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4813   templ->Set(v8_str("ThrowFromC"),
4814              v8::FunctionTemplate::New(isolate, ThrowFromC));
4815   LocalContext context(0, templ);
4816   CompileRun(
4817     "var thrown = false;"
4818     "try {"
4819     "  ThrowFromC();"
4820     "} catch (e) {"
4821     "  thrown = true;"
4822     "}");
4823   Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4824   CHECK(thrown->BooleanValue());
4825 }
4826
4827
4828 THREADED_TEST(APIThrowTryCatch) {
4829   v8::Isolate* isolate = CcTest::isolate();
4830   v8::HandleScope scope(isolate);
4831   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4832   templ->Set(v8_str("ThrowFromC"),
4833              v8::FunctionTemplate::New(isolate, ThrowFromC));
4834   LocalContext context(0, templ);
4835   v8::TryCatch try_catch;
4836   CompileRun("ThrowFromC();");
4837   CHECK(try_catch.HasCaught());
4838 }
4839
4840
4841 // Test that a try-finally block doesn't shadow a try-catch block
4842 // when setting up an external handler.
4843 //
4844 // BUG(271): Some of the exception propagation does not work on the
4845 // ARM simulator because the simulator separates the C++ stack and the
4846 // JS stack.  This test therefore fails on the simulator.  The test is
4847 // not threaded to allow the threading tests to run on the simulator.
4848 TEST(TryCatchInTryFinally) {
4849   v8::Isolate* isolate = CcTest::isolate();
4850   v8::HandleScope scope(isolate);
4851   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4852   templ->Set(v8_str("CCatcher"),
4853              v8::FunctionTemplate::New(isolate, CCatcher));
4854   LocalContext context(0, templ);
4855   Local<Value> result = CompileRun("try {"
4856                                    "  try {"
4857                                    "    CCatcher('throw 7;');"
4858                                    "  } finally {"
4859                                    "  }"
4860                                    "} catch (e) {"
4861                                    "}");
4862   CHECK(result->IsTrue());
4863 }
4864
4865
4866 static void check_reference_error_message(
4867     v8::Handle<v8::Message> message,
4868     v8::Handle<v8::Value> data) {
4869   const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4870   CHECK(message->Get()->Equals(v8_str(reference_error)));
4871 }
4872
4873
4874 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4875   ApiTestFuzzer::Fuzz();
4876   CHECK(false);
4877 }
4878
4879
4880 // Test that overwritten methods are not invoked on uncaught exception
4881 // formatting. However, they are invoked when performing normal error
4882 // string conversions.
4883 TEST(APIThrowMessageOverwrittenToString) {
4884   v8::Isolate* isolate = CcTest::isolate();
4885   v8::HandleScope scope(isolate);
4886   v8::V8::AddMessageListener(check_reference_error_message);
4887   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4888   templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4889   LocalContext context(NULL, templ);
4890   CompileRun("asdf;");
4891   CompileRun("var limit = {};"
4892              "limit.valueOf = fail;"
4893              "Error.stackTraceLimit = limit;");
4894   CompileRun("asdf");
4895   CompileRun("Array.prototype.pop = fail;");
4896   CompileRun("Object.prototype.hasOwnProperty = fail;");
4897   CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4898   CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4899   CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4900   CompileRun("ReferenceError.prototype.toString ="
4901              "  function() { return 'Whoops' }");
4902   CompileRun("asdf;");
4903   CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4904   CompileRun("asdf;");
4905   CompileRun("ReferenceError.prototype.constructor = void 0;");
4906   CompileRun("asdf;");
4907   CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4908   CompileRun("asdf;");
4909   CompileRun("ReferenceError.prototype = new Object();");
4910   CompileRun("asdf;");
4911   v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4912   CHECK(string->Equals(v8_str("Whoops")));
4913   CompileRun("ReferenceError.prototype.constructor = new Object();"
4914              "ReferenceError.prototype.constructor.name = 1;"
4915              "Number.prototype.toString = function() { return 'Whoops'; };"
4916              "ReferenceError.prototype.toString = Object.prototype.toString;");
4917   CompileRun("asdf;");
4918   v8::V8::RemoveMessageListeners(check_reference_error_message);
4919 }
4920
4921
4922 static void check_custom_error_tostring(
4923     v8::Handle<v8::Message> message,
4924     v8::Handle<v8::Value> data) {
4925   const char* uncaught_error = "Uncaught MyError toString";
4926   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4927 }
4928
4929
4930 TEST(CustomErrorToString) {
4931   LocalContext context;
4932   v8::HandleScope scope(context->GetIsolate());
4933   v8::V8::AddMessageListener(check_custom_error_tostring);
4934   CompileRun(
4935     "function MyError(name, message) {                   "
4936     "  this.name = name;                                 "
4937     "  this.message = message;                           "
4938     "}                                                   "
4939     "MyError.prototype = Object.create(Error.prototype); "
4940     "MyError.prototype.toString = function() {           "
4941     "  return 'MyError toString';                        "
4942     "};                                                  "
4943     "throw new MyError('my name', 'my message');         ");
4944   v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4945 }
4946
4947
4948 static void check_custom_error_message(
4949     v8::Handle<v8::Message> message,
4950     v8::Handle<v8::Value> data) {
4951   const char* uncaught_error = "Uncaught MyError: my message";
4952   printf("%s\n", *v8::String::Utf8Value(message->Get()));
4953   CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4954 }
4955
4956
4957 TEST(CustomErrorMessage) {
4958   LocalContext context;
4959   v8::HandleScope scope(context->GetIsolate());
4960   v8::V8::AddMessageListener(check_custom_error_message);
4961
4962   // Handlebars.
4963   CompileRun(
4964     "function MyError(msg) {                             "
4965     "  this.name = 'MyError';                            "
4966     "  this.message = msg;                               "
4967     "}                                                   "
4968     "MyError.prototype = new Error();                    "
4969     "throw new MyError('my message');                    ");
4970
4971   // Closure.
4972   CompileRun(
4973     "function MyError(msg) {                             "
4974     "  this.name = 'MyError';                            "
4975     "  this.message = msg;                               "
4976     "}                                                   "
4977     "inherits = function(childCtor, parentCtor) {        "
4978     "    function tempCtor() {};                         "
4979     "    tempCtor.prototype = parentCtor.prototype;      "
4980     "    childCtor.superClass_ = parentCtor.prototype;   "
4981     "    childCtor.prototype = new tempCtor();           "
4982     "    childCtor.prototype.constructor = childCtor;    "
4983     "};                                                  "
4984     "inherits(MyError, Error);                           "
4985     "throw new MyError('my message');                    ");
4986
4987   // Object.create.
4988   CompileRun(
4989     "function MyError(msg) {                             "
4990     "  this.name = 'MyError';                            "
4991     "  this.message = msg;                               "
4992     "}                                                   "
4993     "MyError.prototype = Object.create(Error.prototype); "
4994     "throw new MyError('my message');                    ");
4995
4996   v8::V8::RemoveMessageListeners(check_custom_error_message);
4997 }
4998
4999
5000 static void receive_message(v8::Handle<v8::Message> message,
5001                             v8::Handle<v8::Value> data) {
5002   message->Get();
5003   message_received = true;
5004 }
5005
5006
5007 TEST(APIThrowMessage) {
5008   message_received = false;
5009   v8::Isolate* isolate = CcTest::isolate();
5010   v8::HandleScope scope(isolate);
5011   v8::V8::AddMessageListener(receive_message);
5012   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5013   templ->Set(v8_str("ThrowFromC"),
5014              v8::FunctionTemplate::New(isolate, ThrowFromC));
5015   LocalContext context(0, templ);
5016   CompileRun("ThrowFromC();");
5017   CHECK(message_received);
5018   v8::V8::RemoveMessageListeners(receive_message);
5019 }
5020
5021
5022 TEST(APIThrowMessageAndVerboseTryCatch) {
5023   message_received = false;
5024   v8::Isolate* isolate = CcTest::isolate();
5025   v8::HandleScope scope(isolate);
5026   v8::V8::AddMessageListener(receive_message);
5027   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5028   templ->Set(v8_str("ThrowFromC"),
5029              v8::FunctionTemplate::New(isolate, ThrowFromC));
5030   LocalContext context(0, templ);
5031   v8::TryCatch try_catch;
5032   try_catch.SetVerbose(true);
5033   Local<Value> result = CompileRun("ThrowFromC();");
5034   CHECK(try_catch.HasCaught());
5035   CHECK(result.IsEmpty());
5036   CHECK(message_received);
5037   v8::V8::RemoveMessageListeners(receive_message);
5038 }
5039
5040
5041 TEST(APIStackOverflowAndVerboseTryCatch) {
5042   message_received = false;
5043   LocalContext context;
5044   v8::HandleScope scope(context->GetIsolate());
5045   v8::V8::AddMessageListener(receive_message);
5046   v8::TryCatch try_catch;
5047   try_catch.SetVerbose(true);
5048   Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5049   CHECK(try_catch.HasCaught());
5050   CHECK(result.IsEmpty());
5051   CHECK(message_received);
5052   v8::V8::RemoveMessageListeners(receive_message);
5053 }
5054
5055
5056 THREADED_TEST(ExternalScriptException) {
5057   v8::Isolate* isolate = CcTest::isolate();
5058   v8::HandleScope scope(isolate);
5059   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5060   templ->Set(v8_str("ThrowFromC"),
5061              v8::FunctionTemplate::New(isolate, ThrowFromC));
5062   LocalContext context(0, templ);
5063
5064   v8::TryCatch try_catch;
5065   Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5066   CHECK(result.IsEmpty());
5067   CHECK(try_catch.HasCaught());
5068   String::Utf8Value exception_value(try_catch.Exception());
5069   CHECK_EQ("konto", *exception_value);
5070 }
5071
5072
5073
5074 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5075   ApiTestFuzzer::Fuzz();
5076   CHECK_EQ(4, args.Length());
5077   int count = args[0]->Int32Value();
5078   int cInterval = args[2]->Int32Value();
5079   if (count == 0) {
5080     args.GetIsolate()->ThrowException(v8_str("FromC"));
5081     return;
5082   } else {
5083     Local<v8::Object> global =
5084         args.GetIsolate()->GetCurrentContext()->Global();
5085     Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5086     v8::Handle<Value> argv[] = { v8_num(count - 1),
5087                                  args[1],
5088                                  args[2],
5089                                  args[3] };
5090     if (count % cInterval == 0) {
5091       v8::TryCatch try_catch;
5092       Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5093       int expected = args[3]->Int32Value();
5094       if (try_catch.HasCaught()) {
5095         CHECK_EQ(expected, count);
5096         CHECK(result.IsEmpty());
5097         CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5098       } else {
5099         CHECK_NE(expected, count);
5100       }
5101       args.GetReturnValue().Set(result);
5102       return;
5103     } else {
5104       args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5105       return;
5106     }
5107   }
5108 }
5109
5110
5111 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5112   ApiTestFuzzer::Fuzz();
5113   CHECK_EQ(3, args.Length());
5114   bool equality = args[0]->BooleanValue();
5115   int count = args[1]->Int32Value();
5116   int expected = args[2]->Int32Value();
5117   if (equality) {
5118     CHECK_EQ(count, expected);
5119   } else {
5120     CHECK_NE(count, expected);
5121   }
5122 }
5123
5124
5125 THREADED_TEST(EvalInTryFinally) {
5126   LocalContext context;
5127   v8::HandleScope scope(context->GetIsolate());
5128   v8::TryCatch try_catch;
5129   CompileRun("(function() {"
5130              "  try {"
5131              "    eval('asldkf (*&^&*^');"
5132              "  } finally {"
5133              "    return;"
5134              "  }"
5135              "})()");
5136   CHECK(!try_catch.HasCaught());
5137 }
5138
5139
5140 // This test works by making a stack of alternating JavaScript and C
5141 // activations.  These activations set up exception handlers with regular
5142 // intervals, one interval for C activations and another for JavaScript
5143 // activations.  When enough activations have been created an exception is
5144 // thrown and we check that the right activation catches the exception and that
5145 // no other activations do.  The right activation is always the topmost one with
5146 // a handler, regardless of whether it is in JavaScript or C.
5147 //
5148 // The notation used to describe a test case looks like this:
5149 //
5150 //    *JS[4] *C[3] @JS[2] C[1] JS[0]
5151 //
5152 // Each entry is an activation, either JS or C.  The index is the count at that
5153 // level.  Stars identify activations with exception handlers, the @ identifies
5154 // the exception handler that should catch the exception.
5155 //
5156 // BUG(271): Some of the exception propagation does not work on the
5157 // ARM simulator because the simulator separates the C++ stack and the
5158 // JS stack.  This test therefore fails on the simulator.  The test is
5159 // not threaded to allow the threading tests to run on the simulator.
5160 TEST(ExceptionOrder) {
5161   v8::Isolate* isolate = CcTest::isolate();
5162   v8::HandleScope scope(isolate);
5163   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5164   templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5165   templ->Set(v8_str("CThrowCountDown"),
5166              v8::FunctionTemplate::New(isolate, CThrowCountDown));
5167   LocalContext context(0, templ);
5168   CompileRun(
5169     "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5170     "  if (count == 0) throw 'FromJS';"
5171     "  if (count % jsInterval == 0) {"
5172     "    try {"
5173     "      var value = CThrowCountDown(count - 1,"
5174     "                                  jsInterval,"
5175     "                                  cInterval,"
5176     "                                  expected);"
5177     "      check(false, count, expected);"
5178     "      return value;"
5179     "    } catch (e) {"
5180     "      check(true, count, expected);"
5181     "    }"
5182     "  } else {"
5183     "    return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5184     "  }"
5185     "}");
5186   Local<Function> fun =
5187       Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5188
5189   const int argc = 4;
5190   //                             count      jsInterval cInterval  expected
5191
5192   // *JS[4] *C[3] @JS[2] C[1] JS[0]
5193   v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5194   fun->Call(fun, argc, a0);
5195
5196   // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5197   v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5198   fun->Call(fun, argc, a1);
5199
5200   // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5201   v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5202   fun->Call(fun, argc, a2);
5203
5204   // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5205   v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5206   fun->Call(fun, argc, a3);
5207
5208   // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5209   v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5210   fun->Call(fun, argc, a4);
5211
5212   // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5213   v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5214   fun->Call(fun, argc, a5);
5215 }
5216
5217
5218 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5219   ApiTestFuzzer::Fuzz();
5220   CHECK_EQ(1, args.Length());
5221   args.GetIsolate()->ThrowException(args[0]);
5222 }
5223
5224
5225 THREADED_TEST(ThrowValues) {
5226   v8::Isolate* isolate = CcTest::isolate();
5227   v8::HandleScope scope(isolate);
5228   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5229   templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5230   LocalContext context(0, templ);
5231   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5232     "function Run(obj) {"
5233     "  try {"
5234     "    Throw(obj);"
5235     "  } catch (e) {"
5236     "    return e;"
5237     "  }"
5238     "  return 'no exception';"
5239     "}"
5240     "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5241   CHECK_EQ(5, result->Length());
5242   CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5243   CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5244   CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5245   CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5246   CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5247   CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5248   CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5249 }
5250
5251
5252 THREADED_TEST(CatchZero) {
5253   LocalContext context;
5254   v8::HandleScope scope(context->GetIsolate());
5255   v8::TryCatch try_catch;
5256   CHECK(!try_catch.HasCaught());
5257   CompileRun("throw 10");
5258   CHECK(try_catch.HasCaught());
5259   CHECK_EQ(10, try_catch.Exception()->Int32Value());
5260   try_catch.Reset();
5261   CHECK(!try_catch.HasCaught());
5262   CompileRun("throw 0");
5263   CHECK(try_catch.HasCaught());
5264   CHECK_EQ(0, try_catch.Exception()->Int32Value());
5265 }
5266
5267
5268 THREADED_TEST(CatchExceptionFromWith) {
5269   LocalContext context;
5270   v8::HandleScope scope(context->GetIsolate());
5271   v8::TryCatch try_catch;
5272   CHECK(!try_catch.HasCaught());
5273   CompileRun("var o = {}; with (o) { throw 42; }");
5274   CHECK(try_catch.HasCaught());
5275 }
5276
5277
5278 THREADED_TEST(TryCatchAndFinallyHidingException) {
5279   LocalContext context;
5280   v8::HandleScope scope(context->GetIsolate());
5281   v8::TryCatch try_catch;
5282   CHECK(!try_catch.HasCaught());
5283   CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5284   CompileRun("f({toString: function() { throw 42; }});");
5285   CHECK(!try_catch.HasCaught());
5286 }
5287
5288
5289 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5290   v8::TryCatch try_catch;
5291 }
5292
5293
5294 THREADED_TEST(TryCatchAndFinally) {
5295   LocalContext context;
5296   v8::Isolate* isolate = context->GetIsolate();
5297   v8::HandleScope scope(isolate);
5298   context->Global()->Set(
5299       v8_str("native_with_try_catch"),
5300       v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5301   v8::TryCatch try_catch;
5302   CHECK(!try_catch.HasCaught());
5303   CompileRun(
5304       "try {\n"
5305       "  throw new Error('a');\n"
5306       "} finally {\n"
5307       "  native_with_try_catch();\n"
5308       "}\n");
5309   CHECK(try_catch.HasCaught());
5310 }
5311
5312
5313 static void TryCatchNested1Helper(int depth) {
5314   if (depth > 0) {
5315     v8::TryCatch try_catch;
5316     try_catch.SetVerbose(true);
5317     TryCatchNested1Helper(depth - 1);
5318     CHECK(try_catch.HasCaught());
5319     try_catch.ReThrow();
5320   } else {
5321     CcTest::isolate()->ThrowException(v8_str("E1"));
5322   }
5323 }
5324
5325
5326 static void TryCatchNested2Helper(int depth) {
5327   if (depth > 0) {
5328     v8::TryCatch try_catch;
5329     try_catch.SetVerbose(true);
5330     TryCatchNested2Helper(depth - 1);
5331     CHECK(try_catch.HasCaught());
5332     try_catch.ReThrow();
5333   } else {
5334     CompileRun("throw 'E2';");
5335   }
5336 }
5337
5338
5339 TEST(TryCatchNested) {
5340   v8::V8::Initialize();
5341   LocalContext context;
5342   v8::HandleScope scope(context->GetIsolate());
5343
5344   {
5345     // Test nested try-catch with a native throw in the end.
5346     v8::TryCatch try_catch;
5347     TryCatchNested1Helper(5);
5348     CHECK(try_catch.HasCaught());
5349     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5350   }
5351
5352   {
5353     // Test nested try-catch with a JavaScript throw in the end.
5354     v8::TryCatch try_catch;
5355     TryCatchNested2Helper(5);
5356     CHECK(try_catch.HasCaught());
5357     CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5358   }
5359 }
5360
5361
5362 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5363   CHECK(try_catch->HasCaught());
5364   Handle<Message> message = try_catch->Message();
5365   Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5366   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5367   CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5368                      "Uncaught Error: a"));
5369   CHECK_EQ(1, message->GetLineNumber());
5370   CHECK_EQ(6, message->GetStartColumn());
5371 }
5372
5373
5374 void TryCatchMixedNestingHelper(
5375     const v8::FunctionCallbackInfo<v8::Value>& args) {
5376   ApiTestFuzzer::Fuzz();
5377   v8::TryCatch try_catch;
5378   CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5379   CHECK(try_catch.HasCaught());
5380   TryCatchMixedNestingCheck(&try_catch);
5381   try_catch.ReThrow();
5382 }
5383
5384
5385 // This test ensures that an outer TryCatch in the following situation:
5386 //   C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5387 // does not clobber the Message object generated for the inner TryCatch.
5388 // This exercises the ability of TryCatch.ReThrow() to restore the
5389 // inner pending Message before throwing the exception again.
5390 TEST(TryCatchMixedNesting) {
5391   v8::Isolate* isolate = CcTest::isolate();
5392   v8::HandleScope scope(isolate);
5393   v8::V8::Initialize();
5394   v8::TryCatch try_catch;
5395   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5396   templ->Set(v8_str("TryCatchMixedNestingHelper"),
5397              v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5398   LocalContext context(0, templ);
5399   CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5400   TryCatchMixedNestingCheck(&try_catch);
5401 }
5402
5403
5404 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5405   ApiTestFuzzer::Fuzz();
5406   v8::TryCatch try_catch;
5407   args.GetIsolate()->ThrowException(v8_str("boom"));
5408   CHECK(try_catch.HasCaught());
5409 }
5410
5411
5412 TEST(TryCatchNative) {
5413   v8::Isolate* isolate = CcTest::isolate();
5414   v8::HandleScope scope(isolate);
5415   v8::V8::Initialize();
5416   v8::TryCatch try_catch;
5417   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5418   templ->Set(v8_str("TryCatchNativeHelper"),
5419              v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5420   LocalContext context(0, templ);
5421   CompileRun("TryCatchNativeHelper();");
5422   CHECK(!try_catch.HasCaught());
5423 }
5424
5425
5426 void TryCatchNativeResetHelper(
5427     const v8::FunctionCallbackInfo<v8::Value>& args) {
5428   ApiTestFuzzer::Fuzz();
5429   v8::TryCatch try_catch;
5430   args.GetIsolate()->ThrowException(v8_str("boom"));
5431   CHECK(try_catch.HasCaught());
5432   try_catch.Reset();
5433   CHECK(!try_catch.HasCaught());
5434 }
5435
5436
5437 TEST(TryCatchNativeReset) {
5438   v8::Isolate* isolate = CcTest::isolate();
5439   v8::HandleScope scope(isolate);
5440   v8::V8::Initialize();
5441   v8::TryCatch try_catch;
5442   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5443   templ->Set(v8_str("TryCatchNativeResetHelper"),
5444              v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5445   LocalContext context(0, templ);
5446   CompileRun("TryCatchNativeResetHelper();");
5447   CHECK(!try_catch.HasCaught());
5448 }
5449
5450
5451 THREADED_TEST(Equality) {
5452   LocalContext context;
5453   v8::Isolate* isolate = context->GetIsolate();
5454   v8::HandleScope scope(context->GetIsolate());
5455   // Check that equality works at all before relying on CHECK_EQ
5456   CHECK(v8_str("a")->Equals(v8_str("a")));
5457   CHECK(!v8_str("a")->Equals(v8_str("b")));
5458
5459   CHECK_EQ(v8_str("a"), v8_str("a"));
5460   CHECK_NE(v8_str("a"), v8_str("b"));
5461   CHECK_EQ(v8_num(1), v8_num(1));
5462   CHECK_EQ(v8_num(1.00), v8_num(1));
5463   CHECK_NE(v8_num(1), v8_num(2));
5464
5465   // Assume String is not internalized.
5466   CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5467   CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5468   CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5469   CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5470   CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5471   CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5472   Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5473   CHECK(!not_a_number->StrictEquals(not_a_number));
5474   CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5475   CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5476
5477   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5478   v8::Persistent<v8::Object> alias(isolate, obj);
5479   CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5480   alias.Reset();
5481
5482   CHECK(v8_str("a")->SameValue(v8_str("a")));
5483   CHECK(!v8_str("a")->SameValue(v8_str("b")));
5484   CHECK(!v8_str("5")->SameValue(v8_num(5)));
5485   CHECK(v8_num(1)->SameValue(v8_num(1)));
5486   CHECK(!v8_num(1)->SameValue(v8_num(2)));
5487   CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5488   CHECK(not_a_number->SameValue(not_a_number));
5489   CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5490   CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5491 }
5492
5493
5494 THREADED_TEST(MultiRun) {
5495   LocalContext context;
5496   v8::HandleScope scope(context->GetIsolate());
5497   Local<Script> script = v8_compile("x");
5498   for (int i = 0; i < 10; i++)
5499     script->Run();
5500 }
5501
5502
5503 static void GetXValue(Local<String> name,
5504                       const v8::PropertyCallbackInfo<v8::Value>& info) {
5505   ApiTestFuzzer::Fuzz();
5506   CHECK_EQ(info.Data(), v8_str("donut"));
5507   CHECK_EQ(name, v8_str("x"));
5508   info.GetReturnValue().Set(name);
5509 }
5510
5511
5512 THREADED_TEST(SimplePropertyRead) {
5513   LocalContext context;
5514   v8::Isolate* isolate = context->GetIsolate();
5515   v8::HandleScope scope(isolate);
5516   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5517   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5518   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5519   Local<Script> script = v8_compile("obj.x");
5520   for (int i = 0; i < 10; i++) {
5521     Local<Value> result = script->Run();
5522     CHECK_EQ(result, v8_str("x"));
5523   }
5524 }
5525
5526
5527 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5528   LocalContext context;
5529   v8::Isolate* isolate = context->GetIsolate();
5530   v8::HandleScope scope(isolate);
5531   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5532   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5533   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5534
5535   // Uses getOwnPropertyDescriptor to check the configurable status
5536   Local<Script> script_desc = v8_compile(
5537       "var prop = Object.getOwnPropertyDescriptor( "
5538       "obj, 'x');"
5539       "prop.configurable;");
5540   Local<Value> result = script_desc->Run();
5541   CHECK_EQ(result->BooleanValue(), true);
5542
5543   // Redefine get - but still configurable
5544   Local<Script> script_define = v8_compile(
5545       "var desc = { get: function(){return 42; },"
5546       "            configurable: true };"
5547       "Object.defineProperty(obj, 'x', desc);"
5548       "obj.x");
5549   result = script_define->Run();
5550   CHECK_EQ(result, v8_num(42));
5551
5552   // Check that the accessor is still configurable
5553   result = script_desc->Run();
5554   CHECK_EQ(result->BooleanValue(), true);
5555
5556   // Redefine to a non-configurable
5557   script_define = v8_compile(
5558       "var desc = { get: function(){return 43; },"
5559       "             configurable: false };"
5560       "Object.defineProperty(obj, 'x', desc);"
5561       "obj.x");
5562   result = script_define->Run();
5563   CHECK_EQ(result, v8_num(43));
5564   result = script_desc->Run();
5565   CHECK_EQ(result->BooleanValue(), false);
5566
5567   // Make sure that it is not possible to redefine again
5568   v8::TryCatch try_catch;
5569   result = script_define->Run();
5570   CHECK(try_catch.HasCaught());
5571   String::Utf8Value exception_value(try_catch.Exception());
5572   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5573 }
5574
5575
5576 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5577   v8::Isolate* isolate = CcTest::isolate();
5578   v8::HandleScope scope(isolate);
5579   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5580   templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5581   LocalContext context;
5582   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5583
5584   Local<Script> script_desc = v8_compile(
5585       "var prop ="
5586       "Object.getOwnPropertyDescriptor( "
5587       "obj, 'x');"
5588       "prop.configurable;");
5589   Local<Value> result = script_desc->Run();
5590   CHECK_EQ(result->BooleanValue(), true);
5591
5592   Local<Script> script_define = v8_compile(
5593       "var desc = {get: function(){return 42; },"
5594       "            configurable: true };"
5595       "Object.defineProperty(obj, 'x', desc);"
5596       "obj.x");
5597   result = script_define->Run();
5598   CHECK_EQ(result, v8_num(42));
5599
5600
5601   result = script_desc->Run();
5602   CHECK_EQ(result->BooleanValue(), true);
5603
5604
5605   script_define = v8_compile(
5606       "var desc = {get: function(){return 43; },"
5607       "            configurable: false };"
5608       "Object.defineProperty(obj, 'x', desc);"
5609       "obj.x");
5610   result = script_define->Run();
5611   CHECK_EQ(result, v8_num(43));
5612   result = script_desc->Run();
5613
5614   CHECK_EQ(result->BooleanValue(), false);
5615
5616   v8::TryCatch try_catch;
5617   result = script_define->Run();
5618   CHECK(try_catch.HasCaught());
5619   String::Utf8Value exception_value(try_catch.Exception());
5620   CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5621 }
5622
5623
5624 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5625                                                 char const* name) {
5626   return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5627 }
5628
5629
5630 THREADED_TEST(DefineAPIAccessorOnObject) {
5631   v8::Isolate* isolate = CcTest::isolate();
5632   v8::HandleScope scope(isolate);
5633   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5634   LocalContext context;
5635
5636   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5637   CompileRun("var obj2 = {};");
5638
5639   CHECK(CompileRun("obj1.x")->IsUndefined());
5640   CHECK(CompileRun("obj2.x")->IsUndefined());
5641
5642   CHECK(GetGlobalProperty(&context, "obj1")->
5643       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5644
5645   ExpectString("obj1.x", "x");
5646   CHECK(CompileRun("obj2.x")->IsUndefined());
5647
5648   CHECK(GetGlobalProperty(&context, "obj2")->
5649       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5650
5651   ExpectString("obj1.x", "x");
5652   ExpectString("obj2.x", "x");
5653
5654   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5655   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5656
5657   CompileRun("Object.defineProperty(obj1, 'x',"
5658              "{ get: function() { return 'y'; }, configurable: true })");
5659
5660   ExpectString("obj1.x", "y");
5661   ExpectString("obj2.x", "x");
5662
5663   CompileRun("Object.defineProperty(obj2, 'x',"
5664              "{ get: function() { return 'y'; }, configurable: true })");
5665
5666   ExpectString("obj1.x", "y");
5667   ExpectString("obj2.x", "y");
5668
5669   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5670   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5671
5672   CHECK(GetGlobalProperty(&context, "obj1")->
5673       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5674   CHECK(GetGlobalProperty(&context, "obj2")->
5675       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5676
5677   ExpectString("obj1.x", "x");
5678   ExpectString("obj2.x", "x");
5679
5680   ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5681   ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5682
5683   // Define getters/setters, but now make them not configurable.
5684   CompileRun("Object.defineProperty(obj1, 'x',"
5685              "{ get: function() { return 'z'; }, configurable: false })");
5686   CompileRun("Object.defineProperty(obj2, 'x',"
5687              "{ get: function() { return 'z'; }, configurable: false })");
5688
5689   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5690   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5691
5692   ExpectString("obj1.x", "z");
5693   ExpectString("obj2.x", "z");
5694
5695   CHECK(!GetGlobalProperty(&context, "obj1")->
5696       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5697   CHECK(!GetGlobalProperty(&context, "obj2")->
5698       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5699
5700   ExpectString("obj1.x", "z");
5701   ExpectString("obj2.x", "z");
5702 }
5703
5704
5705 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5706   v8::Isolate* isolate = CcTest::isolate();
5707   v8::HandleScope scope(isolate);
5708   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5709   LocalContext context;
5710
5711   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5712   CompileRun("var obj2 = {};");
5713
5714   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5715         v8_str("x"),
5716         GetXValue, NULL,
5717         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5718   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5719         v8_str("x"),
5720         GetXValue, NULL,
5721         v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5722
5723   ExpectString("obj1.x", "x");
5724   ExpectString("obj2.x", "x");
5725
5726   ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5727   ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5728
5729   CHECK(!GetGlobalProperty(&context, "obj1")->
5730       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5731   CHECK(!GetGlobalProperty(&context, "obj2")->
5732       SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5733
5734   {
5735     v8::TryCatch try_catch;
5736     CompileRun("Object.defineProperty(obj1, 'x',"
5737         "{get: function() { return 'func'; }})");
5738     CHECK(try_catch.HasCaught());
5739     String::Utf8Value exception_value(try_catch.Exception());
5740     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5741   }
5742   {
5743     v8::TryCatch try_catch;
5744     CompileRun("Object.defineProperty(obj2, 'x',"
5745         "{get: function() { return 'func'; }})");
5746     CHECK(try_catch.HasCaught());
5747     String::Utf8Value exception_value(try_catch.Exception());
5748     CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5749   }
5750 }
5751
5752
5753 static void Get239Value(Local<String> name,
5754                         const v8::PropertyCallbackInfo<v8::Value>& info) {
5755   ApiTestFuzzer::Fuzz();
5756   CHECK_EQ(info.Data(), v8_str("donut"));
5757   CHECK_EQ(name, v8_str("239"));
5758   info.GetReturnValue().Set(name);
5759 }
5760
5761
5762 THREADED_TEST(ElementAPIAccessor) {
5763   v8::Isolate* isolate = CcTest::isolate();
5764   v8::HandleScope scope(isolate);
5765   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5766   LocalContext context;
5767
5768   context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5769   CompileRun("var obj2 = {};");
5770
5771   CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5772         v8_str("239"),
5773         Get239Value, NULL,
5774         v8_str("donut")));
5775   CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5776         v8_str("239"),
5777         Get239Value, NULL,
5778         v8_str("donut")));
5779
5780   ExpectString("obj1[239]", "239");
5781   ExpectString("obj2[239]", "239");
5782   ExpectString("obj1['239']", "239");
5783   ExpectString("obj2['239']", "239");
5784 }
5785
5786
5787 v8::Persistent<Value> xValue;
5788
5789
5790 static void SetXValue(Local<String> name,
5791                       Local<Value> value,
5792                       const v8::PropertyCallbackInfo<void>& info) {
5793   CHECK_EQ(value, v8_num(4));
5794   CHECK_EQ(info.Data(), v8_str("donut"));
5795   CHECK_EQ(name, v8_str("x"));
5796   CHECK(xValue.IsEmpty());
5797   xValue.Reset(info.GetIsolate(), value);
5798 }
5799
5800
5801 THREADED_TEST(SimplePropertyWrite) {
5802   v8::Isolate* isolate = CcTest::isolate();
5803   v8::HandleScope scope(isolate);
5804   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5805   templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5806   LocalContext context;
5807   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5808   Local<Script> script = v8_compile("obj.x = 4");
5809   for (int i = 0; i < 10; i++) {
5810     CHECK(xValue.IsEmpty());
5811     script->Run();
5812     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5813     xValue.Reset();
5814   }
5815 }
5816
5817
5818 THREADED_TEST(SetterOnly) {
5819   v8::Isolate* isolate = CcTest::isolate();
5820   v8::HandleScope scope(isolate);
5821   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5822   templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5823   LocalContext context;
5824   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5825   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5826   for (int i = 0; i < 10; i++) {
5827     CHECK(xValue.IsEmpty());
5828     script->Run();
5829     CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
5830     xValue.Reset();
5831   }
5832 }
5833
5834
5835 THREADED_TEST(NoAccessors) {
5836   v8::Isolate* isolate = CcTest::isolate();
5837   v8::HandleScope scope(isolate);
5838   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5839   templ->SetAccessor(v8_str("x"),
5840                      static_cast<v8::AccessorGetterCallback>(NULL),
5841                      NULL,
5842                      v8_str("donut"));
5843   LocalContext context;
5844   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5845   Local<Script> script = v8_compile("obj.x = 4; obj.x");
5846   for (int i = 0; i < 10; i++) {
5847     script->Run();
5848   }
5849 }
5850
5851
5852 static void XPropertyGetter(Local<String> property,
5853                             const v8::PropertyCallbackInfo<v8::Value>& info) {
5854   ApiTestFuzzer::Fuzz();
5855   CHECK(info.Data()->IsUndefined());
5856   info.GetReturnValue().Set(property);
5857 }
5858
5859
5860 THREADED_TEST(NamedInterceptorPropertyRead) {
5861   v8::Isolate* isolate = CcTest::isolate();
5862   v8::HandleScope scope(isolate);
5863   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5864   templ->SetNamedPropertyHandler(XPropertyGetter);
5865   LocalContext context;
5866   context->Global()->Set(v8_str("obj"), templ->NewInstance());
5867   Local<Script> script = v8_compile("obj.x");
5868   for (int i = 0; i < 10; i++) {
5869     Local<Value> result = script->Run();
5870     CHECK_EQ(result, v8_str("x"));
5871   }
5872 }
5873
5874
5875 THREADED_TEST(NamedInterceptorDictionaryIC) {
5876   v8::Isolate* isolate = CcTest::isolate();
5877   v8::HandleScope scope(isolate);
5878   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5879   templ->SetNamedPropertyHandler(XPropertyGetter);
5880   LocalContext context;
5881   // Create an object with a named interceptor.
5882   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5883   Local<Script> script = v8_compile("interceptor_obj.x");
5884   for (int i = 0; i < 10; i++) {
5885     Local<Value> result = script->Run();
5886     CHECK_EQ(result, v8_str("x"));
5887   }
5888   // Create a slow case object and a function accessing a property in
5889   // that slow case object (with dictionary probing in generated
5890   // code). Then force object with a named interceptor into slow-case,
5891   // pass it to the function, and check that the interceptor is called
5892   // instead of accessing the local property.
5893   Local<Value> result =
5894       CompileRun("function get_x(o) { return o.x; };"
5895                  "var obj = { x : 42, y : 0 };"
5896                  "delete obj.y;"
5897                  "for (var i = 0; i < 10; i++) get_x(obj);"
5898                  "interceptor_obj.x = 42;"
5899                  "interceptor_obj.y = 10;"
5900                  "delete interceptor_obj.y;"
5901                  "get_x(interceptor_obj)");
5902   CHECK_EQ(result, v8_str("x"));
5903 }
5904
5905
5906 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5907   v8::Isolate* isolate = CcTest::isolate();
5908   v8::HandleScope scope(isolate);
5909   v8::Local<Context> context1 = Context::New(isolate);
5910
5911   context1->Enter();
5912   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5913   templ->SetNamedPropertyHandler(XPropertyGetter);
5914   // Create an object with a named interceptor.
5915   v8::Local<v8::Object> object = templ->NewInstance();
5916   context1->Global()->Set(v8_str("interceptor_obj"), object);
5917
5918   // Force the object into the slow case.
5919   CompileRun("interceptor_obj.y = 0;"
5920              "delete interceptor_obj.y;");
5921   context1->Exit();
5922
5923   {
5924     // Introduce the object into a different context.
5925     // Repeat named loads to exercise ICs.
5926     LocalContext context2;
5927     context2->Global()->Set(v8_str("interceptor_obj"), object);
5928     Local<Value> result =
5929       CompileRun("function get_x(o) { return o.x; }"
5930                  "interceptor_obj.x = 42;"
5931                  "for (var i=0; i != 10; i++) {"
5932                  "  get_x(interceptor_obj);"
5933                  "}"
5934                  "get_x(interceptor_obj)");
5935     // Check that the interceptor was actually invoked.
5936     CHECK_EQ(result, v8_str("x"));
5937   }
5938
5939   // Return to the original context and force some object to the slow case
5940   // to cause the NormalizedMapCache to verify.
5941   context1->Enter();
5942   CompileRun("var obj = { x : 0 }; delete obj.x;");
5943   context1->Exit();
5944 }
5945
5946
5947 static void SetXOnPrototypeGetter(
5948     Local<String> property,
5949     const v8::PropertyCallbackInfo<v8::Value>& info) {
5950   // Set x on the prototype object and do not handle the get request.
5951   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5952   proto.As<v8::Object>()->Set(v8_str("x"),
5953                               v8::Integer::New(info.GetIsolate(), 23));
5954 }
5955
5956
5957 // This is a regression test for http://crbug.com/20104. Map
5958 // transitions should not interfere with post interceptor lookup.
5959 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5960   v8::Isolate* isolate = CcTest::isolate();
5961   v8::HandleScope scope(isolate);
5962   Local<v8::FunctionTemplate> function_template =
5963       v8::FunctionTemplate::New(isolate);
5964   Local<v8::ObjectTemplate> instance_template
5965       = function_template->InstanceTemplate();
5966   instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5967   LocalContext context;
5968   context->Global()->Set(v8_str("F"), function_template->GetFunction());
5969   // Create an instance of F and introduce a map transition for x.
5970   CompileRun("var o = new F(); o.x = 23;");
5971   // Create an instance of F and invoke the getter. The result should be 23.
5972   Local<Value> result = CompileRun("o = new F(); o.x");
5973   CHECK_EQ(result->Int32Value(), 23);
5974 }
5975
5976
5977 static void IndexedPropertyGetter(
5978     uint32_t index,
5979     const v8::PropertyCallbackInfo<v8::Value>& info) {
5980   ApiTestFuzzer::Fuzz();
5981   if (index == 37) {
5982     info.GetReturnValue().Set(v8_num(625));
5983   }
5984 }
5985
5986
5987 static void IndexedPropertySetter(
5988     uint32_t index,
5989     Local<Value> value,
5990     const v8::PropertyCallbackInfo<v8::Value>& info) {
5991   ApiTestFuzzer::Fuzz();
5992   if (index == 39) {
5993     info.GetReturnValue().Set(value);
5994   }
5995 }
5996
5997
5998 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5999   v8::Isolate* isolate = CcTest::isolate();
6000   v8::HandleScope scope(isolate);
6001   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6002   templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6003                                    IndexedPropertySetter);
6004   LocalContext context;
6005   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6006   Local<Script> getter_script = v8_compile(
6007       "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6008   Local<Script> setter_script = v8_compile(
6009       "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6010       "obj[17] = 23;"
6011       "obj.foo;");
6012   Local<Script> interceptor_setter_script = v8_compile(
6013       "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6014       "obj[39] = 47;"
6015       "obj.foo;");  // This setter should not run, due to the interceptor.
6016   Local<Script> interceptor_getter_script = v8_compile(
6017       "obj[37];");
6018   Local<Value> result = getter_script->Run();
6019   CHECK_EQ(v8_num(5), result);
6020   result = setter_script->Run();
6021   CHECK_EQ(v8_num(23), result);
6022   result = interceptor_setter_script->Run();
6023   CHECK_EQ(v8_num(23), result);
6024   result = interceptor_getter_script->Run();
6025   CHECK_EQ(v8_num(625), result);
6026 }
6027
6028
6029 static void UnboxedDoubleIndexedPropertyGetter(
6030     uint32_t index,
6031     const v8::PropertyCallbackInfo<v8::Value>& info) {
6032   ApiTestFuzzer::Fuzz();
6033   if (index < 25) {
6034     info.GetReturnValue().Set(v8_num(index));
6035   }
6036 }
6037
6038
6039 static void UnboxedDoubleIndexedPropertySetter(
6040     uint32_t index,
6041     Local<Value> value,
6042     const v8::PropertyCallbackInfo<v8::Value>& info) {
6043   ApiTestFuzzer::Fuzz();
6044   if (index < 25) {
6045     info.GetReturnValue().Set(v8_num(index));
6046   }
6047 }
6048
6049
6050 void UnboxedDoubleIndexedPropertyEnumerator(
6051     const v8::PropertyCallbackInfo<v8::Array>& info) {
6052   // Force the list of returned keys to be stored in a FastDoubleArray.
6053   Local<Script> indexed_property_names_script = v8_compile(
6054       "keys = new Array(); keys[125000] = 1;"
6055       "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6056       "keys.length = 25; keys;");
6057   Local<Value> result = indexed_property_names_script->Run();
6058   info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6059 }
6060
6061
6062 // Make sure that the the interceptor code in the runtime properly handles
6063 // merging property name lists for double-array-backed arrays.
6064 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6065   v8::Isolate* isolate = CcTest::isolate();
6066   v8::HandleScope scope(isolate);
6067   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6068   templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6069                                    UnboxedDoubleIndexedPropertySetter,
6070                                    0,
6071                                    0,
6072                                    UnboxedDoubleIndexedPropertyEnumerator);
6073   LocalContext context;
6074   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6075   // When obj is created, force it to be Stored in a FastDoubleArray.
6076   Local<Script> create_unboxed_double_script = v8_compile(
6077       "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6078       "key_count = 0; "
6079       "for (x in obj) {key_count++;};"
6080       "obj;");
6081   Local<Value> result = create_unboxed_double_script->Run();
6082   CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6083   Local<Script> key_count_check = v8_compile("key_count;");
6084   result = key_count_check->Run();
6085   CHECK_EQ(v8_num(40013), result);
6086 }
6087
6088
6089 void SloppyArgsIndexedPropertyEnumerator(
6090     const v8::PropertyCallbackInfo<v8::Array>& info) {
6091   // Force the list of returned keys to be stored in a Arguments object.
6092   Local<Script> indexed_property_names_script = v8_compile(
6093       "function f(w,x) {"
6094       " return arguments;"
6095       "}"
6096       "keys = f(0, 1, 2, 3);"
6097       "keys;");
6098   Local<Object> result =
6099       Local<Object>::Cast(indexed_property_names_script->Run());
6100   // Have to populate the handle manually, as it's not Cast-able.
6101   i::Handle<i::JSObject> o =
6102       v8::Utils::OpenHandle<Object, i::JSObject>(result);
6103   i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6104   info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6105 }
6106
6107
6108 static void SloppyIndexedPropertyGetter(
6109     uint32_t index,
6110     const v8::PropertyCallbackInfo<v8::Value>& info) {
6111   ApiTestFuzzer::Fuzz();
6112   if (index < 4) {
6113     info.GetReturnValue().Set(v8_num(index));
6114   }
6115 }
6116
6117
6118 // Make sure that the the interceptor code in the runtime properly handles
6119 // merging property name lists for non-string arguments arrays.
6120 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6121   v8::Isolate* isolate = CcTest::isolate();
6122   v8::HandleScope scope(isolate);
6123   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6124   templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6125                                    0,
6126                                    0,
6127                                    0,
6128                                    SloppyArgsIndexedPropertyEnumerator);
6129   LocalContext context;
6130   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6131   Local<Script> create_args_script = v8_compile(
6132       "var key_count = 0;"
6133       "for (x in obj) {key_count++;} key_count;");
6134   Local<Value> result = create_args_script->Run();
6135   CHECK_EQ(v8_num(4), result);
6136 }
6137
6138
6139 static void IdentityIndexedPropertyGetter(
6140     uint32_t index,
6141     const v8::PropertyCallbackInfo<v8::Value>& info) {
6142   info.GetReturnValue().Set(index);
6143 }
6144
6145
6146 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6147   v8::Isolate* isolate = CcTest::isolate();
6148   v8::HandleScope scope(isolate);
6149   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6150   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6151
6152   LocalContext context;
6153   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6154
6155   // Check fast object case.
6156   const char* fast_case_code =
6157       "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6158   ExpectString(fast_case_code, "0");
6159
6160   // Check slow case.
6161   const char* slow_case_code =
6162       "obj.x = 1; delete obj.x;"
6163       "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6164   ExpectString(slow_case_code, "1");
6165 }
6166
6167
6168 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6169   v8::Isolate* isolate = CcTest::isolate();
6170   v8::HandleScope scope(isolate);
6171   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6172   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6173
6174   LocalContext context;
6175   context->Global()->Set(v8_str("obj"), templ->NewInstance());
6176
6177   const char* code =
6178       "try {"
6179       "  obj[0] = 239;"
6180       "  for (var i = 0; i < 100; i++) {"
6181       "    var v = obj[0];"
6182       "    if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6183       "  }"
6184       "  'PASSED'"
6185       "} catch(e) {"
6186       "  e"
6187       "}";
6188   ExpectString(code, "PASSED");
6189 }
6190
6191
6192 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6193   v8::Isolate* isolate = CcTest::isolate();
6194   v8::HandleScope scope(isolate);
6195   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6196   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6197
6198   LocalContext context;
6199   Local<v8::Object> obj = templ->NewInstance();
6200   obj->TurnOnAccessCheck();
6201   context->Global()->Set(v8_str("obj"), obj);
6202
6203   const char* code =
6204       "var result = 'PASSED';"
6205       "for (var i = 0; i < 100; i++) {"
6206       "  try {"
6207       "    var v = obj[0];"
6208       "    result = 'Wrong value ' + v + ' at iteration ' + i;"
6209       "    break;"
6210       "  } catch (e) {"
6211       "    /* pass */"
6212       "  }"
6213       "}"
6214       "result";
6215   ExpectString(code, "PASSED");
6216 }
6217
6218
6219 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6220   i::FLAG_allow_natives_syntax = true;
6221   v8::Isolate* isolate = CcTest::isolate();
6222   v8::HandleScope scope(isolate);
6223   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6224   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6225
6226   LocalContext context;
6227   Local<v8::Object> obj = templ->NewInstance();
6228   context->Global()->Set(v8_str("obj"), obj);
6229
6230   const char* code =
6231       "var result = 'PASSED';"
6232       "for (var i = 0; i < 100; i++) {"
6233       "  var expected = i;"
6234       "  if (i == 5) {"
6235       "    %EnableAccessChecks(obj);"
6236       "  }"
6237       "  try {"
6238       "    var v = obj[i];"
6239       "    if (i == 5) {"
6240       "      result = 'Should not have reached this!';"
6241       "      break;"
6242       "    } else if (v != expected) {"
6243       "      result = 'Wrong value ' + v + ' at iteration ' + i;"
6244       "      break;"
6245       "    }"
6246       "  } catch (e) {"
6247       "    if (i != 5) {"
6248       "      result = e;"
6249       "    }"
6250       "  }"
6251       "  if (i == 5) %DisableAccessChecks(obj);"
6252       "}"
6253       "result";
6254   ExpectString(code, "PASSED");
6255 }
6256
6257
6258 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6259   v8::Isolate* isolate = CcTest::isolate();
6260   v8::HandleScope scope(isolate);
6261   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6262   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6263
6264   LocalContext context;
6265   Local<v8::Object> obj = templ->NewInstance();
6266   context->Global()->Set(v8_str("obj"), obj);
6267
6268   const char* code =
6269       "try {"
6270       "  for (var i = 0; i < 100; i++) {"
6271       "    var v = obj[i];"
6272       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6273       "  }"
6274       "  'PASSED'"
6275       "} catch(e) {"
6276       "  e"
6277       "}";
6278   ExpectString(code, "PASSED");
6279 }
6280
6281
6282 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6283   v8::Isolate* isolate = CcTest::isolate();
6284   v8::HandleScope scope(isolate);
6285   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6286   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6287
6288   LocalContext context;
6289   Local<v8::Object> obj = templ->NewInstance();
6290   context->Global()->Set(v8_str("obj"), obj);
6291
6292   const char* code =
6293       "try {"
6294       "  for (var i = 0; i < 100; i++) {"
6295       "    var expected = i;"
6296       "    var key = i;"
6297       "    if (i == 25) {"
6298       "       key = -1;"
6299       "       expected = undefined;"
6300       "    }"
6301       "    if (i == 50) {"
6302       "       /* probe minimal Smi number on 32-bit platforms */"
6303       "       key = -(1 << 30);"
6304       "       expected = undefined;"
6305       "    }"
6306       "    if (i == 75) {"
6307       "       /* probe minimal Smi number on 64-bit platforms */"
6308       "       key = 1 << 31;"
6309       "       expected = undefined;"
6310       "    }"
6311       "    var v = obj[key];"
6312       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6313       "  }"
6314       "  'PASSED'"
6315       "} catch(e) {"
6316       "  e"
6317       "}";
6318   ExpectString(code, "PASSED");
6319 }
6320
6321
6322 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6323   v8::Isolate* isolate = CcTest::isolate();
6324   v8::HandleScope scope(isolate);
6325   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6326   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6327
6328   LocalContext context;
6329   Local<v8::Object> obj = templ->NewInstance();
6330   context->Global()->Set(v8_str("obj"), obj);
6331
6332   const char* code =
6333       "try {"
6334       "  for (var i = 0; i < 100; i++) {"
6335       "    var expected = i;"
6336       "    var key = i;"
6337       "    if (i == 50) {"
6338       "       key = 'foobar';"
6339       "       expected = undefined;"
6340       "    }"
6341       "    var v = obj[key];"
6342       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6343       "  }"
6344       "  'PASSED'"
6345       "} catch(e) {"
6346       "  e"
6347       "}";
6348   ExpectString(code, "PASSED");
6349 }
6350
6351
6352 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6353   v8::Isolate* isolate = CcTest::isolate();
6354   v8::HandleScope scope(isolate);
6355   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6356   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6357
6358   LocalContext context;
6359   Local<v8::Object> obj = templ->NewInstance();
6360   context->Global()->Set(v8_str("obj"), obj);
6361
6362   const char* code =
6363       "var original = obj;"
6364       "try {"
6365       "  for (var i = 0; i < 100; i++) {"
6366       "    var expected = i;"
6367       "    if (i == 50) {"
6368       "       obj = {50: 'foobar'};"
6369       "       expected = 'foobar';"
6370       "    }"
6371       "    var v = obj[i];"
6372       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6373       "    if (i == 50) obj = original;"
6374       "  }"
6375       "  'PASSED'"
6376       "} catch(e) {"
6377       "  e"
6378       "}";
6379   ExpectString(code, "PASSED");
6380 }
6381
6382
6383 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6384   v8::Isolate* isolate = CcTest::isolate();
6385   v8::HandleScope scope(isolate);
6386   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6387   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6388
6389   LocalContext context;
6390   Local<v8::Object> obj = templ->NewInstance();
6391   context->Global()->Set(v8_str("obj"), obj);
6392
6393   const char* code =
6394       "var original = obj;"
6395       "try {"
6396       "  for (var i = 0; i < 100; i++) {"
6397       "    var expected = i;"
6398       "    if (i == 5) {"
6399       "       obj = 239;"
6400       "       expected = undefined;"
6401       "    }"
6402       "    var v = obj[i];"
6403       "    if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6404       "    if (i == 5) obj = original;"
6405       "  }"
6406       "  'PASSED'"
6407       "} catch(e) {"
6408       "  e"
6409       "}";
6410   ExpectString(code, "PASSED");
6411 }
6412
6413
6414 THREADED_TEST(IndexedInterceptorOnProto) {
6415   v8::Isolate* isolate = CcTest::isolate();
6416   v8::HandleScope scope(isolate);
6417   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6418   templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6419
6420   LocalContext context;
6421   Local<v8::Object> obj = templ->NewInstance();
6422   context->Global()->Set(v8_str("obj"), obj);
6423
6424   const char* code =
6425       "var o = {__proto__: obj};"
6426       "try {"
6427       "  for (var i = 0; i < 100; i++) {"
6428       "    var v = o[i];"
6429       "    if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6430       "  }"
6431       "  'PASSED'"
6432       "} catch(e) {"
6433       "  e"
6434       "}";
6435   ExpectString(code, "PASSED");
6436 }
6437
6438
6439 THREADED_TEST(MultiContexts) {
6440   v8::Isolate* isolate = CcTest::isolate();
6441   v8::HandleScope scope(isolate);
6442   v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6443   templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6444                                                         DummyCallHandler));
6445
6446   Local<String> password = v8_str("Password");
6447
6448   // Create an environment
6449   LocalContext context0(0, templ);
6450   context0->SetSecurityToken(password);
6451   v8::Handle<v8::Object> global0 = context0->Global();
6452   global0->Set(v8_str("custom"), v8_num(1234));
6453   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6454
6455   // Create an independent environment
6456   LocalContext context1(0, templ);
6457   context1->SetSecurityToken(password);
6458   v8::Handle<v8::Object> global1 = context1->Global();
6459   global1->Set(v8_str("custom"), v8_num(1234));
6460   CHECK_NE(global0, global1);
6461   CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6462   CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6463
6464   // Now create a new context with the old global
6465   LocalContext context2(0, templ, global1);
6466   context2->SetSecurityToken(password);
6467   v8::Handle<v8::Object> global2 = context2->Global();
6468   CHECK_EQ(global1, global2);
6469   CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6470   CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6471 }
6472
6473
6474 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6475   // Make sure that functions created by cloning boilerplates cannot
6476   // communicate through their __proto__ field.
6477
6478   v8::HandleScope scope(CcTest::isolate());
6479
6480   LocalContext env0;
6481   v8::Handle<v8::Object> global0 =
6482       env0->Global();
6483   v8::Handle<v8::Object> object0 =
6484       global0->Get(v8_str("Object")).As<v8::Object>();
6485   v8::Handle<v8::Object> tostring0 =
6486       object0->Get(v8_str("toString")).As<v8::Object>();
6487   v8::Handle<v8::Object> proto0 =
6488       tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6489   proto0->Set(v8_str("custom"), v8_num(1234));
6490
6491   LocalContext env1;
6492   v8::Handle<v8::Object> global1 =
6493       env1->Global();
6494   v8::Handle<v8::Object> object1 =
6495       global1->Get(v8_str("Object")).As<v8::Object>();
6496   v8::Handle<v8::Object> tostring1 =
6497       object1->Get(v8_str("toString")).As<v8::Object>();
6498   v8::Handle<v8::Object> proto1 =
6499       tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6500   CHECK(!proto1->Has(v8_str("custom")));
6501 }
6502
6503
6504 THREADED_TEST(Regress892105) {
6505   // Make sure that object and array literals created by cloning
6506   // boilerplates cannot communicate through their __proto__
6507   // field. This is rather difficult to check, but we try to add stuff
6508   // to Object.prototype and Array.prototype and create a new
6509   // environment. This should succeed.
6510
6511   v8::HandleScope scope(CcTest::isolate());
6512
6513   Local<String> source = v8_str("Object.prototype.obj = 1234;"
6514                                 "Array.prototype.arr = 4567;"
6515                                 "8901");
6516
6517   LocalContext env0;
6518   Local<Script> script0 = v8_compile(source);
6519   CHECK_EQ(8901.0, script0->Run()->NumberValue());
6520
6521   LocalContext env1;
6522   Local<Script> script1 = v8_compile(source);
6523   CHECK_EQ(8901.0, script1->Run()->NumberValue());
6524 }
6525
6526
6527 THREADED_TEST(UndetectableObject) {
6528   LocalContext env;
6529   v8::HandleScope scope(env->GetIsolate());
6530
6531   Local<v8::FunctionTemplate> desc =
6532       v8::FunctionTemplate::New(env->GetIsolate());
6533   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6534
6535   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6536   env->Global()->Set(v8_str("undetectable"), obj);
6537
6538   ExpectString("undetectable.toString()", "[object Object]");
6539   ExpectString("typeof undetectable", "undefined");
6540   ExpectString("typeof(undetectable)", "undefined");
6541   ExpectBoolean("typeof undetectable == 'undefined'", true);
6542   ExpectBoolean("typeof undetectable == 'object'", false);
6543   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6544   ExpectBoolean("!undetectable", true);
6545
6546   ExpectObject("true&&undetectable", obj);
6547   ExpectBoolean("false&&undetectable", false);
6548   ExpectBoolean("true||undetectable", true);
6549   ExpectObject("false||undetectable", obj);
6550
6551   ExpectObject("undetectable&&true", obj);
6552   ExpectObject("undetectable&&false", obj);
6553   ExpectBoolean("undetectable||true", true);
6554   ExpectBoolean("undetectable||false", false);
6555
6556   ExpectBoolean("undetectable==null", true);
6557   ExpectBoolean("null==undetectable", true);
6558   ExpectBoolean("undetectable==undefined", true);
6559   ExpectBoolean("undefined==undetectable", true);
6560   ExpectBoolean("undetectable==undetectable", true);
6561
6562
6563   ExpectBoolean("undetectable===null", false);
6564   ExpectBoolean("null===undetectable", false);
6565   ExpectBoolean("undetectable===undefined", false);
6566   ExpectBoolean("undefined===undetectable", false);
6567   ExpectBoolean("undetectable===undetectable", true);
6568 }
6569
6570
6571 THREADED_TEST(VoidLiteral) {
6572   LocalContext env;
6573   v8::Isolate* isolate = env->GetIsolate();
6574   v8::HandleScope scope(isolate);
6575
6576   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6577   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6578
6579   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6580   env->Global()->Set(v8_str("undetectable"), obj);
6581
6582   ExpectBoolean("undefined == void 0", true);
6583   ExpectBoolean("undetectable == void 0", true);
6584   ExpectBoolean("null == void 0", true);
6585   ExpectBoolean("undefined === void 0", true);
6586   ExpectBoolean("undetectable === void 0", false);
6587   ExpectBoolean("null === void 0", false);
6588
6589   ExpectBoolean("void 0 == undefined", true);
6590   ExpectBoolean("void 0 == undetectable", true);
6591   ExpectBoolean("void 0 == null", true);
6592   ExpectBoolean("void 0 === undefined", true);
6593   ExpectBoolean("void 0 === undetectable", false);
6594   ExpectBoolean("void 0 === null", false);
6595
6596   ExpectString("(function() {"
6597                "  try {"
6598                "    return x === void 0;"
6599                "  } catch(e) {"
6600                "    return e.toString();"
6601                "  }"
6602                "})()",
6603                "ReferenceError: x is not defined");
6604   ExpectString("(function() {"
6605                "  try {"
6606                "    return void 0 === x;"
6607                "  } catch(e) {"
6608                "    return e.toString();"
6609                "  }"
6610                "})()",
6611                "ReferenceError: x is not defined");
6612 }
6613
6614
6615 THREADED_TEST(ExtensibleOnUndetectable) {
6616   LocalContext env;
6617   v8::Isolate* isolate = env->GetIsolate();
6618   v8::HandleScope scope(isolate);
6619
6620   Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6621   desc->InstanceTemplate()->MarkAsUndetectable();  // undetectable
6622
6623   Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6624   env->Global()->Set(v8_str("undetectable"), obj);
6625
6626   Local<String> source = v8_str("undetectable.x = 42;"
6627                                 "undetectable.x");
6628
6629   Local<Script> script = v8_compile(source);
6630
6631   CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6632
6633   ExpectBoolean("Object.isExtensible(undetectable)", true);
6634
6635   source = v8_str("Object.preventExtensions(undetectable);");
6636   script = v8_compile(source);
6637   script->Run();
6638   ExpectBoolean("Object.isExtensible(undetectable)", false);
6639
6640   source = v8_str("undetectable.y = 2000;");
6641   script = v8_compile(source);
6642   script->Run();
6643   ExpectBoolean("undetectable.y == undefined", true);
6644 }
6645
6646
6647
6648 THREADED_TEST(UndetectableString) {
6649   LocalContext env;
6650   v8::HandleScope scope(env->GetIsolate());
6651
6652   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6653                                           String::kUndetectableString);
6654   env->Global()->Set(v8_str("undetectable"), obj);
6655
6656   ExpectString("undetectable", "foo");
6657   ExpectString("typeof undetectable", "undefined");
6658   ExpectString("typeof(undetectable)", "undefined");
6659   ExpectBoolean("typeof undetectable == 'undefined'", true);
6660   ExpectBoolean("typeof undetectable == 'string'", false);
6661   ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6662   ExpectBoolean("!undetectable", true);
6663
6664   ExpectObject("true&&undetectable", obj);
6665   ExpectBoolean("false&&undetectable", false);
6666   ExpectBoolean("true||undetectable", true);
6667   ExpectObject("false||undetectable", obj);
6668
6669   ExpectObject("undetectable&&true", obj);
6670   ExpectObject("undetectable&&false", obj);
6671   ExpectBoolean("undetectable||true", true);
6672   ExpectBoolean("undetectable||false", false);
6673
6674   ExpectBoolean("undetectable==null", true);
6675   ExpectBoolean("null==undetectable", true);
6676   ExpectBoolean("undetectable==undefined", true);
6677   ExpectBoolean("undefined==undetectable", true);
6678   ExpectBoolean("undetectable==undetectable", true);
6679
6680
6681   ExpectBoolean("undetectable===null", false);
6682   ExpectBoolean("null===undetectable", false);
6683   ExpectBoolean("undetectable===undefined", false);
6684   ExpectBoolean("undefined===undetectable", false);
6685   ExpectBoolean("undetectable===undetectable", true);
6686 }
6687
6688
6689 TEST(UndetectableOptimized) {
6690   i::FLAG_allow_natives_syntax = true;
6691   LocalContext env;
6692   v8::HandleScope scope(env->GetIsolate());
6693
6694   Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6695                                           String::kUndetectableString);
6696   env->Global()->Set(v8_str("undetectable"), obj);
6697   env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6698
6699   ExpectString(
6700       "function testBranch() {"
6701       "  if (!%_IsUndetectableObject(undetectable)) throw 1;"
6702       "  if (%_IsUndetectableObject(detectable)) throw 2;"
6703       "}\n"
6704       "function testBool() {"
6705       "  var b1 = !%_IsUndetectableObject(undetectable);"
6706       "  var b2 = %_IsUndetectableObject(detectable);"
6707       "  if (b1) throw 3;"
6708       "  if (b2) throw 4;"
6709       "  return b1 == b2;"
6710       "}\n"
6711       "%OptimizeFunctionOnNextCall(testBranch);"
6712       "%OptimizeFunctionOnNextCall(testBool);"
6713       "for (var i = 0; i < 10; i++) {"
6714       "  testBranch();"
6715       "  testBool();"
6716       "}\n"
6717       "\"PASS\"",
6718       "PASS");
6719 }
6720
6721
6722 // The point of this test is type checking. We run it only so compilers
6723 // don't complain about an unused function.
6724 TEST(PersistentHandles) {
6725   LocalContext env;
6726   v8::Isolate* isolate = CcTest::isolate();
6727   v8::HandleScope scope(isolate);
6728   Local<String> str = v8_str("foo");
6729   v8::Persistent<String> p_str(isolate, str);
6730   p_str.Reset();
6731   Local<Script> scr = v8_compile("");
6732   v8::Persistent<Script> p_scr(isolate, scr);
6733   p_scr.Reset();
6734   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6735   v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6736   p_templ.Reset();
6737 }
6738
6739
6740 static void HandleLogDelegator(
6741     const v8::FunctionCallbackInfo<v8::Value>& args) {
6742   ApiTestFuzzer::Fuzz();
6743 }
6744
6745
6746 THREADED_TEST(GlobalObjectTemplate) {
6747   v8::Isolate* isolate = CcTest::isolate();
6748   v8::HandleScope handle_scope(isolate);
6749   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6750   global_template->Set(v8_str("JSNI_Log"),
6751                        v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6752   v8::Local<Context> context = Context::New(isolate, 0, global_template);
6753   Context::Scope context_scope(context);
6754   CompileRun("JSNI_Log('LOG')");
6755 }
6756
6757
6758 static const char* kSimpleExtensionSource =
6759   "function Foo() {"
6760   "  return 4;"
6761   "}";
6762
6763
6764 TEST(SimpleExtensions) {
6765   v8::HandleScope handle_scope(CcTest::isolate());
6766   v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6767   const char* extension_names[] = { "simpletest" };
6768   v8::ExtensionConfiguration extensions(1, extension_names);
6769   v8::Handle<Context> context =
6770       Context::New(CcTest::isolate(), &extensions);
6771   Context::Scope lock(context);
6772   v8::Handle<Value> result = CompileRun("Foo()");
6773   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6774 }
6775
6776
6777 static const char* kStackTraceFromExtensionSource =
6778   "function foo() {"
6779   "  throw new Error();"
6780   "}"
6781   "function bar() {"
6782   "  foo();"
6783   "}";
6784
6785
6786 TEST(StackTraceInExtension) {
6787   v8::HandleScope handle_scope(CcTest::isolate());
6788   v8::RegisterExtension(new Extension("stacktracetest",
6789                         kStackTraceFromExtensionSource));
6790   const char* extension_names[] = { "stacktracetest" };
6791   v8::ExtensionConfiguration extensions(1, extension_names);
6792   v8::Handle<Context> context =
6793       Context::New(CcTest::isolate(), &extensions);
6794   Context::Scope lock(context);
6795   CompileRun("function user() { bar(); }"
6796              "var error;"
6797              "try{ user(); } catch (e) { error = e; }");
6798   CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6799   CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6800   CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6801 }
6802
6803
6804 TEST(NullExtensions) {
6805   v8::HandleScope handle_scope(CcTest::isolate());
6806   v8::RegisterExtension(new Extension("nulltest", NULL));
6807   const char* extension_names[] = { "nulltest" };
6808   v8::ExtensionConfiguration extensions(1, extension_names);
6809   v8::Handle<Context> context =
6810       Context::New(CcTest::isolate(), &extensions);
6811   Context::Scope lock(context);
6812   v8::Handle<Value> result = CompileRun("1+3");
6813   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6814 }
6815
6816
6817 static const char* kEmbeddedExtensionSource =
6818     "function Ret54321(){return 54321;}~~@@$"
6819     "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6820 static const int kEmbeddedExtensionSourceValidLen = 34;
6821
6822
6823 TEST(ExtensionMissingSourceLength) {
6824   v8::HandleScope handle_scope(CcTest::isolate());
6825   v8::RegisterExtension(new Extension("srclentest_fail",
6826                                       kEmbeddedExtensionSource));
6827   const char* extension_names[] = { "srclentest_fail" };
6828   v8::ExtensionConfiguration extensions(1, extension_names);
6829   v8::Handle<Context> context =
6830       Context::New(CcTest::isolate(), &extensions);
6831   CHECK_EQ(0, *context);
6832 }
6833
6834
6835 TEST(ExtensionWithSourceLength) {
6836   for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6837        source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6838     v8::HandleScope handle_scope(CcTest::isolate());
6839     i::ScopedVector<char> extension_name(32);
6840     i::SNPrintF(extension_name, "ext #%d", source_len);
6841     v8::RegisterExtension(new Extension(extension_name.start(),
6842                                         kEmbeddedExtensionSource, 0, 0,
6843                                         source_len));
6844     const char* extension_names[1] = { extension_name.start() };
6845     v8::ExtensionConfiguration extensions(1, extension_names);
6846     v8::Handle<Context> context =
6847       Context::New(CcTest::isolate(), &extensions);
6848     if (source_len == kEmbeddedExtensionSourceValidLen) {
6849       Context::Scope lock(context);
6850       v8::Handle<Value> result = CompileRun("Ret54321()");
6851       CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
6852     } else {
6853       // Anything but exactly the right length should fail to compile.
6854       CHECK_EQ(0, *context);
6855     }
6856   }
6857 }
6858
6859
6860 static const char* kEvalExtensionSource1 =
6861   "function UseEval1() {"
6862   "  var x = 42;"
6863   "  return eval('x');"
6864   "}";
6865
6866
6867 static const char* kEvalExtensionSource2 =
6868   "(function() {"
6869   "  var x = 42;"
6870   "  function e() {"
6871   "    return eval('x');"
6872   "  }"
6873   "  this.UseEval2 = e;"
6874   "})()";
6875
6876
6877 TEST(UseEvalFromExtension) {
6878   v8::HandleScope handle_scope(CcTest::isolate());
6879   v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6880   v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6881   const char* extension_names[] = { "evaltest1", "evaltest2" };
6882   v8::ExtensionConfiguration extensions(2, extension_names);
6883   v8::Handle<Context> context =
6884       Context::New(CcTest::isolate(), &extensions);
6885   Context::Scope lock(context);
6886   v8::Handle<Value> result = CompileRun("UseEval1()");
6887   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6888   result = CompileRun("UseEval2()");
6889   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
6890 }
6891
6892
6893 static const char* kWithExtensionSource1 =
6894   "function UseWith1() {"
6895   "  var x = 42;"
6896   "  with({x:87}) { return x; }"
6897   "}";
6898
6899
6900
6901 static const char* kWithExtensionSource2 =
6902   "(function() {"
6903   "  var x = 42;"
6904   "  function e() {"
6905   "    with ({x:87}) { return x; }"
6906   "  }"
6907   "  this.UseWith2 = e;"
6908   "})()";
6909
6910
6911 TEST(UseWithFromExtension) {
6912   v8::HandleScope handle_scope(CcTest::isolate());
6913   v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6914   v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6915   const char* extension_names[] = { "withtest1", "withtest2" };
6916   v8::ExtensionConfiguration extensions(2, extension_names);
6917   v8::Handle<Context> context =
6918       Context::New(CcTest::isolate(), &extensions);
6919   Context::Scope lock(context);
6920   v8::Handle<Value> result = CompileRun("UseWith1()");
6921   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6922   result = CompileRun("UseWith2()");
6923   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
6924 }
6925
6926
6927 TEST(AutoExtensions) {
6928   v8::HandleScope handle_scope(CcTest::isolate());
6929   Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6930   extension->set_auto_enable(true);
6931   v8::RegisterExtension(extension);
6932   v8::Handle<Context> context =
6933       Context::New(CcTest::isolate());
6934   Context::Scope lock(context);
6935   v8::Handle<Value> result = CompileRun("Foo()");
6936   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
6937 }
6938
6939
6940 static const char* kSyntaxErrorInExtensionSource =
6941     "[";
6942
6943
6944 // Test that a syntax error in an extension does not cause a fatal
6945 // error but results in an empty context.
6946 TEST(SyntaxErrorExtensions) {
6947   v8::HandleScope handle_scope(CcTest::isolate());
6948   v8::RegisterExtension(new Extension("syntaxerror",
6949                                       kSyntaxErrorInExtensionSource));
6950   const char* extension_names[] = { "syntaxerror" };
6951   v8::ExtensionConfiguration extensions(1, extension_names);
6952   v8::Handle<Context> context =
6953       Context::New(CcTest::isolate(), &extensions);
6954   CHECK(context.IsEmpty());
6955 }
6956
6957
6958 static const char* kExceptionInExtensionSource =
6959     "throw 42";
6960
6961
6962 // Test that an exception when installing an extension does not cause
6963 // a fatal error but results in an empty context.
6964 TEST(ExceptionExtensions) {
6965   v8::HandleScope handle_scope(CcTest::isolate());
6966   v8::RegisterExtension(new Extension("exception",
6967                                       kExceptionInExtensionSource));
6968   const char* extension_names[] = { "exception" };
6969   v8::ExtensionConfiguration extensions(1, extension_names);
6970   v8::Handle<Context> context =
6971       Context::New(CcTest::isolate(), &extensions);
6972   CHECK(context.IsEmpty());
6973 }
6974
6975
6976 static const char* kNativeCallInExtensionSource =
6977     "function call_runtime_last_index_of(x) {"
6978     "  return %StringLastIndexOf(x, 'bob', 10);"
6979     "}";
6980
6981
6982 static const char* kNativeCallTest =
6983     "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6984
6985 // Test that a native runtime calls are supported in extensions.
6986 TEST(NativeCallInExtensions) {
6987   v8::HandleScope handle_scope(CcTest::isolate());
6988   v8::RegisterExtension(new Extension("nativecall",
6989                                       kNativeCallInExtensionSource));
6990   const char* extension_names[] = { "nativecall" };
6991   v8::ExtensionConfiguration extensions(1, extension_names);
6992   v8::Handle<Context> context =
6993       Context::New(CcTest::isolate(), &extensions);
6994   Context::Scope lock(context);
6995   v8::Handle<Value> result = CompileRun(kNativeCallTest);
6996   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
6997 }
6998
6999
7000 class NativeFunctionExtension : public Extension {
7001  public:
7002   NativeFunctionExtension(const char* name,
7003                           const char* source,
7004                           v8::FunctionCallback fun = &Echo)
7005       : Extension(name, source),
7006         function_(fun) { }
7007
7008   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7009       v8::Isolate* isolate,
7010       v8::Handle<v8::String> name) {
7011     return v8::FunctionTemplate::New(isolate, function_);
7012   }
7013
7014   static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7015     if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7016   }
7017  private:
7018   v8::FunctionCallback function_;
7019 };
7020
7021
7022 TEST(NativeFunctionDeclaration) {
7023   v8::HandleScope handle_scope(CcTest::isolate());
7024   const char* name = "nativedecl";
7025   v8::RegisterExtension(new NativeFunctionExtension(name,
7026                                                     "native function foo();"));
7027   const char* extension_names[] = { name };
7028   v8::ExtensionConfiguration extensions(1, extension_names);
7029   v8::Handle<Context> context =
7030       Context::New(CcTest::isolate(), &extensions);
7031   Context::Scope lock(context);
7032   v8::Handle<Value> result = CompileRun("foo(42);");
7033   CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7034 }
7035
7036
7037 TEST(NativeFunctionDeclarationError) {
7038   v8::HandleScope handle_scope(CcTest::isolate());
7039   const char* name = "nativedeclerr";
7040   // Syntax error in extension code.
7041   v8::RegisterExtension(new NativeFunctionExtension(name,
7042                                                     "native\nfunction foo();"));
7043   const char* extension_names[] = { name };
7044   v8::ExtensionConfiguration extensions(1, extension_names);
7045   v8::Handle<Context> context =
7046       Context::New(CcTest::isolate(), &extensions);
7047   CHECK(context.IsEmpty());
7048 }
7049
7050
7051 TEST(NativeFunctionDeclarationErrorEscape) {
7052   v8::HandleScope handle_scope(CcTest::isolate());
7053   const char* name = "nativedeclerresc";
7054   // Syntax error in extension code - escape code in "native" means that
7055   // it's not treated as a keyword.
7056   v8::RegisterExtension(new NativeFunctionExtension(
7057       name,
7058       "nativ\\u0065 function foo();"));
7059   const char* extension_names[] = { name };
7060   v8::ExtensionConfiguration extensions(1, extension_names);
7061   v8::Handle<Context> context =
7062       Context::New(CcTest::isolate(), &extensions);
7063   CHECK(context.IsEmpty());
7064 }
7065
7066
7067 static void CheckDependencies(const char* name, const char* expected) {
7068   v8::HandleScope handle_scope(CcTest::isolate());
7069   v8::ExtensionConfiguration config(1, &name);
7070   LocalContext context(&config);
7071   CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7072            context->Global()->Get(v8_str("loaded")));
7073 }
7074
7075
7076 /*
7077  * Configuration:
7078  *
7079  *     /-- B <--\
7080  * A <-          -- D <-- E
7081  *     \-- C <--/
7082  */
7083 THREADED_TEST(ExtensionDependency) {
7084   static const char* kEDeps[] = { "D" };
7085   v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7086   static const char* kDDeps[] = { "B", "C" };
7087   v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7088   static const char* kBCDeps[] = { "A" };
7089   v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7090   v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7091   v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7092   CheckDependencies("A", "undefinedA");
7093   CheckDependencies("B", "undefinedAB");
7094   CheckDependencies("C", "undefinedAC");
7095   CheckDependencies("D", "undefinedABCD");
7096   CheckDependencies("E", "undefinedABCDE");
7097   v8::HandleScope handle_scope(CcTest::isolate());
7098   static const char* exts[2] = { "C", "E" };
7099   v8::ExtensionConfiguration config(2, exts);
7100   LocalContext context(&config);
7101   CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7102 }
7103
7104
7105 static const char* kExtensionTestScript =
7106   "native function A();"
7107   "native function B();"
7108   "native function C();"
7109   "function Foo(i) {"
7110   "  if (i == 0) return A();"
7111   "  if (i == 1) return B();"
7112   "  if (i == 2) return C();"
7113   "}";
7114
7115
7116 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7117   ApiTestFuzzer::Fuzz();
7118   if (args.IsConstructCall()) {
7119     args.This()->Set(v8_str("data"), args.Data());
7120     args.GetReturnValue().SetNull();
7121     return;
7122   }
7123   args.GetReturnValue().Set(args.Data());
7124 }
7125
7126
7127 class FunctionExtension : public Extension {
7128  public:
7129   FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7130   virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7131       v8::Isolate* isolate,
7132       v8::Handle<String> name);
7133 };
7134
7135
7136 static int lookup_count = 0;
7137 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7138     v8::Isolate* isolate, v8::Handle<String> name) {
7139   lookup_count++;
7140   if (name->Equals(v8_str("A"))) {
7141     return v8::FunctionTemplate::New(
7142         isolate, CallFun, v8::Integer::New(isolate, 8));
7143   } else if (name->Equals(v8_str("B"))) {
7144     return v8::FunctionTemplate::New(
7145         isolate, CallFun, v8::Integer::New(isolate, 7));
7146   } else if (name->Equals(v8_str("C"))) {
7147     return v8::FunctionTemplate::New(
7148         isolate, CallFun, v8::Integer::New(isolate, 6));
7149   } else {
7150     return v8::Handle<v8::FunctionTemplate>();
7151   }
7152 }
7153
7154
7155 THREADED_TEST(FunctionLookup) {
7156   v8::RegisterExtension(new FunctionExtension());
7157   v8::HandleScope handle_scope(CcTest::isolate());
7158   static const char* exts[1] = { "functiontest" };
7159   v8::ExtensionConfiguration config(1, exts);
7160   LocalContext context(&config);
7161   CHECK_EQ(3, lookup_count);
7162   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7163            CompileRun("Foo(0)"));
7164   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7165            CompileRun("Foo(1)"));
7166   CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7167            CompileRun("Foo(2)"));
7168 }
7169
7170
7171 THREADED_TEST(NativeFunctionConstructCall) {
7172   v8::RegisterExtension(new FunctionExtension());
7173   v8::HandleScope handle_scope(CcTest::isolate());
7174   static const char* exts[1] = { "functiontest" };
7175   v8::ExtensionConfiguration config(1, exts);
7176   LocalContext context(&config);
7177   for (int i = 0; i < 10; i++) {
7178     // Run a few times to ensure that allocation of objects doesn't
7179     // change behavior of a constructor function.
7180     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7181              CompileRun("(new A()).data"));
7182     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7183              CompileRun("(new B()).data"));
7184     CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7185              CompileRun("(new C()).data"));
7186   }
7187 }
7188
7189
7190 static const char* last_location;
7191 static const char* last_message;
7192 void StoringErrorCallback(const char* location, const char* message) {
7193   if (last_location == NULL) {
7194     last_location = location;
7195     last_message = message;
7196   }
7197 }
7198
7199
7200 // ErrorReporting creates a circular extensions configuration and
7201 // tests that the fatal error handler gets called.  This renders V8
7202 // unusable and therefore this test cannot be run in parallel.
7203 TEST(ErrorReporting) {
7204   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7205   static const char* aDeps[] = { "B" };
7206   v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7207   static const char* bDeps[] = { "A" };
7208   v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7209   last_location = NULL;
7210   v8::ExtensionConfiguration config(1, bDeps);
7211   v8::Handle<Context> context =
7212       Context::New(CcTest::isolate(), &config);
7213   CHECK(context.IsEmpty());
7214   CHECK_NE(last_location, NULL);
7215 }
7216
7217
7218 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7219                                              v8::Handle<Value> data) {
7220   CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7221   CHECK_EQ(v8::Undefined(CcTest::isolate()),
7222       message->GetScriptOrigin().ResourceName());
7223   message->GetLineNumber();
7224   message->GetSourceLine();
7225 }
7226
7227
7228 THREADED_TEST(ErrorWithMissingScriptInfo) {
7229   LocalContext context;
7230   v8::HandleScope scope(context->GetIsolate());
7231   v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7232   CompileRun("throw Error()");
7233   v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7234 }
7235
7236
7237 struct FlagAndPersistent {
7238   bool flag;
7239   v8::Persistent<v8::Object> handle;
7240 };
7241
7242
7243 static void DisposeAndSetFlag(
7244     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7245   data.GetParameter()->handle.Reset();
7246   data.GetParameter()->flag = true;
7247 }
7248
7249
7250 THREADED_TEST(IndependentWeakHandle) {
7251   v8::Isolate* iso = CcTest::isolate();
7252   v8::HandleScope scope(iso);
7253   v8::Handle<Context> context = Context::New(iso);
7254   Context::Scope context_scope(context);
7255
7256   FlagAndPersistent object_a, object_b;
7257
7258   {
7259     v8::HandleScope handle_scope(iso);
7260     object_a.handle.Reset(iso, v8::Object::New(iso));
7261     object_b.handle.Reset(iso, v8::Object::New(iso));
7262   }
7263
7264   object_a.flag = false;
7265   object_b.flag = false;
7266   object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
7267   object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
7268   CHECK(!object_b.handle.IsIndependent());
7269   object_a.handle.MarkIndependent();
7270   object_b.handle.MarkIndependent();
7271   CHECK(object_b.handle.IsIndependent());
7272   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7273   CHECK(object_a.flag);
7274   CHECK(object_b.flag);
7275 }
7276
7277
7278 static void InvokeScavenge() {
7279   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7280 }
7281
7282
7283 static void InvokeMarkSweep() {
7284   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7285 }
7286
7287
7288 static void ForceScavenge(
7289     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7290   data.GetParameter()->handle.Reset();
7291   data.GetParameter()->flag = true;
7292   InvokeScavenge();
7293 }
7294
7295
7296 static void ForceMarkSweep(
7297     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7298   data.GetParameter()->handle.Reset();
7299   data.GetParameter()->flag = true;
7300   InvokeMarkSweep();
7301 }
7302
7303
7304 THREADED_TEST(GCFromWeakCallbacks) {
7305   v8::Isolate* isolate = CcTest::isolate();
7306   v8::HandleScope scope(isolate);
7307   v8::Handle<Context> context = Context::New(isolate);
7308   Context::Scope context_scope(context);
7309
7310   static const int kNumberOfGCTypes = 2;
7311   typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7312       Callback;
7313   Callback gc_forcing_callback[kNumberOfGCTypes] =
7314       {&ForceScavenge, &ForceMarkSweep};
7315
7316   typedef void (*GCInvoker)();
7317   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7318
7319   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7320     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7321       FlagAndPersistent object;
7322       {
7323         v8::HandleScope handle_scope(isolate);
7324         object.handle.Reset(isolate, v8::Object::New(isolate));
7325       }
7326       object.flag = false;
7327       object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7328       object.handle.MarkIndependent();
7329       invoke_gc[outer_gc]();
7330       CHECK(object.flag);
7331     }
7332   }
7333 }
7334
7335
7336 static void RevivingCallback(
7337     const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7338   data.GetParameter()->handle.ClearWeak();
7339   data.GetParameter()->flag = true;
7340 }
7341
7342
7343 THREADED_TEST(IndependentHandleRevival) {
7344   v8::Isolate* isolate = CcTest::isolate();
7345   v8::HandleScope scope(isolate);
7346   v8::Handle<Context> context = Context::New(isolate);
7347   Context::Scope context_scope(context);
7348
7349   FlagAndPersistent object;
7350   {
7351     v8::HandleScope handle_scope(isolate);
7352     v8::Local<v8::Object> o = v8::Object::New(isolate);
7353     object.handle.Reset(isolate, o);
7354     o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7355     v8::Local<String> y_str = v8_str("y");
7356     o->Set(y_str, y_str);
7357   }
7358   object.flag = false;
7359   object.handle.SetWeak(&object, &RevivingCallback);
7360   object.handle.MarkIndependent();
7361   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7362   CHECK(object.flag);
7363   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7364   {
7365     v8::HandleScope handle_scope(isolate);
7366     v8::Local<v8::Object> o =
7367         v8::Local<v8::Object>::New(isolate, object.handle);
7368     v8::Local<String> y_str = v8_str("y");
7369     CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7370     CHECK(o->Get(y_str)->Equals(y_str));
7371   }
7372 }
7373
7374
7375 v8::Handle<Function> args_fun;
7376
7377
7378 static void ArgumentsTestCallback(
7379     const v8::FunctionCallbackInfo<v8::Value>& args) {
7380   ApiTestFuzzer::Fuzz();
7381   v8::Isolate* isolate = args.GetIsolate();
7382   CHECK_EQ(args_fun, args.Callee());
7383   CHECK_EQ(3, args.Length());
7384   CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7385   CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7386   CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7387   CHECK_EQ(v8::Undefined(isolate), args[3]);
7388   v8::HandleScope scope(args.GetIsolate());
7389   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7390 }
7391
7392
7393 THREADED_TEST(Arguments) {
7394   v8::Isolate* isolate = CcTest::isolate();
7395   v8::HandleScope scope(isolate);
7396   v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7397   global->Set(v8_str("f"),
7398               v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7399   LocalContext context(NULL, global);
7400   args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7401   v8_compile("f(1, 2, 3)")->Run();
7402 }
7403
7404
7405 static void NoBlockGetterX(Local<String> name,
7406                            const v8::PropertyCallbackInfo<v8::Value>&) {
7407 }
7408
7409
7410 static void NoBlockGetterI(uint32_t index,
7411                            const v8::PropertyCallbackInfo<v8::Value>&) {
7412 }
7413
7414
7415 static void PDeleter(Local<String> name,
7416                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7417   if (!name->Equals(v8_str("foo"))) {
7418     return;  // not intercepted
7419   }
7420
7421   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7422 }
7423
7424
7425 static void IDeleter(uint32_t index,
7426                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7427   if (index != 2) {
7428     return;  // not intercepted
7429   }
7430
7431   info.GetReturnValue().Set(false);  // intercepted, don't delete the property
7432 }
7433
7434
7435 THREADED_TEST(Deleter) {
7436   v8::Isolate* isolate = CcTest::isolate();
7437   v8::HandleScope scope(isolate);
7438   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7439   obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7440   obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7441   LocalContext context;
7442   context->Global()->Set(v8_str("k"), obj->NewInstance());
7443   CompileRun(
7444     "k.foo = 'foo';"
7445     "k.bar = 'bar';"
7446     "k[2] = 2;"
7447     "k[4] = 4;");
7448   CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7449   CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7450
7451   CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7452   CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7453
7454   CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7455   CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7456
7457   CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7458   CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7459 }
7460
7461
7462 static void GetK(Local<String> name,
7463                  const v8::PropertyCallbackInfo<v8::Value>& info) {
7464   ApiTestFuzzer::Fuzz();
7465   if (name->Equals(v8_str("foo")) ||
7466       name->Equals(v8_str("bar")) ||
7467       name->Equals(v8_str("baz"))) {
7468     info.GetReturnValue().SetUndefined();
7469   }
7470 }
7471
7472
7473 static void IndexedGetK(uint32_t index,
7474                         const v8::PropertyCallbackInfo<v8::Value>& info) {
7475   ApiTestFuzzer::Fuzz();
7476   if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7477 }
7478
7479
7480 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7481   ApiTestFuzzer::Fuzz();
7482   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7483   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7484   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7485   result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7486   info.GetReturnValue().Set(result);
7487 }
7488
7489
7490 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7491   ApiTestFuzzer::Fuzz();
7492   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7493   result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7494   result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7495   info.GetReturnValue().Set(result);
7496 }
7497
7498
7499 THREADED_TEST(Enumerators) {
7500   v8::Isolate* isolate = CcTest::isolate();
7501   v8::HandleScope scope(isolate);
7502   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7503   obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7504   obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7505   LocalContext context;
7506   context->Global()->Set(v8_str("k"), obj->NewInstance());
7507   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7508     "k[10] = 0;"
7509     "k.a = 0;"
7510     "k[5] = 0;"
7511     "k.b = 0;"
7512     "k[4294967295] = 0;"
7513     "k.c = 0;"
7514     "k[4294967296] = 0;"
7515     "k.d = 0;"
7516     "k[140000] = 0;"
7517     "k.e = 0;"
7518     "k[30000000000] = 0;"
7519     "k.f = 0;"
7520     "var result = [];"
7521     "for (var prop in k) {"
7522     "  result.push(prop);"
7523     "}"
7524     "result"));
7525   // Check that we get all the property names returned including the
7526   // ones from the enumerators in the right order: indexed properties
7527   // in numerical order, indexed interceptor properties, named
7528   // properties in insertion order, named interceptor properties.
7529   // This order is not mandated by the spec, so this test is just
7530   // documenting our behavior.
7531   CHECK_EQ(17, result->Length());
7532   // Indexed properties in numerical order.
7533   CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7534   CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7535   CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7536   CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7537   // Indexed interceptor properties in the order they are returned
7538   // from the enumerator interceptor.
7539   CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7540   CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7541   // Named properties in insertion order.
7542   CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7543   CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7544   CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7545   CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7546   CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7547   CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7548   CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7549   CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7550   // Named interceptor properties.
7551   CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7552   CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7553   CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7554 }
7555
7556
7557 int p_getter_count;
7558 int p_getter_count2;
7559
7560
7561 static void PGetter(Local<String> name,
7562                     const v8::PropertyCallbackInfo<v8::Value>& info) {
7563   ApiTestFuzzer::Fuzz();
7564   p_getter_count++;
7565   v8::Handle<v8::Object> global =
7566       info.GetIsolate()->GetCurrentContext()->Global();
7567   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7568   if (name->Equals(v8_str("p1"))) {
7569     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7570   } else if (name->Equals(v8_str("p2"))) {
7571     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7572   } else if (name->Equals(v8_str("p3"))) {
7573     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7574   } else if (name->Equals(v8_str("p4"))) {
7575     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7576   }
7577 }
7578
7579
7580 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7581   ApiTestFuzzer::Fuzz();
7582   LocalContext context;
7583   context->Global()->Set(v8_str("o1"), obj->NewInstance());
7584   CompileRun(
7585     "o1.__proto__ = { };"
7586     "var o2 = { __proto__: o1 };"
7587     "var o3 = { __proto__: o2 };"
7588     "var o4 = { __proto__: o3 };"
7589     "for (var i = 0; i < 10; i++) o4.p4;"
7590     "for (var i = 0; i < 10; i++) o3.p3;"
7591     "for (var i = 0; i < 10; i++) o2.p2;"
7592     "for (var i = 0; i < 10; i++) o1.p1;");
7593 }
7594
7595
7596 static void PGetter2(Local<String> name,
7597                      const v8::PropertyCallbackInfo<v8::Value>& info) {
7598   ApiTestFuzzer::Fuzz();
7599   p_getter_count2++;
7600   v8::Handle<v8::Object> global =
7601       info.GetIsolate()->GetCurrentContext()->Global();
7602   CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7603   if (name->Equals(v8_str("p1"))) {
7604     CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7605   } else if (name->Equals(v8_str("p2"))) {
7606     CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7607   } else if (name->Equals(v8_str("p3"))) {
7608     CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7609   } else if (name->Equals(v8_str("p4"))) {
7610     CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7611   }
7612 }
7613
7614
7615 THREADED_TEST(GetterHolders) {
7616   v8::Isolate* isolate = CcTest::isolate();
7617   v8::HandleScope scope(isolate);
7618   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7619   obj->SetAccessor(v8_str("p1"), PGetter);
7620   obj->SetAccessor(v8_str("p2"), PGetter);
7621   obj->SetAccessor(v8_str("p3"), PGetter);
7622   obj->SetAccessor(v8_str("p4"), PGetter);
7623   p_getter_count = 0;
7624   RunHolderTest(obj);
7625   CHECK_EQ(40, p_getter_count);
7626 }
7627
7628
7629 THREADED_TEST(PreInterceptorHolders) {
7630   v8::Isolate* isolate = CcTest::isolate();
7631   v8::HandleScope scope(isolate);
7632   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7633   obj->SetNamedPropertyHandler(PGetter2);
7634   p_getter_count2 = 0;
7635   RunHolderTest(obj);
7636   CHECK_EQ(40, p_getter_count2);
7637 }
7638
7639
7640 THREADED_TEST(ObjectInstantiation) {
7641   v8::Isolate* isolate = CcTest::isolate();
7642   v8::HandleScope scope(isolate);
7643   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7644   templ->SetAccessor(v8_str("t"), PGetter2);
7645   LocalContext context;
7646   context->Global()->Set(v8_str("o"), templ->NewInstance());
7647   for (int i = 0; i < 100; i++) {
7648     v8::HandleScope inner_scope(CcTest::isolate());
7649     v8::Handle<v8::Object> obj = templ->NewInstance();
7650     CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7651     context->Global()->Set(v8_str("o2"), obj);
7652     v8::Handle<Value> value =
7653         CompileRun("o.__proto__ === o2.__proto__");
7654     CHECK_EQ(v8::True(isolate), value);
7655     context->Global()->Set(v8_str("o"), obj);
7656   }
7657 }
7658
7659
7660 static int StrCmp16(uint16_t* a, uint16_t* b) {
7661   while (true) {
7662     if (*a == 0 && *b == 0) return 0;
7663     if (*a != *b) return 0 + *a - *b;
7664     a++;
7665     b++;
7666   }
7667 }
7668
7669
7670 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
7671   while (true) {
7672     if (n-- == 0) return 0;
7673     if (*a == 0 && *b == 0) return 0;
7674     if (*a != *b) return 0 + *a - *b;
7675     a++;
7676     b++;
7677   }
7678 }
7679
7680
7681 int GetUtf8Length(Handle<String> str) {
7682   int len = str->Utf8Length();
7683   if (len < 0) {
7684     i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
7685     i::String::Flatten(istr);
7686     len = str->Utf8Length();
7687   }
7688   return len;
7689 }
7690
7691
7692 THREADED_TEST(StringWrite) {
7693   LocalContext context;
7694   v8::HandleScope scope(context->GetIsolate());
7695   v8::Handle<String> str = v8_str("abcde");
7696   // abc<Icelandic eth><Unicode snowman>.
7697   v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
7698   v8::Handle<String> str3 = v8::String::NewFromUtf8(
7699       context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
7700   // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
7701   uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
7702   v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
7703       context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7704   // single lead surrogate
7705   uint16_t lead[1] = { 0xd800 };
7706   v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7707       context->GetIsolate(), lead, v8::String::kNormalString, 1);
7708   // single trail surrogate
7709   uint16_t trail[1] = { 0xdc00 };
7710   v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7711       context->GetIsolate(), trail, v8::String::kNormalString, 1);
7712   // surrogate pair
7713   uint16_t pair[2] = { 0xd800,  0xdc00 };
7714   v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7715       context->GetIsolate(), pair, v8::String::kNormalString, 2);
7716   const int kStride = 4;  // Must match stride in for loops in JS below.
7717   CompileRun(
7718       "var left = '';"
7719       "for (var i = 0; i < 0xd800; i += 4) {"
7720       "  left = left + String.fromCharCode(i);"
7721       "}");
7722   CompileRun(
7723       "var right = '';"
7724       "for (var i = 0; i < 0xd800; i += 4) {"
7725       "  right = String.fromCharCode(i) + right;"
7726       "}");
7727   v8::Handle<v8::Object> global = context->Global();
7728   Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7729   Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7730
7731   CHECK_EQ(5, str2->Length());
7732   CHECK_EQ(0xd800 / kStride, left_tree->Length());
7733   CHECK_EQ(0xd800 / kStride, right_tree->Length());
7734
7735   char buf[100];
7736   char utf8buf[0xd800 * 3];
7737   uint16_t wbuf[100];
7738   int len;
7739   int charlen;
7740
7741   memset(utf8buf, 0x1, 1000);
7742   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7743   CHECK_EQ(9, len);
7744   CHECK_EQ(5, charlen);
7745   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7746
7747   memset(utf8buf, 0x1, 1000);
7748   len = str2->WriteUtf8(utf8buf, 8, &charlen);
7749   CHECK_EQ(8, len);
7750   CHECK_EQ(5, charlen);
7751   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7752
7753   memset(utf8buf, 0x1, 1000);
7754   len = str2->WriteUtf8(utf8buf, 7, &charlen);
7755   CHECK_EQ(5, len);
7756   CHECK_EQ(4, charlen);
7757   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7758
7759   memset(utf8buf, 0x1, 1000);
7760   len = str2->WriteUtf8(utf8buf, 6, &charlen);
7761   CHECK_EQ(5, len);
7762   CHECK_EQ(4, charlen);
7763   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7764
7765   memset(utf8buf, 0x1, 1000);
7766   len = str2->WriteUtf8(utf8buf, 5, &charlen);
7767   CHECK_EQ(5, len);
7768   CHECK_EQ(4, charlen);
7769   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7770
7771   memset(utf8buf, 0x1, 1000);
7772   len = str2->WriteUtf8(utf8buf, 4, &charlen);
7773   CHECK_EQ(3, len);
7774   CHECK_EQ(3, charlen);
7775   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7776
7777   memset(utf8buf, 0x1, 1000);
7778   len = str2->WriteUtf8(utf8buf, 3, &charlen);
7779   CHECK_EQ(3, len);
7780   CHECK_EQ(3, charlen);
7781   CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7782
7783   memset(utf8buf, 0x1, 1000);
7784   len = str2->WriteUtf8(utf8buf, 2, &charlen);
7785   CHECK_EQ(2, len);
7786   CHECK_EQ(2, charlen);
7787   CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7788
7789   // allow orphan surrogates by default
7790   memset(utf8buf, 0x1, 1000);
7791   len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7792   CHECK_EQ(13, len);
7793   CHECK_EQ(8, charlen);
7794   CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7795
7796   // replace orphan surrogates with unicode replacement character
7797   memset(utf8buf, 0x1, 1000);
7798   len = orphans_str->WriteUtf8(utf8buf,
7799                                sizeof(utf8buf),
7800                                &charlen,
7801                                String::REPLACE_INVALID_UTF8);
7802   CHECK_EQ(13, len);
7803   CHECK_EQ(8, charlen);
7804   CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7805
7806   // replace single lead surrogate with unicode replacement character
7807   memset(utf8buf, 0x1, 1000);
7808   len = lead_str->WriteUtf8(utf8buf,
7809                             sizeof(utf8buf),
7810                             &charlen,
7811                             String::REPLACE_INVALID_UTF8);
7812   CHECK_EQ(4, len);
7813   CHECK_EQ(1, charlen);
7814   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7815
7816   // replace single trail surrogate with unicode replacement character
7817   memset(utf8buf, 0x1, 1000);
7818   len = trail_str->WriteUtf8(utf8buf,
7819                              sizeof(utf8buf),
7820                              &charlen,
7821                              String::REPLACE_INVALID_UTF8);
7822   CHECK_EQ(4, len);
7823   CHECK_EQ(1, charlen);
7824   CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7825
7826   // do not replace / write anything if surrogate pair does not fit the buffer
7827   // space
7828   memset(utf8buf, 0x1, 1000);
7829   len = pair_str->WriteUtf8(utf8buf,
7830                              3,
7831                              &charlen,
7832                              String::REPLACE_INVALID_UTF8);
7833   CHECK_EQ(0, len);
7834   CHECK_EQ(0, charlen);
7835
7836   memset(utf8buf, 0x1, sizeof(utf8buf));
7837   len = GetUtf8Length(left_tree);
7838   int utf8_expected =
7839       (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7840   CHECK_EQ(utf8_expected, len);
7841   len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7842   CHECK_EQ(utf8_expected, len);
7843   CHECK_EQ(0xd800 / kStride, charlen);
7844   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7845   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7846   CHECK_EQ(0xc0 - kStride,
7847            static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7848   CHECK_EQ(1, utf8buf[utf8_expected]);
7849
7850   memset(utf8buf, 0x1, sizeof(utf8buf));
7851   len = GetUtf8Length(right_tree);
7852   CHECK_EQ(utf8_expected, len);
7853   len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7854   CHECK_EQ(utf8_expected, len);
7855   CHECK_EQ(0xd800 / kStride, charlen);
7856   CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7857   CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7858   CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7859   CHECK_EQ(1, utf8buf[utf8_expected]);
7860
7861   memset(buf, 0x1, sizeof(buf));
7862   memset(wbuf, 0x1, sizeof(wbuf));
7863   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7864   CHECK_EQ(5, len);
7865   len = str->Write(wbuf);
7866   CHECK_EQ(5, len);
7867   CHECK_EQ(0, strcmp("abcde", buf));
7868   uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7869   CHECK_EQ(0, StrCmp16(answer1, wbuf));
7870
7871   memset(buf, 0x1, sizeof(buf));
7872   memset(wbuf, 0x1, sizeof(wbuf));
7873   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7874   CHECK_EQ(4, len);
7875   len = str->Write(wbuf, 0, 4);
7876   CHECK_EQ(4, len);
7877   CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7878   uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7879   CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7880
7881   memset(buf, 0x1, sizeof(buf));
7882   memset(wbuf, 0x1, sizeof(wbuf));
7883   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7884   CHECK_EQ(5, len);
7885   len = str->Write(wbuf, 0, 5);
7886   CHECK_EQ(5, len);
7887   CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7888   uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7889   CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7890
7891   memset(buf, 0x1, sizeof(buf));
7892   memset(wbuf, 0x1, sizeof(wbuf));
7893   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7894   CHECK_EQ(5, len);
7895   len = str->Write(wbuf, 0, 6);
7896   CHECK_EQ(5, len);
7897   CHECK_EQ(0, strcmp("abcde", buf));
7898   uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7899   CHECK_EQ(0, StrCmp16(answer4, wbuf));
7900
7901   memset(buf, 0x1, sizeof(buf));
7902   memset(wbuf, 0x1, sizeof(wbuf));
7903   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7904   CHECK_EQ(1, len);
7905   len = str->Write(wbuf, 4, -1);
7906   CHECK_EQ(1, len);
7907   CHECK_EQ(0, strcmp("e", buf));
7908   uint16_t answer5[] = {'e', '\0'};
7909   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7910
7911   memset(buf, 0x1, sizeof(buf));
7912   memset(wbuf, 0x1, sizeof(wbuf));
7913   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7914   CHECK_EQ(1, len);
7915   len = str->Write(wbuf, 4, 6);
7916   CHECK_EQ(1, len);
7917   CHECK_EQ(0, strcmp("e", buf));
7918   CHECK_EQ(0, StrCmp16(answer5, wbuf));
7919
7920   memset(buf, 0x1, sizeof(buf));
7921   memset(wbuf, 0x1, sizeof(wbuf));
7922   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7923   CHECK_EQ(1, len);
7924   len = str->Write(wbuf, 4, 1);
7925   CHECK_EQ(1, len);
7926   CHECK_EQ(0, strncmp("e\1", buf, 2));
7927   uint16_t answer6[] = {'e', 0x101};
7928   CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7929
7930   memset(buf, 0x1, sizeof(buf));
7931   memset(wbuf, 0x1, sizeof(wbuf));
7932   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7933   CHECK_EQ(1, len);
7934   len = str->Write(wbuf, 3, 1);
7935   CHECK_EQ(1, len);
7936   CHECK_EQ(0, strncmp("d\1", buf, 2));
7937   uint16_t answer7[] = {'d', 0x101};
7938   CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7939
7940   memset(wbuf, 0x1, sizeof(wbuf));
7941   wbuf[5] = 'X';
7942   len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7943   CHECK_EQ(5, len);
7944   CHECK_EQ('X', wbuf[5]);
7945   uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7946   uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7947   CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7948   CHECK_NE(0, StrCmp16(answer8b, wbuf));
7949   wbuf[5] = '\0';
7950   CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7951
7952   memset(buf, 0x1, sizeof(buf));
7953   buf[5] = 'X';
7954   len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7955                           0,
7956                           6,
7957                           String::NO_NULL_TERMINATION);
7958   CHECK_EQ(5, len);
7959   CHECK_EQ('X', buf[5]);
7960   CHECK_EQ(0, strncmp("abcde", buf, 5));
7961   CHECK_NE(0, strcmp("abcde", buf));
7962   buf[5] = '\0';
7963   CHECK_EQ(0, strcmp("abcde", buf));
7964
7965   memset(utf8buf, 0x1, sizeof(utf8buf));
7966   utf8buf[8] = 'X';
7967   len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7968                         String::NO_NULL_TERMINATION);
7969   CHECK_EQ(8, len);
7970   CHECK_EQ('X', utf8buf[8]);
7971   CHECK_EQ(5, charlen);
7972   CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7973   CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7974   utf8buf[8] = '\0';
7975   CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7976
7977   memset(utf8buf, 0x1, sizeof(utf8buf));
7978   utf8buf[5] = 'X';
7979   len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7980                         String::NO_NULL_TERMINATION);
7981   CHECK_EQ(5, len);
7982   CHECK_EQ('X', utf8buf[5]);  // Test that the sixth character is untouched.
7983   CHECK_EQ(5, charlen);
7984   utf8buf[5] = '\0';
7985   CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7986
7987   memset(buf, 0x1, sizeof(buf));
7988   len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7989   CHECK_EQ(7, len);
7990   CHECK_EQ(0, strcmp("abc", buf));
7991   CHECK_EQ(0, buf[3]);
7992   CHECK_EQ(0, strcmp("def", buf + 4));
7993
7994   CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7995   CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7996   CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7997 }
7998
7999
8000 static void Utf16Helper(
8001     LocalContext& context,  // NOLINT
8002     const char* name,
8003     const char* lengths_name,
8004     int len) {
8005   Local<v8::Array> a =
8006       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8007   Local<v8::Array> alens =
8008       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8009   for (int i = 0; i < len; i++) {
8010     Local<v8::String> string =
8011       Local<v8::String>::Cast(a->Get(i));
8012     Local<v8::Number> expected_len =
8013       Local<v8::Number>::Cast(alens->Get(i));
8014     int length = GetUtf8Length(string);
8015     CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8016   }
8017 }
8018
8019
8020 static uint16_t StringGet(Handle<String> str, int index) {
8021   i::Handle<i::String> istring =
8022       v8::Utils::OpenHandle(String::Cast(*str));
8023   return istring->Get(index);
8024 }
8025
8026
8027 static void WriteUtf8Helper(
8028     LocalContext& context,  // NOLINT
8029     const char* name,
8030     const char* lengths_name,
8031     int len) {
8032   Local<v8::Array> b =
8033       Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8034   Local<v8::Array> alens =
8035       Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8036   char buffer[1000];
8037   char buffer2[1000];
8038   for (int i = 0; i < len; i++) {
8039     Local<v8::String> string =
8040       Local<v8::String>::Cast(b->Get(i));
8041     Local<v8::Number> expected_len =
8042       Local<v8::Number>::Cast(alens->Get(i));
8043     int utf8_length = static_cast<int>(expected_len->Value());
8044     for (int j = utf8_length + 1; j >= 0; j--) {
8045       memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8046       memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8047       int nchars;
8048       int utf8_written =
8049           string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8050       int utf8_written2 =
8051           string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8052       CHECK_GE(utf8_length + 1, utf8_written);
8053       CHECK_GE(utf8_length, utf8_written2);
8054       for (int k = 0; k < utf8_written2; k++) {
8055         CHECK_EQ(buffer[k], buffer2[k]);
8056       }
8057       CHECK(nchars * 3 >= utf8_written - 1);
8058       CHECK(nchars <= utf8_written);
8059       if (j == utf8_length + 1) {
8060         CHECK_EQ(utf8_written2, utf8_length);
8061         CHECK_EQ(utf8_written2 + 1, utf8_written);
8062       }
8063       CHECK_EQ(buffer[utf8_written], 42);
8064       if (j > utf8_length) {
8065         if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8066         if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8067         Handle<String> roundtrip = v8_str(buffer);
8068         CHECK(roundtrip->Equals(string));
8069       } else {
8070         if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8071       }
8072       if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8073       if (nchars >= 2) {
8074         uint16_t trail = StringGet(string, nchars - 1);
8075         uint16_t lead = StringGet(string, nchars - 2);
8076         if (((lead & 0xfc00) == 0xd800) &&
8077             ((trail & 0xfc00) == 0xdc00)) {
8078           unsigned char u1 = buffer2[utf8_written2 - 4];
8079           unsigned char u2 = buffer2[utf8_written2 - 3];
8080           unsigned char u3 = buffer2[utf8_written2 - 2];
8081           unsigned char u4 = buffer2[utf8_written2 - 1];
8082           CHECK_EQ((u1 & 0xf8), 0xf0);
8083           CHECK_EQ((u2 & 0xc0), 0x80);
8084           CHECK_EQ((u3 & 0xc0), 0x80);
8085           CHECK_EQ((u4 & 0xc0), 0x80);
8086           uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8087           CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8088           CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8089           CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8090           CHECK_EQ((u1 & 0x3), c >> 18);
8091         }
8092       }
8093     }
8094   }
8095 }
8096
8097
8098 THREADED_TEST(Utf16) {
8099   LocalContext context;
8100   v8::HandleScope scope(context->GetIsolate());
8101   CompileRun(
8102       "var pad = '01234567890123456789';"
8103       "var p = [];"
8104       "var plens = [20, 3, 3];"
8105       "p.push('01234567890123456789');"
8106       "var lead = 0xd800;"
8107       "var trail = 0xdc00;"
8108       "p.push(String.fromCharCode(0xd800));"
8109       "p.push(String.fromCharCode(0xdc00));"
8110       "var a = [];"
8111       "var b = [];"
8112       "var c = [];"
8113       "var alens = [];"
8114       "for (var i = 0; i < 3; i++) {"
8115       "  p[1] = String.fromCharCode(lead++);"
8116       "  for (var j = 0; j < 3; j++) {"
8117       "    p[2] = String.fromCharCode(trail++);"
8118       "    a.push(p[i] + p[j]);"
8119       "    b.push(p[i] + p[j]);"
8120       "    c.push(p[i] + p[j]);"
8121       "    alens.push(plens[i] + plens[j]);"
8122       "  }"
8123       "}"
8124       "alens[5] -= 2;"  // Here the surrogate pairs match up.
8125       "var a2 = [];"
8126       "var b2 = [];"
8127       "var c2 = [];"
8128       "var a2lens = [];"
8129       "for (var m = 0; m < 9; m++) {"
8130       "  for (var n = 0; n < 9; n++) {"
8131       "    a2.push(a[m] + a[n]);"
8132       "    b2.push(b[m] + b[n]);"
8133       "    var newc = 'x' + c[m] + c[n] + 'y';"
8134       "    c2.push(newc.substring(1, newc.length - 1));"
8135       "    var utf = alens[m] + alens[n];"  // And here.
8136            // The 'n's that start with 0xdc.. are 6-8
8137            // The 'm's that end with 0xd8.. are 1, 4 and 7
8138       "    if ((m % 3) == 1 && n >= 6) utf -= 2;"
8139       "    a2lens.push(utf);"
8140       "  }"
8141       "}");
8142   Utf16Helper(context, "a", "alens", 9);
8143   Utf16Helper(context, "a2", "a2lens", 81);
8144   WriteUtf8Helper(context, "b", "alens", 9);
8145   WriteUtf8Helper(context, "b2", "a2lens", 81);
8146   WriteUtf8Helper(context, "c2", "a2lens", 81);
8147 }
8148
8149
8150 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8151   i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8152   i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8153   return *is1 == *is2;
8154 }
8155
8156 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8157                              const char* b) {
8158   Handle<String> symbol1 =
8159       v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8160   Handle<String> symbol2 =
8161       v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8162   CHECK(SameSymbol(symbol1, symbol2));
8163 }
8164
8165
8166 THREADED_TEST(Utf16Symbol) {
8167   LocalContext context;
8168   v8::HandleScope scope(context->GetIsolate());
8169
8170   Handle<String> symbol1 = v8::String::NewFromUtf8(
8171       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8172   Handle<String> symbol2 = v8::String::NewFromUtf8(
8173       context->GetIsolate(), "abc", v8::String::kInternalizedString);
8174   CHECK(SameSymbol(symbol1, symbol2));
8175
8176   SameSymbolHelper(context->GetIsolate(),
8177                    "\360\220\220\205",  // 4 byte encoding.
8178                    "\355\240\201\355\260\205");  // 2 3-byte surrogates.
8179   SameSymbolHelper(context->GetIsolate(),
8180                    "\355\240\201\355\260\206",  // 2 3-byte surrogates.
8181                    "\360\220\220\206");  // 4 byte encoding.
8182   SameSymbolHelper(context->GetIsolate(),
8183                    "x\360\220\220\205",  // 4 byte encoding.
8184                    "x\355\240\201\355\260\205");  // 2 3-byte surrogates.
8185   SameSymbolHelper(context->GetIsolate(),
8186                    "x\355\240\201\355\260\206",  // 2 3-byte surrogates.
8187                    "x\360\220\220\206");  // 4 byte encoding.
8188   CompileRun(
8189       "var sym0 = 'benedictus';"
8190       "var sym0b = 'S\303\270ren';"
8191       "var sym1 = '\355\240\201\355\260\207';"
8192       "var sym2 = '\360\220\220\210';"
8193       "var sym3 = 'x\355\240\201\355\260\207';"
8194       "var sym4 = 'x\360\220\220\210';"
8195       "if (sym1.length != 2) throw sym1;"
8196       "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8197       "if (sym2.length != 2) throw sym2;"
8198       "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8199       "if (sym3.length != 3) throw sym3;"
8200       "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8201       "if (sym4.length != 3) throw sym4;"
8202       "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8203   Handle<String> sym0 = v8::String::NewFromUtf8(
8204       context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8205   Handle<String> sym0b = v8::String::NewFromUtf8(
8206       context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8207   Handle<String> sym1 =
8208       v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8209                               v8::String::kInternalizedString);
8210   Handle<String> sym2 =
8211       v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8212                               v8::String::kInternalizedString);
8213   Handle<String> sym3 = v8::String::NewFromUtf8(
8214       context->GetIsolate(), "x\355\240\201\355\260\207",
8215       v8::String::kInternalizedString);
8216   Handle<String> sym4 =
8217       v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8218                               v8::String::kInternalizedString);
8219   v8::Local<v8::Object> global = context->Global();
8220   Local<Value> s0 = global->Get(v8_str("sym0"));
8221   Local<Value> s0b = global->Get(v8_str("sym0b"));
8222   Local<Value> s1 = global->Get(v8_str("sym1"));
8223   Local<Value> s2 = global->Get(v8_str("sym2"));
8224   Local<Value> s3 = global->Get(v8_str("sym3"));
8225   Local<Value> s4 = global->Get(v8_str("sym4"));
8226   CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8227   CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8228   CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8229   CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8230   CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8231   CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8232 }
8233
8234
8235 THREADED_TEST(ToArrayIndex) {
8236   LocalContext context;
8237   v8::Isolate* isolate = context->GetIsolate();
8238   v8::HandleScope scope(isolate);
8239
8240   v8::Handle<String> str = v8_str("42");
8241   v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8242   CHECK(!index.IsEmpty());
8243   CHECK_EQ(42.0, index->Uint32Value());
8244   str = v8_str("42asdf");
8245   index = str->ToArrayIndex();
8246   CHECK(index.IsEmpty());
8247   str = v8_str("-42");
8248   index = str->ToArrayIndex();
8249   CHECK(index.IsEmpty());
8250   str = v8_str("4294967295");
8251   index = str->ToArrayIndex();
8252   CHECK(!index.IsEmpty());
8253   CHECK_EQ(4294967295.0, index->Uint32Value());
8254   v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8255   index = num->ToArrayIndex();
8256   CHECK(!index.IsEmpty());
8257   CHECK_EQ(1.0, index->Uint32Value());
8258   num = v8::Number::New(isolate, -1);
8259   index = num->ToArrayIndex();
8260   CHECK(index.IsEmpty());
8261   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8262   index = obj->ToArrayIndex();
8263   CHECK(index.IsEmpty());
8264 }
8265
8266
8267 THREADED_TEST(ErrorConstruction) {
8268   LocalContext context;
8269   v8::HandleScope scope(context->GetIsolate());
8270
8271   v8::Handle<String> foo = v8_str("foo");
8272   v8::Handle<String> message = v8_str("message");
8273   v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8274   CHECK(range_error->IsObject());
8275   CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8276   v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8277   CHECK(reference_error->IsObject());
8278   CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8279   v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8280   CHECK(syntax_error->IsObject());
8281   CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8282   v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8283   CHECK(type_error->IsObject());
8284   CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8285   v8::Handle<Value> error = v8::Exception::Error(foo);
8286   CHECK(error->IsObject());
8287   CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8288 }
8289
8290
8291 static void YGetter(Local<String> name,
8292                     const v8::PropertyCallbackInfo<v8::Value>& info) {
8293   ApiTestFuzzer::Fuzz();
8294   info.GetReturnValue().Set(v8_num(10));
8295 }
8296
8297
8298 static void YSetter(Local<String> name,
8299                     Local<Value> value,
8300                     const v8::PropertyCallbackInfo<void>& info) {
8301   Local<Object> this_obj = Local<Object>::Cast(info.This());
8302   if (this_obj->Has(name)) this_obj->Delete(name);
8303   this_obj->Set(name, value);
8304 }
8305
8306
8307 THREADED_TEST(DeleteAccessor) {
8308   v8::Isolate* isolate = CcTest::isolate();
8309   v8::HandleScope scope(isolate);
8310   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8311   obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8312   LocalContext context;
8313   v8::Handle<v8::Object> holder = obj->NewInstance();
8314   context->Global()->Set(v8_str("holder"), holder);
8315   v8::Handle<Value> result = CompileRun(
8316       "holder.y = 11; holder.y = 12; holder.y");
8317   CHECK_EQ(12, result->Uint32Value());
8318 }
8319
8320
8321 THREADED_TEST(TypeSwitch) {
8322   v8::Isolate* isolate = CcTest::isolate();
8323   v8::HandleScope scope(isolate);
8324   v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8325   v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8326   v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8327   v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8328   v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8329   LocalContext context;
8330   v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8331   v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8332   v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8333   v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8334   for (int i = 0; i < 10; i++) {
8335     CHECK_EQ(0, type_switch->match(obj0));
8336     CHECK_EQ(1, type_switch->match(obj1));
8337     CHECK_EQ(2, type_switch->match(obj2));
8338     CHECK_EQ(3, type_switch->match(obj3));
8339     CHECK_EQ(3, type_switch->match(obj3));
8340     CHECK_EQ(2, type_switch->match(obj2));
8341     CHECK_EQ(1, type_switch->match(obj1));
8342     CHECK_EQ(0, type_switch->match(obj0));
8343   }
8344 }
8345
8346
8347 static int trouble_nesting = 0;
8348 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8349   ApiTestFuzzer::Fuzz();
8350   trouble_nesting++;
8351
8352   // Call a JS function that throws an uncaught exception.
8353   Local<v8::Object> arg_this =
8354       args.GetIsolate()->GetCurrentContext()->Global();
8355   Local<Value> trouble_callee = (trouble_nesting == 3) ?
8356     arg_this->Get(v8_str("trouble_callee")) :
8357     arg_this->Get(v8_str("trouble_caller"));
8358   CHECK(trouble_callee->IsFunction());
8359   args.GetReturnValue().Set(
8360       Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8361 }
8362
8363
8364 static int report_count = 0;
8365 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8366                                              v8::Handle<Value>) {
8367   report_count++;
8368 }
8369
8370
8371 // Counts uncaught exceptions, but other tests running in parallel
8372 // also have uncaught exceptions.
8373 TEST(ApiUncaughtException) {
8374   report_count = 0;
8375   LocalContext env;
8376   v8::Isolate* isolate = env->GetIsolate();
8377   v8::HandleScope scope(isolate);
8378   v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8379
8380   Local<v8::FunctionTemplate> fun =
8381       v8::FunctionTemplate::New(isolate, TroubleCallback);
8382   v8::Local<v8::Object> global = env->Global();
8383   global->Set(v8_str("trouble"), fun->GetFunction());
8384
8385   CompileRun(
8386       "function trouble_callee() {"
8387       "  var x = null;"
8388       "  return x.foo;"
8389       "};"
8390       "function trouble_caller() {"
8391       "  trouble();"
8392       "};");
8393   Local<Value> trouble = global->Get(v8_str("trouble"));
8394   CHECK(trouble->IsFunction());
8395   Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8396   CHECK(trouble_callee->IsFunction());
8397   Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8398   CHECK(trouble_caller->IsFunction());
8399   Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8400   CHECK_EQ(1, report_count);
8401   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8402 }
8403
8404 static const char* script_resource_name = "ExceptionInNativeScript.js";
8405 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8406                                                 v8::Handle<Value>) {
8407   v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8408   CHECK(!name_val.IsEmpty() && name_val->IsString());
8409   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8410   CHECK_EQ(script_resource_name, *name);
8411   CHECK_EQ(3, message->GetLineNumber());
8412   v8::String::Utf8Value source_line(message->GetSourceLine());
8413   CHECK_EQ("  new o.foo();", *source_line);
8414 }
8415
8416
8417 TEST(ExceptionInNativeScript) {
8418   LocalContext env;
8419   v8::Isolate* isolate = env->GetIsolate();
8420   v8::HandleScope scope(isolate);
8421   v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8422
8423   Local<v8::FunctionTemplate> fun =
8424       v8::FunctionTemplate::New(isolate, TroubleCallback);
8425   v8::Local<v8::Object> global = env->Global();
8426   global->Set(v8_str("trouble"), fun->GetFunction());
8427
8428   CompileRunWithOrigin(
8429       "function trouble() {\n"
8430       "  var o = {};\n"
8431       "  new o.foo();\n"
8432       "};",
8433       script_resource_name);
8434   Local<Value> trouble = global->Get(v8_str("trouble"));
8435   CHECK(trouble->IsFunction());
8436   Function::Cast(*trouble)->Call(global, 0, NULL);
8437   v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8438 }
8439
8440
8441 TEST(CompilationErrorUsingTryCatchHandler) {
8442   LocalContext env;
8443   v8::HandleScope scope(env->GetIsolate());
8444   v8::TryCatch try_catch;
8445   v8_compile("This doesn't &*&@#$&*^ compile.");
8446   CHECK_NE(NULL, *try_catch.Exception());
8447   CHECK(try_catch.HasCaught());
8448 }
8449
8450
8451 TEST(TryCatchFinallyUsingTryCatchHandler) {
8452   LocalContext env;
8453   v8::HandleScope scope(env->GetIsolate());
8454   v8::TryCatch try_catch;
8455   CompileRun("try { throw ''; } catch (e) {}");
8456   CHECK(!try_catch.HasCaught());
8457   CompileRun("try { throw ''; } finally {}");
8458   CHECK(try_catch.HasCaught());
8459   try_catch.Reset();
8460   CompileRun(
8461       "(function() {"
8462       "try { throw ''; } finally { return; }"
8463       "})()");
8464   CHECK(!try_catch.HasCaught());
8465   CompileRun(
8466       "(function()"
8467       "  { try { throw ''; } finally { throw 0; }"
8468       "})()");
8469   CHECK(try_catch.HasCaught());
8470 }
8471
8472
8473 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8474   v8::HandleScope scope(args.GetIsolate());
8475   CompileRun(args[0]->ToString());
8476 }
8477
8478
8479 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8480   v8::Isolate* isolate = CcTest::isolate();
8481   v8::HandleScope scope(isolate);
8482   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8483   templ->Set(v8_str("CEvaluate"),
8484              v8::FunctionTemplate::New(isolate, CEvaluate));
8485   LocalContext context(0, templ);
8486   v8::TryCatch try_catch;
8487   CompileRun("try {"
8488              "  CEvaluate('throw 1;');"
8489              "} finally {"
8490              "}");
8491   CHECK(try_catch.HasCaught());
8492   CHECK(!try_catch.Message().IsEmpty());
8493   String::Utf8Value exception_value(try_catch.Exception());
8494   CHECK_EQ(*exception_value, "1");
8495   try_catch.Reset();
8496   CompileRun("try {"
8497              "  CEvaluate('throw 1;');"
8498              "} finally {"
8499              "  throw 2;"
8500              "}");
8501   CHECK(try_catch.HasCaught());
8502   CHECK(!try_catch.Message().IsEmpty());
8503   String::Utf8Value finally_exception_value(try_catch.Exception());
8504   CHECK_EQ(*finally_exception_value, "2");
8505 }
8506
8507
8508 // For use within the TestSecurityHandler() test.
8509 static bool g_security_callback_result = false;
8510 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8511                                       Local<Value> name,
8512                                       v8::AccessType type,
8513                                       Local<Value> data) {
8514   printf("a\n");
8515   // Always allow read access.
8516   if (type == v8::ACCESS_GET)
8517     return true;
8518
8519   // Sometimes allow other access.
8520   return g_security_callback_result;
8521 }
8522
8523
8524 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8525                                         uint32_t key,
8526                                         v8::AccessType type,
8527                                         Local<Value> data) {
8528   printf("b\n");
8529   // Always allow read access.
8530   if (type == v8::ACCESS_GET)
8531     return true;
8532
8533   // Sometimes allow other access.
8534   return g_security_callback_result;
8535 }
8536
8537
8538 // SecurityHandler can't be run twice
8539 TEST(SecurityHandler) {
8540   v8::Isolate* isolate = CcTest::isolate();
8541   v8::HandleScope scope0(isolate);
8542   v8::Handle<v8::ObjectTemplate> global_template =
8543       v8::ObjectTemplate::New(isolate);
8544   global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8545                                            IndexedSecurityTestCallback);
8546   // Create an environment
8547   v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8548   context0->Enter();
8549
8550   v8::Handle<v8::Object> global0 = context0->Global();
8551   v8::Handle<Script> script0 = v8_compile("foo = 111");
8552   script0->Run();
8553   global0->Set(v8_str("0"), v8_num(999));
8554   v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8555   CHECK_EQ(111, foo0->Int32Value());
8556   v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8557   CHECK_EQ(999, z0->Int32Value());
8558
8559   // Create another environment, should fail security checks.
8560   v8::HandleScope scope1(isolate);
8561
8562   v8::Handle<Context> context1 =
8563     Context::New(isolate, NULL, global_template);
8564   context1->Enter();
8565
8566   v8::Handle<v8::Object> global1 = context1->Global();
8567   global1->Set(v8_str("othercontext"), global0);
8568   // This set will fail the security check.
8569   v8::Handle<Script> script1 =
8570     v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8571   script1->Run();
8572   // This read will pass the security check.
8573   v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8574   CHECK_EQ(111, foo1->Int32Value());
8575   // This read will pass the security check.
8576   v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8577   CHECK_EQ(999, z1->Int32Value());
8578
8579   // Create another environment, should pass security checks.
8580   { g_security_callback_result = true;  // allow security handler to pass.
8581     v8::HandleScope scope2(isolate);
8582     LocalContext context2;
8583     v8::Handle<v8::Object> global2 = context2->Global();
8584     global2->Set(v8_str("othercontext"), global0);
8585     v8::Handle<Script> script2 =
8586         v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8587     script2->Run();
8588     v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8589     CHECK_EQ(333, foo2->Int32Value());
8590     v8::Handle<Value> z2 = global0->Get(v8_str("0"));
8591     CHECK_EQ(888, z2->Int32Value());
8592   }
8593
8594   context1->Exit();
8595   context0->Exit();
8596 }
8597
8598
8599 THREADED_TEST(SecurityChecks) {
8600   LocalContext env1;
8601   v8::HandleScope handle_scope(env1->GetIsolate());
8602   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8603
8604   Local<Value> foo = v8_str("foo");
8605   Local<Value> bar = v8_str("bar");
8606
8607   // Set to the same domain.
8608   env1->SetSecurityToken(foo);
8609
8610   // Create a function in env1.
8611   CompileRun("spy=function(){return spy;}");
8612   Local<Value> spy = env1->Global()->Get(v8_str("spy"));
8613   CHECK(spy->IsFunction());
8614
8615   // Create another function accessing global objects.
8616   CompileRun("spy2=function(){return new this.Array();}");
8617   Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
8618   CHECK(spy2->IsFunction());
8619
8620   // Switch to env2 in the same domain and invoke spy on env2.
8621   {
8622     env2->SetSecurityToken(foo);
8623     // Enter env2
8624     Context::Scope scope_env2(env2);
8625     Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8626     CHECK(result->IsFunction());
8627   }
8628
8629   {
8630     env2->SetSecurityToken(bar);
8631     Context::Scope scope_env2(env2);
8632
8633     // Call cross_domain_call, it should throw an exception
8634     v8::TryCatch try_catch;
8635     Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8636     CHECK(try_catch.HasCaught());
8637   }
8638 }
8639
8640
8641 // Regression test case for issue 1183439.
8642 THREADED_TEST(SecurityChecksForPrototypeChain) {
8643   LocalContext current;
8644   v8::HandleScope scope(current->GetIsolate());
8645   v8::Handle<Context> other = Context::New(current->GetIsolate());
8646
8647   // Change context to be able to get to the Object function in the
8648   // other context without hitting the security checks.
8649   v8::Local<Value> other_object;
8650   { Context::Scope scope(other);
8651     other_object = other->Global()->Get(v8_str("Object"));
8652     other->Global()->Set(v8_num(42), v8_num(87));
8653   }
8654
8655   current->Global()->Set(v8_str("other"), other->Global());
8656   CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8657
8658   // Make sure the security check fails here and we get an undefined
8659   // result instead of getting the Object function. Repeat in a loop
8660   // to make sure to exercise the IC code.
8661   v8::Local<Script> access_other0 = v8_compile("other.Object");
8662   v8::Local<Script> access_other1 = v8_compile("other[42]");
8663   for (int i = 0; i < 5; i++) {
8664     CHECK(access_other0->Run().IsEmpty());
8665     CHECK(access_other1->Run().IsEmpty());
8666   }
8667
8668   // Create an object that has 'other' in its prototype chain and make
8669   // sure we cannot access the Object function indirectly through
8670   // that. Repeat in a loop to make sure to exercise the IC code.
8671   v8_compile("function F() { };"
8672              "F.prototype = other;"
8673              "var f = new F();")->Run();
8674   v8::Local<Script> access_f0 = v8_compile("f.Object");
8675   v8::Local<Script> access_f1 = v8_compile("f[42]");
8676   for (int j = 0; j < 5; j++) {
8677     CHECK(access_f0->Run().IsEmpty());
8678     CHECK(access_f1->Run().IsEmpty());
8679   }
8680
8681   // Now it gets hairy: Set the prototype for the other global object
8682   // to be the current global object. The prototype chain for 'f' now
8683   // goes through 'other' but ends up in the current global object.
8684   { Context::Scope scope(other);
8685     other->Global()->Set(v8_str("__proto__"), current->Global());
8686   }
8687   // Set a named and an index property on the current global
8688   // object. To force the lookup to go through the other global object,
8689   // the properties must not exist in the other global object.
8690   current->Global()->Set(v8_str("foo"), v8_num(100));
8691   current->Global()->Set(v8_num(99), v8_num(101));
8692   // Try to read the properties from f and make sure that the access
8693   // gets stopped by the security checks on the other global object.
8694   Local<Script> access_f2 = v8_compile("f.foo");
8695   Local<Script> access_f3 = v8_compile("f[99]");
8696   for (int k = 0; k < 5; k++) {
8697     CHECK(access_f2->Run().IsEmpty());
8698     CHECK(access_f3->Run().IsEmpty());
8699   }
8700 }
8701
8702
8703 static bool named_security_check_with_gc_called;
8704
8705 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
8706                                         Local<Value> name,
8707                                         v8::AccessType type,
8708                                         Local<Value> data) {
8709   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8710   named_security_check_with_gc_called = true;
8711   return true;
8712 }
8713
8714
8715 static bool indexed_security_check_with_gc_called;
8716
8717 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
8718                                               uint32_t key,
8719                                               v8::AccessType type,
8720                                               Local<Value> data) {
8721   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8722   indexed_security_check_with_gc_called = true;
8723   return true;
8724 }
8725
8726
8727 TEST(SecurityTestGCAllowed) {
8728   v8::Isolate* isolate = CcTest::isolate();
8729   v8::HandleScope handle_scope(isolate);
8730   v8::Handle<v8::ObjectTemplate> object_template =
8731       v8::ObjectTemplate::New(isolate);
8732   object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
8733                                            IndexedSecurityTestCallbackWithGC);
8734
8735   v8::Handle<Context> context = Context::New(isolate);
8736   v8::Context::Scope context_scope(context);
8737
8738   context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8739
8740   named_security_check_with_gc_called = false;
8741   CompileRun("obj.foo = new String(1001);");
8742   CHECK(named_security_check_with_gc_called);
8743
8744   indexed_security_check_with_gc_called = false;
8745   CompileRun("obj[0] = new String(1002);");
8746   CHECK(indexed_security_check_with_gc_called);
8747
8748   named_security_check_with_gc_called = false;
8749   CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
8750   CHECK(named_security_check_with_gc_called);
8751
8752   indexed_security_check_with_gc_called = false;
8753   CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
8754   CHECK(indexed_security_check_with_gc_called);
8755 }
8756
8757
8758 THREADED_TEST(CrossDomainDelete) {
8759   LocalContext env1;
8760   v8::HandleScope handle_scope(env1->GetIsolate());
8761   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8762
8763   Local<Value> foo = v8_str("foo");
8764   Local<Value> bar = v8_str("bar");
8765
8766   // Set to the same domain.
8767   env1->SetSecurityToken(foo);
8768   env2->SetSecurityToken(foo);
8769
8770   env1->Global()->Set(v8_str("prop"), v8_num(3));
8771   env2->Global()->Set(v8_str("env1"), env1->Global());
8772
8773   // Change env2 to a different domain and delete env1.prop.
8774   env2->SetSecurityToken(bar);
8775   {
8776     Context::Scope scope_env2(env2);
8777     Local<Value> result =
8778         CompileRun("delete env1.prop");
8779     CHECK(result.IsEmpty());
8780   }
8781
8782   // Check that env1.prop still exists.
8783   Local<Value> v = env1->Global()->Get(v8_str("prop"));
8784   CHECK(v->IsNumber());
8785   CHECK_EQ(3, v->Int32Value());
8786 }
8787
8788
8789 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8790   LocalContext env1;
8791   v8::HandleScope handle_scope(env1->GetIsolate());
8792   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8793
8794   Local<Value> foo = v8_str("foo");
8795   Local<Value> bar = v8_str("bar");
8796
8797   // Set to the same domain.
8798   env1->SetSecurityToken(foo);
8799   env2->SetSecurityToken(foo);
8800
8801   env1->Global()->Set(v8_str("prop"), v8_num(3));
8802   env2->Global()->Set(v8_str("env1"), env1->Global());
8803
8804   // env1.prop is enumerable in env2.
8805   Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8806   {
8807     Context::Scope scope_env2(env2);
8808     Local<Value> result = CompileRun(test);
8809     CHECK(result->IsTrue());
8810   }
8811
8812   // Change env2 to a different domain and test again.
8813   env2->SetSecurityToken(bar);
8814   {
8815     Context::Scope scope_env2(env2);
8816     Local<Value> result = CompileRun(test);
8817     CHECK(result.IsEmpty());
8818   }
8819 }
8820
8821
8822 THREADED_TEST(CrossDomainForIn) {
8823   LocalContext env1;
8824   v8::HandleScope handle_scope(env1->GetIsolate());
8825   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8826
8827   Local<Value> foo = v8_str("foo");
8828   Local<Value> bar = v8_str("bar");
8829
8830   // Set to the same domain.
8831   env1->SetSecurityToken(foo);
8832   env2->SetSecurityToken(foo);
8833
8834   env1->Global()->Set(v8_str("prop"), v8_num(3));
8835   env2->Global()->Set(v8_str("env1"), env1->Global());
8836
8837   // Change env2 to a different domain and set env1's global object
8838   // as the __proto__ of an object in env2 and enumerate properties
8839   // in for-in. It shouldn't enumerate properties on env1's global
8840   // object.
8841   env2->SetSecurityToken(bar);
8842   {
8843     Context::Scope scope_env2(env2);
8844     Local<Value> result = CompileRun(
8845         "(function() {"
8846         "  var obj = { '__proto__': env1 };"
8847         "  try {"
8848         "    for (var p in obj) {"
8849         "      if (p == 'prop') return false;"
8850         "    }"
8851         "    return false;"
8852         "  } catch (e) {"
8853         "    return true;"
8854         "  }"
8855         "})()");
8856     CHECK(result->IsTrue());
8857   }
8858 }
8859
8860
8861 TEST(ContextDetachGlobal) {
8862   LocalContext env1;
8863   v8::HandleScope handle_scope(env1->GetIsolate());
8864   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8865
8866   Local<v8::Object> global1 = env1->Global();
8867
8868   Local<Value> foo = v8_str("foo");
8869
8870   // Set to the same domain.
8871   env1->SetSecurityToken(foo);
8872   env2->SetSecurityToken(foo);
8873
8874   // Enter env2
8875   env2->Enter();
8876
8877   // Create a function in env2 and add a reference to it in env1.
8878   Local<v8::Object> global2 = env2->Global();
8879   global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8880   CompileRun("function getProp() {return prop;}");
8881
8882   env1->Global()->Set(v8_str("getProp"),
8883                       global2->Get(v8_str("getProp")));
8884
8885   // Detach env2's global, and reuse the global object of env2
8886   env2->Exit();
8887   env2->DetachGlobal();
8888
8889   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8890                                           0,
8891                                           v8::Handle<v8::ObjectTemplate>(),
8892                                           global2);
8893   env3->SetSecurityToken(v8_str("bar"));
8894   env3->Enter();
8895
8896   Local<v8::Object> global3 = env3->Global();
8897   CHECK_EQ(global2, global3);
8898   CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8899   CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8900   global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8901   global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8902   env3->Exit();
8903
8904   // Call getProp in env1, and it should return the value 1
8905   {
8906     Local<Value> get_prop = global1->Get(v8_str("getProp"));
8907     CHECK(get_prop->IsFunction());
8908     v8::TryCatch try_catch;
8909     Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8910     CHECK(!try_catch.HasCaught());
8911     CHECK_EQ(1, r->Int32Value());
8912   }
8913
8914   // Check that env3 is not accessible from env1
8915   {
8916     Local<Value> r = global3->Get(v8_str("prop2"));
8917     CHECK(r.IsEmpty());
8918   }
8919 }
8920
8921
8922 TEST(DetachGlobal) {
8923   LocalContext env1;
8924   v8::HandleScope scope(env1->GetIsolate());
8925
8926   // Create second environment.
8927   v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8928
8929   Local<Value> foo = v8_str("foo");
8930
8931   // Set same security token for env1 and env2.
8932   env1->SetSecurityToken(foo);
8933   env2->SetSecurityToken(foo);
8934
8935   // Create a property on the global object in env2.
8936   {
8937     v8::Context::Scope scope(env2);
8938     env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8939   }
8940
8941   // Create a reference to env2 global from env1 global.
8942   env1->Global()->Set(v8_str("other"), env2->Global());
8943
8944   // Check that we have access to other.p in env2 from env1.
8945   Local<Value> result = CompileRun("other.p");
8946   CHECK(result->IsInt32());
8947   CHECK_EQ(42, result->Int32Value());
8948
8949   // Hold on to global from env2 and detach global from env2.
8950   Local<v8::Object> global2 = env2->Global();
8951   env2->DetachGlobal();
8952
8953   // Check that the global has been detached. No other.p property can
8954   // be found.
8955   result = CompileRun("other.p");
8956   CHECK(result.IsEmpty());
8957
8958   // Reuse global2 for env3.
8959   v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8960                                           0,
8961                                           v8::Handle<v8::ObjectTemplate>(),
8962                                           global2);
8963   CHECK_EQ(global2, env3->Global());
8964
8965   // Start by using the same security token for env3 as for env1 and env2.
8966   env3->SetSecurityToken(foo);
8967
8968   // Create a property on the global object in env3.
8969   {
8970     v8::Context::Scope scope(env3);
8971     env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8972   }
8973
8974   // Check that other.p is now the property in env3 and that we have access.
8975   result = CompileRun("other.p");
8976   CHECK(result->IsInt32());
8977   CHECK_EQ(24, result->Int32Value());
8978
8979   // Change security token for env3 to something different from env1 and env2.
8980   env3->SetSecurityToken(v8_str("bar"));
8981
8982   // Check that we do not have access to other.p in env1. |other| is now
8983   // the global object for env3 which has a different security token,
8984   // so access should be blocked.
8985   result = CompileRun("other.p");
8986   CHECK(result.IsEmpty());
8987 }
8988
8989
8990 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8991   info.GetReturnValue().Set(
8992       info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8993 }
8994
8995
8996 TEST(DetachedAccesses) {
8997   LocalContext env1;
8998   v8::HandleScope scope(env1->GetIsolate());
8999
9000   // Create second environment.
9001   Local<ObjectTemplate> inner_global_template =
9002       FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9003   inner_global_template ->SetAccessorProperty(
9004       v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9005   v8::Local<Context> env2 =
9006       Context::New(env1->GetIsolate(), NULL, inner_global_template);
9007
9008   Local<Value> foo = v8_str("foo");
9009
9010   // Set same security token for env1 and env2.
9011   env1->SetSecurityToken(foo);
9012   env2->SetSecurityToken(foo);
9013
9014   env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9015
9016   {
9017     v8::Context::Scope scope(env2);
9018     env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9019     CompileRun(
9020         "function bound_x() { return x; }"
9021         "function get_x()   { return this.x; }"
9022         "function get_x_w() { return (function() {return this.x;})(); }");
9023     env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9024     env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9025     env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9026     env1->Global()->Set(
9027         v8_str("this_x"),
9028         CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9029   }
9030
9031   Local<Object> env2_global = env2->Global();
9032   env2_global->TurnOnAccessCheck();
9033   env2->DetachGlobal();
9034
9035   Local<Value> result;
9036   result = CompileRun("bound_x()");
9037   CHECK_EQ(v8_str("env2_x"), result);
9038   result = CompileRun("get_x()");
9039   CHECK(result.IsEmpty());
9040   result = CompileRun("get_x_w()");
9041   CHECK(result.IsEmpty());
9042   result = CompileRun("this_x()");
9043   CHECK_EQ(v8_str("env2_x"), result);
9044
9045   // Reattach env2's proxy
9046   env2 = Context::New(env1->GetIsolate(),
9047                       0,
9048                       v8::Handle<v8::ObjectTemplate>(),
9049                       env2_global);
9050   env2->SetSecurityToken(foo);
9051   {
9052     v8::Context::Scope scope(env2);
9053     env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9054     env2->Global()->Set(v8_str("env1"), env1->Global());
9055     result = CompileRun(
9056         "results = [];"
9057         "for (var i = 0; i < 4; i++ ) {"
9058         "  results.push(env1.bound_x());"
9059         "  results.push(env1.get_x());"
9060         "  results.push(env1.get_x_w());"
9061         "  results.push(env1.this_x());"
9062         "}"
9063         "results");
9064     Local<v8::Array> results = Local<v8::Array>::Cast(result);
9065     CHECK_EQ(16, results->Length());
9066     for (int i = 0; i < 16; i += 4) {
9067       CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9068       CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9069       CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9070       CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9071     }
9072   }
9073
9074   result = CompileRun(
9075       "results = [];"
9076       "for (var i = 0; i < 4; i++ ) {"
9077       "  results.push(bound_x());"
9078       "  results.push(get_x());"
9079       "  results.push(get_x_w());"
9080       "  results.push(this_x());"
9081       "}"
9082       "results");
9083   Local<v8::Array> results = Local<v8::Array>::Cast(result);
9084   CHECK_EQ(16, results->Length());
9085   for (int i = 0; i < 16; i += 4) {
9086     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9087     CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9088     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9089     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9090   }
9091
9092   result = CompileRun(
9093       "results = [];"
9094       "for (var i = 0; i < 4; i++ ) {"
9095       "  results.push(this.bound_x());"
9096       "  results.push(this.get_x());"
9097       "  results.push(this.get_x_w());"
9098       "  results.push(this.this_x());"
9099       "}"
9100       "results");
9101   results = Local<v8::Array>::Cast(result);
9102   CHECK_EQ(16, results->Length());
9103   for (int i = 0; i < 16; i += 4) {
9104     CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9105     CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9106     CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9107     CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9108   }
9109 }
9110
9111
9112 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9113 static bool NamedAccessBlocker(Local<v8::Object> global,
9114                                Local<Value> name,
9115                                v8::AccessType type,
9116                                Local<Value> data) {
9117   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9118       allowed_access_type[type];
9119 }
9120
9121
9122 static bool IndexedAccessBlocker(Local<v8::Object> global,
9123                                  uint32_t key,
9124                                  v8::AccessType type,
9125                                  Local<Value> data) {
9126   return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9127       allowed_access_type[type];
9128 }
9129
9130
9131 static int g_echo_value = -1;
9132
9133
9134 static void EchoGetter(
9135     Local<String> name,
9136     const v8::PropertyCallbackInfo<v8::Value>& info) {
9137   info.GetReturnValue().Set(v8_num(g_echo_value));
9138 }
9139
9140
9141 static void EchoSetter(Local<String> name,
9142                        Local<Value> value,
9143                        const v8::PropertyCallbackInfo<void>&) {
9144   if (value->IsNumber())
9145     g_echo_value = value->Int32Value();
9146 }
9147
9148
9149 static void UnreachableGetter(
9150     Local<String> name,
9151     const v8::PropertyCallbackInfo<v8::Value>& info) {
9152   CHECK(false);  // This function should not be called..
9153 }
9154
9155
9156 static void UnreachableSetter(Local<String>,
9157                               Local<Value>,
9158                               const v8::PropertyCallbackInfo<void>&) {
9159   CHECK(false);  // This function should nto be called.
9160 }
9161
9162
9163 static void UnreachableFunction(
9164     const v8::FunctionCallbackInfo<v8::Value>& info) {
9165   CHECK(false);  // This function should not be called..
9166 }
9167
9168
9169 TEST(AccessControl) {
9170   v8::Isolate* isolate = CcTest::isolate();
9171   v8::HandleScope handle_scope(isolate);
9172   v8::Handle<v8::ObjectTemplate> global_template =
9173       v8::ObjectTemplate::New(isolate);
9174
9175   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9176                                            IndexedAccessBlocker);
9177
9178   // Add an accessor accessible by cross-domain JS code.
9179   global_template->SetAccessor(
9180       v8_str("accessible_prop"),
9181       EchoGetter, EchoSetter,
9182       v8::Handle<Value>(),
9183       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9184
9185
9186   // Add an accessor that is not accessible by cross-domain JS code.
9187   global_template->SetAccessor(v8_str("blocked_prop"),
9188                                UnreachableGetter, UnreachableSetter,
9189                                v8::Handle<Value>(),
9190                                v8::DEFAULT);
9191
9192   global_template->SetAccessorProperty(
9193       v8_str("blocked_js_prop"),
9194       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9195       v8::FunctionTemplate::New(isolate, UnreachableFunction),
9196       v8::None,
9197       v8::DEFAULT);
9198
9199   // Create an environment
9200   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9201   context0->Enter();
9202
9203   v8::Handle<v8::Object> global0 = context0->Global();
9204
9205   // Define a property with JS getter and setter.
9206   CompileRun(
9207       "function getter() { return 'getter'; };\n"
9208       "function setter() { return 'setter'; }\n"
9209       "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9210
9211   Local<Value> getter = global0->Get(v8_str("getter"));
9212   Local<Value> setter = global0->Get(v8_str("setter"));
9213
9214   // And define normal element.
9215   global0->Set(239, v8_str("239"));
9216
9217   // Define an element with JS getter and setter.
9218   CompileRun(
9219       "function el_getter() { return 'el_getter'; };\n"
9220       "function el_setter() { return 'el_setter'; };\n"
9221       "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9222
9223   Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9224   Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9225
9226   v8::HandleScope scope1(isolate);
9227
9228   v8::Local<Context> context1 = Context::New(isolate);
9229   context1->Enter();
9230
9231   v8::Handle<v8::Object> global1 = context1->Global();
9232   global1->Set(v8_str("other"), global0);
9233
9234   // Access blocked property.
9235   CompileRun("other.blocked_prop = 1");
9236
9237   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9238   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9239             .IsEmpty());
9240   CHECK(
9241       CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9242
9243   // Access blocked element.
9244   CHECK(CompileRun("other[239] = 1").IsEmpty());
9245
9246   CHECK(CompileRun("other[239]").IsEmpty());
9247   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9248   CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9249
9250   // Enable ACCESS_HAS
9251   allowed_access_type[v8::ACCESS_HAS] = true;
9252   CHECK(CompileRun("other[239]").IsEmpty());
9253   // ... and now we can get the descriptor...
9254   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9255             .IsEmpty());
9256   // ... and enumerate the property.
9257   ExpectTrue("propertyIsEnumerable.call(other, '239')");
9258   allowed_access_type[v8::ACCESS_HAS] = false;
9259
9260   // Access a property with JS accessor.
9261   CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9262
9263   CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9264   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9265             .IsEmpty());
9266
9267   // Enable both ACCESS_HAS and ACCESS_GET.
9268   allowed_access_type[v8::ACCESS_HAS] = true;
9269   allowed_access_type[v8::ACCESS_GET] = true;
9270
9271   ExpectString("other.js_accessor_p", "getter");
9272   ExpectObject(
9273       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9274   ExpectObject(
9275       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9276   ExpectUndefined(
9277       "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9278
9279   allowed_access_type[v8::ACCESS_HAS] = false;
9280   allowed_access_type[v8::ACCESS_GET] = false;
9281
9282   // Access an element with JS accessor.
9283   CHECK(CompileRun("other[42] = 2").IsEmpty());
9284
9285   CHECK(CompileRun("other[42]").IsEmpty());
9286   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9287
9288   // Enable both ACCESS_HAS and ACCESS_GET.
9289   allowed_access_type[v8::ACCESS_HAS] = true;
9290   allowed_access_type[v8::ACCESS_GET] = true;
9291
9292   ExpectString("other[42]", "el_getter");
9293   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9294   ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9295   ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9296
9297   allowed_access_type[v8::ACCESS_HAS] = false;
9298   allowed_access_type[v8::ACCESS_GET] = false;
9299
9300   v8::Handle<Value> value;
9301
9302   // Access accessible property
9303   value = CompileRun("other.accessible_prop = 3");
9304   CHECK(value->IsNumber());
9305   CHECK_EQ(3, value->Int32Value());
9306   CHECK_EQ(3, g_echo_value);
9307
9308   value = CompileRun("other.accessible_prop");
9309   CHECK(value->IsNumber());
9310   CHECK_EQ(3, value->Int32Value());
9311
9312   value = CompileRun(
9313       "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9314   CHECK(value->IsNumber());
9315   CHECK_EQ(3, value->Int32Value());
9316
9317   value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9318   CHECK(value->IsTrue());
9319
9320   // Enumeration doesn't enumerate accessors from inaccessible objects in
9321   // the prototype chain even if the accessors are in themselves accessible.
9322   value = CompileRun(
9323       "(function() {"
9324       "  var obj = { '__proto__': other };"
9325       "  try {"
9326       "    for (var p in obj) {"
9327       "      if (p == 'accessible_prop' ||"
9328       "          p == 'blocked_js_prop' ||"
9329       "          p == 'blocked_js_prop') {"
9330       "        return false;"
9331       "      }"
9332       "    }"
9333       "    return false;"
9334       "  } catch (e) {"
9335       "    return true;"
9336       "  }"
9337       "})()");
9338   CHECK(value->IsTrue());
9339
9340   context1->Exit();
9341   context0->Exit();
9342 }
9343
9344
9345 TEST(AccessControlES5) {
9346   v8::Isolate* isolate = CcTest::isolate();
9347   v8::HandleScope handle_scope(isolate);
9348   v8::Handle<v8::ObjectTemplate> global_template =
9349       v8::ObjectTemplate::New(isolate);
9350
9351   global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9352                                            IndexedAccessBlocker);
9353
9354   // Add accessible accessor.
9355   global_template->SetAccessor(
9356       v8_str("accessible_prop"),
9357       EchoGetter, EchoSetter,
9358       v8::Handle<Value>(),
9359       v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9360
9361
9362   // Add an accessor that is not accessible by cross-domain JS code.
9363   global_template->SetAccessor(v8_str("blocked_prop"),
9364                                UnreachableGetter, UnreachableSetter,
9365                                v8::Handle<Value>(),
9366                                v8::DEFAULT);
9367
9368   // Create an environment
9369   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9370   context0->Enter();
9371
9372   v8::Handle<v8::Object> global0 = context0->Global();
9373
9374   v8::Local<Context> context1 = Context::New(isolate);
9375   context1->Enter();
9376   v8::Handle<v8::Object> global1 = context1->Global();
9377   global1->Set(v8_str("other"), global0);
9378
9379   // Regression test for issue 1154.
9380   CHECK(CompileRun("Object.keys(other)").IsEmpty());
9381   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9382
9383   // Regression test for issue 1027.
9384   CompileRun("Object.defineProperty(\n"
9385              "  other, 'blocked_prop', {configurable: false})");
9386   CHECK(CompileRun("other.blocked_prop").IsEmpty());
9387   CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9388             .IsEmpty());
9389
9390   // Regression test for issue 1171.
9391   ExpectTrue("Object.isExtensible(other)");
9392   CompileRun("Object.preventExtensions(other)");
9393   ExpectTrue("Object.isExtensible(other)");
9394
9395   // Object.seal and Object.freeze.
9396   CompileRun("Object.freeze(other)");
9397   ExpectTrue("Object.isExtensible(other)");
9398
9399   CompileRun("Object.seal(other)");
9400   ExpectTrue("Object.isExtensible(other)");
9401
9402   // Regression test for issue 1250.
9403   // Make sure that we can set the accessible accessors value using normal
9404   // assignment.
9405   CompileRun("other.accessible_prop = 42");
9406   CHECK_EQ(42, g_echo_value);
9407
9408   v8::Handle<Value> value;
9409   CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9410   value = CompileRun("other.accessible_prop == 42");
9411   CHECK(value->IsTrue());
9412 }
9413
9414
9415 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
9416                                             Local<Value> name,
9417                                             v8::AccessType type,
9418                                             Local<Value> data) {
9419   return false;
9420 }
9421
9422
9423 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
9424                                               uint32_t key,
9425                                               v8::AccessType type,
9426                                               Local<Value> data) {
9427   return false;
9428 }
9429
9430
9431 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9432   v8::Isolate* isolate = CcTest::isolate();
9433   v8::HandleScope handle_scope(isolate);
9434   v8::Handle<v8::ObjectTemplate> obj_template =
9435       v8::ObjectTemplate::New(isolate);
9436
9437   obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9438   obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
9439                                         GetOwnPropertyNamesIndexedBlocker);
9440
9441   // Create an environment
9442   v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9443   context0->Enter();
9444
9445   v8::Handle<v8::Object> global0 = context0->Global();
9446
9447   v8::HandleScope scope1(CcTest::isolate());
9448
9449   v8::Local<Context> context1 = Context::New(isolate);
9450   context1->Enter();
9451
9452   v8::Handle<v8::Object> global1 = context1->Global();
9453   global1->Set(v8_str("other"), global0);
9454   global1->Set(v8_str("object"), obj_template->NewInstance());
9455
9456   v8::Handle<Value> value;
9457
9458   // Attempt to get the property names of the other global object and
9459   // of an object that requires access checks.  Accessing the other
9460   // global object should be blocked by access checks on the global
9461   // proxy object.  Accessing the object that requires access checks
9462   // is blocked by the access checks on the object itself.
9463   value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9464   CHECK(value.IsEmpty());
9465
9466   value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9467   CHECK(value.IsEmpty());
9468
9469   context1->Exit();
9470   context0->Exit();
9471 }
9472
9473
9474 static void IndexedPropertyEnumerator(
9475     const v8::PropertyCallbackInfo<v8::Array>& info) {
9476   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9477   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9478   result->Set(1, v8::Object::New(info.GetIsolate()));
9479   info.GetReturnValue().Set(result);
9480 }
9481
9482
9483 static void NamedPropertyEnumerator(
9484     const v8::PropertyCallbackInfo<v8::Array>& info) {
9485   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9486   result->Set(0, v8_str("x"));
9487   result->Set(1, v8::Object::New(info.GetIsolate()));
9488   info.GetReturnValue().Set(result);
9489 }
9490
9491
9492 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9493   v8::Isolate* isolate = CcTest::isolate();
9494   v8::HandleScope handle_scope(isolate);
9495   v8::Handle<v8::ObjectTemplate> obj_template =
9496       v8::ObjectTemplate::New(isolate);
9497
9498   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9499   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9500   obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9501                                           IndexedPropertyEnumerator);
9502   obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9503                                         NamedPropertyEnumerator);
9504
9505   LocalContext context;
9506   v8::Handle<v8::Object> global = context->Global();
9507   global->Set(v8_str("object"), obj_template->NewInstance());
9508
9509   v8::Handle<v8::Value> result =
9510       CompileRun("Object.getOwnPropertyNames(object)");
9511   CHECK(result->IsArray());
9512   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9513   CHECK_EQ(3, result_array->Length());
9514   CHECK(result_array->Get(0)->IsString());
9515   CHECK(result_array->Get(1)->IsString());
9516   CHECK(result_array->Get(2)->IsString());
9517   CHECK_EQ(v8_str("7"), result_array->Get(0));
9518   CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9519   CHECK_EQ(v8_str("x"), result_array->Get(2));
9520 }
9521
9522
9523 static void ConstTenGetter(Local<String> name,
9524                            const v8::PropertyCallbackInfo<v8::Value>& info) {
9525   info.GetReturnValue().Set(v8_num(10));
9526 }
9527
9528
9529 THREADED_TEST(CrossDomainAccessors) {
9530   v8::Isolate* isolate = CcTest::isolate();
9531   v8::HandleScope handle_scope(isolate);
9532
9533   v8::Handle<v8::FunctionTemplate> func_template =
9534       v8::FunctionTemplate::New(isolate);
9535
9536   v8::Handle<v8::ObjectTemplate> global_template =
9537       func_template->InstanceTemplate();
9538
9539   v8::Handle<v8::ObjectTemplate> proto_template =
9540       func_template->PrototypeTemplate();
9541
9542   // Add an accessor to proto that's accessible by cross-domain JS code.
9543   proto_template->SetAccessor(v8_str("accessible"),
9544                               ConstTenGetter, 0,
9545                               v8::Handle<Value>(),
9546                               v8::ALL_CAN_READ);
9547
9548   // Add an accessor that is not accessible by cross-domain JS code.
9549   global_template->SetAccessor(v8_str("unreachable"),
9550                                UnreachableGetter, 0,
9551                                v8::Handle<Value>(),
9552                                v8::DEFAULT);
9553
9554   v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9555   context0->Enter();
9556
9557   Local<v8::Object> global = context0->Global();
9558   // Add a normal property that shadows 'accessible'
9559   global->Set(v8_str("accessible"), v8_num(11));
9560
9561   // Enter a new context.
9562   v8::HandleScope scope1(CcTest::isolate());
9563   v8::Local<Context> context1 = Context::New(isolate);
9564   context1->Enter();
9565
9566   v8::Handle<v8::Object> global1 = context1->Global();
9567   global1->Set(v8_str("other"), global);
9568
9569   // Should return 10, instead of 11
9570   v8::Handle<Value> value = v8_compile("other.accessible")->Run();
9571   CHECK(value->IsNumber());
9572   CHECK_EQ(10, value->Int32Value());
9573
9574   value = v8_compile("other.unreachable")->Run();
9575   CHECK(value.IsEmpty());
9576
9577   context1->Exit();
9578   context0->Exit();
9579 }
9580
9581
9582 static int named_access_count = 0;
9583 static int indexed_access_count = 0;
9584
9585 static bool NamedAccessCounter(Local<v8::Object> global,
9586                                Local<Value> name,
9587                                v8::AccessType type,
9588                                Local<Value> data) {
9589   named_access_count++;
9590   return true;
9591 }
9592
9593
9594 static bool IndexedAccessCounter(Local<v8::Object> global,
9595                                  uint32_t key,
9596                                  v8::AccessType type,
9597                                  Local<Value> data) {
9598   indexed_access_count++;
9599   return true;
9600 }
9601
9602
9603 // This one is too easily disturbed by other tests.
9604 TEST(AccessControlIC) {
9605   named_access_count = 0;
9606   indexed_access_count = 0;
9607
9608   v8::Isolate* isolate = CcTest::isolate();
9609   v8::HandleScope handle_scope(isolate);
9610
9611   // Create an environment.
9612   v8::Local<Context> context0 = Context::New(isolate);
9613   context0->Enter();
9614
9615   // Create an object that requires access-check functions to be
9616   // called for cross-domain access.
9617   v8::Handle<v8::ObjectTemplate> object_template =
9618       v8::ObjectTemplate::New(isolate);
9619   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9620                                            IndexedAccessCounter);
9621   Local<v8::Object> object = object_template->NewInstance();
9622
9623   v8::HandleScope scope1(isolate);
9624
9625   // Create another environment.
9626   v8::Local<Context> context1 = Context::New(isolate);
9627   context1->Enter();
9628
9629   // Make easy access to the object from the other environment.
9630   v8::Handle<v8::Object> global1 = context1->Global();
9631   global1->Set(v8_str("obj"), object);
9632
9633   v8::Handle<Value> value;
9634
9635   // Check that the named access-control function is called every time.
9636   CompileRun("function testProp(obj) {"
9637              "  for (var i = 0; i < 10; i++) obj.prop = 1;"
9638              "  for (var j = 0; j < 10; j++) obj.prop;"
9639              "  return obj.prop"
9640              "}");
9641   value = CompileRun("testProp(obj)");
9642   CHECK(value->IsNumber());
9643   CHECK_EQ(1, value->Int32Value());
9644   CHECK_EQ(21, named_access_count);
9645
9646   // Check that the named access-control function is called every time.
9647   CompileRun("var p = 'prop';"
9648              "function testKeyed(obj) {"
9649              "  for (var i = 0; i < 10; i++) obj[p] = 1;"
9650              "  for (var j = 0; j < 10; j++) obj[p];"
9651              "  return obj[p];"
9652              "}");
9653   // Use obj which requires access checks.  No inline caching is used
9654   // in that case.
9655   value = CompileRun("testKeyed(obj)");
9656   CHECK(value->IsNumber());
9657   CHECK_EQ(1, value->Int32Value());
9658   CHECK_EQ(42, named_access_count);
9659   // Force the inline caches into generic state and try again.
9660   CompileRun("testKeyed({ a: 0 })");
9661   CompileRun("testKeyed({ b: 0 })");
9662   value = CompileRun("testKeyed(obj)");
9663   CHECK(value->IsNumber());
9664   CHECK_EQ(1, value->Int32Value());
9665   CHECK_EQ(63, named_access_count);
9666
9667   // Check that the indexed access-control function is called every time.
9668   CompileRun("function testIndexed(obj) {"
9669              "  for (var i = 0; i < 10; i++) obj[0] = 1;"
9670              "  for (var j = 0; j < 10; j++) obj[0];"
9671              "  return obj[0]"
9672              "}");
9673   value = CompileRun("testIndexed(obj)");
9674   CHECK(value->IsNumber());
9675   CHECK_EQ(1, value->Int32Value());
9676   CHECK_EQ(21, indexed_access_count);
9677   // Force the inline caches into generic state.
9678   CompileRun("testIndexed(new Array(1))");
9679   // Test that the indexed access check is called.
9680   value = CompileRun("testIndexed(obj)");
9681   CHECK(value->IsNumber());
9682   CHECK_EQ(1, value->Int32Value());
9683   CHECK_EQ(42, indexed_access_count);
9684
9685   // Check that the named access check is called when invoking
9686   // functions on an object that requires access checks.
9687   CompileRun("obj.f = function() {}");
9688   CompileRun("function testCallNormal(obj) {"
9689              "  for (var i = 0; i < 10; i++) obj.f();"
9690              "}");
9691   CompileRun("testCallNormal(obj)");
9692   CHECK_EQ(74, named_access_count);
9693
9694   // Force obj into slow case.
9695   value = CompileRun("delete obj.prop");
9696   CHECK(value->BooleanValue());
9697   // Force inline caches into dictionary probing mode.
9698   CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9699   // Test that the named access check is called.
9700   value = CompileRun("testProp(obj);");
9701   CHECK(value->IsNumber());
9702   CHECK_EQ(1, value->Int32Value());
9703   CHECK_EQ(96, named_access_count);
9704
9705   // Force the call inline cache into dictionary probing mode.
9706   CompileRun("o.f = function() {}; testCallNormal(o)");
9707   // Test that the named access check is still called for each
9708   // invocation of the function.
9709   value = CompileRun("testCallNormal(obj)");
9710   CHECK_EQ(106, named_access_count);
9711
9712   context1->Exit();
9713   context0->Exit();
9714 }
9715
9716
9717 static bool NamedAccessFlatten(Local<v8::Object> global,
9718                                Local<Value> name,
9719                                v8::AccessType type,
9720                                Local<Value> data) {
9721   char buf[100];
9722   int len;
9723
9724   CHECK(name->IsString());
9725
9726   memset(buf, 0x1, sizeof(buf));
9727   len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
9728   CHECK_EQ(4, len);
9729
9730   uint16_t buf2[100];
9731
9732   memset(buf, 0x1, sizeof(buf));
9733   len = name.As<String>()->Write(buf2);
9734   CHECK_EQ(4, len);
9735
9736   return true;
9737 }
9738
9739
9740 static bool IndexedAccessFlatten(Local<v8::Object> global,
9741                                  uint32_t key,
9742                                  v8::AccessType type,
9743                                  Local<Value> data) {
9744   return true;
9745 }
9746
9747
9748 // Regression test.  In access checks, operations that may cause
9749 // garbage collection are not allowed.  It used to be the case that
9750 // using the Write operation on a string could cause a garbage
9751 // collection due to flattening of the string.  This is no longer the
9752 // case.
9753 THREADED_TEST(AccessControlFlatten) {
9754   named_access_count = 0;
9755   indexed_access_count = 0;
9756
9757   v8::Isolate* isolate = CcTest::isolate();
9758   v8::HandleScope handle_scope(isolate);
9759
9760   // Create an environment.
9761   v8::Local<Context> context0 = Context::New(isolate);
9762   context0->Enter();
9763
9764   // Create an object that requires access-check functions to be
9765   // called for cross-domain access.
9766   v8::Handle<v8::ObjectTemplate> object_template =
9767       v8::ObjectTemplate::New(isolate);
9768   object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
9769                                            IndexedAccessFlatten);
9770   Local<v8::Object> object = object_template->NewInstance();
9771
9772   v8::HandleScope scope1(isolate);
9773
9774   // Create another environment.
9775   v8::Local<Context> context1 = Context::New(isolate);
9776   context1->Enter();
9777
9778   // Make easy access to the object from the other environment.
9779   v8::Handle<v8::Object> global1 = context1->Global();
9780   global1->Set(v8_str("obj"), object);
9781
9782   v8::Handle<Value> value;
9783
9784   value = v8_compile("var p = 'as' + 'df';")->Run();
9785   value = v8_compile("obj[p];")->Run();
9786
9787   context1->Exit();
9788   context0->Exit();
9789 }
9790
9791
9792 static void AccessControlNamedGetter(
9793     Local<String>,
9794     const v8::PropertyCallbackInfo<v8::Value>& info) {
9795   info.GetReturnValue().Set(42);
9796 }
9797
9798
9799 static void AccessControlNamedSetter(
9800     Local<String>,
9801     Local<Value> value,
9802     const v8::PropertyCallbackInfo<v8::Value>& info) {
9803   info.GetReturnValue().Set(value);
9804 }
9805
9806
9807 static void AccessControlIndexedGetter(
9808       uint32_t index,
9809       const v8::PropertyCallbackInfo<v8::Value>& info) {
9810   info.GetReturnValue().Set(v8_num(42));
9811 }
9812
9813
9814 static void AccessControlIndexedSetter(
9815     uint32_t,
9816     Local<Value> value,
9817     const v8::PropertyCallbackInfo<v8::Value>& info) {
9818   info.GetReturnValue().Set(value);
9819 }
9820
9821
9822 THREADED_TEST(AccessControlInterceptorIC) {
9823   named_access_count = 0;
9824   indexed_access_count = 0;
9825
9826   v8::Isolate* isolate = CcTest::isolate();
9827   v8::HandleScope handle_scope(isolate);
9828
9829   // Create an environment.
9830   v8::Local<Context> context0 = Context::New(isolate);
9831   context0->Enter();
9832
9833   // Create an object that requires access-check functions to be
9834   // called for cross-domain access.  The object also has interceptors
9835   // interceptor.
9836   v8::Handle<v8::ObjectTemplate> object_template =
9837       v8::ObjectTemplate::New(isolate);
9838   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
9839                                            IndexedAccessCounter);
9840   object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
9841                                            AccessControlNamedSetter);
9842   object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
9843                                              AccessControlIndexedSetter);
9844   Local<v8::Object> object = object_template->NewInstance();
9845
9846   v8::HandleScope scope1(isolate);
9847
9848   // Create another environment.
9849   v8::Local<Context> context1 = Context::New(isolate);
9850   context1->Enter();
9851
9852   // Make easy access to the object from the other environment.
9853   v8::Handle<v8::Object> global1 = context1->Global();
9854   global1->Set(v8_str("obj"), object);
9855
9856   v8::Handle<Value> value;
9857
9858   // Check that the named access-control function is called every time
9859   // eventhough there is an interceptor on the object.
9860   value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
9861   value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
9862                      "obj.x")->Run();
9863   CHECK(value->IsNumber());
9864   CHECK_EQ(42, value->Int32Value());
9865   CHECK_EQ(21, named_access_count);
9866
9867   value = v8_compile("var p = 'x';")->Run();
9868   value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
9869   value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
9870                      "obj[p]")->Run();
9871   CHECK(value->IsNumber());
9872   CHECK_EQ(42, value->Int32Value());
9873   CHECK_EQ(42, named_access_count);
9874
9875   // Check that the indexed access-control function is called every
9876   // time eventhough there is an interceptor on the object.
9877   value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
9878   value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
9879                      "obj[0]")->Run();
9880   CHECK(value->IsNumber());
9881   CHECK_EQ(42, value->Int32Value());
9882   CHECK_EQ(21, indexed_access_count);
9883
9884   context1->Exit();
9885   context0->Exit();
9886 }
9887
9888
9889 THREADED_TEST(Version) {
9890   v8::V8::GetVersion();
9891 }
9892
9893
9894 static void InstanceFunctionCallback(
9895     const v8::FunctionCallbackInfo<v8::Value>& args) {
9896   ApiTestFuzzer::Fuzz();
9897   args.GetReturnValue().Set(v8_num(12));
9898 }
9899
9900
9901 THREADED_TEST(InstanceProperties) {
9902   LocalContext context;
9903   v8::Isolate* isolate = context->GetIsolate();
9904   v8::HandleScope handle_scope(isolate);
9905
9906   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9907   Local<ObjectTemplate> instance = t->InstanceTemplate();
9908
9909   instance->Set(v8_str("x"), v8_num(42));
9910   instance->Set(v8_str("f"),
9911                 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9912
9913   Local<Value> o = t->GetFunction()->NewInstance();
9914
9915   context->Global()->Set(v8_str("i"), o);
9916   Local<Value> value = CompileRun("i.x");
9917   CHECK_EQ(42, value->Int32Value());
9918
9919   value = CompileRun("i.f()");
9920   CHECK_EQ(12, value->Int32Value());
9921 }
9922
9923
9924 static void GlobalObjectInstancePropertiesGet(
9925     Local<String> key,
9926     const v8::PropertyCallbackInfo<v8::Value>&) {
9927   ApiTestFuzzer::Fuzz();
9928 }
9929
9930
9931 THREADED_TEST(GlobalObjectInstanceProperties) {
9932   v8::Isolate* isolate = CcTest::isolate();
9933   v8::HandleScope handle_scope(isolate);
9934
9935   Local<Value> global_object;
9936
9937   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9938   t->InstanceTemplate()->SetNamedPropertyHandler(
9939       GlobalObjectInstancePropertiesGet);
9940   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9941   instance_template->Set(v8_str("x"), v8_num(42));
9942   instance_template->Set(v8_str("f"),
9943                          v8::FunctionTemplate::New(isolate,
9944                                                    InstanceFunctionCallback));
9945
9946   // The script to check how Crankshaft compiles missing global function
9947   // invocations.  function g is not defined and should throw on call.
9948   const char* script =
9949       "function wrapper(call) {"
9950       "  var x = 0, y = 1;"
9951       "  for (var i = 0; i < 1000; i++) {"
9952       "    x += i * 100;"
9953       "    y += i * 100;"
9954       "  }"
9955       "  if (call) g();"
9956       "}"
9957       "for (var i = 0; i < 17; i++) wrapper(false);"
9958       "var thrown = 0;"
9959       "try { wrapper(true); } catch (e) { thrown = 1; };"
9960       "thrown";
9961
9962   {
9963     LocalContext env(NULL, instance_template);
9964     // Hold on to the global object so it can be used again in another
9965     // environment initialization.
9966     global_object = env->Global();
9967
9968     Local<Value> value = CompileRun("x");
9969     CHECK_EQ(42, value->Int32Value());
9970     value = CompileRun("f()");
9971     CHECK_EQ(12, value->Int32Value());
9972     value = CompileRun(script);
9973     CHECK_EQ(1, value->Int32Value());
9974   }
9975
9976   {
9977     // Create new environment reusing the global object.
9978     LocalContext env(NULL, instance_template, global_object);
9979     Local<Value> value = CompileRun("x");
9980     CHECK_EQ(42, value->Int32Value());
9981     value = CompileRun("f()");
9982     CHECK_EQ(12, value->Int32Value());
9983     value = CompileRun(script);
9984     CHECK_EQ(1, value->Int32Value());
9985   }
9986 }
9987
9988
9989 THREADED_TEST(CallKnownGlobalReceiver) {
9990   v8::Isolate* isolate = CcTest::isolate();
9991   v8::HandleScope handle_scope(isolate);
9992
9993   Local<Value> global_object;
9994
9995   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9996   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9997
9998   // The script to check that we leave global object not
9999   // global object proxy on stack when we deoptimize from inside
10000   // arguments evaluation.
10001   // To provoke error we need to both force deoptimization
10002   // from arguments evaluation and to force CallIC to take
10003   // CallIC_Miss code path that can't cope with global proxy.
10004   const char* script =
10005       "function bar(x, y) { try { } finally { } }"
10006       "function baz(x) { try { } finally { } }"
10007       "function bom(x) { try { } finally { } }"
10008       "function foo(x) { bar([x], bom(2)); }"
10009       "for (var i = 0; i < 10000; i++) foo(1);"
10010       "foo";
10011
10012   Local<Value> foo;
10013   {
10014     LocalContext env(NULL, instance_template);
10015     // Hold on to the global object so it can be used again in another
10016     // environment initialization.
10017     global_object = env->Global();
10018     foo = CompileRun(script);
10019   }
10020
10021   {
10022     // Create new environment reusing the global object.
10023     LocalContext env(NULL, instance_template, global_object);
10024     env->Global()->Set(v8_str("foo"), foo);
10025     CompileRun("foo()");
10026   }
10027 }
10028
10029
10030 static void ShadowFunctionCallback(
10031     const v8::FunctionCallbackInfo<v8::Value>& args) {
10032   ApiTestFuzzer::Fuzz();
10033   args.GetReturnValue().Set(v8_num(42));
10034 }
10035
10036
10037 static int shadow_y;
10038 static int shadow_y_setter_call_count;
10039 static int shadow_y_getter_call_count;
10040
10041
10042 static void ShadowYSetter(Local<String>,
10043                           Local<Value>,
10044                           const v8::PropertyCallbackInfo<void>&) {
10045   shadow_y_setter_call_count++;
10046   shadow_y = 42;
10047 }
10048
10049
10050 static void ShadowYGetter(Local<String> name,
10051                           const v8::PropertyCallbackInfo<v8::Value>& info) {
10052   ApiTestFuzzer::Fuzz();
10053   shadow_y_getter_call_count++;
10054   info.GetReturnValue().Set(v8_num(shadow_y));
10055 }
10056
10057
10058 static void ShadowIndexedGet(uint32_t index,
10059                              const v8::PropertyCallbackInfo<v8::Value>&) {
10060 }
10061
10062
10063 static void ShadowNamedGet(Local<String> key,
10064                            const v8::PropertyCallbackInfo<v8::Value>&) {
10065 }
10066
10067
10068 THREADED_TEST(ShadowObject) {
10069   shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10070   v8::Isolate* isolate = CcTest::isolate();
10071   v8::HandleScope handle_scope(isolate);
10072
10073   Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10074   LocalContext context(NULL, global_template);
10075
10076   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10077   t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10078   t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10079   Local<ObjectTemplate> proto = t->PrototypeTemplate();
10080   Local<ObjectTemplate> instance = t->InstanceTemplate();
10081
10082   proto->Set(v8_str("f"),
10083              v8::FunctionTemplate::New(isolate,
10084                                        ShadowFunctionCallback,
10085                                        Local<Value>()));
10086   proto->Set(v8_str("x"), v8_num(12));
10087
10088   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10089
10090   Local<Value> o = t->GetFunction()->NewInstance();
10091   context->Global()->Set(v8_str("__proto__"), o);
10092
10093   Local<Value> value =
10094       CompileRun("this.propertyIsEnumerable(0)");
10095   CHECK(value->IsBoolean());
10096   CHECK(!value->BooleanValue());
10097
10098   value = CompileRun("x");
10099   CHECK_EQ(12, value->Int32Value());
10100
10101   value = CompileRun("f()");
10102   CHECK_EQ(42, value->Int32Value());
10103
10104   CompileRun("y = 43");
10105   CHECK_EQ(1, shadow_y_setter_call_count);
10106   value = CompileRun("y");
10107   CHECK_EQ(1, shadow_y_getter_call_count);
10108   CHECK_EQ(42, value->Int32Value());
10109 }
10110
10111
10112 THREADED_TEST(HiddenPrototype) {
10113   LocalContext context;
10114   v8::Isolate* isolate = context->GetIsolate();
10115   v8::HandleScope handle_scope(isolate);
10116
10117   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10118   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10119   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10120   t1->SetHiddenPrototype(true);
10121   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10122   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10123   t2->SetHiddenPrototype(true);
10124   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10125   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10126   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10127
10128   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10129   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10130   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10131   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10132
10133   // Setting the prototype on an object skips hidden prototypes.
10134   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10135   o0->Set(v8_str("__proto__"), o1);
10136   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10137   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10138   o0->Set(v8_str("__proto__"), o2);
10139   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10140   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10141   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10142   o0->Set(v8_str("__proto__"), o3);
10143   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10144   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10145   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10146   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10147
10148   // Getting the prototype of o0 should get the first visible one
10149   // which is o3.  Therefore, z should not be defined on the prototype
10150   // object.
10151   Local<Value> proto = o0->Get(v8_str("__proto__"));
10152   CHECK(proto->IsObject());
10153   CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10154 }
10155
10156
10157 THREADED_TEST(HiddenPrototypeSet) {
10158   LocalContext context;
10159   v8::Isolate* isolate = context->GetIsolate();
10160   v8::HandleScope handle_scope(isolate);
10161
10162   Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10163   Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10164   ht->SetHiddenPrototype(true);
10165   Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10166   ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10167
10168   Local<v8::Object> o = ot->GetFunction()->NewInstance();
10169   Local<v8::Object> h = ht->GetFunction()->NewInstance();
10170   Local<v8::Object> p = pt->GetFunction()->NewInstance();
10171   o->Set(v8_str("__proto__"), h);
10172   h->Set(v8_str("__proto__"), p);
10173
10174   // Setting a property that exists on the hidden prototype goes there.
10175   o->Set(v8_str("x"), v8_num(7));
10176   CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10177   CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10178   CHECK(p->Get(v8_str("x"))->IsUndefined());
10179
10180   // Setting a new property should not be forwarded to the hidden prototype.
10181   o->Set(v8_str("y"), v8_num(6));
10182   CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10183   CHECK(h->Get(v8_str("y"))->IsUndefined());
10184   CHECK(p->Get(v8_str("y"))->IsUndefined());
10185
10186   // Setting a property that only exists on a prototype of the hidden prototype
10187   // is treated normally again.
10188   p->Set(v8_str("z"), v8_num(8));
10189   CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10190   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10191   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10192   o->Set(v8_str("z"), v8_num(9));
10193   CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10194   CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10195   CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10196 }
10197
10198
10199 // Regression test for issue 2457.
10200 THREADED_TEST(HiddenPrototypeIdentityHash) {
10201   LocalContext context;
10202   v8::HandleScope handle_scope(context->GetIsolate());
10203
10204   Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10205   t->SetHiddenPrototype(true);
10206   t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10207   Handle<Object> p = t->GetFunction()->NewInstance();
10208   Handle<Object> o = Object::New(context->GetIsolate());
10209   o->SetPrototype(p);
10210
10211   int hash = o->GetIdentityHash();
10212   USE(hash);
10213   o->Set(v8_str("foo"), v8_num(42));
10214   DCHECK_EQ(hash, o->GetIdentityHash());
10215 }
10216
10217
10218 THREADED_TEST(SetPrototype) {
10219   LocalContext context;
10220   v8::Isolate* isolate = context->GetIsolate();
10221   v8::HandleScope handle_scope(isolate);
10222
10223   Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10224   t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10225   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10226   t1->SetHiddenPrototype(true);
10227   t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10228   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10229   t2->SetHiddenPrototype(true);
10230   t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10231   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10232   t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10233
10234   Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10235   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10236   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10237   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10238
10239   // Setting the prototype on an object does not skip hidden prototypes.
10240   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10241   CHECK(o0->SetPrototype(o1));
10242   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10243   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10244   CHECK(o1->SetPrototype(o2));
10245   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10246   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10247   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10248   CHECK(o2->SetPrototype(o3));
10249   CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10250   CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10251   CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10252   CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10253
10254   // Getting the prototype of o0 should get the first visible one
10255   // which is o3.  Therefore, z should not be defined on the prototype
10256   // object.
10257   Local<Value> proto = o0->Get(v8_str("__proto__"));
10258   CHECK(proto->IsObject());
10259   CHECK_EQ(proto.As<v8::Object>(), o3);
10260
10261   // However, Object::GetPrototype ignores hidden prototype.
10262   Local<Value> proto0 = o0->GetPrototype();
10263   CHECK(proto0->IsObject());
10264   CHECK_EQ(proto0.As<v8::Object>(), o1);
10265
10266   Local<Value> proto1 = o1->GetPrototype();
10267   CHECK(proto1->IsObject());
10268   CHECK_EQ(proto1.As<v8::Object>(), o2);
10269
10270   Local<Value> proto2 = o2->GetPrototype();
10271   CHECK(proto2->IsObject());
10272   CHECK_EQ(proto2.As<v8::Object>(), o3);
10273 }
10274
10275
10276 // Getting property names of an object with a prototype chain that
10277 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10278 // crash the runtime.
10279 THREADED_TEST(Regress91517) {
10280   i::FLAG_allow_natives_syntax = true;
10281   LocalContext context;
10282   v8::Isolate* isolate = context->GetIsolate();
10283   v8::HandleScope handle_scope(isolate);
10284
10285   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10286   t1->SetHiddenPrototype(true);
10287   t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10288   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10289   t2->SetHiddenPrototype(true);
10290   t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10291   t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10292   t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10293   Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10294   t3->SetHiddenPrototype(true);
10295   t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10296   Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10297   t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10298
10299   // Force dictionary-based properties.
10300   i::ScopedVector<char> name_buf(1024);
10301   for (int i = 1; i <= 1000; i++) {
10302     i::SNPrintF(name_buf, "sdf%d", i);
10303     t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10304   }
10305
10306   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10307   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10308   Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10309   Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10310
10311   // Create prototype chain of hidden prototypes.
10312   CHECK(o4->SetPrototype(o3));
10313   CHECK(o3->SetPrototype(o2));
10314   CHECK(o2->SetPrototype(o1));
10315
10316   // Call the runtime version of GetOwnPropertyNames() on the natively
10317   // created object through JavaScript.
10318   context->Global()->Set(v8_str("obj"), o4);
10319   // PROPERTY_ATTRIBUTES_NONE = 0
10320   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10321
10322   ExpectInt32("names.length", 1006);
10323   ExpectTrue("names.indexOf(\"baz\") >= 0");
10324   ExpectTrue("names.indexOf(\"boo\") >= 0");
10325   ExpectTrue("names.indexOf(\"foo\") >= 0");
10326   ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10327   ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10328   ExpectFalse("names[1005] == undefined");
10329 }
10330
10331
10332 // Getting property names of an object with a hidden and inherited
10333 // prototype should not duplicate the accessor properties inherited.
10334 THREADED_TEST(Regress269562) {
10335   i::FLAG_allow_natives_syntax = true;
10336   LocalContext context;
10337   v8::HandleScope handle_scope(context->GetIsolate());
10338
10339   Local<v8::FunctionTemplate> t1 =
10340       v8::FunctionTemplate::New(context->GetIsolate());
10341   t1->SetHiddenPrototype(true);
10342
10343   Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10344   i1->SetAccessor(v8_str("foo"),
10345                   SimpleAccessorGetter, SimpleAccessorSetter);
10346   i1->SetAccessor(v8_str("bar"),
10347                   SimpleAccessorGetter, SimpleAccessorSetter);
10348   i1->SetAccessor(v8_str("baz"),
10349                   SimpleAccessorGetter, SimpleAccessorSetter);
10350   i1->Set(v8_str("n1"), v8_num(1));
10351   i1->Set(v8_str("n2"), v8_num(2));
10352
10353   Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10354   Local<v8::FunctionTemplate> t2 =
10355       v8::FunctionTemplate::New(context->GetIsolate());
10356   t2->SetHiddenPrototype(true);
10357
10358   // Inherit from t1 and mark prototype as hidden.
10359   t2->Inherit(t1);
10360   t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10361
10362   Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10363   CHECK(o2->SetPrototype(o1));
10364
10365   v8::Local<v8::Symbol> sym =
10366       v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10367   o1->Set(sym, v8_num(3));
10368   o1->SetHiddenValue(
10369       v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10370
10371   // Call the runtime version of GetOwnPropertyNames() on
10372   // the natively created object through JavaScript.
10373   context->Global()->Set(v8_str("obj"), o2);
10374   context->Global()->Set(v8_str("sym"), sym);
10375   // PROPERTY_ATTRIBUTES_NONE = 0
10376   CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10377
10378   ExpectInt32("names.length", 7);
10379   ExpectTrue("names.indexOf(\"foo\") >= 0");
10380   ExpectTrue("names.indexOf(\"bar\") >= 0");
10381   ExpectTrue("names.indexOf(\"baz\") >= 0");
10382   ExpectTrue("names.indexOf(\"n1\") >= 0");
10383   ExpectTrue("names.indexOf(\"n2\") >= 0");
10384   ExpectTrue("names.indexOf(sym) >= 0");
10385   ExpectTrue("names.indexOf(\"mine\") >= 0");
10386 }
10387
10388
10389 THREADED_TEST(FunctionReadOnlyPrototype) {
10390   LocalContext context;
10391   v8::Isolate* isolate = context->GetIsolate();
10392   v8::HandleScope handle_scope(isolate);
10393
10394   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10395   t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10396   t1->ReadOnlyPrototype();
10397   context->Global()->Set(v8_str("func1"), t1->GetFunction());
10398   // Configured value of ReadOnly flag.
10399   CHECK(CompileRun(
10400       "(function() {"
10401       "  descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10402       "  return (descriptor['writable'] == false);"
10403       "})()")->BooleanValue());
10404   CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10405   CHECK_EQ(42,
10406            CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10407
10408   Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10409   t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10410   context->Global()->Set(v8_str("func2"), t2->GetFunction());
10411   // Default value of ReadOnly flag.
10412   CHECK(CompileRun(
10413       "(function() {"
10414       "  descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10415       "  return (descriptor['writable'] == true);"
10416       "})()")->BooleanValue());
10417   CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10418 }
10419
10420
10421 THREADED_TEST(SetPrototypeThrows) {
10422   LocalContext context;
10423   v8::Isolate* isolate = context->GetIsolate();
10424   v8::HandleScope handle_scope(isolate);
10425
10426   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10427
10428   Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10429   Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10430
10431   CHECK(o0->SetPrototype(o1));
10432   // If setting the prototype leads to the cycle, SetPrototype should
10433   // return false and keep VM in sane state.
10434   v8::TryCatch try_catch;
10435   CHECK(!o1->SetPrototype(o0));
10436   CHECK(!try_catch.HasCaught());
10437   DCHECK(!CcTest::i_isolate()->has_pending_exception());
10438
10439   CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10440 }
10441
10442
10443 THREADED_TEST(FunctionRemovePrototype) {
10444   LocalContext context;
10445   v8::Isolate* isolate = context->GetIsolate();
10446   v8::HandleScope handle_scope(isolate);
10447
10448   Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10449   t1->RemovePrototype();
10450   Local<v8::Function> fun = t1->GetFunction();
10451   context->Global()->Set(v8_str("fun"), fun);
10452   CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10453
10454   v8::TryCatch try_catch;
10455   CompileRun("new fun()");
10456   CHECK(try_catch.HasCaught());
10457
10458   try_catch.Reset();
10459   fun->NewInstance();
10460   CHECK(try_catch.HasCaught());
10461 }
10462
10463
10464 THREADED_TEST(GetterSetterExceptions) {
10465   LocalContext context;
10466   v8::Isolate* isolate = context->GetIsolate();
10467   v8::HandleScope handle_scope(isolate);
10468   CompileRun(
10469     "function Foo() { };"
10470     "function Throw() { throw 5; };"
10471     "var x = { };"
10472     "x.__defineSetter__('set', Throw);"
10473     "x.__defineGetter__('get', Throw);");
10474   Local<v8::Object> x =
10475       Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10476   v8::TryCatch try_catch;
10477   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10478   x->Get(v8_str("get"));
10479   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10480   x->Get(v8_str("get"));
10481   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10482   x->Get(v8_str("get"));
10483   x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10484   x->Get(v8_str("get"));
10485 }
10486
10487
10488 THREADED_TEST(Constructor) {
10489   LocalContext context;
10490   v8::Isolate* isolate = context->GetIsolate();
10491   v8::HandleScope handle_scope(isolate);
10492   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10493   templ->SetClassName(v8_str("Fun"));
10494   Local<Function> cons = templ->GetFunction();
10495   context->Global()->Set(v8_str("Fun"), cons);
10496   Local<v8::Object> inst = cons->NewInstance();
10497   i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10498   CHECK(obj->IsJSObject());
10499   Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10500   CHECK(value->BooleanValue());
10501 }
10502
10503
10504 static void ConstructorCallback(
10505     const v8::FunctionCallbackInfo<v8::Value>& args) {
10506   ApiTestFuzzer::Fuzz();
10507   Local<Object> This;
10508
10509   if (args.IsConstructCall()) {
10510     Local<Object> Holder = args.Holder();
10511     This = Object::New(args.GetIsolate());
10512     Local<Value> proto = Holder->GetPrototype();
10513     if (proto->IsObject()) {
10514       This->SetPrototype(proto);
10515     }
10516   } else {
10517     This = args.This();
10518   }
10519
10520   This->Set(v8_str("a"), args[0]);
10521   args.GetReturnValue().Set(This);
10522 }
10523
10524
10525 static void FakeConstructorCallback(
10526     const v8::FunctionCallbackInfo<v8::Value>& args) {
10527   ApiTestFuzzer::Fuzz();
10528   args.GetReturnValue().Set(args[0]);
10529 }
10530
10531
10532 THREADED_TEST(ConstructorForObject) {
10533   LocalContext context;
10534   v8::Isolate* isolate = context->GetIsolate();
10535   v8::HandleScope handle_scope(isolate);
10536
10537   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10538     instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10539     Local<Object> instance = instance_template->NewInstance();
10540     context->Global()->Set(v8_str("obj"), instance);
10541     v8::TryCatch try_catch;
10542     Local<Value> value;
10543     CHECK(!try_catch.HasCaught());
10544
10545     // Call the Object's constructor with a 32-bit signed integer.
10546     value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
10547     CHECK(!try_catch.HasCaught());
10548     CHECK(value->IsInt32());
10549     CHECK_EQ(28, value->Int32Value());
10550
10551     Local<Value> args1[] = { v8_num(28) };
10552     Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
10553     CHECK(value_obj1->IsObject());
10554     Local<Object> object1 = Local<Object>::Cast(value_obj1);
10555     value = object1->Get(v8_str("a"));
10556     CHECK(value->IsInt32());
10557     CHECK(!try_catch.HasCaught());
10558     CHECK_EQ(28, value->Int32Value());
10559
10560     // Call the Object's constructor with a String.
10561     value = CompileRun(
10562         "(function() { var o = new obj('tipli'); return o.a; })()");
10563     CHECK(!try_catch.HasCaught());
10564     CHECK(value->IsString());
10565     String::Utf8Value string_value1(value->ToString());
10566     CHECK_EQ("tipli", *string_value1);
10567
10568     Local<Value> args2[] = { v8_str("tipli") };
10569     Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
10570     CHECK(value_obj2->IsObject());
10571     Local<Object> object2 = Local<Object>::Cast(value_obj2);
10572     value = object2->Get(v8_str("a"));
10573     CHECK(!try_catch.HasCaught());
10574     CHECK(value->IsString());
10575     String::Utf8Value string_value2(value->ToString());
10576     CHECK_EQ("tipli", *string_value2);
10577
10578     // Call the Object's constructor with a Boolean.
10579     value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
10580     CHECK(!try_catch.HasCaught());
10581     CHECK(value->IsBoolean());
10582     CHECK_EQ(true, value->BooleanValue());
10583
10584     Handle<Value> args3[] = { v8::True(isolate) };
10585     Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
10586     CHECK(value_obj3->IsObject());
10587     Local<Object> object3 = Local<Object>::Cast(value_obj3);
10588     value = object3->Get(v8_str("a"));
10589     CHECK(!try_catch.HasCaught());
10590     CHECK(value->IsBoolean());
10591     CHECK_EQ(true, value->BooleanValue());
10592
10593     // Call the Object's constructor with undefined.
10594     Handle<Value> args4[] = { v8::Undefined(isolate) };
10595     Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
10596     CHECK(value_obj4->IsObject());
10597     Local<Object> object4 = Local<Object>::Cast(value_obj4);
10598     value = object4->Get(v8_str("a"));
10599     CHECK(!try_catch.HasCaught());
10600     CHECK(value->IsUndefined());
10601
10602     // Call the Object's constructor with null.
10603     Handle<Value> args5[] = { v8::Null(isolate) };
10604     Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
10605     CHECK(value_obj5->IsObject());
10606     Local<Object> object5 = Local<Object>::Cast(value_obj5);
10607     value = object5->Get(v8_str("a"));
10608     CHECK(!try_catch.HasCaught());
10609     CHECK(value->IsNull());
10610   }
10611
10612   // Check exception handling when there is no constructor set for the Object.
10613   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10614     Local<Object> instance = instance_template->NewInstance();
10615     context->Global()->Set(v8_str("obj2"), instance);
10616     v8::TryCatch try_catch;
10617     Local<Value> value;
10618     CHECK(!try_catch.HasCaught());
10619
10620     value = CompileRun("new obj2(28)");
10621     CHECK(try_catch.HasCaught());
10622     String::Utf8Value exception_value1(try_catch.Exception());
10623     CHECK_EQ("TypeError: object is not a function", *exception_value1);
10624     try_catch.Reset();
10625
10626     Local<Value> args[] = { v8_num(29) };
10627     value = instance->CallAsConstructor(1, args);
10628     CHECK(try_catch.HasCaught());
10629     String::Utf8Value exception_value2(try_catch.Exception());
10630     CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
10631     try_catch.Reset();
10632   }
10633
10634   // Check the case when constructor throws exception.
10635   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10636     instance_template->SetCallAsFunctionHandler(ThrowValue);
10637     Local<Object> instance = instance_template->NewInstance();
10638     context->Global()->Set(v8_str("obj3"), instance);
10639     v8::TryCatch try_catch;
10640     Local<Value> value;
10641     CHECK(!try_catch.HasCaught());
10642
10643     value = CompileRun("new obj3(22)");
10644     CHECK(try_catch.HasCaught());
10645     String::Utf8Value exception_value1(try_catch.Exception());
10646     CHECK_EQ("22", *exception_value1);
10647     try_catch.Reset();
10648
10649     Local<Value> args[] = { v8_num(23) };
10650     value = instance->CallAsConstructor(1, args);
10651     CHECK(try_catch.HasCaught());
10652     String::Utf8Value exception_value2(try_catch.Exception());
10653     CHECK_EQ("23", *exception_value2);
10654     try_catch.Reset();
10655   }
10656
10657   // Check whether constructor returns with an object or non-object.
10658   { Local<FunctionTemplate> function_template =
10659         FunctionTemplate::New(isolate, FakeConstructorCallback);
10660     Local<Function> function = function_template->GetFunction();
10661     Local<Object> instance1 = function;
10662     context->Global()->Set(v8_str("obj4"), instance1);
10663     v8::TryCatch try_catch;
10664     Local<Value> value;
10665     CHECK(!try_catch.HasCaught());
10666
10667     CHECK(instance1->IsObject());
10668     CHECK(instance1->IsFunction());
10669
10670     value = CompileRun("new obj4(28)");
10671     CHECK(!try_catch.HasCaught());
10672     CHECK(value->IsObject());
10673
10674     Local<Value> args1[] = { v8_num(28) };
10675     value = instance1->CallAsConstructor(1, args1);
10676     CHECK(!try_catch.HasCaught());
10677     CHECK(value->IsObject());
10678
10679     Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10680     instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
10681     Local<Object> instance2 = instance_template->NewInstance();
10682     context->Global()->Set(v8_str("obj5"), instance2);
10683     CHECK(!try_catch.HasCaught());
10684
10685     CHECK(instance2->IsObject());
10686     CHECK(!instance2->IsFunction());
10687
10688     value = CompileRun("new obj5(28)");
10689     CHECK(!try_catch.HasCaught());
10690     CHECK(!value->IsObject());
10691
10692     Local<Value> args2[] = { v8_num(28) };
10693     value = instance2->CallAsConstructor(1, args2);
10694     CHECK(!try_catch.HasCaught());
10695     CHECK(!value->IsObject());
10696   }
10697 }
10698
10699
10700 THREADED_TEST(FunctionDescriptorException) {
10701   LocalContext context;
10702   v8::Isolate* isolate = context->GetIsolate();
10703   v8::HandleScope handle_scope(isolate);
10704   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10705   templ->SetClassName(v8_str("Fun"));
10706   Local<Function> cons = templ->GetFunction();
10707   context->Global()->Set(v8_str("Fun"), cons);
10708   Local<Value> value = CompileRun(
10709     "function test() {"
10710     "  try {"
10711     "    (new Fun()).blah()"
10712     "  } catch (e) {"
10713     "    var str = String(e);"
10714     // "    if (str.indexOf('TypeError') == -1) return 1;"
10715     // "    if (str.indexOf('[object Fun]') != -1) return 2;"
10716     // "    if (str.indexOf('#<Fun>') == -1) return 3;"
10717     "    return 0;"
10718     "  }"
10719     "  return 4;"
10720     "}"
10721     "test();");
10722   CHECK_EQ(0, value->Int32Value());
10723 }
10724
10725
10726 THREADED_TEST(EvalAliasedDynamic) {
10727   LocalContext current;
10728   v8::HandleScope scope(current->GetIsolate());
10729
10730   // Tests where aliased eval can only be resolved dynamically.
10731   Local<Script> script = v8_compile(
10732       "function f(x) { "
10733       "  var foo = 2;"
10734       "  with (x) { return eval('foo'); }"
10735       "}"
10736       "foo = 0;"
10737       "result1 = f(new Object());"
10738       "result2 = f(this);"
10739       "var x = new Object();"
10740       "x.eval = function(x) { return 1; };"
10741       "result3 = f(x);");
10742   script->Run();
10743   CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
10744   CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
10745   CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
10746
10747   v8::TryCatch try_catch;
10748   script = v8_compile(
10749       "function f(x) { "
10750       "  var bar = 2;"
10751       "  with (x) { return eval('bar'); }"
10752       "}"
10753       "result4 = f(this)");
10754   script->Run();
10755   CHECK(!try_catch.HasCaught());
10756   CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
10757
10758   try_catch.Reset();
10759 }
10760
10761
10762 THREADED_TEST(CrossEval) {
10763   v8::HandleScope scope(CcTest::isolate());
10764   LocalContext other;
10765   LocalContext current;
10766
10767   Local<String> token = v8_str("<security token>");
10768   other->SetSecurityToken(token);
10769   current->SetSecurityToken(token);
10770
10771   // Set up reference from current to other.
10772   current->Global()->Set(v8_str("other"), other->Global());
10773
10774   // Check that new variables are introduced in other context.
10775   Local<Script> script = v8_compile("other.eval('var foo = 1234')");
10776   script->Run();
10777   Local<Value> foo = other->Global()->Get(v8_str("foo"));
10778   CHECK_EQ(1234, foo->Int32Value());
10779   CHECK(!current->Global()->Has(v8_str("foo")));
10780
10781   // Check that writing to non-existing properties introduces them in
10782   // the other context.
10783   script = v8_compile("other.eval('na = 1234')");
10784   script->Run();
10785   CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
10786   CHECK(!current->Global()->Has(v8_str("na")));
10787
10788   // Check that global variables in current context are not visible in other
10789   // context.
10790   v8::TryCatch try_catch;
10791   script = v8_compile("var bar = 42; other.eval('bar');");
10792   Local<Value> result = script->Run();
10793   CHECK(try_catch.HasCaught());
10794   try_catch.Reset();
10795
10796   // Check that local variables in current context are not visible in other
10797   // context.
10798   script = v8_compile(
10799       "(function() { "
10800       "  var baz = 87;"
10801       "  return other.eval('baz');"
10802       "})();");
10803   result = script->Run();
10804   CHECK(try_catch.HasCaught());
10805   try_catch.Reset();
10806
10807   // Check that global variables in the other environment are visible
10808   // when evaluting code.
10809   other->Global()->Set(v8_str("bis"), v8_num(1234));
10810   script = v8_compile("other.eval('bis')");
10811   CHECK_EQ(1234, script->Run()->Int32Value());
10812   CHECK(!try_catch.HasCaught());
10813
10814   // Check that the 'this' pointer points to the global object evaluating
10815   // code.
10816   other->Global()->Set(v8_str("t"), other->Global());
10817   script = v8_compile("other.eval('this == t')");
10818   result = script->Run();
10819   CHECK(result->IsTrue());
10820   CHECK(!try_catch.HasCaught());
10821
10822   // Check that variables introduced in with-statement are not visible in
10823   // other context.
10824   script = v8_compile("with({x:2}){other.eval('x')}");
10825   result = script->Run();
10826   CHECK(try_catch.HasCaught());
10827   try_catch.Reset();
10828
10829   // Check that you cannot use 'eval.call' with another object than the
10830   // current global object.
10831   script = v8_compile("other.y = 1; eval.call(other, 'y')");
10832   result = script->Run();
10833   CHECK(try_catch.HasCaught());
10834 }
10835
10836
10837 // Test that calling eval in a context which has been detached from
10838 // its global throws an exception.  This behavior is consistent with
10839 // other JavaScript implementations.
10840 THREADED_TEST(EvalInDetachedGlobal) {
10841   v8::Isolate* isolate = CcTest::isolate();
10842   v8::HandleScope scope(isolate);
10843
10844   v8::Local<Context> context0 = Context::New(isolate);
10845   v8::Local<Context> context1 = Context::New(isolate);
10846
10847   // Set up function in context0 that uses eval from context0.
10848   context0->Enter();
10849   v8::Handle<v8::Value> fun =
10850       CompileRun("var x = 42;"
10851                  "(function() {"
10852                  "  var e = eval;"
10853                  "  return function(s) { return e(s); }"
10854                  "})()");
10855   context0->Exit();
10856
10857   // Put the function into context1 and call it before and after
10858   // detaching the global.  Before detaching, the call succeeds and
10859   // after detaching and exception is thrown.
10860   context1->Enter();
10861   context1->Global()->Set(v8_str("fun"), fun);
10862   v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10863   CHECK_EQ(42, x_value->Int32Value());
10864   context0->DetachGlobal();
10865   v8::TryCatch catcher;
10866   x_value = CompileRun("fun('x')");
10867   CHECK(x_value.IsEmpty());
10868   CHECK(catcher.HasCaught());
10869   context1->Exit();
10870 }
10871
10872
10873 THREADED_TEST(CrossLazyLoad) {
10874   v8::HandleScope scope(CcTest::isolate());
10875   LocalContext other;
10876   LocalContext current;
10877
10878   Local<String> token = v8_str("<security token>");
10879   other->SetSecurityToken(token);
10880   current->SetSecurityToken(token);
10881
10882   // Set up reference from current to other.
10883   current->Global()->Set(v8_str("other"), other->Global());
10884
10885   // Trigger lazy loading in other context.
10886   Local<Script> script = v8_compile("other.eval('new Date(42)')");
10887   Local<Value> value = script->Run();
10888   CHECK_EQ(42.0, value->NumberValue());
10889 }
10890
10891
10892 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10893   ApiTestFuzzer::Fuzz();
10894   if (args.IsConstructCall()) {
10895     if (args[0]->IsInt32()) {
10896       args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10897       return;
10898     }
10899   }
10900
10901   args.GetReturnValue().Set(args[0]);
10902 }
10903
10904
10905 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10906   args.GetReturnValue().Set(args.This());
10907 }
10908
10909
10910 // Test that a call handler can be set for objects which will allow
10911 // non-function objects created through the API to be called as
10912 // functions.
10913 THREADED_TEST(CallAsFunction) {
10914   LocalContext context;
10915   v8::Isolate* isolate = context->GetIsolate();
10916   v8::HandleScope scope(isolate);
10917
10918   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10919     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10920     instance_template->SetCallAsFunctionHandler(call_as_function);
10921     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10922     context->Global()->Set(v8_str("obj"), instance);
10923     v8::TryCatch try_catch;
10924     Local<Value> value;
10925     CHECK(!try_catch.HasCaught());
10926
10927     value = CompileRun("obj(42)");
10928     CHECK(!try_catch.HasCaught());
10929     CHECK_EQ(42, value->Int32Value());
10930
10931     value = CompileRun("(function(o){return o(49)})(obj)");
10932     CHECK(!try_catch.HasCaught());
10933     CHECK_EQ(49, value->Int32Value());
10934
10935     // test special case of call as function
10936     value = CompileRun("[obj]['0'](45)");
10937     CHECK(!try_catch.HasCaught());
10938     CHECK_EQ(45, value->Int32Value());
10939
10940     value = CompileRun("obj.call = Function.prototype.call;"
10941                        "obj.call(null, 87)");
10942     CHECK(!try_catch.HasCaught());
10943     CHECK_EQ(87, value->Int32Value());
10944
10945     // Regression tests for bug #1116356: Calling call through call/apply
10946     // must work for non-function receivers.
10947     const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10948     value = CompileRun(apply_99);
10949     CHECK(!try_catch.HasCaught());
10950     CHECK_EQ(99, value->Int32Value());
10951
10952     const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10953     value = CompileRun(call_17);
10954     CHECK(!try_catch.HasCaught());
10955     CHECK_EQ(17, value->Int32Value());
10956
10957     // Check that the call-as-function handler can be called through
10958     // new.
10959     value = CompileRun("new obj(43)");
10960     CHECK(!try_catch.HasCaught());
10961     CHECK_EQ(-43, value->Int32Value());
10962
10963     // Check that the call-as-function handler can be called through
10964     // the API.
10965     v8::Handle<Value> args[] = { v8_num(28) };
10966     value = instance->CallAsFunction(instance, 1, args);
10967     CHECK(!try_catch.HasCaught());
10968     CHECK_EQ(28, value->Int32Value());
10969   }
10970
10971   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10972     Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10973     USE(instance_template);
10974     Local<v8::Object> instance = t->GetFunction()->NewInstance();
10975     context->Global()->Set(v8_str("obj2"), instance);
10976     v8::TryCatch try_catch;
10977     Local<Value> value;
10978     CHECK(!try_catch.HasCaught());
10979
10980     // Call an object without call-as-function handler through the JS
10981     value = CompileRun("obj2(28)");
10982     CHECK(value.IsEmpty());
10983     CHECK(try_catch.HasCaught());
10984     String::Utf8Value exception_value1(try_catch.Exception());
10985     // TODO(verwaest): Better message
10986     CHECK_EQ("TypeError: object is not a function",
10987              *exception_value1);
10988     try_catch.Reset();
10989
10990     // Call an object without call-as-function handler through the API
10991     value = CompileRun("obj2(28)");
10992     v8::Handle<Value> args[] = { v8_num(28) };
10993     value = instance->CallAsFunction(instance, 1, args);
10994     CHECK(value.IsEmpty());
10995     CHECK(try_catch.HasCaught());
10996     String::Utf8Value exception_value2(try_catch.Exception());
10997     CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
10998     try_catch.Reset();
10999   }
11000
11001   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11002     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11003     instance_template->SetCallAsFunctionHandler(ThrowValue);
11004     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11005     context->Global()->Set(v8_str("obj3"), instance);
11006     v8::TryCatch try_catch;
11007     Local<Value> value;
11008     CHECK(!try_catch.HasCaught());
11009
11010     // Catch the exception which is thrown by call-as-function handler
11011     value = CompileRun("obj3(22)");
11012     CHECK(try_catch.HasCaught());
11013     String::Utf8Value exception_value1(try_catch.Exception());
11014     CHECK_EQ("22", *exception_value1);
11015     try_catch.Reset();
11016
11017     v8::Handle<Value> args[] = { v8_num(23) };
11018     value = instance->CallAsFunction(instance, 1, args);
11019     CHECK(try_catch.HasCaught());
11020     String::Utf8Value exception_value2(try_catch.Exception());
11021     CHECK_EQ("23", *exception_value2);
11022     try_catch.Reset();
11023   }
11024
11025   { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11026     Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11027     instance_template->SetCallAsFunctionHandler(ReturnThis);
11028     Local<v8::Object> instance = t->GetFunction()->NewInstance();
11029
11030     Local<v8::Value> a1 =
11031         instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11032     CHECK(a1->StrictEquals(instance));
11033     Local<v8::Value> a2 =
11034         instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11035     CHECK(a2->StrictEquals(instance));
11036     Local<v8::Value> a3 =
11037         instance->CallAsFunction(v8_num(42), 0, NULL);
11038     CHECK(a3->StrictEquals(instance));
11039     Local<v8::Value> a4 =
11040         instance->CallAsFunction(v8_str("hello"), 0, NULL);
11041     CHECK(a4->StrictEquals(instance));
11042     Local<v8::Value> a5 =
11043         instance->CallAsFunction(v8::True(isolate), 0, NULL);
11044     CHECK(a5->StrictEquals(instance));
11045   }
11046
11047   { CompileRun(
11048       "function ReturnThisSloppy() {"
11049       "  return this;"
11050       "}"
11051       "function ReturnThisStrict() {"
11052       "  'use strict';"
11053       "  return this;"
11054       "}");
11055     Local<Function> ReturnThisSloppy =
11056         Local<Function>::Cast(
11057             context->Global()->Get(v8_str("ReturnThisSloppy")));
11058     Local<Function> ReturnThisStrict =
11059         Local<Function>::Cast(
11060             context->Global()->Get(v8_str("ReturnThisStrict")));
11061
11062     Local<v8::Value> a1 =
11063         ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11064     CHECK(a1->StrictEquals(context->Global()));
11065     Local<v8::Value> a2 =
11066         ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11067     CHECK(a2->StrictEquals(context->Global()));
11068     Local<v8::Value> a3 =
11069         ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11070     CHECK(a3->IsNumberObject());
11071     CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11072     Local<v8::Value> a4 =
11073         ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11074     CHECK(a4->IsStringObject());
11075     CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11076     Local<v8::Value> a5 =
11077         ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11078     CHECK(a5->IsBooleanObject());
11079     CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11080
11081     Local<v8::Value> a6 =
11082         ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11083     CHECK(a6->IsUndefined());
11084     Local<v8::Value> a7 =
11085         ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11086     CHECK(a7->IsNull());
11087     Local<v8::Value> a8 =
11088         ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11089     CHECK(a8->StrictEquals(v8_num(42)));
11090     Local<v8::Value> a9 =
11091         ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11092     CHECK(a9->StrictEquals(v8_str("hello")));
11093     Local<v8::Value> a10 =
11094         ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11095     CHECK(a10->StrictEquals(v8::True(isolate)));
11096   }
11097 }
11098
11099
11100 // Check whether a non-function object is callable.
11101 THREADED_TEST(CallableObject) {
11102   LocalContext context;
11103   v8::Isolate* isolate = context->GetIsolate();
11104   v8::HandleScope scope(isolate);
11105
11106   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11107     instance_template->SetCallAsFunctionHandler(call_as_function);
11108     Local<Object> instance = instance_template->NewInstance();
11109     v8::TryCatch try_catch;
11110
11111     CHECK(instance->IsCallable());
11112     CHECK(!try_catch.HasCaught());
11113   }
11114
11115   { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11116     Local<Object> instance = instance_template->NewInstance();
11117     v8::TryCatch try_catch;
11118
11119     CHECK(!instance->IsCallable());
11120     CHECK(!try_catch.HasCaught());
11121   }
11122
11123   { Local<FunctionTemplate> function_template =
11124         FunctionTemplate::New(isolate, call_as_function);
11125     Local<Function> function = function_template->GetFunction();
11126     Local<Object> instance = function;
11127     v8::TryCatch try_catch;
11128
11129     CHECK(instance->IsCallable());
11130     CHECK(!try_catch.HasCaught());
11131   }
11132
11133   { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11134     Local<Function> function = function_template->GetFunction();
11135     Local<Object> instance = function;
11136     v8::TryCatch try_catch;
11137
11138     CHECK(instance->IsCallable());
11139     CHECK(!try_catch.HasCaught());
11140   }
11141 }
11142
11143
11144 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11145   v8::HandleScope scope(isolate);
11146   if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11147   for (int i = 0; i < iterations; i++) {
11148     Local<v8::Number> n(v8::Integer::New(isolate, 42));
11149   }
11150   return Recurse(isolate, depth - 1, iterations);
11151 }
11152
11153
11154 THREADED_TEST(HandleIteration) {
11155   static const int kIterations = 500;
11156   static const int kNesting = 200;
11157   LocalContext context;
11158   v8::Isolate* isolate = context->GetIsolate();
11159   v8::HandleScope scope0(isolate);
11160   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11161   {
11162     v8::HandleScope scope1(isolate);
11163     CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11164     for (int i = 0; i < kIterations; i++) {
11165       Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11166       CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11167     }
11168
11169     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11170     {
11171       v8::HandleScope scope2(CcTest::isolate());
11172       for (int j = 0; j < kIterations; j++) {
11173         Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11174         CHECK_EQ(j + 1 + kIterations,
11175                  v8::HandleScope::NumberOfHandles(isolate));
11176       }
11177     }
11178     CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11179   }
11180   CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11181   CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11182 }
11183
11184
11185 static void InterceptorHasOwnPropertyGetter(
11186     Local<String> name,
11187     const v8::PropertyCallbackInfo<v8::Value>& info) {
11188   ApiTestFuzzer::Fuzz();
11189 }
11190
11191
11192 THREADED_TEST(InterceptorHasOwnProperty) {
11193   LocalContext context;
11194   v8::Isolate* isolate = context->GetIsolate();
11195   v8::HandleScope scope(isolate);
11196   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11197   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11198   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11199   Local<Function> function = fun_templ->GetFunction();
11200   context->Global()->Set(v8_str("constructor"), function);
11201   v8::Handle<Value> value = CompileRun(
11202       "var o = new constructor();"
11203       "o.hasOwnProperty('ostehaps');");
11204   CHECK_EQ(false, value->BooleanValue());
11205   value = CompileRun(
11206       "o.ostehaps = 42;"
11207       "o.hasOwnProperty('ostehaps');");
11208   CHECK_EQ(true, value->BooleanValue());
11209   value = CompileRun(
11210       "var p = new constructor();"
11211       "p.hasOwnProperty('ostehaps');");
11212   CHECK_EQ(false, value->BooleanValue());
11213 }
11214
11215
11216 static void InterceptorHasOwnPropertyGetterGC(
11217     Local<String> name,
11218     const v8::PropertyCallbackInfo<v8::Value>& info) {
11219   ApiTestFuzzer::Fuzz();
11220   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11221 }
11222
11223
11224 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11225   LocalContext context;
11226   v8::Isolate* isolate = context->GetIsolate();
11227   v8::HandleScope scope(isolate);
11228   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11229   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11230   instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11231   Local<Function> function = fun_templ->GetFunction();
11232   context->Global()->Set(v8_str("constructor"), function);
11233   // Let's first make some stuff so we can be sure to get a good GC.
11234   CompileRun(
11235       "function makestr(size) {"
11236       "  switch (size) {"
11237       "    case 1: return 'f';"
11238       "    case 2: return 'fo';"
11239       "    case 3: return 'foo';"
11240       "  }"
11241       "  return makestr(size >> 1) + makestr((size + 1) >> 1);"
11242       "}"
11243       "var x = makestr(12345);"
11244       "x = makestr(31415);"
11245       "x = makestr(23456);");
11246   v8::Handle<Value> value = CompileRun(
11247       "var o = new constructor();"
11248       "o.__proto__ = new String(x);"
11249       "o.hasOwnProperty('ostehaps');");
11250   CHECK_EQ(false, value->BooleanValue());
11251 }
11252
11253
11254 typedef void (*NamedPropertyGetter)(
11255     Local<String> property,
11256     const v8::PropertyCallbackInfo<v8::Value>& info);
11257
11258
11259 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11260                                    const char* source,
11261                                    int expected) {
11262   v8::Isolate* isolate = CcTest::isolate();
11263   v8::HandleScope scope(isolate);
11264   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11265   templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11266   LocalContext context;
11267   context->Global()->Set(v8_str("o"), templ->NewInstance());
11268   v8::Handle<Value> value = CompileRun(source);
11269   CHECK_EQ(expected, value->Int32Value());
11270 }
11271
11272
11273 static void InterceptorLoadICGetter(
11274     Local<String> name,
11275     const v8::PropertyCallbackInfo<v8::Value>& info) {
11276   ApiTestFuzzer::Fuzz();
11277   v8::Isolate* isolate = CcTest::isolate();
11278   CHECK_EQ(isolate, info.GetIsolate());
11279   CHECK_EQ(v8_str("data"), info.Data());
11280   CHECK_EQ(v8_str("x"), name);
11281   info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11282 }
11283
11284
11285 // This test should hit the load IC for the interceptor case.
11286 THREADED_TEST(InterceptorLoadIC) {
11287   CheckInterceptorLoadIC(InterceptorLoadICGetter,
11288     "var result = 0;"
11289     "for (var i = 0; i < 1000; i++) {"
11290     "  result = o.x;"
11291     "}",
11292     42);
11293 }
11294
11295
11296 // Below go several tests which verify that JITing for various
11297 // configurations of interceptor and explicit fields works fine
11298 // (those cases are special cased to get better performance).
11299
11300 static void InterceptorLoadXICGetter(
11301     Local<String> name,
11302     const v8::PropertyCallbackInfo<v8::Value>& info) {
11303   ApiTestFuzzer::Fuzz();
11304   info.GetReturnValue().Set(
11305       v8_str("x")->Equals(name) ?
11306           v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11307           v8::Handle<v8::Value>());
11308 }
11309
11310
11311 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11312   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11313     "var result = 0;"
11314     "o.y = 239;"
11315     "for (var i = 0; i < 1000; i++) {"
11316     "  result = o.y;"
11317     "}",
11318     239);
11319 }
11320
11321
11322 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11323   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11324     "var result = 0;"
11325     "o.__proto__ = { 'y': 239 };"
11326     "for (var i = 0; i < 1000; i++) {"
11327     "  result = o.y + o.x;"
11328     "}",
11329     239 + 42);
11330 }
11331
11332
11333 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11334   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11335     "var result = 0;"
11336     "o.__proto__.y = 239;"
11337     "for (var i = 0; i < 1000; i++) {"
11338     "  result = o.y + o.x;"
11339     "}",
11340     239 + 42);
11341 }
11342
11343
11344 THREADED_TEST(InterceptorLoadICUndefined) {
11345   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11346     "var result = 0;"
11347     "for (var i = 0; i < 1000; i++) {"
11348     "  result = (o.y == undefined) ? 239 : 42;"
11349     "}",
11350     239);
11351 }
11352
11353
11354 THREADED_TEST(InterceptorLoadICWithOverride) {
11355   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11356     "fst = new Object();  fst.__proto__ = o;"
11357     "snd = new Object();  snd.__proto__ = fst;"
11358     "var result1 = 0;"
11359     "for (var i = 0; i < 1000;  i++) {"
11360     "  result1 = snd.x;"
11361     "}"
11362     "fst.x = 239;"
11363     "var result = 0;"
11364     "for (var i = 0; i < 1000; i++) {"
11365     "  result = snd.x;"
11366     "}"
11367     "result + result1",
11368     239 + 42);
11369 }
11370
11371
11372 // Test the case when we stored field into
11373 // a stub, but interceptor produced value on its own.
11374 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11375   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11376     "proto = new Object();"
11377     "o.__proto__ = proto;"
11378     "proto.x = 239;"
11379     "for (var i = 0; i < 1000; i++) {"
11380     "  o.x;"
11381     // Now it should be ICed and keep a reference to x defined on proto
11382     "}"
11383     "var result = 0;"
11384     "for (var i = 0; i < 1000; i++) {"
11385     "  result += o.x;"
11386     "}"
11387     "result;",
11388     42 * 1000);
11389 }
11390
11391
11392 // Test the case when we stored field into
11393 // a stub, but it got invalidated later on.
11394 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11395   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11396     "proto1 = new Object();"
11397     "proto2 = new Object();"
11398     "o.__proto__ = proto1;"
11399     "proto1.__proto__ = proto2;"
11400     "proto2.y = 239;"
11401     "for (var i = 0; i < 1000; i++) {"
11402     "  o.y;"
11403     // Now it should be ICed and keep a reference to y defined on proto2
11404     "}"
11405     "proto1.y = 42;"
11406     "var result = 0;"
11407     "for (var i = 0; i < 1000; i++) {"
11408     "  result += o.y;"
11409     "}"
11410     "result;",
11411     42 * 1000);
11412 }
11413
11414
11415 static int interceptor_load_not_handled_calls = 0;
11416 static void InterceptorLoadNotHandled(
11417     Local<String> name,
11418     const v8::PropertyCallbackInfo<v8::Value>& info) {
11419   ++interceptor_load_not_handled_calls;
11420 }
11421
11422
11423 // Test how post-interceptor lookups are done in the non-cacheable
11424 // case: the interceptor should not be invoked during this lookup.
11425 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11426   interceptor_load_not_handled_calls = 0;
11427   CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11428     "receiver = new Object();"
11429     "receiver.__proto__ = o;"
11430     "proto = new Object();"
11431     "/* Make proto a slow-case object. */"
11432     "for (var i = 0; i < 1000; i++) {"
11433     "  proto[\"xxxxxxxx\" + i] = [];"
11434     "}"
11435     "proto.x = 17;"
11436     "o.__proto__ = proto;"
11437     "var result = 0;"
11438     "for (var i = 0; i < 1000; i++) {"
11439     "  result += receiver.x;"
11440     "}"
11441     "result;",
11442     17 * 1000);
11443   CHECK_EQ(1000, interceptor_load_not_handled_calls);
11444 }
11445
11446
11447 // Test the case when we stored field into
11448 // a stub, but it got invalidated later on due to override on
11449 // global object which is between interceptor and fields' holders.
11450 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11451   CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11452     "o.__proto__ = this;"  // set a global to be a proto of o.
11453     "this.__proto__.y = 239;"
11454     "for (var i = 0; i < 10; i++) {"
11455     "  if (o.y != 239) throw 'oops: ' + o.y;"
11456     // Now it should be ICed and keep a reference to y defined on field_holder.
11457     "}"
11458     "this.y = 42;"  // Assign on a global.
11459     "var result = 0;"
11460     "for (var i = 0; i < 10; i++) {"
11461     "  result += o.y;"
11462     "}"
11463     "result;",
11464     42 * 10);
11465 }
11466
11467
11468 static void SetOnThis(Local<String> name,
11469                       Local<Value> value,
11470                       const v8::PropertyCallbackInfo<void>& info) {
11471   Local<Object>::Cast(info.This())->ForceSet(name, value);
11472 }
11473
11474
11475 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11476   v8::Isolate* isolate = CcTest::isolate();
11477   v8::HandleScope scope(isolate);
11478   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11479   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11480   templ->SetAccessor(v8_str("y"), Return239Callback);
11481   LocalContext context;
11482   context->Global()->Set(v8_str("o"), templ->NewInstance());
11483
11484   // Check the case when receiver and interceptor's holder
11485   // are the same objects.
11486   v8::Handle<Value> value = CompileRun(
11487       "var result = 0;"
11488       "for (var i = 0; i < 7; i++) {"
11489       "  result = o.y;"
11490       "}");
11491   CHECK_EQ(239, value->Int32Value());
11492
11493   // Check the case when interceptor's holder is in proto chain
11494   // of receiver.
11495   value = CompileRun(
11496       "r = { __proto__: o };"
11497       "var result = 0;"
11498       "for (var i = 0; i < 7; i++) {"
11499       "  result = r.y;"
11500       "}");
11501   CHECK_EQ(239, value->Int32Value());
11502 }
11503
11504
11505 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11506   v8::Isolate* isolate = CcTest::isolate();
11507   v8::HandleScope scope(isolate);
11508   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11509   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11510   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11511   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11512
11513   LocalContext context;
11514   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11515   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11516
11517   // Check the case when receiver and interceptor's holder
11518   // are the same objects.
11519   v8::Handle<Value> value = CompileRun(
11520       "o.__proto__ = p;"
11521       "var result = 0;"
11522       "for (var i = 0; i < 7; i++) {"
11523       "  result = o.x + o.y;"
11524       "}");
11525   CHECK_EQ(239 + 42, value->Int32Value());
11526
11527   // Check the case when interceptor's holder is in proto chain
11528   // of receiver.
11529   value = CompileRun(
11530       "r = { __proto__: o };"
11531       "var result = 0;"
11532       "for (var i = 0; i < 7; i++) {"
11533       "  result = r.x + r.y;"
11534       "}");
11535   CHECK_EQ(239 + 42, value->Int32Value());
11536 }
11537
11538
11539 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11540   v8::Isolate* isolate = CcTest::isolate();
11541   v8::HandleScope scope(isolate);
11542   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11543   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11544   templ->SetAccessor(v8_str("y"), Return239Callback);
11545
11546   LocalContext context;
11547   context->Global()->Set(v8_str("o"), templ->NewInstance());
11548
11549   v8::Handle<Value> value = CompileRun(
11550     "fst = new Object();  fst.__proto__ = o;"
11551     "snd = new Object();  snd.__proto__ = fst;"
11552     "var result1 = 0;"
11553     "for (var i = 0; i < 7;  i++) {"
11554     "  result1 = snd.x;"
11555     "}"
11556     "fst.x = 239;"
11557     "var result = 0;"
11558     "for (var i = 0; i < 7; i++) {"
11559     "  result = snd.x;"
11560     "}"
11561     "result + result1");
11562   CHECK_EQ(239 + 42, value->Int32Value());
11563 }
11564
11565
11566 // Test the case when we stored callback into
11567 // a stub, but interceptor produced value on its own.
11568 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
11569   v8::Isolate* isolate = CcTest::isolate();
11570   v8::HandleScope scope(isolate);
11571   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11572   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11573   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11574   templ_p->SetAccessor(v8_str("y"), Return239Callback);
11575
11576   LocalContext context;
11577   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11578   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11579
11580   v8::Handle<Value> value = CompileRun(
11581     "o.__proto__ = p;"
11582     "for (var i = 0; i < 7; i++) {"
11583     "  o.x;"
11584     // Now it should be ICed and keep a reference to x defined on p
11585     "}"
11586     "var result = 0;"
11587     "for (var i = 0; i < 7; i++) {"
11588     "  result += o.x;"
11589     "}"
11590     "result");
11591   CHECK_EQ(42 * 7, value->Int32Value());
11592 }
11593
11594
11595 // Test the case when we stored callback into
11596 // a stub, but it got invalidated later on.
11597 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
11598   v8::Isolate* isolate = CcTest::isolate();
11599   v8::HandleScope scope(isolate);
11600   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11601   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11602   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11603   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11604
11605   LocalContext context;
11606   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11607   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11608
11609   v8::Handle<Value> value = CompileRun(
11610     "inbetween = new Object();"
11611     "o.__proto__ = inbetween;"
11612     "inbetween.__proto__ = p;"
11613     "for (var i = 0; i < 10; i++) {"
11614     "  o.y;"
11615     // Now it should be ICed and keep a reference to y defined on p
11616     "}"
11617     "inbetween.y = 42;"
11618     "var result = 0;"
11619     "for (var i = 0; i < 10; i++) {"
11620     "  result += o.y;"
11621     "}"
11622     "result");
11623   CHECK_EQ(42 * 10, value->Int32Value());
11624 }
11625
11626
11627 // Test the case when we stored callback into
11628 // a stub, but it got invalidated later on due to override on
11629 // global object which is between interceptor and callbacks' holders.
11630 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
11631   v8::Isolate* isolate = CcTest::isolate();
11632   v8::HandleScope scope(isolate);
11633   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11634   templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11635   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11636   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
11637
11638   LocalContext context;
11639   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11640   context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11641
11642   v8::Handle<Value> value = CompileRun(
11643     "o.__proto__ = this;"
11644     "this.__proto__ = p;"
11645     "for (var i = 0; i < 10; i++) {"
11646     "  if (o.y != 239) throw 'oops: ' + o.y;"
11647     // Now it should be ICed and keep a reference to y defined on p
11648     "}"
11649     "this.y = 42;"
11650     "var result = 0;"
11651     "for (var i = 0; i < 10; i++) {"
11652     "  result += o.y;"
11653     "}"
11654     "result");
11655   CHECK_EQ(42 * 10, value->Int32Value());
11656 }
11657
11658
11659 static void InterceptorLoadICGetter0(
11660     Local<String> name,
11661     const v8::PropertyCallbackInfo<v8::Value>& info) {
11662   ApiTestFuzzer::Fuzz();
11663   CHECK(v8_str("x")->Equals(name));
11664   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
11665 }
11666
11667
11668 THREADED_TEST(InterceptorReturningZero) {
11669   CheckInterceptorLoadIC(InterceptorLoadICGetter0,
11670      "o.x == undefined ? 1 : 0",
11671      0);
11672 }
11673
11674
11675 static void InterceptorStoreICSetter(
11676     Local<String> key,
11677     Local<Value> value,
11678     const v8::PropertyCallbackInfo<v8::Value>& info) {
11679   CHECK(v8_str("x")->Equals(key));
11680   CHECK_EQ(42, value->Int32Value());
11681   info.GetReturnValue().Set(value);
11682 }
11683
11684
11685 // This test should hit the store IC for the interceptor case.
11686 THREADED_TEST(InterceptorStoreIC) {
11687   v8::Isolate* isolate = CcTest::isolate();
11688   v8::HandleScope scope(isolate);
11689   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11690   templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
11691                                  InterceptorStoreICSetter,
11692                                  0, 0, 0, v8_str("data"));
11693   LocalContext context;
11694   context->Global()->Set(v8_str("o"), templ->NewInstance());
11695   CompileRun(
11696       "for (var i = 0; i < 1000; i++) {"
11697       "  o.x = 42;"
11698       "}");
11699 }
11700
11701
11702 THREADED_TEST(InterceptorStoreICWithNoSetter) {
11703   v8::Isolate* isolate = CcTest::isolate();
11704   v8::HandleScope scope(isolate);
11705   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11706   templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11707   LocalContext context;
11708   context->Global()->Set(v8_str("o"), templ->NewInstance());
11709   v8::Handle<Value> value = CompileRun(
11710     "for (var i = 0; i < 1000; i++) {"
11711     "  o.y = 239;"
11712     "}"
11713     "42 + o.y");
11714   CHECK_EQ(239 + 42, value->Int32Value());
11715 }
11716
11717
11718
11719
11720 v8::Handle<Value> call_ic_function;
11721 v8::Handle<Value> call_ic_function2;
11722 v8::Handle<Value> call_ic_function3;
11723
11724 static void InterceptorCallICGetter(
11725     Local<String> name,
11726     const v8::PropertyCallbackInfo<v8::Value>& info) {
11727   ApiTestFuzzer::Fuzz();
11728   CHECK(v8_str("x")->Equals(name));
11729   info.GetReturnValue().Set(call_ic_function);
11730 }
11731
11732
11733 // This test should hit the call IC for the interceptor case.
11734 THREADED_TEST(InterceptorCallIC) {
11735   v8::Isolate* isolate = CcTest::isolate();
11736   v8::HandleScope scope(isolate);
11737   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11738   templ->SetNamedPropertyHandler(InterceptorCallICGetter);
11739   LocalContext context;
11740   context->Global()->Set(v8_str("o"), templ->NewInstance());
11741   call_ic_function =
11742       v8_compile("function f(x) { return x + 1; }; f")->Run();
11743   v8::Handle<Value> value = CompileRun(
11744     "var result = 0;"
11745     "for (var i = 0; i < 1000; i++) {"
11746     "  result = o.x(41);"
11747     "}");
11748   CHECK_EQ(42, value->Int32Value());
11749 }
11750
11751
11752 // This test checks that if interceptor doesn't provide
11753 // a value, we can fetch regular value.
11754 THREADED_TEST(InterceptorCallICSeesOthers) {
11755   v8::Isolate* isolate = CcTest::isolate();
11756   v8::HandleScope scope(isolate);
11757   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11758   templ->SetNamedPropertyHandler(NoBlockGetterX);
11759   LocalContext context;
11760   context->Global()->Set(v8_str("o"), templ->NewInstance());
11761   v8::Handle<Value> value = CompileRun(
11762     "o.x = function f(x) { return x + 1; };"
11763     "var result = 0;"
11764     "for (var i = 0; i < 7; i++) {"
11765     "  result = o.x(41);"
11766     "}");
11767   CHECK_EQ(42, value->Int32Value());
11768 }
11769
11770
11771 static v8::Handle<Value> call_ic_function4;
11772 static void InterceptorCallICGetter4(
11773     Local<String> name,
11774     const v8::PropertyCallbackInfo<v8::Value>& info) {
11775   ApiTestFuzzer::Fuzz();
11776   CHECK(v8_str("x")->Equals(name));
11777   info.GetReturnValue().Set(call_ic_function4);
11778 }
11779
11780
11781 // This test checks that if interceptor provides a function,
11782 // even if we cached shadowed variant, interceptor's function
11783 // is invoked
11784 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
11785   v8::Isolate* isolate = CcTest::isolate();
11786   v8::HandleScope scope(isolate);
11787   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11788   templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
11789   LocalContext context;
11790   context->Global()->Set(v8_str("o"), templ->NewInstance());
11791   call_ic_function4 =
11792       v8_compile("function f(x) { return x - 1; }; f")->Run();
11793   v8::Handle<Value> value = CompileRun(
11794     "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
11795     "var result = 0;"
11796     "for (var i = 0; i < 1000; i++) {"
11797     "  result = o.x(42);"
11798     "}");
11799   CHECK_EQ(41, value->Int32Value());
11800 }
11801
11802
11803 // Test the case when we stored cacheable lookup into
11804 // a stub, but it got invalidated later on
11805 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
11806   v8::Isolate* isolate = CcTest::isolate();
11807   v8::HandleScope scope(isolate);
11808   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11809   templ->SetNamedPropertyHandler(NoBlockGetterX);
11810   LocalContext context;
11811   context->Global()->Set(v8_str("o"), templ->NewInstance());
11812   v8::Handle<Value> value = CompileRun(
11813     "proto1 = new Object();"
11814     "proto2 = new Object();"
11815     "o.__proto__ = proto1;"
11816     "proto1.__proto__ = proto2;"
11817     "proto2.y = function(x) { return x + 1; };"
11818     // Invoke it many times to compile a stub
11819     "for (var i = 0; i < 7; i++) {"
11820     "  o.y(42);"
11821     "}"
11822     "proto1.y = function(x) { return x - 1; };"
11823     "var result = 0;"
11824     "for (var i = 0; i < 7; i++) {"
11825     "  result += o.y(42);"
11826     "}");
11827   CHECK_EQ(41 * 7, value->Int32Value());
11828 }
11829
11830
11831 // This test checks that if interceptor doesn't provide a function,
11832 // cached constant function is used
11833 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
11834   v8::Isolate* isolate = CcTest::isolate();
11835   v8::HandleScope scope(isolate);
11836   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11837   templ->SetNamedPropertyHandler(NoBlockGetterX);
11838   LocalContext context;
11839   context->Global()->Set(v8_str("o"), templ->NewInstance());
11840   v8::Handle<Value> value = CompileRun(
11841     "function inc(x) { return x + 1; };"
11842     "inc(1);"
11843     "o.x = inc;"
11844     "var result = 0;"
11845     "for (var i = 0; i < 1000; i++) {"
11846     "  result = o.x(42);"
11847     "}");
11848   CHECK_EQ(43, value->Int32Value());
11849 }
11850
11851
11852 static v8::Handle<Value> call_ic_function5;
11853 static void InterceptorCallICGetter5(
11854     Local<String> name,
11855     const v8::PropertyCallbackInfo<v8::Value>& info) {
11856   ApiTestFuzzer::Fuzz();
11857   if (v8_str("x")->Equals(name))
11858     info.GetReturnValue().Set(call_ic_function5);
11859 }
11860
11861
11862 // This test checks that if interceptor provides a function,
11863 // even if we cached constant function, interceptor's function
11864 // is invoked
11865 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
11866   v8::Isolate* isolate = CcTest::isolate();
11867   v8::HandleScope scope(isolate);
11868   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11869   templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
11870   LocalContext context;
11871   context->Global()->Set(v8_str("o"), templ->NewInstance());
11872   call_ic_function5 =
11873       v8_compile("function f(x) { return x - 1; }; f")->Run();
11874   v8::Handle<Value> value = CompileRun(
11875     "function inc(x) { return x + 1; };"
11876     "inc(1);"
11877     "o.x = inc;"
11878     "var result = 0;"
11879     "for (var i = 0; i < 1000; i++) {"
11880     "  result = o.x(42);"
11881     "}");
11882   CHECK_EQ(41, value->Int32Value());
11883 }
11884
11885
11886 static v8::Handle<Value> call_ic_function6;
11887 static void InterceptorCallICGetter6(
11888     Local<String> name,
11889     const v8::PropertyCallbackInfo<v8::Value>& info) {
11890   ApiTestFuzzer::Fuzz();
11891   if (v8_str("x")->Equals(name))
11892     info.GetReturnValue().Set(call_ic_function6);
11893 }
11894
11895
11896 // Same test as above, except the code is wrapped in a function
11897 // to test the optimized compiler.
11898 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
11899   i::FLAG_allow_natives_syntax = true;
11900   v8::Isolate* isolate = CcTest::isolate();
11901   v8::HandleScope scope(isolate);
11902   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11903   templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
11904   LocalContext context;
11905   context->Global()->Set(v8_str("o"), templ->NewInstance());
11906   call_ic_function6 =
11907       v8_compile("function f(x) { return x - 1; }; f")->Run();
11908   v8::Handle<Value> value = CompileRun(
11909     "function inc(x) { return x + 1; };"
11910     "inc(1);"
11911     "o.x = inc;"
11912     "function test() {"
11913     "  var result = 0;"
11914     "  for (var i = 0; i < 1000; i++) {"
11915     "    result = o.x(42);"
11916     "  }"
11917     "  return result;"
11918     "};"
11919     "test();"
11920     "test();"
11921     "test();"
11922     "%OptimizeFunctionOnNextCall(test);"
11923     "test()");
11924   CHECK_EQ(41, value->Int32Value());
11925 }
11926
11927
11928 // Test the case when we stored constant function into
11929 // a stub, but it got invalidated later on
11930 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
11931   v8::Isolate* isolate = CcTest::isolate();
11932   v8::HandleScope scope(isolate);
11933   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11934   templ->SetNamedPropertyHandler(NoBlockGetterX);
11935   LocalContext context;
11936   context->Global()->Set(v8_str("o"), templ->NewInstance());
11937   v8::Handle<Value> value = CompileRun(
11938     "function inc(x) { return x + 1; };"
11939     "inc(1);"
11940     "proto1 = new Object();"
11941     "proto2 = new Object();"
11942     "o.__proto__ = proto1;"
11943     "proto1.__proto__ = proto2;"
11944     "proto2.y = inc;"
11945     // Invoke it many times to compile a stub
11946     "for (var i = 0; i < 7; i++) {"
11947     "  o.y(42);"
11948     "}"
11949     "proto1.y = function(x) { return x - 1; };"
11950     "var result = 0;"
11951     "for (var i = 0; i < 7; i++) {"
11952     "  result += o.y(42);"
11953     "}");
11954   CHECK_EQ(41 * 7, value->Int32Value());
11955 }
11956
11957
11958 // Test the case when we stored constant function into
11959 // a stub, but it got invalidated later on due to override on
11960 // global object which is between interceptor and constant function' holders.
11961 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
11962   v8::Isolate* isolate = CcTest::isolate();
11963   v8::HandleScope scope(isolate);
11964   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11965   templ->SetNamedPropertyHandler(NoBlockGetterX);
11966   LocalContext context;
11967   context->Global()->Set(v8_str("o"), templ->NewInstance());
11968   v8::Handle<Value> value = CompileRun(
11969     "function inc(x) { return x + 1; };"
11970     "inc(1);"
11971     "o.__proto__ = this;"
11972     "this.__proto__.y = inc;"
11973     // Invoke it many times to compile a stub
11974     "for (var i = 0; i < 7; i++) {"
11975     "  if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
11976     "}"
11977     "this.y = function(x) { return x - 1; };"
11978     "var result = 0;"
11979     "for (var i = 0; i < 7; i++) {"
11980     "  result += o.y(42);"
11981     "}");
11982   CHECK_EQ(41 * 7, value->Int32Value());
11983 }
11984
11985
11986 // Test the case when actual function to call sits on global object.
11987 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
11988   v8::Isolate* isolate = CcTest::isolate();
11989   v8::HandleScope scope(isolate);
11990   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11991   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11992
11993   LocalContext context;
11994   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11995
11996   v8::Handle<Value> value = CompileRun(
11997     "try {"
11998     "  o.__proto__ = this;"
11999     "  for (var i = 0; i < 10; i++) {"
12000     "    var v = o.parseFloat('239');"
12001     "    if (v != 239) throw v;"
12002       // Now it should be ICed and keep a reference to parseFloat.
12003     "  }"
12004     "  var result = 0;"
12005     "  for (var i = 0; i < 10; i++) {"
12006     "    result += o.parseFloat('239');"
12007     "  }"
12008     "  result"
12009     "} catch(e) {"
12010     "  e"
12011     "};");
12012   CHECK_EQ(239 * 10, value->Int32Value());
12013 }
12014
12015 static void InterceptorCallICFastApi(
12016     Local<String> name,
12017     const v8::PropertyCallbackInfo<v8::Value>& info) {
12018   ApiTestFuzzer::Fuzz();
12019   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12020   int* call_count =
12021       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12022   ++(*call_count);
12023   if ((*call_count) % 20 == 0) {
12024     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12025   }
12026 }
12027
12028 static void FastApiCallback_TrivialSignature(
12029     const v8::FunctionCallbackInfo<v8::Value>& args) {
12030   ApiTestFuzzer::Fuzz();
12031   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12032   v8::Isolate* isolate = CcTest::isolate();
12033   CHECK_EQ(isolate, args.GetIsolate());
12034   CHECK_EQ(args.This(), args.Holder());
12035   CHECK(args.Data()->Equals(v8_str("method_data")));
12036   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12037 }
12038
12039 static void FastApiCallback_SimpleSignature(
12040     const v8::FunctionCallbackInfo<v8::Value>& args) {
12041   ApiTestFuzzer::Fuzz();
12042   CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12043   v8::Isolate* isolate = CcTest::isolate();
12044   CHECK_EQ(isolate, args.GetIsolate());
12045   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12046   CHECK(args.Data()->Equals(v8_str("method_data")));
12047   // Note, we're using HasRealNamedProperty instead of Has to avoid
12048   // invoking the interceptor again.
12049   CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12050   args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12051 }
12052
12053
12054 // Helper to maximize the odds of object moving.
12055 static void GenerateSomeGarbage() {
12056   CompileRun(
12057       "var garbage;"
12058       "for (var i = 0; i < 1000; i++) {"
12059       "  garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12060       "}"
12061       "garbage = undefined;");
12062 }
12063
12064
12065 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12066   static int count = 0;
12067   if (count++ % 3 == 0) {
12068     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12069         // This should move the stub
12070     GenerateSomeGarbage();  // This should ensure the old stub memory is flushed
12071   }
12072 }
12073
12074
12075 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12076   LocalContext context;
12077   v8::Isolate* isolate = context->GetIsolate();
12078   v8::HandleScope scope(isolate);
12079   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12080       v8::ObjectTemplate::New(isolate);
12081   nativeobject_templ->Set(isolate, "callback",
12082                           v8::FunctionTemplate::New(isolate,
12083                                                     DirectApiCallback));
12084   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12085   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12086   // call the api function multiple times to ensure direct call stub creation.
12087   CompileRun(
12088         "function f() {"
12089         "  for (var i = 1; i <= 30; i++) {"
12090         "    nativeobject.callback();"
12091         "  }"
12092         "}"
12093         "f();");
12094 }
12095
12096
12097 void ThrowingDirectApiCallback(
12098     const v8::FunctionCallbackInfo<v8::Value>& args) {
12099   args.GetIsolate()->ThrowException(v8_str("g"));
12100 }
12101
12102
12103 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12104   LocalContext context;
12105   v8::Isolate* isolate = context->GetIsolate();
12106   v8::HandleScope scope(isolate);
12107   v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12108       v8::ObjectTemplate::New(isolate);
12109   nativeobject_templ->Set(isolate, "callback",
12110                           v8::FunctionTemplate::New(isolate,
12111                                                     ThrowingDirectApiCallback));
12112   v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12113   context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12114   // call the api function multiple times to ensure direct call stub creation.
12115   v8::Handle<Value> result = CompileRun(
12116       "var result = '';"
12117       "function f() {"
12118       "  for (var i = 1; i <= 5; i++) {"
12119       "    try { nativeobject.callback(); } catch (e) { result += e; }"
12120       "  }"
12121       "}"
12122       "f(); result;");
12123   CHECK_EQ(v8_str("ggggg"), result);
12124 }
12125
12126
12127 static Handle<Value> DoDirectGetter() {
12128   if (++p_getter_count % 3 == 0) {
12129     CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12130     GenerateSomeGarbage();
12131   }
12132   return v8_str("Direct Getter Result");
12133 }
12134
12135 static void DirectGetterCallback(
12136     Local<String> name,
12137     const v8::PropertyCallbackInfo<v8::Value>& info) {
12138   CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12139   info.GetReturnValue().Set(DoDirectGetter());
12140 }
12141
12142
12143 template<typename Accessor>
12144 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12145   LocalContext context;
12146   v8::Isolate* isolate = context->GetIsolate();
12147   v8::HandleScope scope(isolate);
12148   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12149   obj->SetAccessor(v8_str("p1"), accessor);
12150   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12151   p_getter_count = 0;
12152   v8::Handle<v8::Value> result = CompileRun(
12153       "function f() {"
12154       "  for (var i = 0; i < 30; i++) o1.p1;"
12155       "  return o1.p1"
12156       "}"
12157       "f();");
12158   CHECK_EQ(v8_str("Direct Getter Result"), result);
12159   CHECK_EQ(31, p_getter_count);
12160 }
12161
12162
12163 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12164   LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12165 }
12166
12167
12168 void ThrowingDirectGetterCallback(
12169     Local<String> name,
12170     const v8::PropertyCallbackInfo<v8::Value>& info) {
12171   info.GetIsolate()->ThrowException(v8_str("g"));
12172 }
12173
12174
12175 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12176   LocalContext context;
12177   v8::Isolate* isolate = context->GetIsolate();
12178   v8::HandleScope scope(isolate);
12179   v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12180   obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12181   context->Global()->Set(v8_str("o1"), obj->NewInstance());
12182   v8::Handle<Value> result = CompileRun(
12183       "var result = '';"
12184       "for (var i = 0; i < 5; i++) {"
12185       "    try { o1.p1; } catch (e) { result += e; }"
12186       "}"
12187       "result;");
12188   CHECK_EQ(v8_str("ggggg"), result);
12189 }
12190
12191
12192 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12193   int interceptor_call_count = 0;
12194   v8::Isolate* isolate = CcTest::isolate();
12195   v8::HandleScope scope(isolate);
12196   v8::Handle<v8::FunctionTemplate> fun_templ =
12197       v8::FunctionTemplate::New(isolate);
12198   v8::Handle<v8::FunctionTemplate> method_templ =
12199       v8::FunctionTemplate::New(isolate,
12200                                 FastApiCallback_TrivialSignature,
12201                                 v8_str("method_data"),
12202                                 v8::Handle<v8::Signature>());
12203   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12204   proto_templ->Set(v8_str("method"), method_templ);
12205   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12206   templ->SetNamedPropertyHandler(
12207       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12208       v8::External::New(isolate, &interceptor_call_count));
12209   LocalContext context;
12210   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12211   GenerateSomeGarbage();
12212   context->Global()->Set(v8_str("o"), fun->NewInstance());
12213   CompileRun(
12214       "var result = 0;"
12215       "for (var i = 0; i < 100; i++) {"
12216       "  result = o.method(41);"
12217       "}");
12218   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12219   CHECK_EQ(100, interceptor_call_count);
12220 }
12221
12222
12223 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12224   int interceptor_call_count = 0;
12225   v8::Isolate* isolate = CcTest::isolate();
12226   v8::HandleScope scope(isolate);
12227   v8::Handle<v8::FunctionTemplate> fun_templ =
12228       v8::FunctionTemplate::New(isolate);
12229   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12230       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12231       v8::Signature::New(isolate, fun_templ));
12232   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12233   proto_templ->Set(v8_str("method"), method_templ);
12234   fun_templ->SetHiddenPrototype(true);
12235   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12236   templ->SetNamedPropertyHandler(
12237       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12238       v8::External::New(isolate, &interceptor_call_count));
12239   LocalContext context;
12240   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12241   GenerateSomeGarbage();
12242   context->Global()->Set(v8_str("o"), fun->NewInstance());
12243   CompileRun(
12244       "o.foo = 17;"
12245       "var receiver = {};"
12246       "receiver.__proto__ = o;"
12247       "var result = 0;"
12248       "for (var i = 0; i < 100; i++) {"
12249       "  result = receiver.method(41);"
12250       "}");
12251   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12252   CHECK_EQ(100, interceptor_call_count);
12253 }
12254
12255
12256 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12257   int interceptor_call_count = 0;
12258   v8::Isolate* isolate = CcTest::isolate();
12259   v8::HandleScope scope(isolate);
12260   v8::Handle<v8::FunctionTemplate> fun_templ =
12261       v8::FunctionTemplate::New(isolate);
12262   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12263       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12264       v8::Signature::New(isolate, fun_templ));
12265   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12266   proto_templ->Set(v8_str("method"), method_templ);
12267   fun_templ->SetHiddenPrototype(true);
12268   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12269   templ->SetNamedPropertyHandler(
12270       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12271       v8::External::New(isolate, &interceptor_call_count));
12272   LocalContext context;
12273   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12274   GenerateSomeGarbage();
12275   context->Global()->Set(v8_str("o"), fun->NewInstance());
12276   CompileRun(
12277       "o.foo = 17;"
12278       "var receiver = {};"
12279       "receiver.__proto__ = o;"
12280       "var result = 0;"
12281       "var saved_result = 0;"
12282       "for (var i = 0; i < 100; i++) {"
12283       "  result = receiver.method(41);"
12284       "  if (i == 50) {"
12285       "    saved_result = result;"
12286       "    receiver = {method: function(x) { return x - 1 }};"
12287       "  }"
12288       "}");
12289   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12290   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12291   CHECK_GE(interceptor_call_count, 50);
12292 }
12293
12294
12295 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12296   int interceptor_call_count = 0;
12297   v8::Isolate* isolate = CcTest::isolate();
12298   v8::HandleScope scope(isolate);
12299   v8::Handle<v8::FunctionTemplate> fun_templ =
12300       v8::FunctionTemplate::New(isolate);
12301   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12302       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12303       v8::Signature::New(isolate, fun_templ));
12304   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12305   proto_templ->Set(v8_str("method"), method_templ);
12306   fun_templ->SetHiddenPrototype(true);
12307   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12308   templ->SetNamedPropertyHandler(
12309       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12310       v8::External::New(isolate, &interceptor_call_count));
12311   LocalContext context;
12312   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12313   GenerateSomeGarbage();
12314   context->Global()->Set(v8_str("o"), fun->NewInstance());
12315   CompileRun(
12316       "o.foo = 17;"
12317       "var receiver = {};"
12318       "receiver.__proto__ = o;"
12319       "var result = 0;"
12320       "var saved_result = 0;"
12321       "for (var i = 0; i < 100; i++) {"
12322       "  result = receiver.method(41);"
12323       "  if (i == 50) {"
12324       "    saved_result = result;"
12325       "    o.method = function(x) { return x - 1 };"
12326       "  }"
12327       "}");
12328   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12329   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12330   CHECK_GE(interceptor_call_count, 50);
12331 }
12332
12333
12334 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12335   int interceptor_call_count = 0;
12336   v8::Isolate* isolate = CcTest::isolate();
12337   v8::HandleScope scope(isolate);
12338   v8::Handle<v8::FunctionTemplate> fun_templ =
12339       v8::FunctionTemplate::New(isolate);
12340   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12341       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12342       v8::Signature::New(isolate, fun_templ));
12343   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12344   proto_templ->Set(v8_str("method"), method_templ);
12345   fun_templ->SetHiddenPrototype(true);
12346   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12347   templ->SetNamedPropertyHandler(
12348       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12349       v8::External::New(isolate, &interceptor_call_count));
12350   LocalContext context;
12351   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12352   GenerateSomeGarbage();
12353   context->Global()->Set(v8_str("o"), fun->NewInstance());
12354   v8::TryCatch try_catch;
12355   CompileRun(
12356       "o.foo = 17;"
12357       "var receiver = {};"
12358       "receiver.__proto__ = o;"
12359       "var result = 0;"
12360       "var saved_result = 0;"
12361       "for (var i = 0; i < 100; i++) {"
12362       "  result = receiver.method(41);"
12363       "  if (i == 50) {"
12364       "    saved_result = result;"
12365       "    receiver = 333;"
12366       "  }"
12367       "}");
12368   CHECK(try_catch.HasCaught());
12369   // TODO(verwaest): Adjust message.
12370   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12371            try_catch.Exception()->ToString());
12372   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12373   CHECK_GE(interceptor_call_count, 50);
12374 }
12375
12376
12377 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12378   int interceptor_call_count = 0;
12379   v8::Isolate* isolate = CcTest::isolate();
12380   v8::HandleScope scope(isolate);
12381   v8::Handle<v8::FunctionTemplate> fun_templ =
12382       v8::FunctionTemplate::New(isolate);
12383   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12384       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12385       v8::Signature::New(isolate, fun_templ));
12386   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12387   proto_templ->Set(v8_str("method"), method_templ);
12388   fun_templ->SetHiddenPrototype(true);
12389   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12390   templ->SetNamedPropertyHandler(
12391       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12392       v8::External::New(isolate, &interceptor_call_count));
12393   LocalContext context;
12394   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12395   GenerateSomeGarbage();
12396   context->Global()->Set(v8_str("o"), fun->NewInstance());
12397   v8::TryCatch try_catch;
12398   CompileRun(
12399       "o.foo = 17;"
12400       "var receiver = {};"
12401       "receiver.__proto__ = o;"
12402       "var result = 0;"
12403       "var saved_result = 0;"
12404       "for (var i = 0; i < 100; i++) {"
12405       "  result = receiver.method(41);"
12406       "  if (i == 50) {"
12407       "    saved_result = result;"
12408       "    receiver = {method: receiver.method};"
12409       "  }"
12410       "}");
12411   CHECK(try_catch.HasCaught());
12412   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12413            try_catch.Exception()->ToString());
12414   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12415   CHECK_GE(interceptor_call_count, 50);
12416 }
12417
12418
12419 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12420   v8::Isolate* isolate = CcTest::isolate();
12421   v8::HandleScope scope(isolate);
12422   v8::Handle<v8::FunctionTemplate> fun_templ =
12423       v8::FunctionTemplate::New(isolate);
12424   v8::Handle<v8::FunctionTemplate> method_templ =
12425       v8::FunctionTemplate::New(isolate,
12426                                 FastApiCallback_TrivialSignature,
12427                                 v8_str("method_data"),
12428                                 v8::Handle<v8::Signature>());
12429   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12430   proto_templ->Set(v8_str("method"), method_templ);
12431   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12432   USE(templ);
12433   LocalContext context;
12434   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12435   GenerateSomeGarbage();
12436   context->Global()->Set(v8_str("o"), fun->NewInstance());
12437   CompileRun(
12438       "var result = 0;"
12439       "for (var i = 0; i < 100; i++) {"
12440       "  result = o.method(41);"
12441       "}");
12442
12443   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12444 }
12445
12446
12447 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12448   v8::Isolate* isolate = CcTest::isolate();
12449   v8::HandleScope scope(isolate);
12450   v8::Handle<v8::FunctionTemplate> fun_templ =
12451       v8::FunctionTemplate::New(isolate);
12452   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12453       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12454       v8::Signature::New(isolate, fun_templ));
12455   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12456   proto_templ->Set(v8_str("method"), method_templ);
12457   fun_templ->SetHiddenPrototype(true);
12458   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12459   CHECK(!templ.IsEmpty());
12460   LocalContext context;
12461   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12462   GenerateSomeGarbage();
12463   context->Global()->Set(v8_str("o"), fun->NewInstance());
12464   CompileRun(
12465       "o.foo = 17;"
12466       "var receiver = {};"
12467       "receiver.__proto__ = o;"
12468       "var result = 0;"
12469       "for (var i = 0; i < 100; i++) {"
12470       "  result = receiver.method(41);"
12471       "}");
12472
12473   CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12474 }
12475
12476
12477 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12478   v8::Isolate* isolate = CcTest::isolate();
12479   v8::HandleScope scope(isolate);
12480   v8::Handle<v8::FunctionTemplate> fun_templ =
12481       v8::FunctionTemplate::New(isolate);
12482   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12483       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12484       v8::Signature::New(isolate, fun_templ));
12485   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12486   proto_templ->Set(v8_str("method"), method_templ);
12487   fun_templ->SetHiddenPrototype(true);
12488   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12489   CHECK(!templ.IsEmpty());
12490   LocalContext context;
12491   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12492   GenerateSomeGarbage();
12493   context->Global()->Set(v8_str("o"), fun->NewInstance());
12494   CompileRun(
12495       "o.foo = 17;"
12496       "var receiver = {};"
12497       "receiver.__proto__ = o;"
12498       "var result = 0;"
12499       "var saved_result = 0;"
12500       "for (var i = 0; i < 100; i++) {"
12501       "  result = receiver.method(41);"
12502       "  if (i == 50) {"
12503       "    saved_result = result;"
12504       "    receiver = {method: function(x) { return x - 1 }};"
12505       "  }"
12506       "}");
12507   CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12508   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12509 }
12510
12511
12512 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12513   v8::Isolate* isolate = CcTest::isolate();
12514   v8::HandleScope scope(isolate);
12515   v8::Handle<v8::FunctionTemplate> fun_templ =
12516       v8::FunctionTemplate::New(isolate);
12517   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12518       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12519       v8::Signature::New(isolate, fun_templ));
12520   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12521   proto_templ->Set(v8_str("method"), method_templ);
12522   fun_templ->SetHiddenPrototype(true);
12523   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12524   CHECK(!templ.IsEmpty());
12525   LocalContext context;
12526   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12527   GenerateSomeGarbage();
12528   context->Global()->Set(v8_str("o"), fun->NewInstance());
12529   v8::TryCatch try_catch;
12530   CompileRun(
12531       "o.foo = 17;"
12532       "var receiver = {};"
12533       "receiver.__proto__ = o;"
12534       "var result = 0;"
12535       "var saved_result = 0;"
12536       "for (var i = 0; i < 100; i++) {"
12537       "  result = receiver.method(41);"
12538       "  if (i == 50) {"
12539       "    saved_result = result;"
12540       "    receiver = 333;"
12541       "  }"
12542       "}");
12543   CHECK(try_catch.HasCaught());
12544   // TODO(verwaest): Adjust message.
12545   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12546            try_catch.Exception()->ToString());
12547   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12548 }
12549
12550
12551 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
12552   v8::Isolate* isolate = CcTest::isolate();
12553   v8::HandleScope scope(isolate);
12554   v8::Handle<v8::FunctionTemplate> fun_templ =
12555       v8::FunctionTemplate::New(isolate);
12556   v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12557       isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12558       v8::Signature::New(isolate, fun_templ));
12559   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12560   proto_templ->Set(v8_str("method"), method_templ);
12561   fun_templ->SetHiddenPrototype(true);
12562   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12563   CHECK(!templ.IsEmpty());
12564   LocalContext context;
12565   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12566   GenerateSomeGarbage();
12567   context->Global()->Set(v8_str("o"), fun->NewInstance());
12568   v8::TryCatch try_catch;
12569   CompileRun(
12570       "o.foo = 17;"
12571       "var receiver = {};"
12572       "receiver.__proto__ = o;"
12573       "var result = 0;"
12574       "var saved_result = 0;"
12575       "for (var i = 0; i < 100; i++) {"
12576       "  result = receiver.method(41);"
12577       "  if (i == 50) {"
12578       "    saved_result = result;"
12579       "    receiver = Object.create(receiver);"
12580       "  }"
12581       "}");
12582   CHECK(try_catch.HasCaught());
12583   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12584            try_catch.Exception()->ToString());
12585   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12586 }
12587
12588
12589 v8::Handle<Value> keyed_call_ic_function;
12590
12591 static void InterceptorKeyedCallICGetter(
12592     Local<String> name,
12593     const v8::PropertyCallbackInfo<v8::Value>& info) {
12594   ApiTestFuzzer::Fuzz();
12595   if (v8_str("x")->Equals(name)) {
12596     info.GetReturnValue().Set(keyed_call_ic_function);
12597   }
12598 }
12599
12600
12601 // Test the case when we stored cacheable lookup into
12602 // a stub, but the function name changed (to another cacheable function).
12603 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
12604   v8::Isolate* isolate = CcTest::isolate();
12605   v8::HandleScope scope(isolate);
12606   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12607   templ->SetNamedPropertyHandler(NoBlockGetterX);
12608   LocalContext context;
12609   context->Global()->Set(v8_str("o"), templ->NewInstance());
12610   CompileRun(
12611     "proto = new Object();"
12612     "proto.y = function(x) { return x + 1; };"
12613     "proto.z = function(x) { return x - 1; };"
12614     "o.__proto__ = proto;"
12615     "var result = 0;"
12616     "var method = 'y';"
12617     "for (var i = 0; i < 10; i++) {"
12618     "  if (i == 5) { method = 'z'; };"
12619     "  result += o[method](41);"
12620     "}");
12621   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12622 }
12623
12624
12625 // Test the case when we stored cacheable lookup into
12626 // a stub, but the function name changed (and the new function is present
12627 // both before and after the interceptor in the prototype chain).
12628 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
12629   v8::Isolate* isolate = CcTest::isolate();
12630   v8::HandleScope scope(isolate);
12631   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12632   templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
12633   LocalContext context;
12634   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
12635   keyed_call_ic_function =
12636       v8_compile("function f(x) { return x - 1; }; f")->Run();
12637   CompileRun(
12638     "o = new Object();"
12639     "proto2 = new Object();"
12640     "o.y = function(x) { return x + 1; };"
12641     "proto2.y = function(x) { return x + 2; };"
12642     "o.__proto__ = proto1;"
12643     "proto1.__proto__ = proto2;"
12644     "var result = 0;"
12645     "var method = 'x';"
12646     "for (var i = 0; i < 10; i++) {"
12647     "  if (i == 5) { method = 'y'; };"
12648     "  result += o[method](41);"
12649     "}");
12650   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12651 }
12652
12653
12654 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
12655 // on the global object.
12656 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
12657   v8::Isolate* isolate = CcTest::isolate();
12658   v8::HandleScope scope(isolate);
12659   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12660   templ->SetNamedPropertyHandler(NoBlockGetterX);
12661   LocalContext context;
12662   context->Global()->Set(v8_str("o"), templ->NewInstance());
12663   CompileRun(
12664     "function inc(x) { return x + 1; };"
12665     "inc(1);"
12666     "function dec(x) { return x - 1; };"
12667     "dec(1);"
12668     "o.__proto__ = this;"
12669     "this.__proto__.x = inc;"
12670     "this.__proto__.y = dec;"
12671     "var result = 0;"
12672     "var method = 'x';"
12673     "for (var i = 0; i < 10; i++) {"
12674     "  if (i == 5) { method = 'y'; };"
12675     "  result += o[method](41);"
12676     "}");
12677   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12678 }
12679
12680
12681 // Test the case when actual function to call sits on global object.
12682 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
12683   v8::Isolate* isolate = CcTest::isolate();
12684   v8::HandleScope scope(isolate);
12685   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12686   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12687   LocalContext context;
12688   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12689
12690   CompileRun(
12691     "function len(x) { return x.length; };"
12692     "o.__proto__ = this;"
12693     "var m = 'parseFloat';"
12694     "var result = 0;"
12695     "for (var i = 0; i < 10; i++) {"
12696     "  if (i == 5) {"
12697     "    m = 'len';"
12698     "    saved_result = result;"
12699     "  };"
12700     "  result = o[m]('239');"
12701     "}");
12702   CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
12703   CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12704 }
12705
12706
12707 // Test the map transition before the interceptor.
12708 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
12709   v8::Isolate* isolate = CcTest::isolate();
12710   v8::HandleScope scope(isolate);
12711   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12712   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12713   LocalContext context;
12714   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
12715
12716   CompileRun(
12717     "var o = new Object();"
12718     "o.__proto__ = proto;"
12719     "o.method = function(x) { return x + 1; };"
12720     "var m = 'method';"
12721     "var result = 0;"
12722     "for (var i = 0; i < 10; i++) {"
12723     "  if (i == 5) { o.method = function(x) { return x - 1; }; };"
12724     "  result += o[m](41);"
12725     "}");
12726   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12727 }
12728
12729
12730 // Test the map transition after the interceptor.
12731 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
12732   v8::Isolate* isolate = CcTest::isolate();
12733   v8::HandleScope scope(isolate);
12734   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12735   templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12736   LocalContext context;
12737   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12738
12739   CompileRun(
12740     "var proto = new Object();"
12741     "o.__proto__ = proto;"
12742     "proto.method = function(x) { return x + 1; };"
12743     "var m = 'method';"
12744     "var result = 0;"
12745     "for (var i = 0; i < 10; i++) {"
12746     "  if (i == 5) { proto.method = function(x) { return x - 1; }; };"
12747     "  result += o[m](41);"
12748     "}");
12749   CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
12750 }
12751
12752
12753 static int interceptor_call_count = 0;
12754
12755 static void InterceptorICRefErrorGetter(
12756     Local<String> name,
12757     const v8::PropertyCallbackInfo<v8::Value>& info) {
12758   ApiTestFuzzer::Fuzz();
12759   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
12760     info.GetReturnValue().Set(call_ic_function2);
12761   }
12762 }
12763
12764
12765 // This test should hit load and call ICs for the interceptor case.
12766 // Once in a while, the interceptor will reply that a property was not
12767 // found in which case we should get a reference error.
12768 THREADED_TEST(InterceptorICReferenceErrors) {
12769   v8::Isolate* isolate = CcTest::isolate();
12770   v8::HandleScope scope(isolate);
12771   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12772   templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
12773   LocalContext context(0, templ, v8::Handle<Value>());
12774   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
12775   v8::Handle<Value> value = CompileRun(
12776     "function f() {"
12777     "  for (var i = 0; i < 1000; i++) {"
12778     "    try { x; } catch(e) { return true; }"
12779     "  }"
12780     "  return false;"
12781     "};"
12782     "f();");
12783   CHECK_EQ(true, value->BooleanValue());
12784   interceptor_call_count = 0;
12785   value = CompileRun(
12786     "function g() {"
12787     "  for (var i = 0; i < 1000; i++) {"
12788     "    try { x(42); } catch(e) { return true; }"
12789     "  }"
12790     "  return false;"
12791     "};"
12792     "g();");
12793   CHECK_EQ(true, value->BooleanValue());
12794 }
12795
12796
12797 static int interceptor_ic_exception_get_count = 0;
12798
12799 static void InterceptorICExceptionGetter(
12800     Local<String> name,
12801     const v8::PropertyCallbackInfo<v8::Value>& info) {
12802   ApiTestFuzzer::Fuzz();
12803   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
12804     info.GetReturnValue().Set(call_ic_function3);
12805   }
12806   if (interceptor_ic_exception_get_count == 20) {
12807     info.GetIsolate()->ThrowException(v8_num(42));
12808     return;
12809   }
12810 }
12811
12812
12813 // Test interceptor load/call IC where the interceptor throws an
12814 // exception once in a while.
12815 THREADED_TEST(InterceptorICGetterExceptions) {
12816   interceptor_ic_exception_get_count = 0;
12817   v8::Isolate* isolate = CcTest::isolate();
12818   v8::HandleScope scope(isolate);
12819   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12820   templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
12821   LocalContext context(0, templ, v8::Handle<Value>());
12822   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
12823   v8::Handle<Value> value = CompileRun(
12824     "function f() {"
12825     "  for (var i = 0; i < 100; i++) {"
12826     "    try { x; } catch(e) { return true; }"
12827     "  }"
12828     "  return false;"
12829     "};"
12830     "f();");
12831   CHECK_EQ(true, value->BooleanValue());
12832   interceptor_ic_exception_get_count = 0;
12833   value = CompileRun(
12834     "function f() {"
12835     "  for (var i = 0; i < 100; i++) {"
12836     "    try { x(42); } catch(e) { return true; }"
12837     "  }"
12838     "  return false;"
12839     "};"
12840     "f();");
12841   CHECK_EQ(true, value->BooleanValue());
12842 }
12843
12844
12845 static int interceptor_ic_exception_set_count = 0;
12846
12847 static void InterceptorICExceptionSetter(
12848       Local<String> key,
12849       Local<Value> value,
12850       const v8::PropertyCallbackInfo<v8::Value>& info) {
12851   ApiTestFuzzer::Fuzz();
12852   if (++interceptor_ic_exception_set_count > 20) {
12853     info.GetIsolate()->ThrowException(v8_num(42));
12854   }
12855 }
12856
12857
12858 // Test interceptor store IC where the interceptor throws an exception
12859 // once in a while.
12860 THREADED_TEST(InterceptorICSetterExceptions) {
12861   interceptor_ic_exception_set_count = 0;
12862   v8::Isolate* isolate = CcTest::isolate();
12863   v8::HandleScope scope(isolate);
12864   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12865   templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
12866   LocalContext context(0, templ, v8::Handle<Value>());
12867   v8::Handle<Value> value = CompileRun(
12868     "function f() {"
12869     "  for (var i = 0; i < 100; i++) {"
12870     "    try { x = 42; } catch(e) { return true; }"
12871     "  }"
12872     "  return false;"
12873     "};"
12874     "f();");
12875   CHECK_EQ(true, value->BooleanValue());
12876 }
12877
12878
12879 // Test that we ignore null interceptors.
12880 THREADED_TEST(NullNamedInterceptor) {
12881   v8::Isolate* isolate = CcTest::isolate();
12882   v8::HandleScope scope(isolate);
12883   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12884   templ->SetNamedPropertyHandler(
12885       static_cast<v8::NamedPropertyGetterCallback>(0));
12886   LocalContext context;
12887   templ->Set(CcTest::isolate(), "x", v8_num(42));
12888   v8::Handle<v8::Object> obj = templ->NewInstance();
12889   context->Global()->Set(v8_str("obj"), obj);
12890   v8::Handle<Value> value = CompileRun("obj.x");
12891   CHECK(value->IsInt32());
12892   CHECK_EQ(42, value->Int32Value());
12893 }
12894
12895
12896 // Test that we ignore null interceptors.
12897 THREADED_TEST(NullIndexedInterceptor) {
12898   v8::Isolate* isolate = CcTest::isolate();
12899   v8::HandleScope scope(isolate);
12900   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12901   templ->SetIndexedPropertyHandler(
12902       static_cast<v8::IndexedPropertyGetterCallback>(0));
12903   LocalContext context;
12904   templ->Set(CcTest::isolate(), "42", v8_num(42));
12905   v8::Handle<v8::Object> obj = templ->NewInstance();
12906   context->Global()->Set(v8_str("obj"), obj);
12907   v8::Handle<Value> value = CompileRun("obj[42]");
12908   CHECK(value->IsInt32());
12909   CHECK_EQ(42, value->Int32Value());
12910 }
12911
12912
12913 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
12914   v8::Isolate* isolate = CcTest::isolate();
12915   v8::HandleScope scope(isolate);
12916   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
12917   templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12918   LocalContext env;
12919   env->Global()->Set(v8_str("obj"),
12920                      templ->GetFunction()->NewInstance());
12921   ExpectTrue("obj.x === 42");
12922   ExpectTrue("!obj.propertyIsEnumerable('x')");
12923 }
12924
12925
12926 static void ThrowingGetter(Local<String> name,
12927                            const v8::PropertyCallbackInfo<v8::Value>& info) {
12928   ApiTestFuzzer::Fuzz();
12929   info.GetIsolate()->ThrowException(Handle<Value>());
12930   info.GetReturnValue().SetUndefined();
12931 }
12932
12933
12934 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
12935   LocalContext context;
12936   HandleScope scope(context->GetIsolate());
12937
12938   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
12939   Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
12940   instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
12941
12942   Local<Object> instance = templ->GetFunction()->NewInstance();
12943
12944   Local<Object> another = Object::New(context->GetIsolate());
12945   another->SetPrototype(instance);
12946
12947   Local<Object> with_js_getter = CompileRun(
12948       "o = {};\n"
12949       "o.__defineGetter__('f', function() { throw undefined; });\n"
12950       "o\n").As<Object>();
12951   CHECK(!with_js_getter.IsEmpty());
12952
12953   TryCatch try_catch;
12954
12955   Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
12956   CHECK(try_catch.HasCaught());
12957   try_catch.Reset();
12958   CHECK(result.IsEmpty());
12959
12960   result = another->GetRealNamedProperty(v8_str("f"));
12961   CHECK(try_catch.HasCaught());
12962   try_catch.Reset();
12963   CHECK(result.IsEmpty());
12964
12965   result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
12966   CHECK(try_catch.HasCaught());
12967   try_catch.Reset();
12968   CHECK(result.IsEmpty());
12969
12970   result = another->Get(v8_str("f"));
12971   CHECK(try_catch.HasCaught());
12972   try_catch.Reset();
12973   CHECK(result.IsEmpty());
12974
12975   result = with_js_getter->GetRealNamedProperty(v8_str("f"));
12976   CHECK(try_catch.HasCaught());
12977   try_catch.Reset();
12978   CHECK(result.IsEmpty());
12979
12980   result = with_js_getter->Get(v8_str("f"));
12981   CHECK(try_catch.HasCaught());
12982   try_catch.Reset();
12983   CHECK(result.IsEmpty());
12984 }
12985
12986
12987 static void ThrowingCallbackWithTryCatch(
12988     const v8::FunctionCallbackInfo<v8::Value>& args) {
12989   TryCatch try_catch;
12990   // Verboseness is important: it triggers message delivery which can call into
12991   // external code.
12992   try_catch.SetVerbose(true);
12993   CompileRun("throw 'from JS';");
12994   CHECK(try_catch.HasCaught());
12995   CHECK(!CcTest::i_isolate()->has_pending_exception());
12996   CHECK(!CcTest::i_isolate()->has_scheduled_exception());
12997 }
12998
12999
13000 static int call_depth;
13001
13002
13003 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13004   TryCatch try_catch;
13005 }
13006
13007
13008 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13009   if (--call_depth) CompileRun("throw 'ThrowInJS';");
13010 }
13011
13012
13013 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13014   if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13015 }
13016
13017
13018 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13019   Handle<String> errorMessageString = message->Get();
13020   CHECK(!errorMessageString.IsEmpty());
13021   message->GetStackTrace();
13022   message->GetScriptOrigin().ResourceName();
13023 }
13024
13025
13026 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13027   LocalContext context;
13028   v8::Isolate* isolate = context->GetIsolate();
13029   HandleScope scope(isolate);
13030
13031   Local<Function> func =
13032       FunctionTemplate::New(isolate,
13033                             ThrowingCallbackWithTryCatch)->GetFunction();
13034   context->Global()->Set(v8_str("func"), func);
13035
13036   MessageCallback callbacks[] =
13037       { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13038   for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13039     MessageCallback callback = callbacks[i];
13040     if (callback != NULL) {
13041       V8::AddMessageListener(callback);
13042     }
13043     // Some small number to control number of times message handler should
13044     // throw an exception.
13045     call_depth = 5;
13046     ExpectFalse(
13047         "var thrown = false;\n"
13048         "try { func(); } catch(e) { thrown = true; }\n"
13049         "thrown\n");
13050     if (callback != NULL) {
13051       V8::RemoveMessageListeners(callback);
13052     }
13053   }
13054 }
13055
13056
13057 static void ParentGetter(Local<String> name,
13058                          const v8::PropertyCallbackInfo<v8::Value>& info) {
13059   ApiTestFuzzer::Fuzz();
13060   info.GetReturnValue().Set(v8_num(1));
13061 }
13062
13063
13064 static void ChildGetter(Local<String> name,
13065                         const v8::PropertyCallbackInfo<v8::Value>& info) {
13066   ApiTestFuzzer::Fuzz();
13067   info.GetReturnValue().Set(v8_num(42));
13068 }
13069
13070
13071 THREADED_TEST(Overriding) {
13072   LocalContext context;
13073   v8::Isolate* isolate = context->GetIsolate();
13074   v8::HandleScope scope(isolate);
13075
13076   // Parent template.
13077   Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13078   Local<ObjectTemplate> parent_instance_templ =
13079       parent_templ->InstanceTemplate();
13080   parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13081
13082   // Template that inherits from the parent template.
13083   Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13084   Local<ObjectTemplate> child_instance_templ =
13085       child_templ->InstanceTemplate();
13086   child_templ->Inherit(parent_templ);
13087   // Override 'f'.  The child version of 'f' should get called for child
13088   // instances.
13089   child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13090   // Add 'g' twice.  The 'g' added last should get called for instances.
13091   child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13092   child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13093
13094   // Add 'h' as an accessor to the proto template with ReadOnly attributes
13095   // so 'h' can be shadowed on the instance object.
13096   Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13097   child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13098       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13099
13100   // Add 'i' as an accessor to the instance template with ReadOnly attributes
13101   // but the attribute does not have effect because it is duplicated with
13102   // NULL setter.
13103   child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13104       v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13105
13106
13107
13108   // Instantiate the child template.
13109   Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13110
13111   // Check that the child function overrides the parent one.
13112   context->Global()->Set(v8_str("o"), instance);
13113   Local<Value> value = v8_compile("o.f")->Run();
13114   // Check that the 'g' that was added last is hit.
13115   CHECK_EQ(42, value->Int32Value());
13116   value = v8_compile("o.g")->Run();
13117   CHECK_EQ(42, value->Int32Value());
13118
13119   // Check that 'h' cannot be shadowed.
13120   value = v8_compile("o.h = 3; o.h")->Run();
13121   CHECK_EQ(1, value->Int32Value());
13122
13123   // Check that 'i' cannot be shadowed or changed.
13124   value = v8_compile("o.i = 3; o.i")->Run();
13125   CHECK_EQ(42, value->Int32Value());
13126 }
13127
13128
13129 static void IsConstructHandler(
13130     const v8::FunctionCallbackInfo<v8::Value>& args) {
13131   ApiTestFuzzer::Fuzz();
13132   args.GetReturnValue().Set(args.IsConstructCall());
13133 }
13134
13135
13136 THREADED_TEST(IsConstructCall) {
13137   v8::Isolate* isolate = CcTest::isolate();
13138   v8::HandleScope scope(isolate);
13139
13140   // Function template with call handler.
13141   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13142   templ->SetCallHandler(IsConstructHandler);
13143
13144   LocalContext context;
13145
13146   context->Global()->Set(v8_str("f"), templ->GetFunction());
13147   Local<Value> value = v8_compile("f()")->Run();
13148   CHECK(!value->BooleanValue());
13149   value = v8_compile("new f()")->Run();
13150   CHECK(value->BooleanValue());
13151 }
13152
13153
13154 THREADED_TEST(ObjectProtoToString) {
13155   v8::Isolate* isolate = CcTest::isolate();
13156   v8::HandleScope scope(isolate);
13157   Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13158   templ->SetClassName(v8_str("MyClass"));
13159
13160   LocalContext context;
13161
13162   Local<String> customized_tostring = v8_str("customized toString");
13163
13164   // Replace Object.prototype.toString
13165   v8_compile("Object.prototype.toString = function() {"
13166                   "  return 'customized toString';"
13167                   "}")->Run();
13168
13169   // Normal ToString call should call replaced Object.prototype.toString
13170   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13171   Local<String> value = instance->ToString();
13172   CHECK(value->IsString() && value->Equals(customized_tostring));
13173
13174   // ObjectProtoToString should not call replace toString function.
13175   value = instance->ObjectProtoToString();
13176   CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13177
13178   // Check global
13179   value = context->Global()->ObjectProtoToString();
13180   CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13181
13182   // Check ordinary object
13183   Local<Value> object = v8_compile("new Object()")->Run();
13184   value = object.As<v8::Object>()->ObjectProtoToString();
13185   CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13186 }
13187
13188
13189 THREADED_TEST(ObjectGetConstructorName) {
13190   LocalContext context;
13191   v8::HandleScope scope(context->GetIsolate());
13192   v8_compile("function Parent() {};"
13193              "function Child() {};"
13194              "Child.prototype = new Parent();"
13195              "var outer = { inner: function() { } };"
13196              "var p = new Parent();"
13197              "var c = new Child();"
13198              "var x = new outer.inner();")->Run();
13199
13200   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13201   CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13202       v8_str("Parent")));
13203
13204   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13205   CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13206       v8_str("Child")));
13207
13208   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13209   CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13210       v8_str("outer.inner")));
13211 }
13212
13213
13214 bool ApiTestFuzzer::fuzzing_ = false;
13215 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13216 int ApiTestFuzzer::active_tests_;
13217 int ApiTestFuzzer::tests_being_run_;
13218 int ApiTestFuzzer::current_;
13219
13220
13221 // We are in a callback and want to switch to another thread (if we
13222 // are currently running the thread fuzzing test).
13223 void ApiTestFuzzer::Fuzz() {
13224   if (!fuzzing_) return;
13225   ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13226   test->ContextSwitch();
13227 }
13228
13229
13230 // Let the next thread go.  Since it is also waiting on the V8 lock it may
13231 // not start immediately.
13232 bool ApiTestFuzzer::NextThread() {
13233   int test_position = GetNextTestNumber();
13234   const char* test_name = RegisterThreadedTest::nth(current_)->name();
13235   if (test_position == current_) {
13236     if (kLogThreading)
13237       printf("Stay with %s\n", test_name);
13238     return false;
13239   }
13240   if (kLogThreading) {
13241     printf("Switch from %s to %s\n",
13242            test_name,
13243            RegisterThreadedTest::nth(test_position)->name());
13244   }
13245   current_ = test_position;
13246   RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13247   return true;
13248 }
13249
13250
13251 void ApiTestFuzzer::Run() {
13252   // When it is our turn...
13253   gate_.Wait();
13254   {
13255     // ... get the V8 lock and start running the test.
13256     v8::Locker locker(CcTest::isolate());
13257     CallTest();
13258   }
13259   // This test finished.
13260   active_ = false;
13261   active_tests_--;
13262   // If it was the last then signal that fact.
13263   if (active_tests_ == 0) {
13264     all_tests_done_.Signal();
13265   } else {
13266     // Otherwise select a new test and start that.
13267     NextThread();
13268   }
13269 }
13270
13271
13272 static unsigned linear_congruential_generator;
13273
13274
13275 void ApiTestFuzzer::SetUp(PartOfTest part) {
13276   linear_congruential_generator = i::FLAG_testing_prng_seed;
13277   fuzzing_ = true;
13278   int count = RegisterThreadedTest::count();
13279   int start =  count * part / (LAST_PART + 1);
13280   int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13281   active_tests_ = tests_being_run_ = end - start + 1;
13282   for (int i = 0; i < tests_being_run_; i++) {
13283     RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13284   }
13285   for (int i = 0; i < active_tests_; i++) {
13286     RegisterThreadedTest::nth(i)->fuzzer_->Start();
13287   }
13288 }
13289
13290
13291 static void CallTestNumber(int test_number) {
13292   (RegisterThreadedTest::nth(test_number)->callback())();
13293 }
13294
13295
13296 void ApiTestFuzzer::RunAllTests() {
13297   // Set off the first test.
13298   current_ = -1;
13299   NextThread();
13300   // Wait till they are all done.
13301   all_tests_done_.Wait();
13302 }
13303
13304
13305 int ApiTestFuzzer::GetNextTestNumber() {
13306   int next_test;
13307   do {
13308     next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13309     linear_congruential_generator *= 1664525u;
13310     linear_congruential_generator += 1013904223u;
13311   } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13312   return next_test;
13313 }
13314
13315
13316 void ApiTestFuzzer::ContextSwitch() {
13317   // If the new thread is the same as the current thread there is nothing to do.
13318   if (NextThread()) {
13319     // Now it can start.
13320     v8::Unlocker unlocker(CcTest::isolate());
13321     // Wait till someone starts us again.
13322     gate_.Wait();
13323     // And we're off.
13324   }
13325 }
13326
13327
13328 void ApiTestFuzzer::TearDown() {
13329   fuzzing_ = false;
13330   for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13331     ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13332     if (fuzzer != NULL) fuzzer->Join();
13333   }
13334 }
13335
13336
13337 // Lets not be needlessly self-referential.
13338 TEST(Threading1) {
13339   ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13340   ApiTestFuzzer::RunAllTests();
13341   ApiTestFuzzer::TearDown();
13342 }
13343
13344
13345 TEST(Threading2) {
13346   ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13347   ApiTestFuzzer::RunAllTests();
13348   ApiTestFuzzer::TearDown();
13349 }
13350
13351
13352 TEST(Threading3) {
13353   ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13354   ApiTestFuzzer::RunAllTests();
13355   ApiTestFuzzer::TearDown();
13356 }
13357
13358
13359 TEST(Threading4) {
13360   ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13361   ApiTestFuzzer::RunAllTests();
13362   ApiTestFuzzer::TearDown();
13363 }
13364
13365
13366 void ApiTestFuzzer::CallTest() {
13367   v8::Isolate::Scope scope(CcTest::isolate());
13368   if (kLogThreading)
13369     printf("Start test %d\n", test_number_);
13370   CallTestNumber(test_number_);
13371   if (kLogThreading)
13372     printf("End test %d\n", test_number_);
13373 }
13374
13375
13376 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13377   v8::Isolate* isolate = args.GetIsolate();
13378   CHECK(v8::Locker::IsLocked(isolate));
13379   ApiTestFuzzer::Fuzz();
13380   v8::Unlocker unlocker(isolate);
13381   const char* code = "throw 7;";
13382   {
13383     v8::Locker nested_locker(isolate);
13384     v8::HandleScope scope(isolate);
13385     v8::Handle<Value> exception;
13386     { v8::TryCatch try_catch;
13387       v8::Handle<Value> value = CompileRun(code);
13388       CHECK(value.IsEmpty());
13389       CHECK(try_catch.HasCaught());
13390       // Make sure to wrap the exception in a new handle because
13391       // the handle returned from the TryCatch is destroyed
13392       // when the TryCatch is destroyed.
13393       exception = Local<Value>::New(isolate, try_catch.Exception());
13394     }
13395     args.GetIsolate()->ThrowException(exception);
13396   }
13397 }
13398
13399
13400 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13401   CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13402   ApiTestFuzzer::Fuzz();
13403   v8::Unlocker unlocker(CcTest::isolate());
13404   const char* code = "throw 7;";
13405   {
13406     v8::Locker nested_locker(CcTest::isolate());
13407     v8::HandleScope scope(args.GetIsolate());
13408     v8::Handle<Value> value = CompileRun(code);
13409     CHECK(value.IsEmpty());
13410     args.GetReturnValue().Set(v8_str("foo"));
13411   }
13412 }
13413
13414
13415 // These are locking tests that don't need to be run again
13416 // as part of the locking aggregation tests.
13417 TEST(NestedLockers) {
13418   v8::Isolate* isolate = CcTest::isolate();
13419   v8::Locker locker(isolate);
13420   CHECK(v8::Locker::IsLocked(isolate));
13421   LocalContext env;
13422   v8::HandleScope scope(env->GetIsolate());
13423   Local<v8::FunctionTemplate> fun_templ =
13424       v8::FunctionTemplate::New(isolate, ThrowInJS);
13425   Local<Function> fun = fun_templ->GetFunction();
13426   env->Global()->Set(v8_str("throw_in_js"), fun);
13427   Local<Script> script = v8_compile("(function () {"
13428                                     "  try {"
13429                                     "    throw_in_js();"
13430                                     "    return 42;"
13431                                     "  } catch (e) {"
13432                                     "    return e * 13;"
13433                                     "  }"
13434                                     "})();");
13435   CHECK_EQ(91, script->Run()->Int32Value());
13436 }
13437
13438
13439 // These are locking tests that don't need to be run again
13440 // as part of the locking aggregation tests.
13441 TEST(NestedLockersNoTryCatch) {
13442   v8::Locker locker(CcTest::isolate());
13443   LocalContext env;
13444   v8::HandleScope scope(env->GetIsolate());
13445   Local<v8::FunctionTemplate> fun_templ =
13446       v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
13447   Local<Function> fun = fun_templ->GetFunction();
13448   env->Global()->Set(v8_str("throw_in_js"), fun);
13449   Local<Script> script = v8_compile("(function () {"
13450                                     "  try {"
13451                                     "    throw_in_js();"
13452                                     "    return 42;"
13453                                     "  } catch (e) {"
13454                                     "    return e * 13;"
13455                                     "  }"
13456                                     "})();");
13457   CHECK_EQ(91, script->Run()->Int32Value());
13458 }
13459
13460
13461 THREADED_TEST(RecursiveLocking) {
13462   v8::Locker locker(CcTest::isolate());
13463   {
13464     v8::Locker locker2(CcTest::isolate());
13465     CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13466   }
13467 }
13468
13469
13470 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
13471   ApiTestFuzzer::Fuzz();
13472   v8::Unlocker unlocker(CcTest::isolate());
13473 }
13474
13475
13476 THREADED_TEST(LockUnlockLock) {
13477   {
13478     v8::Locker locker(CcTest::isolate());
13479     v8::HandleScope scope(CcTest::isolate());
13480     LocalContext env;
13481     Local<v8::FunctionTemplate> fun_templ =
13482         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13483     Local<Function> fun = fun_templ->GetFunction();
13484     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13485     Local<Script> script = v8_compile("(function () {"
13486                                       "  unlock_for_a_moment();"
13487                                       "  return 42;"
13488                                       "})();");
13489     CHECK_EQ(42, script->Run()->Int32Value());
13490   }
13491   {
13492     v8::Locker locker(CcTest::isolate());
13493     v8::HandleScope scope(CcTest::isolate());
13494     LocalContext env;
13495     Local<v8::FunctionTemplate> fun_templ =
13496         v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
13497     Local<Function> fun = fun_templ->GetFunction();
13498     env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
13499     Local<Script> script = v8_compile("(function () {"
13500                                       "  unlock_for_a_moment();"
13501                                       "  return 42;"
13502                                       "})();");
13503     CHECK_EQ(42, script->Run()->Int32Value());
13504   }
13505 }
13506
13507
13508 static int GetGlobalObjectsCount() {
13509   int count = 0;
13510   i::HeapIterator it(CcTest::heap());
13511   for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
13512     if (object->IsJSGlobalObject()) count++;
13513   return count;
13514 }
13515
13516
13517 static void CheckSurvivingGlobalObjectsCount(int expected) {
13518   // We need to collect all garbage twice to be sure that everything
13519   // has been collected.  This is because inline caches are cleared in
13520   // the first garbage collection but some of the maps have already
13521   // been marked at that point.  Therefore some of the maps are not
13522   // collected until the second garbage collection.
13523   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13524   CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
13525   int count = GetGlobalObjectsCount();
13526 #ifdef DEBUG
13527   if (count != expected) CcTest::heap()->TracePathToGlobal();
13528 #endif
13529   CHECK_EQ(expected, count);
13530 }
13531
13532
13533 TEST(DontLeakGlobalObjects) {
13534   // Regression test for issues 1139850 and 1174891.
13535
13536   i::FLAG_expose_gc = true;
13537   v8::V8::Initialize();
13538
13539   for (int i = 0; i < 5; i++) {
13540     { v8::HandleScope scope(CcTest::isolate());
13541       LocalContext context;
13542     }
13543     CcTest::isolate()->ContextDisposedNotification();
13544     CheckSurvivingGlobalObjectsCount(0);
13545
13546     { v8::HandleScope scope(CcTest::isolate());
13547       LocalContext context;
13548       v8_compile("Date")->Run();
13549     }
13550     CcTest::isolate()->ContextDisposedNotification();
13551     CheckSurvivingGlobalObjectsCount(0);
13552
13553     { v8::HandleScope scope(CcTest::isolate());
13554       LocalContext context;
13555       v8_compile("/aaa/")->Run();
13556     }
13557     CcTest::isolate()->ContextDisposedNotification();
13558     CheckSurvivingGlobalObjectsCount(0);
13559
13560     { v8::HandleScope scope(CcTest::isolate());
13561       const char* extension_list[] = { "v8/gc" };
13562       v8::ExtensionConfiguration extensions(1, extension_list);
13563       LocalContext context(&extensions);
13564       v8_compile("gc();")->Run();
13565     }
13566     CcTest::isolate()->ContextDisposedNotification();
13567     CheckSurvivingGlobalObjectsCount(0);
13568   }
13569 }
13570
13571
13572 TEST(CopyablePersistent) {
13573   LocalContext context;
13574   v8::Isolate* isolate = context->GetIsolate();
13575   i::GlobalHandles* globals =
13576       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13577   int initial_handles = globals->global_handles_count();
13578   typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
13579       CopyableObject;
13580   {
13581     CopyableObject handle1;
13582     {
13583       v8::HandleScope scope(isolate);
13584       handle1.Reset(isolate, v8::Object::New(isolate));
13585     }
13586     CHECK_EQ(initial_handles + 1, globals->global_handles_count());
13587     CopyableObject  handle2;
13588     handle2 = handle1;
13589     CHECK(handle1 == handle2);
13590     CHECK_EQ(initial_handles + 2, globals->global_handles_count());
13591     CopyableObject handle3(handle2);
13592     CHECK(handle1 == handle3);
13593     CHECK_EQ(initial_handles + 3, globals->global_handles_count());
13594   }
13595   // Verify autodispose
13596   CHECK_EQ(initial_handles, globals->global_handles_count());
13597 }
13598
13599
13600 static void WeakApiCallback(
13601     const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
13602   Local<Value> value = data.GetValue()->Get(v8_str("key"));
13603   CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
13604   data.GetParameter()->Reset();
13605   delete data.GetParameter();
13606 }
13607
13608
13609 TEST(WeakCallbackApi) {
13610   LocalContext context;
13611   v8::Isolate* isolate = context->GetIsolate();
13612   i::GlobalHandles* globals =
13613       reinterpret_cast<i::Isolate*>(isolate)->global_handles();
13614   int initial_handles = globals->global_handles_count();
13615   {
13616     v8::HandleScope scope(isolate);
13617     v8::Local<v8::Object> obj = v8::Object::New(isolate);
13618     obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
13619     v8::Persistent<v8::Object>* handle =
13620         new v8::Persistent<v8::Object>(isolate, obj);
13621     handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
13622                                                              WeakApiCallback);
13623   }
13624   reinterpret_cast<i::Isolate*>(isolate)->heap()->
13625       CollectAllGarbage(i::Heap::kNoGCFlags);
13626   // Verify disposed.
13627   CHECK_EQ(initial_handles, globals->global_handles_count());
13628 }
13629
13630
13631 v8::Persistent<v8::Object> some_object;
13632 v8::Persistent<v8::Object> bad_handle;
13633
13634 void NewPersistentHandleCallback(
13635     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13636   v8::HandleScope scope(data.GetIsolate());
13637   bad_handle.Reset(data.GetIsolate(), some_object);
13638   data.GetParameter()->Reset();
13639 }
13640
13641
13642 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
13643   LocalContext context;
13644   v8::Isolate* isolate = context->GetIsolate();
13645
13646   v8::Persistent<v8::Object> handle1, handle2;
13647   {
13648     v8::HandleScope scope(isolate);
13649     some_object.Reset(isolate, v8::Object::New(isolate));
13650     handle1.Reset(isolate, v8::Object::New(isolate));
13651     handle2.Reset(isolate, v8::Object::New(isolate));
13652   }
13653   // Note: order is implementation dependent alas: currently
13654   // global handle nodes are processed by PostGarbageCollectionProcessing
13655   // in reverse allocation order, so if second allocated handle is deleted,
13656   // weak callback of the first handle would be able to 'reallocate' it.
13657   handle1.SetWeak(&handle1, NewPersistentHandleCallback);
13658   handle2.Reset();
13659   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13660 }
13661
13662
13663 v8::Persistent<v8::Object> to_be_disposed;
13664
13665 void DisposeAndForceGcCallback(
13666     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13667   to_be_disposed.Reset();
13668   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13669   data.GetParameter()->Reset();
13670 }
13671
13672
13673 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
13674   LocalContext context;
13675   v8::Isolate* isolate = context->GetIsolate();
13676
13677   v8::Persistent<v8::Object> handle1, handle2;
13678   {
13679     v8::HandleScope scope(isolate);
13680     handle1.Reset(isolate, v8::Object::New(isolate));
13681     handle2.Reset(isolate, v8::Object::New(isolate));
13682   }
13683   handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
13684   to_be_disposed.Reset(isolate, handle2);
13685   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13686 }
13687
13688 void DisposingCallback(
13689     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13690   data.GetParameter()->Reset();
13691 }
13692
13693 void HandleCreatingCallback(
13694     const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
13695   v8::HandleScope scope(data.GetIsolate());
13696   v8::Persistent<v8::Object>(data.GetIsolate(),
13697                              v8::Object::New(data.GetIsolate()));
13698   data.GetParameter()->Reset();
13699 }
13700
13701
13702 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
13703   LocalContext context;
13704   v8::Isolate* isolate = context->GetIsolate();
13705
13706   v8::Persistent<v8::Object> handle1, handle2, handle3;
13707   {
13708     v8::HandleScope scope(isolate);
13709     handle3.Reset(isolate, v8::Object::New(isolate));
13710     handle2.Reset(isolate, v8::Object::New(isolate));
13711     handle1.Reset(isolate, v8::Object::New(isolate));
13712   }
13713   handle2.SetWeak(&handle2, DisposingCallback);
13714   handle3.SetWeak(&handle3, HandleCreatingCallback);
13715   CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
13716 }
13717
13718
13719 THREADED_TEST(CheckForCrossContextObjectLiterals) {
13720   v8::V8::Initialize();
13721
13722   const int nof = 2;
13723   const char* sources[nof] = {
13724     "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
13725     "Object()"
13726   };
13727
13728   for (int i = 0; i < nof; i++) {
13729     const char* source = sources[i];
13730     { v8::HandleScope scope(CcTest::isolate());
13731       LocalContext context;
13732       CompileRun(source);
13733     }
13734     { v8::HandleScope scope(CcTest::isolate());
13735       LocalContext context;
13736       CompileRun(source);
13737     }
13738   }
13739 }
13740
13741
13742 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
13743   v8::EscapableHandleScope inner(env->GetIsolate());
13744   env->Enter();
13745   v8::Local<Value> three = v8_num(3);
13746   v8::Local<Value> value = inner.Escape(three);
13747   env->Exit();
13748   return value;
13749 }
13750
13751
13752 THREADED_TEST(NestedHandleScopeAndContexts) {
13753   v8::Isolate* isolate = CcTest::isolate();
13754   v8::HandleScope outer(isolate);
13755   v8::Local<Context> env = Context::New(isolate);
13756   env->Enter();
13757   v8::Handle<Value> value = NestedScope(env);
13758   v8::Handle<String> str(value->ToString());
13759   CHECK(!str.IsEmpty());
13760   env->Exit();
13761 }
13762
13763
13764 static bool MatchPointers(void* key1, void* key2) {
13765   return key1 == key2;
13766 }
13767
13768
13769 struct SymbolInfo {
13770   size_t id;
13771   size_t size;
13772   std::string name;
13773 };
13774
13775
13776 class SetFunctionEntryHookTest {
13777  public:
13778   SetFunctionEntryHookTest() {
13779     CHECK(instance_ == NULL);
13780     instance_ = this;
13781   }
13782   ~SetFunctionEntryHookTest() {
13783     CHECK(instance_ == this);
13784     instance_ = NULL;
13785   }
13786   void Reset() {
13787     symbols_.clear();
13788     symbol_locations_.clear();
13789     invocations_.clear();
13790   }
13791   void RunTest();
13792   void OnJitEvent(const v8::JitCodeEvent* event);
13793   static void JitEvent(const v8::JitCodeEvent* event) {
13794     CHECK(instance_ != NULL);
13795     instance_->OnJitEvent(event);
13796   }
13797
13798   void OnEntryHook(uintptr_t function,
13799                    uintptr_t return_addr_location);
13800   static void EntryHook(uintptr_t function,
13801                         uintptr_t return_addr_location) {
13802     CHECK(instance_ != NULL);
13803     instance_->OnEntryHook(function, return_addr_location);
13804   }
13805
13806   static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
13807     CHECK(instance_ != NULL);
13808     args.GetReturnValue().Set(v8_num(42));
13809   }
13810   void RunLoopInNewEnv(v8::Isolate* isolate);
13811
13812   // Records addr as location of symbol.
13813   void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
13814
13815   // Finds the symbol containing addr
13816   SymbolInfo* FindSymbolForAddr(i::Address addr);
13817   // Returns the number of invocations where the caller name contains
13818   // \p caller_name and the function name contains \p function_name.
13819   int CountInvocations(const char* caller_name,
13820                        const char* function_name);
13821
13822   i::Handle<i::JSFunction> foo_func_;
13823   i::Handle<i::JSFunction> bar_func_;
13824
13825   typedef std::map<size_t, SymbolInfo> SymbolMap;
13826   typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
13827   typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
13828   SymbolMap symbols_;
13829   SymbolLocationMap symbol_locations_;
13830   InvocationMap invocations_;
13831
13832   static SetFunctionEntryHookTest* instance_;
13833 };
13834 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
13835
13836
13837 // Returns true if addr is in the range [start, start+len).
13838 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
13839   if (start <= addr && start + len > addr)
13840     return true;
13841
13842   return false;
13843 }
13844
13845 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
13846                                               SymbolInfo* symbol) {
13847   // Insert the symbol at the new location.
13848   SymbolLocationMap::iterator it =
13849       symbol_locations_.insert(std::make_pair(addr, symbol)).first;
13850   // Now erase symbols to the left and right that overlap this one.
13851   while (it != symbol_locations_.begin()) {
13852     SymbolLocationMap::iterator left = it;
13853     --left;
13854     if (!Overlaps(left->first, left->second->size, addr))
13855       break;
13856     symbol_locations_.erase(left);
13857   }
13858
13859   // Now erase symbols to the left and right that overlap this one.
13860   while (true) {
13861     SymbolLocationMap::iterator right = it;
13862     ++right;
13863     if (right == symbol_locations_.end())
13864         break;
13865     if (!Overlaps(addr, symbol->size, right->first))
13866       break;
13867     symbol_locations_.erase(right);
13868   }
13869 }
13870
13871
13872 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
13873   switch (event->type) {
13874     case v8::JitCodeEvent::CODE_ADDED: {
13875         CHECK(event->code_start != NULL);
13876         CHECK_NE(0, static_cast<int>(event->code_len));
13877         CHECK(event->name.str != NULL);
13878         size_t symbol_id = symbols_.size();
13879
13880         // Record the new symbol.
13881         SymbolInfo& info = symbols_[symbol_id];
13882         info.id = symbol_id;
13883         info.size = event->code_len;
13884         info.name.assign(event->name.str, event->name.str + event->name.len);
13885
13886         // And record it's location.
13887         InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
13888       }
13889       break;
13890
13891     case v8::JitCodeEvent::CODE_MOVED: {
13892         // We would like to never see code move that we haven't seen before,
13893         // but the code creation event does not happen until the line endings
13894         // have been calculated (this is so that we can report the line in the
13895         // script at which the function source is found, see
13896         // Compiler::RecordFunctionCompilation) and the line endings
13897         // calculations can cause a GC, which can move the newly created code
13898         // before its existence can be logged.
13899         SymbolLocationMap::iterator it(
13900             symbol_locations_.find(
13901                 reinterpret_cast<i::Address>(event->code_start)));
13902         if (it != symbol_locations_.end()) {
13903           // Found a symbol at this location, move it.
13904           SymbolInfo* info = it->second;
13905           symbol_locations_.erase(it);
13906           InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
13907                          info);
13908         }
13909       }
13910     default:
13911       break;
13912   }
13913 }
13914
13915 void SetFunctionEntryHookTest::OnEntryHook(
13916     uintptr_t function, uintptr_t return_addr_location) {
13917   // Get the function's code object.
13918   i::Code* function_code = i::Code::GetCodeFromTargetAddress(
13919       reinterpret_cast<i::Address>(function));
13920   CHECK(function_code != NULL);
13921
13922   // Then try and look up the caller's code object.
13923   i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
13924
13925   // Count the invocation.
13926   SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
13927   SymbolInfo* function_symbol =
13928       FindSymbolForAddr(reinterpret_cast<i::Address>(function));
13929   ++invocations_[std::make_pair(caller_symbol, function_symbol)];
13930
13931   if (!bar_func_.is_null() && function_code == bar_func_->code()) {
13932     // Check that we have a symbol for the "bar" function at the right location.
13933     SymbolLocationMap::iterator it(
13934         symbol_locations_.find(function_code->instruction_start()));
13935     CHECK(it != symbol_locations_.end());
13936   }
13937
13938   if (!foo_func_.is_null() && function_code == foo_func_->code()) {
13939     // Check that we have a symbol for "foo" at the right location.
13940     SymbolLocationMap::iterator it(
13941         symbol_locations_.find(function_code->instruction_start()));
13942     CHECK(it != symbol_locations_.end());
13943   }
13944 }
13945
13946
13947 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
13948   SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
13949   // Do we have a direct hit on a symbol?
13950   if (it != symbol_locations_.end()) {
13951     if (it->first == addr)
13952       return it->second;
13953   }
13954
13955   // If not a direct hit, it'll have to be the previous symbol.
13956   if (it == symbol_locations_.begin())
13957     return NULL;
13958
13959   --it;
13960   size_t offs = addr - it->first;
13961   if (offs < it->second->size)
13962     return it->second;
13963
13964   return NULL;
13965 }
13966
13967
13968 int SetFunctionEntryHookTest::CountInvocations(
13969     const char* caller_name, const char* function_name) {
13970   InvocationMap::iterator it(invocations_.begin());
13971   int invocations = 0;
13972   for (; it != invocations_.end(); ++it) {
13973     SymbolInfo* caller = it->first.first;
13974     SymbolInfo* function = it->first.second;
13975
13976     // Filter out non-matching functions.
13977     if (function_name != NULL) {
13978       if (function->name.find(function_name) == std::string::npos)
13979         continue;
13980     }
13981
13982     // Filter out non-matching callers.
13983     if (caller_name != NULL) {
13984       if (caller == NULL)
13985         continue;
13986       if (caller->name.find(caller_name) == std::string::npos)
13987         continue;
13988     }
13989
13990     // It matches add the invocation count to the tally.
13991     invocations += it->second;
13992   }
13993
13994   return invocations;
13995 }
13996
13997
13998 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
13999   v8::HandleScope outer(isolate);
14000   v8::Local<Context> env = Context::New(isolate);
14001   env->Enter();
14002
14003   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14004   t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14005   env->Global()->Set(v8_str("obj"), t->NewInstance());
14006
14007   const char* script =
14008       "function bar() {\n"
14009       "  var sum = 0;\n"
14010       "  for (i = 0; i < 100; ++i)\n"
14011       "    sum = foo(i);\n"
14012       "  return sum;\n"
14013       "}\n"
14014       "function foo(i) { return i * i; }\n"
14015       "// Invoke on the runtime function.\n"
14016       "obj.asdf()";
14017   CompileRun(script);
14018   bar_func_ = i::Handle<i::JSFunction>::cast(
14019           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14020   DCHECK(!bar_func_.is_null());
14021
14022   foo_func_ =
14023       i::Handle<i::JSFunction>::cast(
14024            v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14025   DCHECK(!foo_func_.is_null());
14026
14027   v8::Handle<v8::Value> value = CompileRun("bar();");
14028   CHECK(value->IsNumber());
14029   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14030
14031   // Test the optimized codegen path.
14032   value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14033                      "bar();");
14034   CHECK(value->IsNumber());
14035   CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14036
14037   env->Exit();
14038 }
14039
14040
14041 void SetFunctionEntryHookTest::RunTest() {
14042   // Work in a new isolate throughout.
14043   v8::Isolate* isolate = v8::Isolate::New();
14044
14045   // Test setting the entry hook on the new isolate.
14046   CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14047
14048   // Replacing the hook, once set should fail.
14049   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14050
14051   {
14052     v8::Isolate::Scope scope(isolate);
14053
14054     v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
14055
14056     RunLoopInNewEnv(isolate);
14057
14058     // Check the exepected invocation counts.
14059     CHECK_EQ(2, CountInvocations(NULL, "bar"));
14060     CHECK_EQ(200, CountInvocations("bar", "foo"));
14061     CHECK_EQ(200, CountInvocations(NULL, "foo"));
14062
14063     // Verify that we have an entry hook on some specific stubs.
14064     CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14065     CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14066     CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14067   }
14068   isolate->Dispose();
14069
14070   Reset();
14071
14072   // Make sure a second isolate is unaffected by the previous entry hook.
14073   isolate = v8::Isolate::New();
14074   {
14075     v8::Isolate::Scope scope(isolate);
14076
14077     // Reset the entry count to zero and set the entry hook.
14078     RunLoopInNewEnv(isolate);
14079
14080     // We should record no invocations in this isolate.
14081     CHECK_EQ(0, static_cast<int>(invocations_.size()));
14082   }
14083   // Since the isolate has been used, we shouldn't be able to set an entry
14084   // hook anymore.
14085   CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
14086
14087   isolate->Dispose();
14088 }
14089
14090
14091 TEST(SetFunctionEntryHook) {
14092   // FunctionEntryHook does not work well with experimental natives.
14093   // Experimental natives are compiled during snapshot deserialization.
14094   // This test breaks because InstallGetter (function from snapshot that
14095   // only gets called from experimental natives) is compiled with entry hooks.
14096   i::FLAG_allow_natives_syntax = true;
14097   i::FLAG_use_inlining = false;
14098
14099   SetFunctionEntryHookTest test;
14100   test.RunTest();
14101 }
14102
14103
14104 static i::HashMap* code_map = NULL;
14105 static i::HashMap* jitcode_line_info = NULL;
14106 static int saw_bar = 0;
14107 static int move_events = 0;
14108
14109
14110 static bool FunctionNameIs(const char* expected,
14111                            const v8::JitCodeEvent* event) {
14112   // Log lines for functions are of the general form:
14113   // "LazyCompile:<type><function_name>", where the type is one of
14114   // "*", "~" or "".
14115   static const char kPreamble[] = "LazyCompile:";
14116   static size_t kPreambleLen = sizeof(kPreamble) - 1;
14117
14118   if (event->name.len < sizeof(kPreamble) - 1 ||
14119       strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14120     return false;
14121   }
14122
14123   const char* tail = event->name.str + kPreambleLen;
14124   size_t tail_len = event->name.len - kPreambleLen;
14125   size_t expected_len = strlen(expected);
14126   if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14127     --tail_len;
14128     ++tail;
14129   }
14130
14131   // Check for tails like 'bar :1'.
14132   if (tail_len > expected_len + 2 &&
14133       tail[expected_len] == ' ' &&
14134       tail[expected_len + 1] == ':' &&
14135       tail[expected_len + 2] &&
14136       !strncmp(tail, expected, expected_len)) {
14137     return true;
14138   }
14139
14140   if (tail_len != expected_len)
14141     return false;
14142
14143   return strncmp(tail, expected, expected_len) == 0;
14144 }
14145
14146
14147 static void event_handler(const v8::JitCodeEvent* event) {
14148   CHECK(event != NULL);
14149   CHECK(code_map != NULL);
14150   CHECK(jitcode_line_info != NULL);
14151
14152   class DummyJitCodeLineInfo {
14153   };
14154
14155   switch (event->type) {
14156     case v8::JitCodeEvent::CODE_ADDED: {
14157         CHECK(event->code_start != NULL);
14158         CHECK_NE(0, static_cast<int>(event->code_len));
14159         CHECK(event->name.str != NULL);
14160         i::HashMap::Entry* entry =
14161             code_map->Lookup(event->code_start,
14162                              i::ComputePointerHash(event->code_start),
14163                              true);
14164         entry->value = reinterpret_cast<void*>(event->code_len);
14165
14166         if (FunctionNameIs("bar", event)) {
14167           ++saw_bar;
14168         }
14169       }
14170       break;
14171
14172     case v8::JitCodeEvent::CODE_MOVED: {
14173         uint32_t hash = i::ComputePointerHash(event->code_start);
14174         // We would like to never see code move that we haven't seen before,
14175         // but the code creation event does not happen until the line endings
14176         // have been calculated (this is so that we can report the line in the
14177         // script at which the function source is found, see
14178         // Compiler::RecordFunctionCompilation) and the line endings
14179         // calculations can cause a GC, which can move the newly created code
14180         // before its existence can be logged.
14181         i::HashMap::Entry* entry =
14182             code_map->Lookup(event->code_start, hash, false);
14183         if (entry != NULL) {
14184           ++move_events;
14185
14186           CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14187           code_map->Remove(event->code_start, hash);
14188
14189           entry = code_map->Lookup(event->new_code_start,
14190                                    i::ComputePointerHash(event->new_code_start),
14191                                    true);
14192           CHECK(entry != NULL);
14193           entry->value = reinterpret_cast<void*>(event->code_len);
14194         }
14195       }
14196       break;
14197
14198     case v8::JitCodeEvent::CODE_REMOVED:
14199       // Object/code removal events are currently not dispatched from the GC.
14200       CHECK(false);
14201       break;
14202
14203     // For CODE_START_LINE_INFO_RECORDING event, we will create one
14204     // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14205     // record it in jitcode_line_info.
14206     case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14207         DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14208         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14209         temp_event->user_data = line_info;
14210         i::HashMap::Entry* entry =
14211             jitcode_line_info->Lookup(line_info,
14212                                       i::ComputePointerHash(line_info),
14213                                       true);
14214         entry->value = reinterpret_cast<void*>(line_info);
14215       }
14216       break;
14217     // For these two events, we will check whether the event->user_data
14218     // data structure is created before during CODE_START_LINE_INFO_RECORDING
14219     // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14220     case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14221         CHECK(event->user_data != NULL);
14222         uint32_t hash = i::ComputePointerHash(event->user_data);
14223         i::HashMap::Entry* entry =
14224             jitcode_line_info->Lookup(event->user_data, hash, false);
14225         CHECK(entry != NULL);
14226         delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14227       }
14228       break;
14229
14230     case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14231         CHECK(event->user_data != NULL);
14232         uint32_t hash = i::ComputePointerHash(event->user_data);
14233         i::HashMap::Entry* entry =
14234             jitcode_line_info->Lookup(event->user_data, hash, false);
14235         CHECK(entry != NULL);
14236       }
14237       break;
14238
14239     default:
14240       // Impossible event.
14241       CHECK(false);
14242       break;
14243   }
14244 }
14245
14246
14247 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14248   i::FLAG_stress_compaction = true;
14249   i::FLAG_incremental_marking = false;
14250   if (i::FLAG_never_compact) return;
14251   const char* script =
14252     "function bar() {"
14253     "  var sum = 0;"
14254     "  for (i = 0; i < 100; ++i)"
14255     "    sum = foo(i);"
14256     "  return sum;"
14257     "}"
14258     "function foo(i) { return i * i; };"
14259     "bar();";
14260
14261   // Run this test in a new isolate to make sure we don't
14262   // have remnants of state from other code.
14263   v8::Isolate* isolate = v8::Isolate::New();
14264   isolate->Enter();
14265   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14266   i::Heap* heap = i_isolate->heap();
14267
14268   {
14269     v8::HandleScope scope(isolate);
14270     i::HashMap code(MatchPointers);
14271     code_map = &code;
14272
14273     i::HashMap lineinfo(MatchPointers);
14274     jitcode_line_info = &lineinfo;
14275
14276     saw_bar = 0;
14277     move_events = 0;
14278
14279     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14280
14281     // Generate new code objects sparsely distributed across several
14282     // different fragmented code-space pages.
14283     const int kIterations = 10;
14284     for (int i = 0; i < kIterations; ++i) {
14285       LocalContext env(isolate);
14286       i::AlwaysAllocateScope always_allocate(i_isolate);
14287       SimulateFullSpace(heap->code_space());
14288       CompileRun(script);
14289
14290       // Keep a strong reference to the code object in the handle scope.
14291       i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14292           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14293       i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14294           v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14295
14296       // Clear the compilation cache to get more wastage.
14297       reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14298     }
14299
14300     // Force code movement.
14301     heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14302
14303     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14304
14305     CHECK_LE(kIterations, saw_bar);
14306     CHECK_LT(0, move_events);
14307
14308     code_map = NULL;
14309     jitcode_line_info = NULL;
14310   }
14311
14312   isolate->Exit();
14313   isolate->Dispose();
14314
14315   // Do this in a new isolate.
14316   isolate = v8::Isolate::New();
14317   isolate->Enter();
14318
14319   // Verify that we get callbacks for existing code objects when we
14320   // request enumeration of existing code.
14321   {
14322     v8::HandleScope scope(isolate);
14323     LocalContext env(isolate);
14324     CompileRun(script);
14325
14326     // Now get code through initial iteration.
14327     i::HashMap code(MatchPointers);
14328     code_map = &code;
14329
14330     i::HashMap lineinfo(MatchPointers);
14331     jitcode_line_info = &lineinfo;
14332
14333     V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
14334     V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14335
14336     jitcode_line_info = NULL;
14337     // We expect that we got some events. Note that if we could get code removal
14338     // notifications, we could compare two collections, one created by listening
14339     // from the time of creation of an isolate, and the other by subscribing
14340     // with EnumExisting.
14341     CHECK_LT(0, code.occupancy());
14342
14343     code_map = NULL;
14344   }
14345
14346   isolate->Exit();
14347   isolate->Dispose();
14348 }
14349
14350
14351 THREADED_TEST(ExternalAllocatedMemory) {
14352   v8::Isolate* isolate = CcTest::isolate();
14353   v8::HandleScope outer(isolate);
14354   v8::Local<Context> env(Context::New(isolate));
14355   CHECK(!env.IsEmpty());
14356   const int64_t kSize = 1024*1024;
14357   int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14358   CHECK_EQ(baseline + kSize,
14359            isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14360   CHECK_EQ(baseline,
14361            isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14362 }
14363
14364
14365 // Regression test for issue 54, object templates with internal fields
14366 // but no accessors or interceptors did not get their internal field
14367 // count set on instances.
14368 THREADED_TEST(Regress54) {
14369   LocalContext context;
14370   v8::Isolate* isolate = context->GetIsolate();
14371   v8::HandleScope outer(isolate);
14372   static v8::Persistent<v8::ObjectTemplate> templ;
14373   if (templ.IsEmpty()) {
14374     v8::EscapableHandleScope inner(isolate);
14375     v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14376     local->SetInternalFieldCount(1);
14377     templ.Reset(isolate, inner.Escape(local));
14378   }
14379   v8::Handle<v8::Object> result =
14380       v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14381   CHECK_EQ(1, result->InternalFieldCount());
14382 }
14383
14384
14385 // If part of the threaded tests, this test makes ThreadingTest fail
14386 // on mac.
14387 TEST(CatchStackOverflow) {
14388   LocalContext context;
14389   v8::HandleScope scope(context->GetIsolate());
14390   v8::TryCatch try_catch;
14391   v8::Handle<v8::Value> result = CompileRun(
14392     "function f() {"
14393     "  return f();"
14394     "}"
14395     ""
14396     "f();");
14397   CHECK(result.IsEmpty());
14398 }
14399
14400
14401 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14402                                     const char* resource_name,
14403                                     int line_offset) {
14404   v8::HandleScope scope(CcTest::isolate());
14405   v8::TryCatch try_catch;
14406   v8::Handle<v8::Value> result = script->Run();
14407   CHECK(result.IsEmpty());
14408   CHECK(try_catch.HasCaught());
14409   v8::Handle<v8::Message> message = try_catch.Message();
14410   CHECK(!message.IsEmpty());
14411   CHECK_EQ(10 + line_offset, message->GetLineNumber());
14412   CHECK_EQ(91, message->GetStartPosition());
14413   CHECK_EQ(92, message->GetEndPosition());
14414   CHECK_EQ(2, message->GetStartColumn());
14415   CHECK_EQ(3, message->GetEndColumn());
14416   v8::String::Utf8Value line(message->GetSourceLine());
14417   CHECK_EQ("  throw 'nirk';", *line);
14418   v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14419   CHECK_EQ(resource_name, *name);
14420 }
14421
14422
14423 THREADED_TEST(TryCatchSourceInfo) {
14424   LocalContext context;
14425   v8::HandleScope scope(context->GetIsolate());
14426   v8::Local<v8::String> source = v8_str(
14427       "function Foo() {\n"
14428       "  return Bar();\n"
14429       "}\n"
14430       "\n"
14431       "function Bar() {\n"
14432       "  return Baz();\n"
14433       "}\n"
14434       "\n"
14435       "function Baz() {\n"
14436       "  throw 'nirk';\n"
14437       "}\n"
14438       "\n"
14439       "Foo();\n");
14440
14441   const char* resource_name;
14442   v8::Handle<v8::Script> script;
14443   resource_name = "test.js";
14444   script = CompileWithOrigin(source, resource_name);
14445   CheckTryCatchSourceInfo(script, resource_name, 0);
14446
14447   resource_name = "test1.js";
14448   v8::ScriptOrigin origin1(
14449       v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
14450   script = v8::Script::Compile(source, &origin1);
14451   CheckTryCatchSourceInfo(script, resource_name, 0);
14452
14453   resource_name = "test2.js";
14454   v8::ScriptOrigin origin2(
14455       v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
14456       v8::Integer::New(context->GetIsolate(), 7));
14457   script = v8::Script::Compile(source, &origin2);
14458   CheckTryCatchSourceInfo(script, resource_name, 7);
14459 }
14460
14461
14462 THREADED_TEST(CompilationCache) {
14463   LocalContext context;
14464   v8::HandleScope scope(context->GetIsolate());
14465   v8::Handle<v8::String> source0 =
14466       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14467   v8::Handle<v8::String> source1 =
14468       v8::String::NewFromUtf8(context->GetIsolate(), "1234");
14469   v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
14470   v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
14471   v8::Handle<v8::Script> script2 =
14472       v8::Script::Compile(source0);  // different origin
14473   CHECK_EQ(1234, script0->Run()->Int32Value());
14474   CHECK_EQ(1234, script1->Run()->Int32Value());
14475   CHECK_EQ(1234, script2->Run()->Int32Value());
14476 }
14477
14478
14479 static void FunctionNameCallback(
14480     const v8::FunctionCallbackInfo<v8::Value>& args) {
14481   ApiTestFuzzer::Fuzz();
14482   args.GetReturnValue().Set(v8_num(42));
14483 }
14484
14485
14486 THREADED_TEST(CallbackFunctionName) {
14487   LocalContext context;
14488   v8::Isolate* isolate = context->GetIsolate();
14489   v8::HandleScope scope(isolate);
14490   Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14491   t->Set(v8_str("asdf"),
14492          v8::FunctionTemplate::New(isolate, FunctionNameCallback));
14493   context->Global()->Set(v8_str("obj"), t->NewInstance());
14494   v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
14495   CHECK(value->IsString());
14496   v8::String::Utf8Value name(value);
14497   CHECK_EQ("asdf", *name);
14498 }
14499
14500
14501 THREADED_TEST(DateAccess) {
14502   LocalContext context;
14503   v8::HandleScope scope(context->GetIsolate());
14504   v8::Handle<v8::Value> date =
14505       v8::Date::New(context->GetIsolate(), 1224744689038.0);
14506   CHECK(date->IsDate());
14507   CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
14508 }
14509
14510
14511 void CheckProperties(v8::Isolate* isolate,
14512                      v8::Handle<v8::Value> val,
14513                      int elmc,
14514                      const char* elmv[]) {
14515   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14516   v8::Handle<v8::Array> props = obj->GetPropertyNames();
14517   CHECK_EQ(elmc, props->Length());
14518   for (int i = 0; i < elmc; i++) {
14519     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14520     CHECK_EQ(elmv[i], *elm);
14521   }
14522 }
14523
14524
14525 void CheckOwnProperties(v8::Isolate* isolate,
14526                         v8::Handle<v8::Value> val,
14527                         int elmc,
14528                         const char* elmv[]) {
14529   v8::Handle<v8::Object> obj = val.As<v8::Object>();
14530   v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
14531   CHECK_EQ(elmc, props->Length());
14532   for (int i = 0; i < elmc; i++) {
14533     v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
14534     CHECK_EQ(elmv[i], *elm);
14535   }
14536 }
14537
14538
14539 THREADED_TEST(PropertyEnumeration) {
14540   LocalContext context;
14541   v8::Isolate* isolate = context->GetIsolate();
14542   v8::HandleScope scope(isolate);
14543   v8::Handle<v8::Value> obj = CompileRun(
14544       "var result = [];"
14545       "result[0] = {};"
14546       "result[1] = {a: 1, b: 2};"
14547       "result[2] = [1, 2, 3];"
14548       "var proto = {x: 1, y: 2, z: 3};"
14549       "var x = { __proto__: proto, w: 0, z: 1 };"
14550       "result[3] = x;"
14551       "result;");
14552   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14553   CHECK_EQ(4, elms->Length());
14554   int elmc0 = 0;
14555   const char** elmv0 = NULL;
14556   CheckProperties(
14557       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14558   CheckOwnProperties(
14559       isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14560   int elmc1 = 2;
14561   const char* elmv1[] = {"a", "b"};
14562   CheckProperties(
14563       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14564   CheckOwnProperties(
14565       isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
14566   int elmc2 = 3;
14567   const char* elmv2[] = {"0", "1", "2"};
14568   CheckProperties(
14569       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14570   CheckOwnProperties(
14571       isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
14572   int elmc3 = 4;
14573   const char* elmv3[] = {"w", "z", "x", "y"};
14574   CheckProperties(
14575       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
14576   int elmc4 = 2;
14577   const char* elmv4[] = {"w", "z"};
14578   CheckOwnProperties(
14579       isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
14580 }
14581
14582
14583 THREADED_TEST(PropertyEnumeration2) {
14584   LocalContext context;
14585   v8::Isolate* isolate = context->GetIsolate();
14586   v8::HandleScope scope(isolate);
14587   v8::Handle<v8::Value> obj = CompileRun(
14588       "var result = [];"
14589       "result[0] = {};"
14590       "result[1] = {a: 1, b: 2};"
14591       "result[2] = [1, 2, 3];"
14592       "var proto = {x: 1, y: 2, z: 3};"
14593       "var x = { __proto__: proto, w: 0, z: 1 };"
14594       "result[3] = x;"
14595       "result;");
14596   v8::Handle<v8::Array> elms = obj.As<v8::Array>();
14597   CHECK_EQ(4, elms->Length());
14598   int elmc0 = 0;
14599   const char** elmv0 = NULL;
14600   CheckProperties(isolate,
14601                   elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
14602
14603   v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
14604   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
14605   CHECK_EQ(0, props->Length());
14606   for (uint32_t i = 0; i < props->Length(); i++) {
14607     printf("p[%d]\n", i);
14608   }
14609 }
14610
14611 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
14612                                   Local<Value> name,
14613                                   v8::AccessType type,
14614                                   Local<Value> data) {
14615   return type != v8::ACCESS_SET;
14616 }
14617
14618
14619 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
14620                                     uint32_t key,
14621                                     v8::AccessType type,
14622                                     Local<Value> data) {
14623   return type != v8::ACCESS_SET;
14624 }
14625
14626
14627 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
14628   LocalContext context;
14629   v8::Isolate* isolate = context->GetIsolate();
14630   v8::HandleScope scope(isolate);
14631   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14632   templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14633                                  IndexedSetAccessBlocker);
14634   templ->Set(v8_str("x"), v8::True(isolate));
14635   Local<v8::Object> instance = templ->NewInstance();
14636   context->Global()->Set(v8_str("obj"), instance);
14637   Local<Value> value = CompileRun("obj.x");
14638   CHECK(value->BooleanValue());
14639 }
14640
14641
14642 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
14643                                   Local<Value> name,
14644                                   v8::AccessType type,
14645                                   Local<Value> data) {
14646   return false;
14647 }
14648
14649
14650 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
14651                                     uint32_t key,
14652                                     v8::AccessType type,
14653                                     Local<Value> data) {
14654   return false;
14655 }
14656
14657
14658
14659 THREADED_TEST(AccessChecksReenabledCorrectly) {
14660   LocalContext context;
14661   v8::Isolate* isolate = context->GetIsolate();
14662   v8::HandleScope scope(isolate);
14663   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14664   templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14665                                  IndexedGetAccessBlocker);
14666   templ->Set(v8_str("a"), v8_str("a"));
14667   // Add more than 8 (see kMaxFastProperties) properties
14668   // so that the constructor will force copying map.
14669   // Cannot sprintf, gcc complains unsafety.
14670   char buf[4];
14671   for (char i = '0'; i <= '9' ; i++) {
14672     buf[0] = i;
14673     for (char j = '0'; j <= '9'; j++) {
14674       buf[1] = j;
14675       for (char k = '0'; k <= '9'; k++) {
14676         buf[2] = k;
14677         buf[3] = 0;
14678         templ->Set(v8_str(buf), v8::Number::New(isolate, k));
14679       }
14680     }
14681   }
14682
14683   Local<v8::Object> instance_1 = templ->NewInstance();
14684   context->Global()->Set(v8_str("obj_1"), instance_1);
14685
14686   Local<Value> value_1 = CompileRun("obj_1.a");
14687   CHECK(value_1.IsEmpty());
14688
14689   Local<v8::Object> instance_2 = templ->NewInstance();
14690   context->Global()->Set(v8_str("obj_2"), instance_2);
14691
14692   Local<Value> value_2 = CompileRun("obj_2.a");
14693   CHECK(value_2.IsEmpty());
14694 }
14695
14696
14697 // This tests that access check information remains on the global
14698 // object template when creating contexts.
14699 THREADED_TEST(AccessControlRepeatedContextCreation) {
14700   v8::Isolate* isolate = CcTest::isolate();
14701   v8::HandleScope handle_scope(isolate);
14702   v8::Handle<v8::ObjectTemplate> global_template =
14703       v8::ObjectTemplate::New(isolate);
14704   global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
14705                                            IndexedSetAccessBlocker);
14706   i::Handle<i::ObjectTemplateInfo> internal_template =
14707       v8::Utils::OpenHandle(*global_template);
14708   CHECK(!internal_template->constructor()->IsUndefined());
14709   i::Handle<i::FunctionTemplateInfo> constructor(
14710       i::FunctionTemplateInfo::cast(internal_template->constructor()));
14711   CHECK(!constructor->access_check_info()->IsUndefined());
14712   v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
14713   CHECK(!context0.IsEmpty());
14714   CHECK(!constructor->access_check_info()->IsUndefined());
14715 }
14716
14717
14718 THREADED_TEST(TurnOnAccessCheck) {
14719   v8::Isolate* isolate = CcTest::isolate();
14720   v8::HandleScope handle_scope(isolate);
14721
14722   // Create an environment with access check to the global object disabled by
14723   // default.
14724   v8::Handle<v8::ObjectTemplate> global_template =
14725       v8::ObjectTemplate::New(isolate);
14726   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
14727                                            IndexedGetAccessBlocker,
14728                                            v8::Handle<v8::Value>(),
14729                                            false);
14730   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14731   Context::Scope context_scope(context);
14732
14733   // Set up a property and a number of functions.
14734   context->Global()->Set(v8_str("a"), v8_num(1));
14735   CompileRun("function f1() {return a;}"
14736              "function f2() {return a;}"
14737              "function g1() {return h();}"
14738              "function g2() {return h();}"
14739              "function h() {return 1;}");
14740   Local<Function> f1 =
14741       Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14742   Local<Function> f2 =
14743       Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14744   Local<Function> g1 =
14745       Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14746   Local<Function> g2 =
14747       Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14748   Local<Function> h =
14749       Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14750
14751   // Get the global object.
14752   v8::Handle<v8::Object> global = context->Global();
14753
14754   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14755   // uses the runtime system to retreive property a whereas f2 uses global load
14756   // inline cache.
14757   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14758   for (int i = 0; i < 4; i++) {
14759     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14760   }
14761
14762   // Same for g1 and g2.
14763   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14764   for (int i = 0; i < 4; i++) {
14765     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14766   }
14767
14768   // Detach the global and turn on access check.
14769   Local<Object> hidden_global = Local<Object>::Cast(
14770       context->Global()->GetPrototype());
14771   context->DetachGlobal();
14772   hidden_global->TurnOnAccessCheck();
14773
14774   // Failing access check results in exception.
14775   CHECK(f1->Call(global, 0, NULL).IsEmpty());
14776   CHECK(f2->Call(global, 0, NULL).IsEmpty());
14777   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14778   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14779
14780   // No failing access check when just returning a constant.
14781   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14782 }
14783
14784
14785 static const char* kPropertyA = "a";
14786 static const char* kPropertyH = "h";
14787
14788 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
14789                                        Local<Value> name,
14790                                        v8::AccessType type,
14791                                        Local<Value> data) {
14792   if (!name->IsString()) return false;
14793   i::Handle<i::String> name_handle =
14794       v8::Utils::OpenHandle(String::Cast(*name));
14795   return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
14796       && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
14797 }
14798
14799
14800 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
14801   v8::Isolate* isolate = CcTest::isolate();
14802   v8::HandleScope handle_scope(isolate);
14803
14804   // Create an environment with access check to the global object disabled by
14805   // default. When the registered access checker will block access to properties
14806   // a and h.
14807   v8::Handle<v8::ObjectTemplate> global_template =
14808      v8::ObjectTemplate::New(isolate);
14809   global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
14810                                            IndexedGetAccessBlocker,
14811                                            v8::Handle<v8::Value>(),
14812                                            false);
14813   v8::Local<Context> context = Context::New(isolate, NULL, global_template);
14814   Context::Scope context_scope(context);
14815
14816   // Set up a property and a number of functions.
14817   context->Global()->Set(v8_str("a"), v8_num(1));
14818   static const char* source = "function f1() {return a;}"
14819                               "function f2() {return a;}"
14820                               "function g1() {return h();}"
14821                               "function g2() {return h();}"
14822                               "function h() {return 1;}";
14823
14824   CompileRun(source);
14825   Local<Function> f1;
14826   Local<Function> f2;
14827   Local<Function> g1;
14828   Local<Function> g2;
14829   Local<Function> h;
14830   f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
14831   f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
14832   g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
14833   g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
14834   h =  Local<Function>::Cast(context->Global()->Get(v8_str("h")));
14835
14836   // Get the global object.
14837   v8::Handle<v8::Object> global = context->Global();
14838
14839   // Call f1 one time and f2 a number of times. This will ensure that f1 still
14840   // uses the runtime system to retreive property a whereas f2 uses global load
14841   // inline cache.
14842   CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
14843   for (int i = 0; i < 4; i++) {
14844     CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
14845   }
14846
14847   // Same for g1 and g2.
14848   CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
14849   for (int i = 0; i < 4; i++) {
14850     CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
14851   }
14852
14853   // Detach the global and turn on access check now blocking access to property
14854   // a and function h.
14855   Local<Object> hidden_global = Local<Object>::Cast(
14856       context->Global()->GetPrototype());
14857   context->DetachGlobal();
14858   hidden_global->TurnOnAccessCheck();
14859
14860   // Failing access check results in exception.
14861   CHECK(f1->Call(global, 0, NULL).IsEmpty());
14862   CHECK(f2->Call(global, 0, NULL).IsEmpty());
14863   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14864   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14865
14866   // No failing access check when just returning a constant.
14867   CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
14868
14869   // Now compile the source again. And get the newly compiled functions, except
14870   // for h for which access is blocked.
14871   CompileRun(source);
14872   f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
14873   f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
14874   g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
14875   g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
14876   CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
14877
14878   // Failing access check results in exception.
14879   v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
14880   CHECK(result.IsEmpty());
14881   CHECK(f1->Call(global, 0, NULL).IsEmpty());
14882   CHECK(f2->Call(global, 0, NULL).IsEmpty());
14883   CHECK(g1->Call(global, 0, NULL).IsEmpty());
14884   CHECK(g2->Call(global, 0, NULL).IsEmpty());
14885 }
14886
14887
14888 // Tests that ScriptData can be serialized and deserialized.
14889 TEST(PreCompileSerialization) {
14890   v8::V8::Initialize();
14891   LocalContext env;
14892   v8::Isolate* isolate = env->GetIsolate();
14893   HandleScope handle_scope(isolate);
14894
14895   i::FLAG_min_preparse_length = 0;
14896   const char* script = "function foo(a) { return a+1; }";
14897   v8::ScriptCompiler::Source source(v8_str(script));
14898   v8::ScriptCompiler::Compile(isolate, &source,
14899                               v8::ScriptCompiler::kProduceParserCache);
14900   // Serialize.
14901   const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
14902   i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
14903   i::MemCopy(serialized_data, cd->data, cd->length);
14904
14905   // Deserialize.
14906   i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
14907
14908   // Verify that the original is the same as the deserialized.
14909   CHECK_EQ(cd->length, deserialized->length());
14910   CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
14911
14912   delete deserialized;
14913   i::DeleteArray(serialized_data);
14914 }
14915
14916
14917 // This tests that we do not allow dictionary load/call inline caches
14918 // to use functions that have not yet been compiled.  The potential
14919 // problem of loading a function that has not yet been compiled can
14920 // arise because we share code between contexts via the compilation
14921 // cache.
14922 THREADED_TEST(DictionaryICLoadedFunction) {
14923   v8::HandleScope scope(CcTest::isolate());
14924   // Test LoadIC.
14925   for (int i = 0; i < 2; i++) {
14926     LocalContext context;
14927     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14928     context->Global()->Delete(v8_str("tmp"));
14929     CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
14930   }
14931   // Test CallIC.
14932   for (int i = 0; i < 2; i++) {
14933     LocalContext context;
14934     context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
14935     context->Global()->Delete(v8_str("tmp"));
14936     CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
14937   }
14938 }
14939
14940
14941 // Test that cross-context new calls use the context of the callee to
14942 // create the new JavaScript object.
14943 THREADED_TEST(CrossContextNew) {
14944   v8::Isolate* isolate = CcTest::isolate();
14945   v8::HandleScope scope(isolate);
14946   v8::Local<Context> context0 = Context::New(isolate);
14947   v8::Local<Context> context1 = Context::New(isolate);
14948
14949   // Allow cross-domain access.
14950   Local<String> token = v8_str("<security token>");
14951   context0->SetSecurityToken(token);
14952   context1->SetSecurityToken(token);
14953
14954   // Set an 'x' property on the Object prototype and define a
14955   // constructor function in context0.
14956   context0->Enter();
14957   CompileRun("Object.prototype.x = 42; function C() {};");
14958   context0->Exit();
14959
14960   // Call the constructor function from context0 and check that the
14961   // result has the 'x' property.
14962   context1->Enter();
14963   context1->Global()->Set(v8_str("other"), context0->Global());
14964   Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
14965   CHECK(value->IsInt32());
14966   CHECK_EQ(42, value->Int32Value());
14967   context1->Exit();
14968 }
14969
14970
14971 // Verify that we can clone an object
14972 TEST(ObjectClone) {
14973   LocalContext env;
14974   v8::Isolate* isolate = env->GetIsolate();
14975   v8::HandleScope scope(isolate);
14976
14977   const char* sample =
14978     "var rv = {};"      \
14979     "rv.alpha = 'hello';" \
14980     "rv.beta = 123;"     \
14981     "rv;";
14982
14983   // Create an object, verify basics.
14984   Local<Value> val = CompileRun(sample);
14985   CHECK(val->IsObject());
14986   Local<v8::Object> obj = val.As<v8::Object>();
14987   obj->Set(v8_str("gamma"), v8_str("cloneme"));
14988
14989   CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14990   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
14991   CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14992
14993   // Clone it.
14994   Local<v8::Object> clone = obj->Clone();
14995   CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14996   CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
14997   CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14998
14999   // Set a property on the clone, verify each object.
15000   clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15001   CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15002   CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15003 }
15004
15005
15006 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
15007  public:
15008   explicit AsciiVectorResource(i::Vector<const char> vector)
15009       : data_(vector) {}
15010   virtual ~AsciiVectorResource() {}
15011   virtual size_t length() const { return data_.length(); }
15012   virtual const char* data() const { return data_.start(); }
15013  private:
15014   i::Vector<const char> data_;
15015 };
15016
15017
15018 class UC16VectorResource : public v8::String::ExternalStringResource {
15019  public:
15020   explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15021       : data_(vector) {}
15022   virtual ~UC16VectorResource() {}
15023   virtual size_t length() const { return data_.length(); }
15024   virtual const i::uc16* data() const { return data_.start(); }
15025  private:
15026   i::Vector<const i::uc16> data_;
15027 };
15028
15029
15030 static void MorphAString(i::String* string,
15031                          AsciiVectorResource* ascii_resource,
15032                          UC16VectorResource* uc16_resource) {
15033   CHECK(i::StringShape(string).IsExternal());
15034   if (string->IsOneByteRepresentation()) {
15035     // Check old map is not internalized or long.
15036     CHECK(string->map() == CcTest::heap()->external_ascii_string_map());
15037     // Morph external string to be TwoByte string.
15038     string->set_map(CcTest::heap()->external_string_map());
15039     i::ExternalTwoByteString* morphed =
15040          i::ExternalTwoByteString::cast(string);
15041     morphed->set_resource(uc16_resource);
15042   } else {
15043     // Check old map is not internalized or long.
15044     CHECK(string->map() == CcTest::heap()->external_string_map());
15045     // Morph external string to be ASCII string.
15046     string->set_map(CcTest::heap()->external_ascii_string_map());
15047     i::ExternalAsciiString* morphed =
15048          i::ExternalAsciiString::cast(string);
15049     morphed->set_resource(ascii_resource);
15050   }
15051 }
15052
15053
15054 // Test that we can still flatten a string if the components it is built up
15055 // from have been turned into 16 bit strings in the mean time.
15056 THREADED_TEST(MorphCompositeStringTest) {
15057   char utf_buffer[129];
15058   const char* c_string = "Now is the time for all good men"
15059                          " to come to the aid of the party";
15060   uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15061   {
15062     LocalContext env;
15063     i::Factory* factory = CcTest::i_isolate()->factory();
15064     v8::HandleScope scope(env->GetIsolate());
15065     AsciiVectorResource ascii_resource(
15066         i::Vector<const char>(c_string, i::StrLength(c_string)));
15067     UC16VectorResource uc16_resource(
15068         i::Vector<const uint16_t>(two_byte_string,
15069                                   i::StrLength(c_string)));
15070
15071     Local<String> lhs(v8::Utils::ToLocal(
15072         factory->NewExternalStringFromAscii(&ascii_resource)
15073             .ToHandleChecked()));
15074     Local<String> rhs(v8::Utils::ToLocal(
15075         factory->NewExternalStringFromAscii(&ascii_resource)
15076             .ToHandleChecked()));
15077
15078     env->Global()->Set(v8_str("lhs"), lhs);
15079     env->Global()->Set(v8_str("rhs"), rhs);
15080
15081     CompileRun(
15082         "var cons = lhs + rhs;"
15083         "var slice = lhs.substring(1, lhs.length - 1);"
15084         "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15085
15086     CHECK(lhs->IsOneByte());
15087     CHECK(rhs->IsOneByte());
15088
15089     MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
15090     MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
15091
15092     // This should UTF-8 without flattening, since everything is ASCII.
15093     Handle<String> cons = v8_compile("cons")->Run().As<String>();
15094     CHECK_EQ(128, cons->Utf8Length());
15095     int nchars = -1;
15096     CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15097     CHECK_EQ(128, nchars);
15098     CHECK_EQ(0, strcmp(
15099         utf_buffer,
15100         "Now is the time for all good men to come to the aid of the party"
15101         "Now is the time for all good men to come to the aid of the party"));
15102
15103     // Now do some stuff to make sure the strings are flattened, etc.
15104     CompileRun(
15105         "/[^a-z]/.test(cons);"
15106         "/[^a-z]/.test(slice);"
15107         "/[^a-z]/.test(slice_on_cons);");
15108     const char* expected_cons =
15109         "Now is the time for all good men to come to the aid of the party"
15110         "Now is the time for all good men to come to the aid of the party";
15111     const char* expected_slice =
15112         "ow is the time for all good men to come to the aid of the part";
15113     const char* expected_slice_on_cons =
15114         "ow is the time for all good men to come to the aid of the party"
15115         "Now is the time for all good men to come to the aid of the part";
15116     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15117              env->Global()->Get(v8_str("cons")));
15118     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15119              env->Global()->Get(v8_str("slice")));
15120     CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15121              env->Global()->Get(v8_str("slice_on_cons")));
15122   }
15123   i::DeleteArray(two_byte_string);
15124 }
15125
15126
15127 TEST(CompileExternalTwoByteSource) {
15128   LocalContext context;
15129   v8::HandleScope scope(context->GetIsolate());
15130
15131   // This is a very short list of sources, which currently is to check for a
15132   // regression caused by r2703.
15133   const char* ascii_sources[] = {
15134     "0.5",
15135     "-0.5",   // This mainly testes PushBack in the Scanner.
15136     "--0.5",  // This mainly testes PushBack in the Scanner.
15137     NULL
15138   };
15139
15140   // Compile the sources as external two byte strings.
15141   for (int i = 0; ascii_sources[i] != NULL; i++) {
15142     uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
15143     TestResource* uc16_resource = new TestResource(two_byte_string);
15144     v8::Local<v8::String> source =
15145         v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15146     v8::Script::Compile(source);
15147   }
15148 }
15149
15150
15151 #ifndef V8_INTERPRETED_REGEXP
15152
15153 struct RegExpInterruptionData {
15154   int loop_count;
15155   UC16VectorResource* string_resource;
15156   v8::Persistent<v8::String> string;
15157 } regexp_interruption_data;
15158
15159
15160 class RegExpInterruptionThread : public v8::base::Thread {
15161  public:
15162   explicit RegExpInterruptionThread(v8::Isolate* isolate)
15163       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15164
15165   virtual void Run() {
15166     for (regexp_interruption_data.loop_count = 0;
15167          regexp_interruption_data.loop_count < 7;
15168          regexp_interruption_data.loop_count++) {
15169       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
15170       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15171     }
15172     v8::base::OS::Sleep(50);  // Wait a bit before terminating.
15173     v8::V8::TerminateExecution(isolate_);
15174   }
15175
15176  private:
15177   v8::Isolate* isolate_;
15178 };
15179
15180
15181 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15182   if (regexp_interruption_data.loop_count != 2) return;
15183   v8::HandleScope scope(CcTest::isolate());
15184   v8::Local<v8::String> string = v8::Local<v8::String>::New(
15185       CcTest::isolate(), regexp_interruption_data.string);
15186   string->MakeExternal(regexp_interruption_data.string_resource);
15187 }
15188
15189
15190 // Test that RegExp execution can be interrupted.  Specifically, we test
15191 // * interrupting with GC
15192 // * turn the subject string from one-byte internal to two-byte external string
15193 // * force termination
15194 TEST(RegExpInterruption) {
15195   v8::HandleScope scope(CcTest::isolate());
15196   LocalContext env;
15197
15198   RegExpInterruptionThread timeout_thread(CcTest::isolate());
15199
15200   v8::V8::AddGCPrologueCallback(RunBeforeGC);
15201   static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15202   i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
15203   v8::Local<v8::String> string = v8_str(ascii_content);
15204
15205   CcTest::global()->Set(v8_str("a"), string);
15206   regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15207   regexp_interruption_data.string_resource = new UC16VectorResource(
15208       i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
15209
15210   v8::TryCatch try_catch;
15211   timeout_thread.Start();
15212
15213   CompileRun("/((a*)*)*b/.exec(a)");
15214   CHECK(try_catch.HasTerminated());
15215
15216   timeout_thread.Join();
15217
15218   regexp_interruption_data.string.Reset();
15219   i::DeleteArray(uc16_content);
15220 }
15221
15222 #endif  // V8_INTERPRETED_REGEXP
15223
15224
15225 // Test that we cannot set a property on the global object if there
15226 // is a read-only property in the prototype chain.
15227 TEST(ReadOnlyPropertyInGlobalProto) {
15228   v8::Isolate* isolate = CcTest::isolate();
15229   v8::HandleScope scope(isolate);
15230   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15231   LocalContext context(0, templ);
15232   v8::Handle<v8::Object> global = context->Global();
15233   v8::Handle<v8::Object> global_proto =
15234       v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15235   global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15236                          v8::ReadOnly);
15237   global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15238                          v8::ReadOnly);
15239   // Check without 'eval' or 'with'.
15240   v8::Handle<v8::Value> res =
15241       CompileRun("function f() { x = 42; return x; }; f()");
15242   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15243   // Check with 'eval'.
15244   res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15245   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15246   // Check with 'with'.
15247   res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15248   CHECK_EQ(v8::Integer::New(isolate, 0), res);
15249 }
15250
15251 static int force_set_set_count = 0;
15252 static int force_set_get_count = 0;
15253 bool pass_on_get = false;
15254
15255 static void ForceSetGetter(v8::Local<v8::String> name,
15256                            const v8::PropertyCallbackInfo<v8::Value>& info) {
15257   force_set_get_count++;
15258   if (pass_on_get) {
15259     return;
15260   }
15261   info.GetReturnValue().Set(3);
15262 }
15263
15264 static void ForceSetSetter(v8::Local<v8::String> name,
15265                            v8::Local<v8::Value> value,
15266                            const v8::PropertyCallbackInfo<void>& info) {
15267   force_set_set_count++;
15268 }
15269
15270 static void ForceSetInterceptSetter(
15271     v8::Local<v8::String> name,
15272     v8::Local<v8::Value> value,
15273     const v8::PropertyCallbackInfo<v8::Value>& info) {
15274   force_set_set_count++;
15275   info.GetReturnValue().SetUndefined();
15276 }
15277
15278
15279 TEST(ForceSet) {
15280   force_set_get_count = 0;
15281   force_set_set_count = 0;
15282   pass_on_get = false;
15283
15284   v8::Isolate* isolate = CcTest::isolate();
15285   v8::HandleScope scope(isolate);
15286   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15287   v8::Handle<v8::String> access_property =
15288       v8::String::NewFromUtf8(isolate, "a");
15289   templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15290   LocalContext context(NULL, templ);
15291   v8::Handle<v8::Object> global = context->Global();
15292
15293   // Ordinary properties
15294   v8::Handle<v8::String> simple_property =
15295       v8::String::NewFromUtf8(isolate, "p");
15296   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15297   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15298   // This should fail because the property is read-only
15299   global->Set(simple_property, v8::Int32::New(isolate, 5));
15300   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15301   // This should succeed even though the property is read-only
15302   global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15303   CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15304
15305   // Accessors
15306   CHECK_EQ(0, force_set_set_count);
15307   CHECK_EQ(0, force_set_get_count);
15308   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15309   // CHECK_EQ the property shouldn't override it, just call the setter
15310   // which in this case does nothing.
15311   global->Set(access_property, v8::Int32::New(isolate, 7));
15312   CHECK_EQ(3, global->Get(access_property)->Int32Value());
15313   CHECK_EQ(1, force_set_set_count);
15314   CHECK_EQ(2, force_set_get_count);
15315   // Forcing the property to be set should override the accessor without
15316   // calling it
15317   global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15318   CHECK_EQ(8, global->Get(access_property)->Int32Value());
15319   CHECK_EQ(1, force_set_set_count);
15320   CHECK_EQ(2, force_set_get_count);
15321 }
15322
15323
15324 TEST(ForceSetWithInterceptor) {
15325   force_set_get_count = 0;
15326   force_set_set_count = 0;
15327   pass_on_get = false;
15328
15329   v8::Isolate* isolate = CcTest::isolate();
15330   v8::HandleScope scope(isolate);
15331   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15332   templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15333   LocalContext context(NULL, templ);
15334   v8::Handle<v8::Object> global = context->Global();
15335
15336   v8::Handle<v8::String> some_property =
15337       v8::String::NewFromUtf8(isolate, "a");
15338   CHECK_EQ(0, force_set_set_count);
15339   CHECK_EQ(0, force_set_get_count);
15340   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15341   // Setting the property shouldn't override it, just call the setter
15342   // which in this case does nothing.
15343   global->Set(some_property, v8::Int32::New(isolate, 7));
15344   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15345   CHECK_EQ(1, force_set_set_count);
15346   CHECK_EQ(2, force_set_get_count);
15347   // Getting the property when the interceptor returns an empty handle
15348   // should yield undefined, since the property isn't present on the
15349   // object itself yet.
15350   pass_on_get = true;
15351   CHECK(global->Get(some_property)->IsUndefined());
15352   CHECK_EQ(1, force_set_set_count);
15353   CHECK_EQ(3, force_set_get_count);
15354   // Forcing the property to be set should cause the value to be
15355   // set locally without calling the interceptor.
15356   global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15357   CHECK_EQ(8, global->Get(some_property)->Int32Value());
15358   CHECK_EQ(1, force_set_set_count);
15359   CHECK_EQ(4, force_set_get_count);
15360   // Reenabling the interceptor should cause it to take precedence over
15361   // the property
15362   pass_on_get = false;
15363   CHECK_EQ(3, global->Get(some_property)->Int32Value());
15364   CHECK_EQ(1, force_set_set_count);
15365   CHECK_EQ(5, force_set_get_count);
15366   // The interceptor should also work for other properties
15367   CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15368                   ->Int32Value());
15369   CHECK_EQ(1, force_set_set_count);
15370   CHECK_EQ(6, force_set_get_count);
15371 }
15372
15373
15374 THREADED_TEST(ForceDelete) {
15375   v8::Isolate* isolate = CcTest::isolate();
15376   v8::HandleScope scope(isolate);
15377   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15378   LocalContext context(NULL, templ);
15379   v8::Handle<v8::Object> global = context->Global();
15380
15381   // Ordinary properties
15382   v8::Handle<v8::String> simple_property =
15383       v8::String::NewFromUtf8(isolate, "p");
15384   global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15385   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15386   // This should fail because the property is dont-delete.
15387   CHECK(!global->Delete(simple_property));
15388   CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15389   // This should succeed even though the property is dont-delete.
15390   CHECK(global->ForceDelete(simple_property));
15391   CHECK(global->Get(simple_property)->IsUndefined());
15392 }
15393
15394
15395 static int force_delete_interceptor_count = 0;
15396 static bool pass_on_delete = false;
15397
15398
15399 static void ForceDeleteDeleter(
15400     v8::Local<v8::String> name,
15401     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15402   force_delete_interceptor_count++;
15403   if (pass_on_delete) return;
15404   info.GetReturnValue().Set(true);
15405 }
15406
15407
15408 THREADED_TEST(ForceDeleteWithInterceptor) {
15409   force_delete_interceptor_count = 0;
15410   pass_on_delete = false;
15411
15412   v8::Isolate* isolate = CcTest::isolate();
15413   v8::HandleScope scope(isolate);
15414   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15415   templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15416   LocalContext context(NULL, templ);
15417   v8::Handle<v8::Object> global = context->Global();
15418
15419   v8::Handle<v8::String> some_property =
15420       v8::String::NewFromUtf8(isolate, "a");
15421   global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15422                    v8::DontDelete);
15423
15424   // Deleting a property should get intercepted and nothing should
15425   // happen.
15426   CHECK_EQ(0, force_delete_interceptor_count);
15427   CHECK(global->Delete(some_property));
15428   CHECK_EQ(1, force_delete_interceptor_count);
15429   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15430   // Deleting the property when the interceptor returns an empty
15431   // handle should not delete the property since it is DontDelete.
15432   pass_on_delete = true;
15433   CHECK(!global->Delete(some_property));
15434   CHECK_EQ(2, force_delete_interceptor_count);
15435   CHECK_EQ(42, global->Get(some_property)->Int32Value());
15436   // Forcing the property to be deleted should delete the value
15437   // without calling the interceptor.
15438   CHECK(global->ForceDelete(some_property));
15439   CHECK(global->Get(some_property)->IsUndefined());
15440   CHECK_EQ(2, force_delete_interceptor_count);
15441 }
15442
15443
15444 // Make sure that forcing a delete invalidates any IC stubs, so we
15445 // don't read the hole value.
15446 THREADED_TEST(ForceDeleteIC) {
15447   LocalContext context;
15448   v8::HandleScope scope(context->GetIsolate());
15449   // Create a DontDelete variable on the global object.
15450   CompileRun("this.__proto__ = { foo: 'horse' };"
15451              "var foo = 'fish';"
15452              "function f() { return foo.length; }");
15453   // Initialize the IC for foo in f.
15454   CompileRun("for (var i = 0; i < 4; i++) f();");
15455   // Make sure the value of foo is correct before the deletion.
15456   CHECK_EQ(4, CompileRun("f()")->Int32Value());
15457   // Force the deletion of foo.
15458   CHECK(context->Global()->ForceDelete(v8_str("foo")));
15459   // Make sure the value for foo is read from the prototype, and that
15460   // we don't get in trouble with reading the deleted cell value
15461   // sentinel.
15462   CHECK_EQ(5, CompileRun("f()")->Int32Value());
15463 }
15464
15465
15466 TEST(InlinedFunctionAcrossContexts) {
15467   i::FLAG_allow_natives_syntax = true;
15468   v8::Isolate* isolate = CcTest::isolate();
15469   v8::HandleScope outer_scope(isolate);
15470   v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
15471   v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
15472   ctx1->Enter();
15473
15474   {
15475     v8::HandleScope inner_scope(CcTest::isolate());
15476     CompileRun("var G = 42; function foo() { return G; }");
15477     v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
15478     ctx2->Enter();
15479     ctx2->Global()->Set(v8_str("o"), foo);
15480     v8::Local<v8::Value> res = CompileRun(
15481         "function f() { return o(); }"
15482         "for (var i = 0; i < 10; ++i) f();"
15483         "%OptimizeFunctionOnNextCall(f);"
15484         "f();");
15485     CHECK_EQ(42, res->Int32Value());
15486     ctx2->Exit();
15487     v8::Handle<v8::String> G_property =
15488         v8::String::NewFromUtf8(CcTest::isolate(), "G");
15489     CHECK(ctx1->Global()->ForceDelete(G_property));
15490     ctx2->Enter();
15491     ExpectString(
15492         "(function() {"
15493         "  try {"
15494         "    return f();"
15495         "  } catch(e) {"
15496         "    return e.toString();"
15497         "  }"
15498         " })()",
15499         "ReferenceError: G is not defined");
15500     ctx2->Exit();
15501     ctx1->Exit();
15502   }
15503 }
15504
15505
15506 static v8::Local<Context> calling_context0;
15507 static v8::Local<Context> calling_context1;
15508 static v8::Local<Context> calling_context2;
15509
15510
15511 // Check that the call to the callback is initiated in
15512 // calling_context2, the directly calling context is calling_context1
15513 // and the callback itself is in calling_context0.
15514 static void GetCallingContextCallback(
15515     const v8::FunctionCallbackInfo<v8::Value>& args) {
15516   ApiTestFuzzer::Fuzz();
15517   CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
15518   CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
15519   CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
15520   args.GetReturnValue().Set(42);
15521 }
15522
15523
15524 THREADED_TEST(GetCurrentContextWhenNotInContext) {
15525   i::Isolate* isolate = CcTest::i_isolate();
15526   CHECK(isolate != NULL);
15527   CHECK(isolate->context() == NULL);
15528   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
15529   v8::HandleScope scope(v8_isolate);
15530   // The following should not crash, but return an empty handle.
15531   v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
15532   CHECK(current.IsEmpty());
15533 }
15534
15535
15536 THREADED_TEST(GetCallingContext) {
15537   v8::Isolate* isolate = CcTest::isolate();
15538   v8::HandleScope scope(isolate);
15539
15540   Local<Context> calling_context0(Context::New(isolate));
15541   Local<Context> calling_context1(Context::New(isolate));
15542   Local<Context> calling_context2(Context::New(isolate));
15543   ::calling_context0 = calling_context0;
15544   ::calling_context1 = calling_context1;
15545   ::calling_context2 = calling_context2;
15546
15547   // Allow cross-domain access.
15548   Local<String> token = v8_str("<security token>");
15549   calling_context0->SetSecurityToken(token);
15550   calling_context1->SetSecurityToken(token);
15551   calling_context2->SetSecurityToken(token);
15552
15553   // Create an object with a C++ callback in context0.
15554   calling_context0->Enter();
15555   Local<v8::FunctionTemplate> callback_templ =
15556       v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
15557   calling_context0->Global()->Set(v8_str("callback"),
15558                                   callback_templ->GetFunction());
15559   calling_context0->Exit();
15560
15561   // Expose context0 in context1 and set up a function that calls the
15562   // callback function.
15563   calling_context1->Enter();
15564   calling_context1->Global()->Set(v8_str("context0"),
15565                                   calling_context0->Global());
15566   CompileRun("function f() { context0.callback() }");
15567   calling_context1->Exit();
15568
15569   // Expose context1 in context2 and call the callback function in
15570   // context0 indirectly through f in context1.
15571   calling_context2->Enter();
15572   calling_context2->Global()->Set(v8_str("context1"),
15573                                   calling_context1->Global());
15574   CompileRun("context1.f()");
15575   calling_context2->Exit();
15576   ::calling_context0.Clear();
15577   ::calling_context1.Clear();
15578   ::calling_context2.Clear();
15579 }
15580
15581
15582 // Check that a variable declaration with no explicit initialization
15583 // value does shadow an existing property in the prototype chain.
15584 THREADED_TEST(InitGlobalVarInProtoChain) {
15585   LocalContext context;
15586   v8::HandleScope scope(context->GetIsolate());
15587   // Introduce a variable in the prototype chain.
15588   CompileRun("__proto__.x = 42");
15589   v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
15590   CHECK(!result->IsUndefined());
15591   CHECK_EQ(43, result->Int32Value());
15592 }
15593
15594
15595 // Regression test for issue 398.
15596 // If a function is added to an object, creating a constant function
15597 // field, and the result is cloned, replacing the constant function on the
15598 // original should not affect the clone.
15599 // See http://code.google.com/p/v8/issues/detail?id=398
15600 THREADED_TEST(ReplaceConstantFunction) {
15601   LocalContext context;
15602   v8::Isolate* isolate = context->GetIsolate();
15603   v8::HandleScope scope(isolate);
15604   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
15605   v8::Handle<v8::FunctionTemplate> func_templ =
15606       v8::FunctionTemplate::New(isolate);
15607   v8::Handle<v8::String> foo_string =
15608       v8::String::NewFromUtf8(isolate, "foo");
15609   obj->Set(foo_string, func_templ->GetFunction());
15610   v8::Handle<v8::Object> obj_clone = obj->Clone();
15611   obj_clone->Set(foo_string,
15612                  v8::String::NewFromUtf8(isolate, "Hello"));
15613   CHECK(!obj->Get(foo_string)->IsUndefined());
15614 }
15615
15616
15617 static void CheckElementValue(i::Isolate* isolate,
15618                               int expected,
15619                               i::Handle<i::Object> obj,
15620                               int offset) {
15621   i::Object* element =
15622       *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
15623   CHECK_EQ(expected, i::Smi::cast(element)->value());
15624 }
15625
15626
15627 THREADED_TEST(PixelArray) {
15628   LocalContext context;
15629   i::Isolate* isolate = CcTest::i_isolate();
15630   i::Factory* factory = isolate->factory();
15631   v8::HandleScope scope(context->GetIsolate());
15632   const int kElementCount = 260;
15633   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15634   i::Handle<i::ExternalUint8ClampedArray> pixels =
15635       i::Handle<i::ExternalUint8ClampedArray>::cast(
15636           factory->NewExternalArray(kElementCount,
15637                                     v8::kExternalUint8ClampedArray,
15638                                     pixel_data));
15639   // Force GC to trigger verification.
15640   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15641   for (int i = 0; i < kElementCount; i++) {
15642     pixels->set(i, i % 256);
15643   }
15644   // Force GC to trigger verification.
15645   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
15646   for (int i = 0; i < kElementCount; i++) {
15647     CHECK_EQ(i % 256, pixels->get_scalar(i));
15648     CHECK_EQ(i % 256, pixel_data[i]);
15649   }
15650
15651   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
15652   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15653   // Set the elements to be the pixels.
15654   // jsobj->set_elements(*pixels);
15655   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15656   CheckElementValue(isolate, 1, jsobj, 1);
15657   obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
15658   context->Global()->Set(v8_str("pixels"), obj);
15659   v8::Handle<v8::Value> result = CompileRun("pixels.field");
15660   CHECK_EQ(1503, result->Int32Value());
15661   result = CompileRun("pixels[1]");
15662   CHECK_EQ(1, result->Int32Value());
15663
15664   result = CompileRun("var sum = 0;"
15665                       "for (var i = 0; i < 8; i++) {"
15666                       "  sum += pixels[i] = pixels[i] = -i;"
15667                       "}"
15668                       "sum;");
15669   CHECK_EQ(-28, result->Int32Value());
15670
15671   result = CompileRun("var sum = 0;"
15672                       "for (var i = 0; i < 8; i++) {"
15673                       "  sum += pixels[i] = pixels[i] = 0;"
15674                       "}"
15675                       "sum;");
15676   CHECK_EQ(0, result->Int32Value());
15677
15678   result = CompileRun("var sum = 0;"
15679                       "for (var i = 0; i < 8; i++) {"
15680                       "  sum += pixels[i] = pixels[i] = 255;"
15681                       "}"
15682                       "sum;");
15683   CHECK_EQ(8 * 255, result->Int32Value());
15684
15685   result = CompileRun("var sum = 0;"
15686                       "for (var i = 0; i < 8; i++) {"
15687                       "  sum += pixels[i] = pixels[i] = 256 + i;"
15688                       "}"
15689                       "sum;");
15690   CHECK_EQ(2076, result->Int32Value());
15691
15692   result = CompileRun("var sum = 0;"
15693                       "for (var i = 0; i < 8; i++) {"
15694                       "  sum += pixels[i] = pixels[i] = i;"
15695                       "}"
15696                       "sum;");
15697   CHECK_EQ(28, result->Int32Value());
15698
15699   result = CompileRun("var sum = 0;"
15700                       "for (var i = 0; i < 8; i++) {"
15701                       "  sum += pixels[i];"
15702                       "}"
15703                       "sum;");
15704   CHECK_EQ(28, result->Int32Value());
15705
15706   i::Handle<i::Smi> value(i::Smi::FromInt(2),
15707                           reinterpret_cast<i::Isolate*>(context->GetIsolate()));
15708   i::Handle<i::Object> no_failure;
15709   no_failure = i::JSObject::SetElement(
15710       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15711   DCHECK(!no_failure.is_null());
15712   USE(no_failure);
15713   CheckElementValue(isolate, 2, jsobj, 1);
15714   *value.location() = i::Smi::FromInt(256);
15715   no_failure = i::JSObject::SetElement(
15716       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15717   DCHECK(!no_failure.is_null());
15718   USE(no_failure);
15719   CheckElementValue(isolate, 255, jsobj, 1);
15720   *value.location() = i::Smi::FromInt(-1);
15721   no_failure = i::JSObject::SetElement(
15722       jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
15723   DCHECK(!no_failure.is_null());
15724   USE(no_failure);
15725   CheckElementValue(isolate, 0, jsobj, 1);
15726
15727   result = CompileRun("for (var i = 0; i < 8; i++) {"
15728                       "  pixels[i] = (i * 65) - 109;"
15729                       "}"
15730                       "pixels[1] + pixels[6];");
15731   CHECK_EQ(255, result->Int32Value());
15732   CheckElementValue(isolate, 0, jsobj, 0);
15733   CheckElementValue(isolate, 0, jsobj, 1);
15734   CheckElementValue(isolate, 21, jsobj, 2);
15735   CheckElementValue(isolate, 86, jsobj, 3);
15736   CheckElementValue(isolate, 151, jsobj, 4);
15737   CheckElementValue(isolate, 216, jsobj, 5);
15738   CheckElementValue(isolate, 255, jsobj, 6);
15739   CheckElementValue(isolate, 255, jsobj, 7);
15740   result = CompileRun("var sum = 0;"
15741                       "for (var i = 0; i < 8; i++) {"
15742                       "  sum += pixels[i];"
15743                       "}"
15744                       "sum;");
15745   CHECK_EQ(984, result->Int32Value());
15746
15747   result = CompileRun("for (var i = 0; i < 8; i++) {"
15748                       "  pixels[i] = (i * 1.1);"
15749                       "}"
15750                       "pixels[1] + pixels[6];");
15751   CHECK_EQ(8, result->Int32Value());
15752   CheckElementValue(isolate, 0, jsobj, 0);
15753   CheckElementValue(isolate, 1, jsobj, 1);
15754   CheckElementValue(isolate, 2, jsobj, 2);
15755   CheckElementValue(isolate, 3, jsobj, 3);
15756   CheckElementValue(isolate, 4, jsobj, 4);
15757   CheckElementValue(isolate, 6, jsobj, 5);
15758   CheckElementValue(isolate, 7, jsobj, 6);
15759   CheckElementValue(isolate, 8, jsobj, 7);
15760
15761   result = CompileRun("for (var i = 0; i < 8; i++) {"
15762                       "  pixels[7] = undefined;"
15763                       "}"
15764                       "pixels[7];");
15765   CHECK_EQ(0, result->Int32Value());
15766   CheckElementValue(isolate, 0, jsobj, 7);
15767
15768   result = CompileRun("for (var i = 0; i < 8; i++) {"
15769                       "  pixels[6] = '2.3';"
15770                       "}"
15771                       "pixels[6];");
15772   CHECK_EQ(2, result->Int32Value());
15773   CheckElementValue(isolate, 2, jsobj, 6);
15774
15775   result = CompileRun("for (var i = 0; i < 8; i++) {"
15776                       "  pixels[5] = NaN;"
15777                       "}"
15778                       "pixels[5];");
15779   CHECK_EQ(0, result->Int32Value());
15780   CheckElementValue(isolate, 0, jsobj, 5);
15781
15782   result = CompileRun("for (var i = 0; i < 8; i++) {"
15783                       "  pixels[8] = Infinity;"
15784                       "}"
15785                       "pixels[8];");
15786   CHECK_EQ(255, result->Int32Value());
15787   CheckElementValue(isolate, 255, jsobj, 8);
15788
15789   result = CompileRun("for (var i = 0; i < 8; i++) {"
15790                       "  pixels[9] = -Infinity;"
15791                       "}"
15792                       "pixels[9];");
15793   CHECK_EQ(0, result->Int32Value());
15794   CheckElementValue(isolate, 0, jsobj, 9);
15795
15796   result = CompileRun("pixels[3] = 33;"
15797                       "delete pixels[3];"
15798                       "pixels[3];");
15799   CHECK_EQ(33, result->Int32Value());
15800
15801   result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
15802                       "pixels[2] = 12; pixels[3] = 13;"
15803                       "pixels.__defineGetter__('2',"
15804                       "function() { return 120; });"
15805                       "pixels[2];");
15806   CHECK_EQ(12, result->Int32Value());
15807
15808   result = CompileRun("var js_array = new Array(40);"
15809                       "js_array[0] = 77;"
15810                       "js_array;");
15811   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15812
15813   result = CompileRun("pixels[1] = 23;"
15814                       "pixels.__proto__ = [];"
15815                       "js_array.__proto__ = pixels;"
15816                       "js_array.concat(pixels);");
15817   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15818   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15819
15820   result = CompileRun("pixels[1] = 23;");
15821   CHECK_EQ(23, result->Int32Value());
15822
15823   // Test for index greater than 255.  Regression test for:
15824   // http://code.google.com/p/chromium/issues/detail?id=26337.
15825   result = CompileRun("pixels[256] = 255;");
15826   CHECK_EQ(255, result->Int32Value());
15827   result = CompileRun("var i = 0;"
15828                       "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
15829                       "i");
15830   CHECK_EQ(255, result->Int32Value());
15831
15832   // Make sure that pixel array ICs recognize when a non-pixel array
15833   // is passed to it.
15834   result = CompileRun("function pa_load(p) {"
15835                       "  var sum = 0;"
15836                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15837                       "  return sum;"
15838                       "}"
15839                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15840                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15841                       "just_ints = new Object();"
15842                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15843                       "for (var i = 0; i < 10; ++i) {"
15844                       "  result = pa_load(just_ints);"
15845                       "}"
15846                       "result");
15847   CHECK_EQ(32640, result->Int32Value());
15848
15849   // Make sure that pixel array ICs recognize out-of-bound accesses.
15850   result = CompileRun("function pa_load(p, start) {"
15851                       "  var sum = 0;"
15852                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15853                       "  return sum;"
15854                       "}"
15855                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15856                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15857                       "for (var i = 0; i < 10; ++i) {"
15858                       "  result = pa_load(pixels,-10);"
15859                       "}"
15860                       "result");
15861   CHECK_EQ(0, result->Int32Value());
15862
15863   // Make sure that generic ICs properly handles a pixel array.
15864   result = CompileRun("function pa_load(p) {"
15865                       "  var sum = 0;"
15866                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15867                       "  return sum;"
15868                       "}"
15869                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15870                       "just_ints = new Object();"
15871                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15872                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15873                       "for (var i = 0; i < 10; ++i) {"
15874                       "  result = pa_load(pixels);"
15875                       "}"
15876                       "result");
15877   CHECK_EQ(32640, result->Int32Value());
15878
15879   // Make sure that generic load ICs recognize out-of-bound accesses in
15880   // pixel arrays.
15881   result = CompileRun("function pa_load(p, start) {"
15882                       "  var sum = 0;"
15883                       "  for (var j = start; j < 256; j++) { sum += p[j]; }"
15884                       "  return sum;"
15885                       "}"
15886                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15887                       "just_ints = new Object();"
15888                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15889                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15890                       "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15891                       "for (var i = 0; i < 10; ++i) {"
15892                       "  result = pa_load(pixels,-10);"
15893                       "}"
15894                       "result");
15895   CHECK_EQ(0, result->Int32Value());
15896
15897   // Make sure that generic ICs properly handles other types than pixel
15898   // arrays (that the inlined fast pixel array test leaves the right information
15899   // in the right registers).
15900   result = CompileRun("function pa_load(p) {"
15901                       "  var sum = 0;"
15902                       "  for (var j = 0; j < 256; j++) { sum += p[j]; }"
15903                       "  return sum;"
15904                       "}"
15905                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15906                       "just_ints = new Object();"
15907                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15908                       "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15909                       "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15910                       "sparse_array = new Object();"
15911                       "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15912                       "sparse_array[1000000] = 3;"
15913                       "for (var i = 0; i < 10; ++i) {"
15914                       "  result = pa_load(sparse_array);"
15915                       "}"
15916                       "result");
15917   CHECK_EQ(32640, result->Int32Value());
15918
15919   // Make sure that pixel array store ICs clamp values correctly.
15920   result = CompileRun("function pa_store(p) {"
15921                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15922                       "}"
15923                       "pa_store(pixels);"
15924                       "var sum = 0;"
15925                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15926                       "sum");
15927   CHECK_EQ(48896, result->Int32Value());
15928
15929   // Make sure that pixel array stores correctly handle accesses outside
15930   // of the pixel array..
15931   result = CompileRun("function pa_store(p,start) {"
15932                       "  for (var j = 0; j < 256; j++) {"
15933                       "    p[j+start] = j * 2;"
15934                       "  }"
15935                       "}"
15936                       "pa_store(pixels,0);"
15937                       "pa_store(pixels,-128);"
15938                       "var sum = 0;"
15939                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15940                       "sum");
15941   CHECK_EQ(65280, result->Int32Value());
15942
15943   // Make sure that the generic store stub correctly handle accesses outside
15944   // of the pixel array..
15945   result = CompileRun("function pa_store(p,start) {"
15946                       "  for (var j = 0; j < 256; j++) {"
15947                       "    p[j+start] = j * 2;"
15948                       "  }"
15949                       "}"
15950                       "pa_store(pixels,0);"
15951                       "just_ints = new Object();"
15952                       "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15953                       "pa_store(just_ints, 0);"
15954                       "pa_store(pixels,-128);"
15955                       "var sum = 0;"
15956                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15957                       "sum");
15958   CHECK_EQ(65280, result->Int32Value());
15959
15960   // Make sure that the generic keyed store stub clamps pixel array values
15961   // correctly.
15962   result = CompileRun("function pa_store(p) {"
15963                       "  for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15964                       "}"
15965                       "pa_store(pixels);"
15966                       "just_ints = new Object();"
15967                       "pa_store(just_ints);"
15968                       "pa_store(pixels);"
15969                       "var sum = 0;"
15970                       "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15971                       "sum");
15972   CHECK_EQ(48896, result->Int32Value());
15973
15974   // Make sure that pixel array loads are optimized by crankshaft.
15975   result = CompileRun("function pa_load(p) {"
15976                       "  var sum = 0;"
15977                       "  for (var i=0; i<256; ++i) {"
15978                       "    sum += p[i];"
15979                       "  }"
15980                       "  return sum; "
15981                       "}"
15982                       "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15983                       "for (var i = 0; i < 5000; ++i) {"
15984                       "  result = pa_load(pixels);"
15985                       "}"
15986                       "result");
15987   CHECK_EQ(32640, result->Int32Value());
15988
15989   // Make sure that pixel array stores are optimized by crankshaft.
15990   result = CompileRun("function pa_init(p) {"
15991                       "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15992                       "}"
15993                       "function pa_load(p) {"
15994                       "  var sum = 0;"
15995                       "  for (var i=0; i<256; ++i) {"
15996                       "    sum += p[i];"
15997                       "  }"
15998                       "  return sum; "
15999                       "}"
16000                       "for (var i = 0; i < 5000; ++i) {"
16001                       "  pa_init(pixels);"
16002                       "}"
16003                       "result = pa_load(pixels);"
16004                       "result");
16005   CHECK_EQ(32640, result->Int32Value());
16006
16007   free(pixel_data);
16008 }
16009
16010
16011 THREADED_TEST(PixelArrayInfo) {
16012   LocalContext context;
16013   v8::HandleScope scope(context->GetIsolate());
16014   for (int size = 0; size < 100; size += 10) {
16015     uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16016     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16017     obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16018     CHECK(obj->HasIndexedPropertiesInPixelData());
16019     CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16020     CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16021     free(pixel_data);
16022   }
16023 }
16024
16025
16026 static void NotHandledIndexedPropertyGetter(
16027     uint32_t index,
16028     const v8::PropertyCallbackInfo<v8::Value>& info) {
16029   ApiTestFuzzer::Fuzz();
16030 }
16031
16032
16033 static void NotHandledIndexedPropertySetter(
16034     uint32_t index,
16035     Local<Value> value,
16036     const v8::PropertyCallbackInfo<v8::Value>& info) {
16037   ApiTestFuzzer::Fuzz();
16038 }
16039
16040
16041 THREADED_TEST(PixelArrayWithInterceptor) {
16042   LocalContext context;
16043   i::Factory* factory = CcTest::i_isolate()->factory();
16044   v8::Isolate* isolate = context->GetIsolate();
16045   v8::HandleScope scope(isolate);
16046   const int kElementCount = 260;
16047   uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16048   i::Handle<i::ExternalUint8ClampedArray> pixels =
16049       i::Handle<i::ExternalUint8ClampedArray>::cast(
16050           factory->NewExternalArray(kElementCount,
16051                                     v8::kExternalUint8ClampedArray,
16052                                     pixel_data));
16053   for (int i = 0; i < kElementCount; i++) {
16054     pixels->set(i, i % 256);
16055   }
16056   v8::Handle<v8::ObjectTemplate> templ =
16057       v8::ObjectTemplate::New(context->GetIsolate());
16058   templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16059                                    NotHandledIndexedPropertySetter);
16060   v8::Handle<v8::Object> obj = templ->NewInstance();
16061   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16062   context->Global()->Set(v8_str("pixels"), obj);
16063   v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16064   CHECK_EQ(1, result->Int32Value());
16065   result = CompileRun("var sum = 0;"
16066                       "for (var i = 0; i < 8; i++) {"
16067                       "  sum += pixels[i] = pixels[i] = -i;"
16068                       "}"
16069                       "sum;");
16070   CHECK_EQ(-28, result->Int32Value());
16071   result = CompileRun("pixels.hasOwnProperty('1')");
16072   CHECK(result->BooleanValue());
16073   free(pixel_data);
16074 }
16075
16076
16077 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16078   switch (array_type) {
16079     case v8::kExternalInt8Array:
16080     case v8::kExternalUint8Array:
16081     case v8::kExternalUint8ClampedArray:
16082       return 1;
16083       break;
16084     case v8::kExternalInt16Array:
16085     case v8::kExternalUint16Array:
16086       return 2;
16087       break;
16088     case v8::kExternalInt32Array:
16089     case v8::kExternalUint32Array:
16090     case v8::kExternalFloat32Array:
16091       return 4;
16092       break;
16093     case v8::kExternalFloat64Array:
16094       return 8;
16095       break;
16096     default:
16097       UNREACHABLE();
16098       return -1;
16099   }
16100   UNREACHABLE();
16101   return -1;
16102 }
16103
16104
16105 template <class ExternalArrayClass, class ElementType>
16106 static void ObjectWithExternalArrayTestHelper(
16107     Handle<Context> context,
16108     v8::Handle<Object> obj,
16109     int element_count,
16110     v8::ExternalArrayType array_type,
16111     int64_t low, int64_t high) {
16112   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16113   i::Isolate* isolate = jsobj->GetIsolate();
16114   obj->Set(v8_str("field"),
16115            v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16116   context->Global()->Set(v8_str("ext_array"), obj);
16117   v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16118   CHECK_EQ(1503, result->Int32Value());
16119   result = CompileRun("ext_array[1]");
16120   CHECK_EQ(1, result->Int32Value());
16121
16122   // Check assigned smis
16123   result = CompileRun("for (var i = 0; i < 8; i++) {"
16124                       "  ext_array[i] = i;"
16125                       "}"
16126                       "var sum = 0;"
16127                       "for (var i = 0; i < 8; i++) {"
16128                       "  sum += ext_array[i];"
16129                       "}"
16130                       "sum;");
16131
16132   CHECK_EQ(28, result->Int32Value());
16133   // Check pass through of assigned smis
16134   result = CompileRun("var sum = 0;"
16135                       "for (var i = 0; i < 8; i++) {"
16136                       "  sum += ext_array[i] = ext_array[i] = -i;"
16137                       "}"
16138                       "sum;");
16139   CHECK_EQ(-28, result->Int32Value());
16140
16141
16142   // Check assigned smis in reverse order
16143   result = CompileRun("for (var i = 8; --i >= 0; ) {"
16144                       "  ext_array[i] = i;"
16145                       "}"
16146                       "var sum = 0;"
16147                       "for (var i = 0; i < 8; i++) {"
16148                       "  sum += ext_array[i];"
16149                       "}"
16150                       "sum;");
16151   CHECK_EQ(28, result->Int32Value());
16152
16153   // Check pass through of assigned HeapNumbers
16154   result = CompileRun("var sum = 0;"
16155                       "for (var i = 0; i < 16; i+=2) {"
16156                       "  sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16157                       "}"
16158                       "sum;");
16159   CHECK_EQ(-28, result->Int32Value());
16160
16161   // Check assigned HeapNumbers
16162   result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16163                       "  ext_array[i] = (i * 0.5);"
16164                       "}"
16165                       "var sum = 0;"
16166                       "for (var i = 0; i < 16; i+=2) {"
16167                       "  sum += ext_array[i];"
16168                       "}"
16169                       "sum;");
16170   CHECK_EQ(28, result->Int32Value());
16171
16172   // Check assigned HeapNumbers in reverse order
16173   result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16174                       "  ext_array[i] = (i * 0.5);"
16175                       "}"
16176                       "var sum = 0;"
16177                       "for (var i = 0; i < 16; i+=2) {"
16178                       "  sum += ext_array[i];"
16179                       "}"
16180                       "sum;");
16181   CHECK_EQ(28, result->Int32Value());
16182
16183   i::ScopedVector<char> test_buf(1024);
16184
16185   // Check legal boundary conditions.
16186   // The repeated loads and stores ensure the ICs are exercised.
16187   const char* boundary_program =
16188       "var res = 0;"
16189       "for (var i = 0; i < 16; i++) {"
16190       "  ext_array[i] = %lld;"
16191       "  if (i > 8) {"
16192       "    res = ext_array[i];"
16193       "  }"
16194       "}"
16195       "res;";
16196   i::SNPrintF(test_buf,
16197               boundary_program,
16198               low);
16199   result = CompileRun(test_buf.start());
16200   CHECK_EQ(low, result->IntegerValue());
16201
16202   i::SNPrintF(test_buf,
16203               boundary_program,
16204               high);
16205   result = CompileRun(test_buf.start());
16206   CHECK_EQ(high, result->IntegerValue());
16207
16208   // Check misprediction of type in IC.
16209   result = CompileRun("var tmp_array = ext_array;"
16210                       "var sum = 0;"
16211                       "for (var i = 0; i < 8; i++) {"
16212                       "  tmp_array[i] = i;"
16213                       "  sum += tmp_array[i];"
16214                       "  if (i == 4) {"
16215                       "    tmp_array = {};"
16216                       "  }"
16217                       "}"
16218                       "sum;");
16219   // Force GC to trigger verification.
16220   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16221   CHECK_EQ(28, result->Int32Value());
16222
16223   // Make sure out-of-range loads do not throw.
16224   i::SNPrintF(test_buf,
16225               "var caught_exception = false;"
16226               "try {"
16227               "  ext_array[%d];"
16228               "} catch (e) {"
16229               "  caught_exception = true;"
16230               "}"
16231               "caught_exception;",
16232               element_count);
16233   result = CompileRun(test_buf.start());
16234   CHECK_EQ(false, result->BooleanValue());
16235
16236   // Make sure out-of-range stores do not throw.
16237   i::SNPrintF(test_buf,
16238               "var caught_exception = false;"
16239               "try {"
16240               "  ext_array[%d] = 1;"
16241               "} catch (e) {"
16242               "  caught_exception = true;"
16243               "}"
16244               "caught_exception;",
16245               element_count);
16246   result = CompileRun(test_buf.start());
16247   CHECK_EQ(false, result->BooleanValue());
16248
16249   // Check other boundary conditions, values and operations.
16250   result = CompileRun("for (var i = 0; i < 8; i++) {"
16251                       "  ext_array[7] = undefined;"
16252                       "}"
16253                       "ext_array[7];");
16254   CHECK_EQ(0, result->Int32Value());
16255   if (array_type == v8::kExternalFloat64Array ||
16256       array_type == v8::kExternalFloat32Array) {
16257     CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16258              static_cast<int>(
16259                  i::Object::GetElement(
16260                      isolate, jsobj, 7).ToHandleChecked()->Number()));
16261   } else {
16262     CheckElementValue(isolate, 0, jsobj, 7);
16263   }
16264
16265   result = CompileRun("for (var i = 0; i < 8; i++) {"
16266                       "  ext_array[6] = '2.3';"
16267                       "}"
16268                       "ext_array[6];");
16269   CHECK_EQ(2, result->Int32Value());
16270   CHECK_EQ(2,
16271            static_cast<int>(
16272                i::Object::GetElement(
16273                    isolate, jsobj, 6).ToHandleChecked()->Number()));
16274
16275   if (array_type != v8::kExternalFloat32Array &&
16276       array_type != v8::kExternalFloat64Array) {
16277     // Though the specification doesn't state it, be explicit about
16278     // converting NaNs and +/-Infinity to zero.
16279     result = CompileRun("for (var i = 0; i < 8; i++) {"
16280                         "  ext_array[i] = 5;"
16281                         "}"
16282                         "for (var i = 0; i < 8; i++) {"
16283                         "  ext_array[i] = NaN;"
16284                         "}"
16285                         "ext_array[5];");
16286     CHECK_EQ(0, result->Int32Value());
16287     CheckElementValue(isolate, 0, jsobj, 5);
16288
16289     result = CompileRun("for (var i = 0; i < 8; i++) {"
16290                         "  ext_array[i] = 5;"
16291                         "}"
16292                         "for (var i = 0; i < 8; i++) {"
16293                         "  ext_array[i] = Infinity;"
16294                         "}"
16295                         "ext_array[5];");
16296     int expected_value =
16297         (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16298     CHECK_EQ(expected_value, result->Int32Value());
16299     CheckElementValue(isolate, expected_value, jsobj, 5);
16300
16301     result = CompileRun("for (var i = 0; i < 8; i++) {"
16302                         "  ext_array[i] = 5;"
16303                         "}"
16304                         "for (var i = 0; i < 8; i++) {"
16305                         "  ext_array[i] = -Infinity;"
16306                         "}"
16307                         "ext_array[5];");
16308     CHECK_EQ(0, result->Int32Value());
16309     CheckElementValue(isolate, 0, jsobj, 5);
16310
16311     // Check truncation behavior of integral arrays.
16312     const char* unsigned_data =
16313         "var source_data = [0.6, 10.6];"
16314         "var expected_results = [0, 10];";
16315     const char* signed_data =
16316         "var source_data = [0.6, 10.6, -0.6, -10.6];"
16317         "var expected_results = [0, 10, 0, -10];";
16318     const char* pixel_data =
16319         "var source_data = [0.6, 10.6];"
16320         "var expected_results = [1, 11];";
16321     bool is_unsigned =
16322         (array_type == v8::kExternalUint8Array ||
16323          array_type == v8::kExternalUint16Array ||
16324          array_type == v8::kExternalUint32Array);
16325     bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16326
16327     i::SNPrintF(test_buf,
16328                 "%s"
16329                 "var all_passed = true;"
16330                 "for (var i = 0; i < source_data.length; i++) {"
16331                 "  for (var j = 0; j < 8; j++) {"
16332                 "    ext_array[j] = source_data[i];"
16333                 "  }"
16334                 "  all_passed = all_passed &&"
16335                 "               (ext_array[5] == expected_results[i]);"
16336                 "}"
16337                 "all_passed;",
16338                 (is_unsigned ?
16339                      unsigned_data :
16340                      (is_pixel_data ? pixel_data : signed_data)));
16341     result = CompileRun(test_buf.start());
16342     CHECK_EQ(true, result->BooleanValue());
16343   }
16344
16345   i::Handle<ExternalArrayClass> array(
16346       ExternalArrayClass::cast(jsobj->elements()));
16347   for (int i = 0; i < element_count; i++) {
16348     array->set(i, static_cast<ElementType>(i));
16349   }
16350
16351   // Test complex assignments
16352   result = CompileRun("function ee_op_test_complex_func(sum) {"
16353                       " for (var i = 0; i < 40; ++i) {"
16354                       "   sum += (ext_array[i] += 1);"
16355                       "   sum += (ext_array[i] -= 1);"
16356                       " } "
16357                       " return sum;"
16358                       "}"
16359                       "sum=0;"
16360                       "for (var i=0;i<10000;++i) {"
16361                       "  sum=ee_op_test_complex_func(sum);"
16362                       "}"
16363                       "sum;");
16364   CHECK_EQ(16000000, result->Int32Value());
16365
16366   // Test count operations
16367   result = CompileRun("function ee_op_test_count_func(sum) {"
16368                       " for (var i = 0; i < 40; ++i) {"
16369                       "   sum += (++ext_array[i]);"
16370                       "   sum += (--ext_array[i]);"
16371                       " } "
16372                       " return sum;"
16373                       "}"
16374                       "sum=0;"
16375                       "for (var i=0;i<10000;++i) {"
16376                       "  sum=ee_op_test_count_func(sum);"
16377                       "}"
16378                       "sum;");
16379   CHECK_EQ(16000000, result->Int32Value());
16380
16381   result = CompileRun("ext_array[3] = 33;"
16382                       "delete ext_array[3];"
16383                       "ext_array[3];");
16384   CHECK_EQ(33, result->Int32Value());
16385
16386   result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16387                       "ext_array[2] = 12; ext_array[3] = 13;"
16388                       "ext_array.__defineGetter__('2',"
16389                       "function() { return 120; });"
16390                       "ext_array[2];");
16391   CHECK_EQ(12, result->Int32Value());
16392
16393   result = CompileRun("var js_array = new Array(40);"
16394                       "js_array[0] = 77;"
16395                       "js_array;");
16396   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16397
16398   result = CompileRun("ext_array[1] = 23;"
16399                       "ext_array.__proto__ = [];"
16400                       "js_array.__proto__ = ext_array;"
16401                       "js_array.concat(ext_array);");
16402   CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16403   CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16404
16405   result = CompileRun("ext_array[1] = 23;");
16406   CHECK_EQ(23, result->Int32Value());
16407 }
16408
16409
16410 template <class FixedTypedArrayClass,
16411           i::ElementsKind elements_kind,
16412           class ElementType>
16413 static void FixedTypedArrayTestHelper(
16414     v8::ExternalArrayType array_type,
16415     ElementType low,
16416     ElementType high) {
16417   i::FLAG_allow_natives_syntax = true;
16418   LocalContext context;
16419   i::Isolate* isolate = CcTest::i_isolate();
16420   i::Factory* factory = isolate->factory();
16421   v8::HandleScope scope(context->GetIsolate());
16422   const int kElementCount = 260;
16423   i::Handle<FixedTypedArrayClass> fixed_array =
16424     i::Handle<FixedTypedArrayClass>::cast(
16425         factory->NewFixedTypedArray(kElementCount, array_type));
16426   CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16427            fixed_array->map()->instance_type());
16428   CHECK_EQ(kElementCount, fixed_array->length());
16429   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16430   for (int i = 0; i < kElementCount; i++) {
16431     fixed_array->set(i, static_cast<ElementType>(i));
16432   }
16433   // Force GC to trigger verification.
16434   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16435   for (int i = 0; i < kElementCount; i++) {
16436     CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
16437              static_cast<int64_t>(fixed_array->get_scalar(i)));
16438   }
16439   v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
16440   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16441   i::Handle<i::Map> fixed_array_map =
16442       i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
16443   jsobj->set_map(*fixed_array_map);
16444   jsobj->set_elements(*fixed_array);
16445
16446   ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
16447       context.local(), obj, kElementCount, array_type,
16448       static_cast<int64_t>(low),
16449       static_cast<int64_t>(high));
16450 }
16451
16452
16453 THREADED_TEST(FixedUint8Array) {
16454   FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
16455     v8::kExternalUint8Array,
16456     0x0, 0xFF);
16457 }
16458
16459
16460 THREADED_TEST(FixedUint8ClampedArray) {
16461   FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
16462                             i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
16463     v8::kExternalUint8ClampedArray,
16464     0x0, 0xFF);
16465 }
16466
16467
16468 THREADED_TEST(FixedInt8Array) {
16469   FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
16470     v8::kExternalInt8Array,
16471     -0x80, 0x7F);
16472 }
16473
16474
16475 THREADED_TEST(FixedUint16Array) {
16476   FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
16477     v8::kExternalUint16Array,
16478     0x0, 0xFFFF);
16479 }
16480
16481
16482 THREADED_TEST(FixedInt16Array) {
16483   FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
16484     v8::kExternalInt16Array,
16485     -0x8000, 0x7FFF);
16486 }
16487
16488
16489 THREADED_TEST(FixedUint32Array) {
16490   FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
16491     v8::kExternalUint32Array,
16492     0x0, UINT_MAX);
16493 }
16494
16495
16496 THREADED_TEST(FixedInt32Array) {
16497   FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
16498     v8::kExternalInt32Array,
16499     INT_MIN, INT_MAX);
16500 }
16501
16502
16503 THREADED_TEST(FixedFloat32Array) {
16504   FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
16505     v8::kExternalFloat32Array,
16506     -500, 500);
16507 }
16508
16509
16510 THREADED_TEST(FixedFloat64Array) {
16511   FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
16512     v8::kExternalFloat64Array,
16513     -500, 500);
16514 }
16515
16516
16517 template <class ExternalArrayClass, class ElementType>
16518 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
16519                                     int64_t low,
16520                                     int64_t high) {
16521   LocalContext context;
16522   i::Isolate* isolate = CcTest::i_isolate();
16523   i::Factory* factory = isolate->factory();
16524   v8::HandleScope scope(context->GetIsolate());
16525   const int kElementCount = 40;
16526   int element_size = ExternalArrayElementSize(array_type);
16527   ElementType* array_data =
16528       static_cast<ElementType*>(malloc(kElementCount * element_size));
16529   i::Handle<ExternalArrayClass> array =
16530       i::Handle<ExternalArrayClass>::cast(
16531           factory->NewExternalArray(kElementCount, array_type, array_data));
16532   // Force GC to trigger verification.
16533   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16534   for (int i = 0; i < kElementCount; i++) {
16535     array->set(i, static_cast<ElementType>(i));
16536   }
16537   // Force GC to trigger verification.
16538   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16539   for (int i = 0; i < kElementCount; i++) {
16540     CHECK_EQ(static_cast<int64_t>(i),
16541              static_cast<int64_t>(array->get_scalar(i)));
16542     CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
16543   }
16544
16545   v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16546   i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16547   // Set the elements to be the external array.
16548   obj->SetIndexedPropertiesToExternalArrayData(array_data,
16549                                                array_type,
16550                                                kElementCount);
16551   CHECK_EQ(1,
16552            static_cast<int>(
16553                i::Object::GetElement(
16554                    isolate, jsobj, 1).ToHandleChecked()->Number()));
16555
16556   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16557       context.local(), obj, kElementCount, array_type, low, high);
16558
16559   v8::Handle<v8::Value> result;
16560
16561   // Test more complex manipulations which cause eax to contain values
16562   // that won't be completely overwritten by loads from the arrays.
16563   // This catches bugs in the instructions used for the KeyedLoadIC
16564   // for byte and word types.
16565   {
16566     const int kXSize = 300;
16567     const int kYSize = 300;
16568     const int kLargeElementCount = kXSize * kYSize * 4;
16569     ElementType* large_array_data =
16570         static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
16571     v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
16572     // Set the elements to be the external array.
16573     large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
16574                                                        array_type,
16575                                                        kLargeElementCount);
16576     context->Global()->Set(v8_str("large_array"), large_obj);
16577     // Initialize contents of a few rows.
16578     for (int x = 0; x < 300; x++) {
16579       int row = 0;
16580       int offset = row * 300 * 4;
16581       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16582       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16583       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16584       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16585       row = 150;
16586       offset = row * 300 * 4;
16587       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16588       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16589       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16590       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16591       row = 298;
16592       offset = row * 300 * 4;
16593       large_array_data[offset + 4 * x + 0] = (ElementType) 127;
16594       large_array_data[offset + 4 * x + 1] = (ElementType) 0;
16595       large_array_data[offset + 4 * x + 2] = (ElementType) 0;
16596       large_array_data[offset + 4 * x + 3] = (ElementType) 127;
16597     }
16598     // The goal of the code below is to make "offset" large enough
16599     // that the computation of the index (which goes into eax) has
16600     // high bits set which will not be overwritten by a byte or short
16601     // load.
16602     result = CompileRun("var failed = false;"
16603                         "var offset = 0;"
16604                         "for (var i = 0; i < 300; i++) {"
16605                         "  if (large_array[4 * i] != 127 ||"
16606                         "      large_array[4 * i + 1] != 0 ||"
16607                         "      large_array[4 * i + 2] != 0 ||"
16608                         "      large_array[4 * i + 3] != 127) {"
16609                         "    failed = true;"
16610                         "  }"
16611                         "}"
16612                         "offset = 150 * 300 * 4;"
16613                         "for (var i = 0; i < 300; i++) {"
16614                         "  if (large_array[offset + 4 * i] != 127 ||"
16615                         "      large_array[offset + 4 * i + 1] != 0 ||"
16616                         "      large_array[offset + 4 * i + 2] != 0 ||"
16617                         "      large_array[offset + 4 * i + 3] != 127) {"
16618                         "    failed = true;"
16619                         "  }"
16620                         "}"
16621                         "offset = 298 * 300 * 4;"
16622                         "for (var i = 0; i < 300; i++) {"
16623                         "  if (large_array[offset + 4 * i] != 127 ||"
16624                         "      large_array[offset + 4 * i + 1] != 0 ||"
16625                         "      large_array[offset + 4 * i + 2] != 0 ||"
16626                         "      large_array[offset + 4 * i + 3] != 127) {"
16627                         "    failed = true;"
16628                         "  }"
16629                         "}"
16630                         "!failed;");
16631     CHECK_EQ(true, result->BooleanValue());
16632     free(large_array_data);
16633   }
16634
16635   // The "" property descriptor is overloaded to store information about
16636   // the external array. Ensure that setting and accessing the "" property
16637   // works (it should overwrite the information cached about the external
16638   // array in the DescriptorArray) in various situations.
16639   result = CompileRun("ext_array[''] = 23; ext_array['']");
16640   CHECK_EQ(23, result->Int32Value());
16641
16642   // Property "" set after the external array is associated with the object.
16643   {
16644     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16645     obj2->Set(v8_str("ee_test_field"),
16646               v8::Int32::New(context->GetIsolate(), 256));
16647     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16648     // Set the elements to be the external array.
16649     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16650                                                   array_type,
16651                                                   kElementCount);
16652     context->Global()->Set(v8_str("ext_array"), obj2);
16653     result = CompileRun("ext_array['']");
16654     CHECK_EQ(1503, result->Int32Value());
16655   }
16656
16657   // Property "" set after the external array is associated with the object.
16658   {
16659     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16660     obj2->Set(v8_str("ee_test_field_2"),
16661               v8::Int32::New(context->GetIsolate(), 256));
16662     // Set the elements to be the external array.
16663     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16664                                                   array_type,
16665                                                   kElementCount);
16666     obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
16667     context->Global()->Set(v8_str("ext_array"), obj2);
16668     result = CompileRun("ext_array['']");
16669     CHECK_EQ(1503, result->Int32Value());
16670   }
16671
16672   // Should reuse the map from previous test.
16673   {
16674     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16675     obj2->Set(v8_str("ee_test_field_2"),
16676               v8::Int32::New(context->GetIsolate(), 256));
16677     // Set the elements to be the external array. Should re-use the map
16678     // from previous test.
16679     obj2->SetIndexedPropertiesToExternalArrayData(array_data,
16680                                                   array_type,
16681                                                   kElementCount);
16682     context->Global()->Set(v8_str("ext_array"), obj2);
16683     result = CompileRun("ext_array['']");
16684   }
16685
16686   // Property "" is a constant function that shouldn't not be interfered with
16687   // when an external array is set.
16688   {
16689     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16690     // Start
16691     obj2->Set(v8_str("ee_test_field3"),
16692               v8::Int32::New(context->GetIsolate(), 256));
16693
16694     // Add a constant function to an object.
16695     context->Global()->Set(v8_str("ext_array"), obj2);
16696     result = CompileRun("ext_array[''] = function() {return 1503;};"
16697                         "ext_array['']();");
16698
16699     // Add an external array transition to the same map that
16700     // has the constant transition.
16701     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16702     obj3->Set(v8_str("ee_test_field3"),
16703               v8::Int32::New(context->GetIsolate(), 256));
16704     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16705                                                   array_type,
16706                                                   kElementCount);
16707     context->Global()->Set(v8_str("ext_array"), obj3);
16708   }
16709
16710   // If a external array transition is in the map, it should get clobbered
16711   // by a constant function.
16712   {
16713     // Add an external array transition.
16714     v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
16715     obj3->Set(v8_str("ee_test_field4"),
16716               v8::Int32::New(context->GetIsolate(), 256));
16717     obj3->SetIndexedPropertiesToExternalArrayData(array_data,
16718                                                   array_type,
16719                                                   kElementCount);
16720
16721     // Add a constant function to the same map that just got an external array
16722     // transition.
16723     v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
16724     obj2->Set(v8_str("ee_test_field4"),
16725               v8::Int32::New(context->GetIsolate(), 256));
16726     context->Global()->Set(v8_str("ext_array"), obj2);
16727     result = CompileRun("ext_array[''] = function() {return 1503;};"
16728                         "ext_array['']();");
16729   }
16730
16731   free(array_data);
16732 }
16733
16734
16735 THREADED_TEST(ExternalInt8Array) {
16736   ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
16737       v8::kExternalInt8Array,
16738       -128,
16739       127);
16740 }
16741
16742
16743 THREADED_TEST(ExternalUint8Array) {
16744   ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
16745       v8::kExternalUint8Array,
16746       0,
16747       255);
16748 }
16749
16750
16751 THREADED_TEST(ExternalUint8ClampedArray) {
16752   ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
16753       v8::kExternalUint8ClampedArray,
16754       0,
16755       255);
16756 }
16757
16758
16759 THREADED_TEST(ExternalInt16Array) {
16760   ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
16761       v8::kExternalInt16Array,
16762       -32768,
16763       32767);
16764 }
16765
16766
16767 THREADED_TEST(ExternalUint16Array) {
16768   ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
16769       v8::kExternalUint16Array,
16770       0,
16771       65535);
16772 }
16773
16774
16775 THREADED_TEST(ExternalInt32Array) {
16776   ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
16777       v8::kExternalInt32Array,
16778       INT_MIN,   // -2147483648
16779       INT_MAX);  //  2147483647
16780 }
16781
16782
16783 THREADED_TEST(ExternalUint32Array) {
16784   ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
16785       v8::kExternalUint32Array,
16786       0,
16787       UINT_MAX);  // 4294967295
16788 }
16789
16790
16791 THREADED_TEST(ExternalFloat32Array) {
16792   ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
16793       v8::kExternalFloat32Array,
16794       -500,
16795       500);
16796 }
16797
16798
16799 THREADED_TEST(ExternalFloat64Array) {
16800   ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
16801       v8::kExternalFloat64Array,
16802       -500,
16803       500);
16804 }
16805
16806
16807 THREADED_TEST(ExternalArrays) {
16808   TestExternalInt8Array();
16809   TestExternalUint8Array();
16810   TestExternalInt16Array();
16811   TestExternalUint16Array();
16812   TestExternalInt32Array();
16813   TestExternalUint32Array();
16814   TestExternalFloat32Array();
16815 }
16816
16817
16818 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
16819   LocalContext context;
16820   v8::HandleScope scope(context->GetIsolate());
16821   for (int size = 0; size < 100; size += 10) {
16822     int element_size = ExternalArrayElementSize(array_type);
16823     void* external_data = malloc(size * element_size);
16824     v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16825     obj->SetIndexedPropertiesToExternalArrayData(
16826         external_data, array_type, size);
16827     CHECK(obj->HasIndexedPropertiesInExternalArrayData());
16828     CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
16829     CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
16830     CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
16831     free(external_data);
16832   }
16833 }
16834
16835
16836 THREADED_TEST(ExternalArrayInfo) {
16837   ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
16838   ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
16839   ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
16840   ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
16841   ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
16842   ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
16843   ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
16844   ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
16845   ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
16846 }
16847
16848
16849 void ExtArrayLimitsHelper(v8::Isolate* isolate,
16850                           v8::ExternalArrayType array_type,
16851                           int size) {
16852   v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16853   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16854   last_location = last_message = NULL;
16855   obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
16856   CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
16857   CHECK_NE(NULL, last_location);
16858   CHECK_NE(NULL, last_message);
16859 }
16860
16861
16862 TEST(ExternalArrayLimits) {
16863   LocalContext context;
16864   v8::Isolate* isolate = context->GetIsolate();
16865   v8::HandleScope scope(isolate);
16866   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
16867   ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
16868   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
16869   ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
16870   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
16871   ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
16872   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
16873   ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
16874   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
16875   ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
16876   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
16877   ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
16878   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
16879   ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
16880   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
16881   ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
16882   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
16883   ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
16884 }
16885
16886
16887 template <typename ElementType, typename TypedArray,
16888           class ExternalArrayClass>
16889 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
16890                           int64_t low, int64_t high) {
16891   const int kElementCount = 50;
16892
16893   i::ScopedVector<ElementType> backing_store(kElementCount+2);
16894
16895   LocalContext env;
16896   v8::Isolate* isolate = env->GetIsolate();
16897   v8::HandleScope handle_scope(isolate);
16898
16899   Local<v8::ArrayBuffer> ab =
16900       v8::ArrayBuffer::New(isolate, backing_store.start(),
16901                            (kElementCount + 2) * sizeof(ElementType));
16902   Local<TypedArray> ta =
16903       TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
16904   CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
16905   CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
16906   CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
16907   CHECK_EQ(kElementCount*sizeof(ElementType),
16908            static_cast<int>(ta->ByteLength()));
16909   CHECK_EQ(ab, ta->Buffer());
16910
16911   ElementType* data = backing_store.start() + 2;
16912   for (int i = 0; i < kElementCount; i++) {
16913     data[i] = static_cast<ElementType>(i);
16914   }
16915
16916   ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
16917       env.local(), ta, kElementCount, array_type, low, high);
16918 }
16919
16920
16921 THREADED_TEST(Uint8Array) {
16922   TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
16923       v8::kExternalUint8Array, 0, 0xFF);
16924 }
16925
16926
16927 THREADED_TEST(Int8Array) {
16928   TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
16929       v8::kExternalInt8Array, -0x80, 0x7F);
16930 }
16931
16932
16933 THREADED_TEST(Uint16Array) {
16934   TypedArrayTestHelper<uint16_t,
16935                        v8::Uint16Array,
16936                        i::ExternalUint16Array>(
16937       v8::kExternalUint16Array, 0, 0xFFFF);
16938 }
16939
16940
16941 THREADED_TEST(Int16Array) {
16942   TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
16943       v8::kExternalInt16Array, -0x8000, 0x7FFF);
16944 }
16945
16946
16947 THREADED_TEST(Uint32Array) {
16948   TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
16949       v8::kExternalUint32Array, 0, UINT_MAX);
16950 }
16951
16952
16953 THREADED_TEST(Int32Array) {
16954   TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
16955       v8::kExternalInt32Array, INT_MIN, INT_MAX);
16956 }
16957
16958
16959 THREADED_TEST(Float32Array) {
16960   TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
16961       v8::kExternalFloat32Array, -500, 500);
16962 }
16963
16964
16965 THREADED_TEST(Float64Array) {
16966   TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
16967       v8::kExternalFloat64Array, -500, 500);
16968 }
16969
16970
16971 THREADED_TEST(Uint8ClampedArray) {
16972   TypedArrayTestHelper<uint8_t,
16973                        v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
16974       v8::kExternalUint8ClampedArray, 0, 0xFF);
16975 }
16976
16977
16978 THREADED_TEST(DataView) {
16979   const int kSize = 50;
16980
16981   i::ScopedVector<uint8_t> backing_store(kSize+2);
16982
16983   LocalContext env;
16984   v8::Isolate* isolate = env->GetIsolate();
16985   v8::HandleScope handle_scope(isolate);
16986
16987   Local<v8::ArrayBuffer> ab =
16988       v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
16989   Local<v8::DataView> dv =
16990       v8::DataView::New(ab, 2, kSize);
16991   CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
16992   CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
16993   CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
16994   CHECK_EQ(ab, dv->Buffer());
16995 }
16996
16997
16998 #define IS_ARRAY_BUFFER_VIEW_TEST(View)                                       \
16999   THREADED_TEST(Is##View) {                                                   \
17000     LocalContext env;                                                         \
17001     v8::Isolate* isolate = env->GetIsolate();                                 \
17002     v8::HandleScope handle_scope(isolate);                                    \
17003                                                                               \
17004     Handle<Value> result = CompileRun(                                        \
17005         "var ab = new ArrayBuffer(128);"                                      \
17006         "new " #View "(ab)");                                                 \
17007     CHECK(result->IsArrayBufferView());                                       \
17008     CHECK(result->Is##View());                                                \
17009     CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>());   \
17010   }
17011
17012 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17013 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17014 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17015 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17016 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17017 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17018 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17019 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17020 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17021 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17022
17023 #undef IS_ARRAY_BUFFER_VIEW_TEST
17024
17025
17026
17027 THREADED_TEST(ScriptContextDependence) {
17028   LocalContext c1;
17029   v8::HandleScope scope(c1->GetIsolate());
17030   const char *source = "foo";
17031   v8::Handle<v8::Script> dep = v8_compile(source);
17032   v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17033       c1->GetIsolate(), source));
17034   v8::Handle<v8::UnboundScript> indep =
17035       v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17036   c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17037                     v8::Integer::New(c1->GetIsolate(), 100));
17038   CHECK_EQ(dep->Run()->Int32Value(), 100);
17039   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17040   LocalContext c2;
17041   c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17042                     v8::Integer::New(c2->GetIsolate(), 101));
17043   CHECK_EQ(dep->Run()->Int32Value(), 100);
17044   CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17045 }
17046
17047
17048 THREADED_TEST(StackTrace) {
17049   LocalContext context;
17050   v8::HandleScope scope(context->GetIsolate());
17051   v8::TryCatch try_catch;
17052   const char *source = "function foo() { FAIL.FAIL; }; foo();";
17053   v8::Handle<v8::String> src =
17054       v8::String::NewFromUtf8(context->GetIsolate(), source);
17055   v8::Handle<v8::String> origin =
17056       v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17057   v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17058   v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17059       ->BindToCurrentContext()
17060       ->Run();
17061   CHECK(try_catch.HasCaught());
17062   v8::String::Utf8Value stack(try_catch.StackTrace());
17063   CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17064 }
17065
17066
17067 // Checks that a StackFrame has certain expected values.
17068 void checkStackFrame(const char* expected_script_name,
17069     const char* expected_func_name, int expected_line_number,
17070     int expected_column, bool is_eval, bool is_constructor,
17071     v8::Handle<v8::StackFrame> frame) {
17072   v8::HandleScope scope(CcTest::isolate());
17073   v8::String::Utf8Value func_name(frame->GetFunctionName());
17074   v8::String::Utf8Value script_name(frame->GetScriptName());
17075   if (*script_name == NULL) {
17076     // The situation where there is no associated script, like for evals.
17077     CHECK(expected_script_name == NULL);
17078   } else {
17079     CHECK(strstr(*script_name, expected_script_name) != NULL);
17080   }
17081   CHECK(strstr(*func_name, expected_func_name) != NULL);
17082   CHECK_EQ(expected_line_number, frame->GetLineNumber());
17083   CHECK_EQ(expected_column, frame->GetColumn());
17084   CHECK_EQ(is_eval, frame->IsEval());
17085   CHECK_EQ(is_constructor, frame->IsConstructor());
17086 }
17087
17088
17089 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17090   v8::HandleScope scope(args.GetIsolate());
17091   const char* origin = "capture-stack-trace-test";
17092   const int kOverviewTest = 1;
17093   const int kDetailedTest = 2;
17094
17095   DCHECK(args.Length() == 1);
17096
17097   int testGroup = args[0]->Int32Value();
17098   if (testGroup == kOverviewTest) {
17099     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17100         args.GetIsolate(), 10, v8::StackTrace::kOverview);
17101     CHECK_EQ(4, stackTrace->GetFrameCount());
17102     checkStackFrame(origin, "bar", 2, 10, false, false,
17103                     stackTrace->GetFrame(0));
17104     checkStackFrame(origin, "foo", 6, 3, false, false,
17105                     stackTrace->GetFrame(1));
17106     // This is the source string inside the eval which has the call to foo.
17107     checkStackFrame(NULL, "", 1, 5, false, false,
17108                     stackTrace->GetFrame(2));
17109     // The last frame is an anonymous function which has the initial eval call.
17110     checkStackFrame(origin, "", 8, 7, false, false,
17111                     stackTrace->GetFrame(3));
17112
17113     CHECK(stackTrace->AsArray()->IsArray());
17114   } else if (testGroup == kDetailedTest) {
17115     v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17116         args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17117     CHECK_EQ(4, stackTrace->GetFrameCount());
17118     checkStackFrame(origin, "bat", 4, 22, false, false,
17119                     stackTrace->GetFrame(0));
17120     checkStackFrame(origin, "baz", 8, 3, false, true,
17121                     stackTrace->GetFrame(1));
17122     bool is_eval = true;
17123     // This is the source string inside the eval which has the call to baz.
17124     checkStackFrame(NULL, "", 1, 5, is_eval, false,
17125                     stackTrace->GetFrame(2));
17126     // The last frame is an anonymous function which has the initial eval call.
17127     checkStackFrame(origin, "", 10, 1, false, false,
17128                     stackTrace->GetFrame(3));
17129
17130     CHECK(stackTrace->AsArray()->IsArray());
17131   }
17132 }
17133
17134
17135 // Tests the C++ StackTrace API.
17136 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17137 // THREADED_TEST(CaptureStackTrace) {
17138 TEST(CaptureStackTrace) {
17139   v8::Isolate* isolate = CcTest::isolate();
17140   v8::HandleScope scope(isolate);
17141   v8::Handle<v8::String> origin =
17142       v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17143   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17144   templ->Set(v8_str("AnalyzeStackInNativeCode"),
17145              v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17146   LocalContext context(0, templ);
17147
17148   // Test getting OVERVIEW information. Should ignore information that is not
17149   // script name, function name, line number, and column offset.
17150   const char *overview_source =
17151     "function bar() {\n"
17152     "  var y; AnalyzeStackInNativeCode(1);\n"
17153     "}\n"
17154     "function foo() {\n"
17155     "\n"
17156     "  bar();\n"
17157     "}\n"
17158     "var x;eval('new foo();');";
17159   v8::Handle<v8::String> overview_src =
17160       v8::String::NewFromUtf8(isolate, overview_source);
17161   v8::ScriptCompiler::Source script_source(overview_src,
17162                                            v8::ScriptOrigin(origin));
17163   v8::Handle<Value> overview_result(
17164       v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17165           ->BindToCurrentContext()
17166           ->Run());
17167   CHECK(!overview_result.IsEmpty());
17168   CHECK(overview_result->IsObject());
17169
17170   // Test getting DETAILED information.
17171   const char *detailed_source =
17172     "function bat() {AnalyzeStackInNativeCode(2);\n"
17173     "}\n"
17174     "\n"
17175     "function baz() {\n"
17176     "  bat();\n"
17177     "}\n"
17178     "eval('new baz();');";
17179   v8::Handle<v8::String> detailed_src =
17180       v8::String::NewFromUtf8(isolate, detailed_source);
17181   // Make the script using a non-zero line and column offset.
17182   v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17183   v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17184   v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17185   v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17186   v8::Handle<v8::UnboundScript> detailed_script(
17187       v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17188   v8::Handle<Value> detailed_result(
17189       detailed_script->BindToCurrentContext()->Run());
17190   CHECK(!detailed_result.IsEmpty());
17191   CHECK(detailed_result->IsObject());
17192 }
17193
17194
17195 static void StackTraceForUncaughtExceptionListener(
17196     v8::Handle<v8::Message> message,
17197     v8::Handle<Value>) {
17198   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17199   CHECK_EQ(2, stack_trace->GetFrameCount());
17200   checkStackFrame("origin", "foo", 2, 3, false, false,
17201                   stack_trace->GetFrame(0));
17202   checkStackFrame("origin", "bar", 5, 3, false, false,
17203                   stack_trace->GetFrame(1));
17204 }
17205
17206
17207 TEST(CaptureStackTraceForUncaughtException) {
17208   report_count = 0;
17209   LocalContext env;
17210   v8::HandleScope scope(env->GetIsolate());
17211   v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17212   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17213
17214   CompileRunWithOrigin(
17215       "function foo() {\n"
17216       "  throw 1;\n"
17217       "};\n"
17218       "function bar() {\n"
17219       "  foo();\n"
17220       "};",
17221       "origin");
17222   v8::Local<v8::Object> global = env->Global();
17223   Local<Value> trouble = global->Get(v8_str("bar"));
17224   CHECK(trouble->IsFunction());
17225   Function::Cast(*trouble)->Call(global, 0, NULL);
17226   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17227   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17228 }
17229
17230
17231 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17232   LocalContext env;
17233   v8::HandleScope scope(env->GetIsolate());
17234   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17235                                                     1024,
17236                                                     v8::StackTrace::kDetailed);
17237
17238   CompileRun(
17239       "var setters = ['column', 'lineNumber', 'scriptName',\n"
17240       "    'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17241       "    'isConstructor'];\n"
17242       "for (var i = 0; i < setters.length; i++) {\n"
17243       "  var prop = setters[i];\n"
17244       "  Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17245       "}\n");
17246   CompileRun("throw 'exception';");
17247   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17248 }
17249
17250
17251 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17252                                      v8::Handle<v8::Value> data) {
17253   // Use the frame where JavaScript is called from.
17254   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17255   CHECK(!stack_trace.IsEmpty());
17256   int frame_count = stack_trace->GetFrameCount();
17257   CHECK_EQ(3, frame_count);
17258   int line_number[] = {1, 2, 5};
17259   for (int i = 0; i < frame_count; i++) {
17260     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17261   }
17262 }
17263
17264
17265 // Test that we only return the stack trace at the site where the exception
17266 // is first thrown (not where it is rethrown).
17267 TEST(RethrowStackTrace) {
17268   LocalContext env;
17269   v8::HandleScope scope(env->GetIsolate());
17270   // We make sure that
17271   // - the stack trace of the ReferenceError in g() is reported.
17272   // - the stack trace is not overwritten when e1 is rethrown by t().
17273   // - the stack trace of e2 does not overwrite that of e1.
17274   const char* source =
17275       "function g() { error; }          \n"
17276       "function f() { g(); }            \n"
17277       "function t(e) { throw e; }       \n"
17278       "try {                            \n"
17279       "  f();                           \n"
17280       "} catch (e1) {                   \n"
17281       "  try {                          \n"
17282       "    error;                       \n"
17283       "  } catch (e2) {                 \n"
17284       "    t(e1);                       \n"
17285       "  }                              \n"
17286       "}                                \n";
17287   v8::V8::AddMessageListener(RethrowStackTraceHandler);
17288   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17289   CompileRun(source);
17290   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17291   v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17292 }
17293
17294
17295 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17296                                               v8::Handle<v8::Value> data) {
17297   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17298   CHECK(!stack_trace.IsEmpty());
17299   int frame_count = stack_trace->GetFrameCount();
17300   CHECK_EQ(2, frame_count);
17301   int line_number[] = {3, 7};
17302   for (int i = 0; i < frame_count; i++) {
17303     CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17304   }
17305 }
17306
17307
17308 // Test that we do not recognize identity for primitive exceptions.
17309 TEST(RethrowPrimitiveStackTrace) {
17310   LocalContext env;
17311   v8::HandleScope scope(env->GetIsolate());
17312   // We do not capture stack trace for non Error objects on creation time.
17313   // Instead, we capture the stack trace on last throw.
17314   const char* source =
17315       "function g() { throw 404; }      \n"
17316       "function f() { g(); }            \n"
17317       "function t(e) { throw e; }       \n"
17318       "try {                            \n"
17319       "  f();                           \n"
17320       "} catch (e1) {                   \n"
17321       "  t(e1)                          \n"
17322       "}                                \n";
17323   v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17324   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17325   CompileRun(source);
17326   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17327   v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17328 }
17329
17330
17331 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17332                                               v8::Handle<v8::Value> data) {
17333   // Use the frame where JavaScript is called from.
17334   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17335   CHECK(!stack_trace.IsEmpty());
17336   CHECK_EQ(1, stack_trace->GetFrameCount());
17337   CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17338 }
17339
17340
17341 // Test that the stack trace is captured when the error object is created and
17342 // not where it is thrown.
17343 TEST(RethrowExistingStackTrace) {
17344   LocalContext env;
17345   v8::HandleScope scope(env->GetIsolate());
17346   const char* source =
17347       "var e = new Error();           \n"
17348       "throw e;                       \n";
17349   v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17350   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17351   CompileRun(source);
17352   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17353   v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17354 }
17355
17356
17357 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17358                                                v8::Handle<v8::Value> data) {
17359   // Use the frame where JavaScript is called from.
17360   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17361   CHECK(!stack_trace.IsEmpty());
17362   CHECK_EQ(1, stack_trace->GetFrameCount());
17363   CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17364 }
17365
17366
17367 // Test that the stack trace is captured where the bogus Error object is thrown.
17368 TEST(RethrowBogusErrorStackTrace) {
17369   LocalContext env;
17370   v8::HandleScope scope(env->GetIsolate());
17371   const char* source =
17372       "var e = {__proto__: new Error()} \n"
17373       "throw e;                         \n";
17374   v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17375   v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17376   CompileRun(source);
17377   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17378   v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17379 }
17380
17381
17382 void AnalyzeStackOfEvalWithSourceURL(
17383     const v8::FunctionCallbackInfo<v8::Value>& args) {
17384   v8::HandleScope scope(args.GetIsolate());
17385   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17386       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17387   CHECK_EQ(5, stackTrace->GetFrameCount());
17388   v8::Handle<v8::String> url = v8_str("eval_url");
17389   for (int i = 0; i < 3; i++) {
17390     v8::Handle<v8::String> name =
17391         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17392     CHECK(!name.IsEmpty());
17393     CHECK_EQ(url, name);
17394   }
17395 }
17396
17397
17398 TEST(SourceURLInStackTrace) {
17399   v8::Isolate* isolate = CcTest::isolate();
17400   v8::HandleScope scope(isolate);
17401   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17402   templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
17403              v8::FunctionTemplate::New(isolate,
17404                                        AnalyzeStackOfEvalWithSourceURL));
17405   LocalContext context(0, templ);
17406
17407   const char *source =
17408     "function outer() {\n"
17409     "function bar() {\n"
17410     "  AnalyzeStackOfEvalWithSourceURL();\n"
17411     "}\n"
17412     "function foo() {\n"
17413     "\n"
17414     "  bar();\n"
17415     "}\n"
17416     "foo();\n"
17417     "}\n"
17418     "eval('(' + outer +')()%s');";
17419
17420   i::ScopedVector<char> code(1024);
17421   i::SNPrintF(code, source, "//# sourceURL=eval_url");
17422   CHECK(CompileRun(code.start())->IsUndefined());
17423   i::SNPrintF(code, source, "//@ sourceURL=eval_url");
17424   CHECK(CompileRun(code.start())->IsUndefined());
17425 }
17426
17427
17428 static int scriptIdInStack[2];
17429
17430 void AnalyzeScriptIdInStack(
17431     const v8::FunctionCallbackInfo<v8::Value>& args) {
17432   v8::HandleScope scope(args.GetIsolate());
17433   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17434       args.GetIsolate(), 10, v8::StackTrace::kScriptId);
17435   CHECK_EQ(2, stackTrace->GetFrameCount());
17436   for (int i = 0; i < 2; i++) {
17437     scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
17438   }
17439 }
17440
17441
17442 TEST(ScriptIdInStackTrace) {
17443   v8::Isolate* isolate = CcTest::isolate();
17444   v8::HandleScope scope(isolate);
17445   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17446   templ->Set(v8_str("AnalyzeScriptIdInStack"),
17447              v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
17448   LocalContext context(0, templ);
17449
17450   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
17451     isolate,
17452     "function foo() {\n"
17453     "  AnalyzeScriptIdInStack();"
17454     "}\n"
17455     "foo();\n");
17456   v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
17457   script->Run();
17458   for (int i = 0; i < 2; i++) {
17459     CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
17460     CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
17461   }
17462 }
17463
17464
17465 void AnalyzeStackOfInlineScriptWithSourceURL(
17466     const v8::FunctionCallbackInfo<v8::Value>& args) {
17467   v8::HandleScope scope(args.GetIsolate());
17468   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17469       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17470   CHECK_EQ(4, stackTrace->GetFrameCount());
17471   v8::Handle<v8::String> url = v8_str("url");
17472   for (int i = 0; i < 3; i++) {
17473     v8::Handle<v8::String> name =
17474         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17475     CHECK(!name.IsEmpty());
17476     CHECK_EQ(url, name);
17477   }
17478 }
17479
17480
17481 TEST(InlineScriptWithSourceURLInStackTrace) {
17482   v8::Isolate* isolate = CcTest::isolate();
17483   v8::HandleScope scope(isolate);
17484   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17485   templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
17486              v8::FunctionTemplate::New(
17487                  CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
17488   LocalContext context(0, templ);
17489
17490   const char *source =
17491     "function outer() {\n"
17492     "function bar() {\n"
17493     "  AnalyzeStackOfInlineScriptWithSourceURL();\n"
17494     "}\n"
17495     "function foo() {\n"
17496     "\n"
17497     "  bar();\n"
17498     "}\n"
17499     "foo();\n"
17500     "}\n"
17501     "outer()\n%s";
17502
17503   i::ScopedVector<char> code(1024);
17504   i::SNPrintF(code, source, "//# sourceURL=source_url");
17505   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17506   i::SNPrintF(code, source, "//@ sourceURL=source_url");
17507   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
17508 }
17509
17510
17511 void AnalyzeStackOfDynamicScriptWithSourceURL(
17512     const v8::FunctionCallbackInfo<v8::Value>& args) {
17513   v8::HandleScope scope(args.GetIsolate());
17514   v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17515       args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17516   CHECK_EQ(4, stackTrace->GetFrameCount());
17517   v8::Handle<v8::String> url = v8_str("source_url");
17518   for (int i = 0; i < 3; i++) {
17519     v8::Handle<v8::String> name =
17520         stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
17521     CHECK(!name.IsEmpty());
17522     CHECK_EQ(url, name);
17523   }
17524 }
17525
17526
17527 TEST(DynamicWithSourceURLInStackTrace) {
17528   v8::Isolate* isolate = CcTest::isolate();
17529   v8::HandleScope scope(isolate);
17530   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17531   templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
17532              v8::FunctionTemplate::New(
17533                  CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
17534   LocalContext context(0, templ);
17535
17536   const char *source =
17537     "function outer() {\n"
17538     "function bar() {\n"
17539     "  AnalyzeStackOfDynamicScriptWithSourceURL();\n"
17540     "}\n"
17541     "function foo() {\n"
17542     "\n"
17543     "  bar();\n"
17544     "}\n"
17545     "foo();\n"
17546     "}\n"
17547     "outer()\n%s";
17548
17549   i::ScopedVector<char> code(1024);
17550   i::SNPrintF(code, source, "//# sourceURL=source_url");
17551   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17552   i::SNPrintF(code, source, "//@ sourceURL=source_url");
17553   CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
17554 }
17555
17556
17557 TEST(DynamicWithSourceURLInStackTraceString) {
17558   LocalContext context;
17559   v8::HandleScope scope(context->GetIsolate());
17560
17561   const char *source =
17562     "function outer() {\n"
17563     "  function foo() {\n"
17564     "    FAIL.FAIL;\n"
17565     "  }\n"
17566     "  foo();\n"
17567     "}\n"
17568     "outer()\n%s";
17569
17570   i::ScopedVector<char> code(1024);
17571   i::SNPrintF(code, source, "//# sourceURL=source_url");
17572   v8::TryCatch try_catch;
17573   CompileRunWithOrigin(code.start(), "", 0, 0);
17574   CHECK(try_catch.HasCaught());
17575   v8::String::Utf8Value stack(try_catch.StackTrace());
17576   CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
17577 }
17578
17579
17580 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17581   LocalContext context;
17582   v8::HandleScope scope(context->GetIsolate());
17583
17584   const char *source =
17585     "function outer() {\n"
17586     "  var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
17587     "  //# sourceURL=source_url\";\n"
17588     "  eval(scriptContents);\n"
17589     "  foo(); }\n"
17590     "outer();\n"
17591     "//# sourceURL=outer_url";
17592
17593   v8::TryCatch try_catch;
17594   CompileRun(source);
17595   CHECK(try_catch.HasCaught());
17596
17597   Local<v8::Message> message = try_catch.Message();
17598   Handle<Value> sourceURL =
17599     message->GetScriptOrigin().ResourceName();
17600   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17601 }
17602
17603
17604 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
17605   LocalContext context;
17606   v8::HandleScope scope(context->GetIsolate());
17607
17608   const char *source =
17609     "function outer() {\n"
17610     "  var scriptContents = \"function boo(){ boo(); }\\\n"
17611     "  //# sourceURL=source_url\";\n"
17612     "  eval(scriptContents);\n"
17613     "  boo(); }\n"
17614     "outer();\n"
17615     "//# sourceURL=outer_url";
17616
17617   v8::TryCatch try_catch;
17618   CompileRun(source);
17619   CHECK(try_catch.HasCaught());
17620
17621   Local<v8::Message> message = try_catch.Message();
17622   Handle<Value> sourceURL =
17623     message->GetScriptOrigin().ResourceName();
17624   CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
17625 }
17626
17627
17628 static void CreateGarbageInOldSpace() {
17629   i::Factory* factory = CcTest::i_isolate()->factory();
17630   v8::HandleScope scope(CcTest::isolate());
17631   i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
17632   for (int i = 0; i < 1000; i++) {
17633     factory->NewFixedArray(1000, i::TENURED);
17634   }
17635 }
17636
17637
17638 // Test that idle notification can be handled and eventually returns true.
17639 TEST(IdleNotification) {
17640   const intptr_t MB = 1024 * 1024;
17641   const int IdlePauseInMs = 1000;
17642   LocalContext env;
17643   v8::HandleScope scope(env->GetIsolate());
17644   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17645   CreateGarbageInOldSpace();
17646   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17647   CHECK_GT(size_with_garbage, initial_size + MB);
17648   bool finished = false;
17649   for (int i = 0; i < 200 && !finished; i++) {
17650     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17651   }
17652   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17653   CHECK(finished);
17654   CHECK_LT(final_size, initial_size + 1);
17655 }
17656
17657
17658 // Test that idle notification can be handled and eventually collects garbage.
17659 TEST(IdleNotificationWithSmallHint) {
17660   const intptr_t MB = 1024 * 1024;
17661   const int IdlePauseInMs = 900;
17662   LocalContext env;
17663   v8::HandleScope scope(env->GetIsolate());
17664   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17665   CreateGarbageInOldSpace();
17666   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17667   CHECK_GT(size_with_garbage, initial_size + MB);
17668   bool finished = false;
17669   for (int i = 0; i < 200 && !finished; i++) {
17670     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17671   }
17672   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17673   CHECK(finished);
17674   CHECK_LT(final_size, initial_size + 1);
17675 }
17676
17677
17678 // Test that idle notification can be handled and eventually collects garbage.
17679 TEST(IdleNotificationWithLargeHint) {
17680   const intptr_t MB = 1024 * 1024;
17681   const int IdlePauseInMs = 900;
17682   LocalContext env;
17683   v8::HandleScope scope(env->GetIsolate());
17684   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17685   CreateGarbageInOldSpace();
17686   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17687   CHECK_GT(size_with_garbage, initial_size + MB);
17688   bool finished = false;
17689   for (int i = 0; i < 200 && !finished; i++) {
17690     finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
17691   }
17692   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17693   CHECK(finished);
17694   CHECK_LT(final_size, initial_size + 1);
17695 }
17696
17697
17698 TEST(Regress2107) {
17699   const intptr_t MB = 1024 * 1024;
17700   const int kShortIdlePauseInMs = 100;
17701   const int kLongIdlePauseInMs = 1000;
17702   LocalContext env;
17703   v8::Isolate* isolate = env->GetIsolate();
17704   v8::HandleScope scope(env->GetIsolate());
17705   intptr_t initial_size = CcTest::heap()->SizeOfObjects();
17706   // Send idle notification to start a round of incremental GCs.
17707   env->GetIsolate()->IdleNotification(kShortIdlePauseInMs);
17708   // Emulate 7 page reloads.
17709   for (int i = 0; i < 7; i++) {
17710     {
17711       v8::HandleScope inner_scope(env->GetIsolate());
17712       v8::Local<v8::Context> ctx = v8::Context::New(isolate);
17713       ctx->Enter();
17714       CreateGarbageInOldSpace();
17715       ctx->Exit();
17716     }
17717     env->GetIsolate()->ContextDisposedNotification();
17718     env->GetIsolate()->IdleNotification(kLongIdlePauseInMs);
17719   }
17720   // Create garbage and check that idle notification still collects it.
17721   CreateGarbageInOldSpace();
17722   intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
17723   CHECK_GT(size_with_garbage, initial_size + MB);
17724   bool finished = false;
17725   for (int i = 0; i < 200 && !finished; i++) {
17726     finished = env->GetIsolate()->IdleNotification(kShortIdlePauseInMs);
17727   }
17728   intptr_t final_size = CcTest::heap()->SizeOfObjects();
17729   CHECK_LT(final_size, initial_size + 1);
17730 }
17731
17732
17733 TEST(Regress2333) {
17734   LocalContext env;
17735   for (int i = 0; i < 3; i++) {
17736     CcTest::heap()->CollectGarbage(i::NEW_SPACE);
17737   }
17738 }
17739
17740 static uint32_t* stack_limit;
17741
17742 static void GetStackLimitCallback(
17743     const v8::FunctionCallbackInfo<v8::Value>& args) {
17744   stack_limit = reinterpret_cast<uint32_t*>(
17745       CcTest::i_isolate()->stack_guard()->real_climit());
17746 }
17747
17748
17749 // Uses the address of a local variable to determine the stack top now.
17750 // Given a size, returns an address that is that far from the current
17751 // top of stack.
17752 static uint32_t* ComputeStackLimit(uint32_t size) {
17753   uint32_t* answer = &size - (size / sizeof(size));
17754   // If the size is very large and the stack is very near the bottom of
17755   // memory then the calculation above may wrap around and give an address
17756   // that is above the (downwards-growing) stack.  In that case we return
17757   // a very low address.
17758   if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
17759   return answer;
17760 }
17761
17762
17763 // We need at least 165kB for an x64 debug build with clang and ASAN.
17764 static const int stack_breathing_room = 256 * i::KB;
17765
17766
17767 TEST(SetResourceConstraints) {
17768   uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
17769
17770   // Set stack limit.
17771   v8::ResourceConstraints constraints;
17772   constraints.set_stack_limit(set_limit);
17773   CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17774
17775   // Execute a script.
17776   LocalContext env;
17777   v8::HandleScope scope(env->GetIsolate());
17778   Local<v8::FunctionTemplate> fun_templ =
17779       v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
17780   Local<Function> fun = fun_templ->GetFunction();
17781   env->Global()->Set(v8_str("get_stack_limit"), fun);
17782   CompileRun("get_stack_limit();");
17783
17784   CHECK(stack_limit == set_limit);
17785 }
17786
17787
17788 TEST(SetResourceConstraintsInThread) {
17789   uint32_t* set_limit;
17790   {
17791     v8::Locker locker(CcTest::isolate());
17792     set_limit = ComputeStackLimit(stack_breathing_room);
17793
17794     // Set stack limit.
17795     v8::ResourceConstraints constraints;
17796     constraints.set_stack_limit(set_limit);
17797     CHECK(v8::SetResourceConstraints(CcTest::isolate(), &constraints));
17798
17799     // Execute a script.
17800     v8::HandleScope scope(CcTest::isolate());
17801     LocalContext env;
17802     Local<v8::FunctionTemplate> fun_templ =
17803         v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
17804     Local<Function> fun = fun_templ->GetFunction();
17805     env->Global()->Set(v8_str("get_stack_limit"), fun);
17806     CompileRun("get_stack_limit();");
17807
17808     CHECK(stack_limit == set_limit);
17809   }
17810   {
17811     v8::Locker locker(CcTest::isolate());
17812     CHECK(stack_limit == set_limit);
17813   }
17814 }
17815
17816
17817 THREADED_TEST(GetHeapStatistics) {
17818   LocalContext c1;
17819   v8::HandleScope scope(c1->GetIsolate());
17820   v8::HeapStatistics heap_statistics;
17821   CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
17822   CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
17823   c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
17824   CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
17825   CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
17826 }
17827
17828
17829 class VisitorImpl : public v8::ExternalResourceVisitor {
17830  public:
17831   explicit VisitorImpl(TestResource** resource) {
17832     for (int i = 0; i < 4; i++) {
17833       resource_[i] = resource[i];
17834       found_resource_[i] = false;
17835     }
17836   }
17837   virtual ~VisitorImpl() {}
17838   virtual void VisitExternalString(v8::Handle<v8::String> string) {
17839     if (!string->IsExternal()) {
17840       CHECK(string->IsExternalAscii());
17841       return;
17842     }
17843     v8::String::ExternalStringResource* resource =
17844         string->GetExternalStringResource();
17845     CHECK(resource);
17846     for (int i = 0; i < 4; i++) {
17847       if (resource_[i] == resource) {
17848         CHECK(!found_resource_[i]);
17849         found_resource_[i] = true;
17850       }
17851     }
17852   }
17853   void CheckVisitedResources() {
17854     for (int i = 0; i < 4; i++) {
17855       CHECK(found_resource_[i]);
17856     }
17857   }
17858
17859  private:
17860   v8::String::ExternalStringResource* resource_[4];
17861   bool found_resource_[4];
17862 };
17863
17864
17865 TEST(ExternalizeOldSpaceTwoByteCons) {
17866   LocalContext env;
17867   v8::HandleScope scope(env->GetIsolate());
17868   v8::Local<v8::String> cons =
17869       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17870   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17871   CcTest::heap()->CollectAllAvailableGarbage();
17872   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17873             *v8::Utils::OpenHandle(*cons)));
17874
17875   TestResource* resource = new TestResource(
17876       AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
17877   cons->MakeExternal(resource);
17878
17879   CHECK(cons->IsExternal());
17880   CHECK_EQ(resource, cons->GetExternalStringResource());
17881   String::Encoding encoding;
17882   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17883   CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
17884 }
17885
17886
17887 TEST(ExternalizeOldSpaceOneByteCons) {
17888   LocalContext env;
17889   v8::HandleScope scope(env->GetIsolate());
17890   v8::Local<v8::String> cons =
17891       CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
17892   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
17893   CcTest::heap()->CollectAllAvailableGarbage();
17894   CHECK(CcTest::heap()->old_pointer_space()->Contains(
17895             *v8::Utils::OpenHandle(*cons)));
17896
17897   TestAsciiResource* resource =
17898       new TestAsciiResource(i::StrDup("Romeo Montague Juliet Capulet"));
17899   cons->MakeExternal(resource);
17900
17901   CHECK(cons->IsExternalAscii());
17902   CHECK_EQ(resource, cons->GetExternalAsciiStringResource());
17903   String::Encoding encoding;
17904   CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
17905   CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
17906 }
17907
17908
17909 TEST(VisitExternalStrings) {
17910   LocalContext env;
17911   v8::HandleScope scope(env->GetIsolate());
17912   const char* string = "Some string";
17913   uint16_t* two_byte_string = AsciiToTwoByteString(string);
17914   TestResource* resource[4];
17915   resource[0] = new TestResource(two_byte_string);
17916   v8::Local<v8::String> string0 =
17917       v8::String::NewExternal(env->GetIsolate(), resource[0]);
17918   resource[1] = new TestResource(two_byte_string, NULL, false);
17919   v8::Local<v8::String> string1 =
17920       v8::String::NewExternal(env->GetIsolate(), resource[1]);
17921
17922   // Externalized symbol.
17923   resource[2] = new TestResource(two_byte_string, NULL, false);
17924   v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
17925       env->GetIsolate(), string, v8::String::kInternalizedString);
17926   CHECK(string2->MakeExternal(resource[2]));
17927
17928   // Symbolized External.
17929   resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
17930   v8::Local<v8::String> string3 =
17931       v8::String::NewExternal(env->GetIsolate(), resource[3]);
17932   CcTest::heap()->CollectAllAvailableGarbage();  // Tenure string.
17933   // Turn into a symbol.
17934   i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
17935   CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
17936       string3_i).is_null());
17937   CHECK(string3_i->IsInternalizedString());
17938
17939   // We need to add usages for string* to avoid warnings in GCC 4.7
17940   CHECK(string0->IsExternal());
17941   CHECK(string1->IsExternal());
17942   CHECK(string2->IsExternal());
17943   CHECK(string3->IsExternal());
17944
17945   VisitorImpl visitor(resource);
17946   v8::V8::VisitExternalResources(&visitor);
17947   visitor.CheckVisitedResources();
17948 }
17949
17950
17951 TEST(ExternalStringCollectedAtTearDown) {
17952   int destroyed = 0;
17953   v8::Isolate* isolate = v8::Isolate::New();
17954   { v8::Isolate::Scope isolate_scope(isolate);
17955     v8::HandleScope handle_scope(isolate);
17956     const char* s = "One string to test them all, one string to find them.";
17957     TestAsciiResource* inscription =
17958         new TestAsciiResource(i::StrDup(s), &destroyed);
17959     v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
17960     // Ring is still alive.  Orcs are roaming freely across our lands.
17961     CHECK_EQ(0, destroyed);
17962     USE(ring);
17963   }
17964
17965   isolate->Dispose();
17966   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17967   CHECK_EQ(1, destroyed);
17968 }
17969
17970
17971 TEST(ExternalInternalizedStringCollectedAtTearDown) {
17972   int destroyed = 0;
17973   v8::Isolate* isolate = v8::Isolate::New();
17974   { v8::Isolate::Scope isolate_scope(isolate);
17975     LocalContext env(isolate);
17976     v8::HandleScope handle_scope(isolate);
17977     CompileRun("var ring = 'One string to test them all';");
17978     const char* s = "One string to test them all";
17979     TestAsciiResource* inscription =
17980         new TestAsciiResource(i::StrDup(s), &destroyed);
17981     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
17982     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
17983     ring->MakeExternal(inscription);
17984     // Ring is still alive.  Orcs are roaming freely across our lands.
17985     CHECK_EQ(0, destroyed);
17986     USE(ring);
17987   }
17988
17989   isolate->Dispose();
17990   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
17991   CHECK_EQ(1, destroyed);
17992 }
17993
17994
17995 TEST(ExternalInternalizedStringCollectedAtGC) {
17996   int destroyed = 0;
17997   { LocalContext env;
17998     v8::HandleScope handle_scope(env->GetIsolate());
17999     CompileRun("var ring = 'One string to test them all';");
18000     const char* s = "One string to test them all";
18001     TestAsciiResource* inscription =
18002         new TestAsciiResource(i::StrDup(s), &destroyed);
18003     v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18004     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18005     ring->MakeExternal(inscription);
18006     // Ring is still alive.  Orcs are roaming freely across our lands.
18007     CHECK_EQ(0, destroyed);
18008     USE(ring);
18009   }
18010
18011   // Garbage collector deals swift blows to evil.
18012   CcTest::i_isolate()->compilation_cache()->Clear();
18013   CcTest::heap()->CollectAllAvailableGarbage();
18014
18015   // Ring has been destroyed.  Free Peoples of Middle-earth Rejoice.
18016   CHECK_EQ(1, destroyed);
18017 }
18018
18019
18020 static double DoubleFromBits(uint64_t value) {
18021   double target;
18022   i::MemCopy(&target, &value, sizeof(target));
18023   return target;
18024 }
18025
18026
18027 static uint64_t DoubleToBits(double value) {
18028   uint64_t target;
18029   i::MemCopy(&target, &value, sizeof(target));
18030   return target;
18031 }
18032
18033
18034 static double DoubleToDateTime(double input) {
18035   double date_limit = 864e13;
18036   if (std::isnan(input) || input < -date_limit || input > date_limit) {
18037     return v8::base::OS::nan_value();
18038   }
18039   return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18040 }
18041
18042
18043 // We don't have a consistent way to write 64-bit constants syntactically, so we
18044 // split them into two 32-bit constants and combine them programmatically.
18045 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18046   return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18047 }
18048
18049
18050 THREADED_TEST(QuietSignalingNaNs) {
18051   LocalContext context;
18052   v8::Isolate* isolate = context->GetIsolate();
18053   v8::HandleScope scope(isolate);
18054   v8::TryCatch try_catch;
18055
18056   // Special double values.
18057   double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18058   double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18059   double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18060   double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18061   double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18062   double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18063   double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18064
18065   // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18066   // on either side of the epoch.
18067   double date_limit = 864e13;
18068
18069   double test_values[] = {
18070       snan,
18071       qnan,
18072       infinity,
18073       max_normal,
18074       date_limit + 1,
18075       date_limit,
18076       min_normal,
18077       max_denormal,
18078       min_denormal,
18079       0,
18080       -0,
18081       -min_denormal,
18082       -max_denormal,
18083       -min_normal,
18084       -date_limit,
18085       -date_limit - 1,
18086       -max_normal,
18087       -infinity,
18088       -qnan,
18089       -snan
18090   };
18091   int num_test_values = 20;
18092
18093   for (int i = 0; i < num_test_values; i++) {
18094     double test_value = test_values[i];
18095
18096     // Check that Number::New preserves non-NaNs and quiets SNaNs.
18097     v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
18098     double stored_number = number->NumberValue();
18099     if (!std::isnan(test_value)) {
18100       CHECK_EQ(test_value, stored_number);
18101     } else {
18102       uint64_t stored_bits = DoubleToBits(stored_number);
18103       // Check if quiet nan (bits 51..62 all set).
18104 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18105     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18106       // Most significant fraction bit for quiet nan is set to 0
18107       // on MIPS architecture. Allowed by IEEE-754.
18108       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18109 #else
18110       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18111 #endif
18112     }
18113
18114     // Check that Date::New preserves non-NaNs in the date range and
18115     // quiets SNaNs.
18116     v8::Handle<v8::Value> date =
18117         v8::Date::New(isolate, test_value);
18118     double expected_stored_date = DoubleToDateTime(test_value);
18119     double stored_date = date->NumberValue();
18120     if (!std::isnan(expected_stored_date)) {
18121       CHECK_EQ(expected_stored_date, stored_date);
18122     } else {
18123       uint64_t stored_bits = DoubleToBits(stored_date);
18124       // Check if quiet nan (bits 51..62 all set).
18125 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
18126     !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
18127       // Most significant fraction bit for quiet nan is set to 0
18128       // on MIPS architecture. Allowed by IEEE-754.
18129       CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
18130 #else
18131       CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
18132 #endif
18133     }
18134   }
18135 }
18136
18137
18138 static void SpaghettiIncident(
18139     const v8::FunctionCallbackInfo<v8::Value>& args) {
18140   v8::HandleScope scope(args.GetIsolate());
18141   v8::TryCatch tc;
18142   v8::Handle<v8::String> str(args[0]->ToString());
18143   USE(str);
18144   if (tc.HasCaught())
18145     tc.ReThrow();
18146 }
18147
18148
18149 // Test that an exception can be propagated down through a spaghetti
18150 // stack using ReThrow.
18151 THREADED_TEST(SpaghettiStackReThrow) {
18152   v8::Isolate* isolate = CcTest::isolate();
18153   v8::HandleScope scope(isolate);
18154   LocalContext context;
18155   context->Global()->Set(
18156       v8::String::NewFromUtf8(isolate, "s"),
18157       v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
18158   v8::TryCatch try_catch;
18159   CompileRun(
18160       "var i = 0;"
18161       "var o = {"
18162       "  toString: function () {"
18163       "    if (i == 10) {"
18164       "      throw 'Hey!';"
18165       "    } else {"
18166       "      i++;"
18167       "      return s(o);"
18168       "    }"
18169       "  }"
18170       "};"
18171       "s(o);");
18172   CHECK(try_catch.HasCaught());
18173   v8::String::Utf8Value value(try_catch.Exception());
18174   CHECK_EQ(0, strcmp(*value, "Hey!"));
18175 }
18176
18177
18178 TEST(Regress528) {
18179   v8::V8::Initialize();
18180   v8::Isolate* isolate = CcTest::isolate();
18181   v8::HandleScope scope(isolate);
18182   v8::Local<Context> other_context;
18183   int gc_count;
18184
18185   // Create a context used to keep the code from aging in the compilation
18186   // cache.
18187   other_context = Context::New(isolate);
18188
18189   // Context-dependent context data creates reference from the compilation
18190   // cache to the global object.
18191   const char* source_simple = "1";
18192   {
18193     v8::HandleScope scope(isolate);
18194     v8::Local<Context> context = Context::New(isolate);
18195
18196     context->Enter();
18197     Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
18198     context->SetEmbedderData(0, obj);
18199     CompileRun(source_simple);
18200     context->Exit();
18201   }
18202   isolate->ContextDisposedNotification();
18203   for (gc_count = 1; gc_count < 10; gc_count++) {
18204     other_context->Enter();
18205     CompileRun(source_simple);
18206     other_context->Exit();
18207     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18208     if (GetGlobalObjectsCount() == 1) break;
18209   }
18210   CHECK_GE(2, gc_count);
18211   CHECK_EQ(1, GetGlobalObjectsCount());
18212
18213   // Eval in a function creates reference from the compilation cache to the
18214   // global object.
18215   const char* source_eval = "function f(){eval('1')}; f()";
18216   {
18217     v8::HandleScope scope(isolate);
18218     v8::Local<Context> context = Context::New(isolate);
18219
18220     context->Enter();
18221     CompileRun(source_eval);
18222     context->Exit();
18223   }
18224   isolate->ContextDisposedNotification();
18225   for (gc_count = 1; gc_count < 10; gc_count++) {
18226     other_context->Enter();
18227     CompileRun(source_eval);
18228     other_context->Exit();
18229     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18230     if (GetGlobalObjectsCount() == 1) break;
18231   }
18232   CHECK_GE(2, gc_count);
18233   CHECK_EQ(1, GetGlobalObjectsCount());
18234
18235   // Looking up the line number for an exception creates reference from the
18236   // compilation cache to the global object.
18237   const char* source_exception = "function f(){throw 1;} f()";
18238   {
18239     v8::HandleScope scope(isolate);
18240     v8::Local<Context> context = Context::New(isolate);
18241
18242     context->Enter();
18243     v8::TryCatch try_catch;
18244     CompileRun(source_exception);
18245     CHECK(try_catch.HasCaught());
18246     v8::Handle<v8::Message> message = try_catch.Message();
18247     CHECK(!message.IsEmpty());
18248     CHECK_EQ(1, message->GetLineNumber());
18249     context->Exit();
18250   }
18251   isolate->ContextDisposedNotification();
18252   for (gc_count = 1; gc_count < 10; gc_count++) {
18253     other_context->Enter();
18254     CompileRun(source_exception);
18255     other_context->Exit();
18256     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18257     if (GetGlobalObjectsCount() == 1) break;
18258   }
18259   CHECK_GE(2, gc_count);
18260   CHECK_EQ(1, GetGlobalObjectsCount());
18261
18262   isolate->ContextDisposedNotification();
18263 }
18264
18265
18266 THREADED_TEST(ScriptOrigin) {
18267   LocalContext env;
18268   v8::HandleScope scope(env->GetIsolate());
18269   v8::ScriptOrigin origin =
18270       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18271   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18272       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18273   v8::Script::Compile(script, &origin)->Run();
18274   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18275       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18276   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18277       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18278
18279   v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
18280   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
18281   CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
18282
18283   v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
18284   CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
18285   CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
18286 }
18287
18288
18289 THREADED_TEST(FunctionGetInferredName) {
18290   LocalContext env;
18291   v8::HandleScope scope(env->GetIsolate());
18292   v8::ScriptOrigin origin =
18293       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18294   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18295       env->GetIsolate(),
18296       "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
18297   v8::Script::Compile(script, &origin)->Run();
18298   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18299       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18300   CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
18301 }
18302
18303
18304 THREADED_TEST(FunctionGetDisplayName) {
18305   LocalContext env;
18306   v8::HandleScope scope(env->GetIsolate());
18307   const char* code = "var error = false;"
18308                      "function a() { this.x = 1; };"
18309                      "a.displayName = 'display_a';"
18310                      "var b = (function() {"
18311                      "  var f = function() { this.x = 2; };"
18312                      "  f.displayName = 'display_b';"
18313                      "  return f;"
18314                      "})();"
18315                      "var c = function() {};"
18316                      "c.__defineGetter__('displayName', function() {"
18317                      "  error = true;"
18318                      "  throw new Error();"
18319                      "});"
18320                      "function d() {};"
18321                      "d.__defineGetter__('displayName', function() {"
18322                      "  error = true;"
18323                      "  return 'wrong_display_name';"
18324                      "});"
18325                      "function e() {};"
18326                      "e.displayName = 'wrong_display_name';"
18327                      "e.__defineSetter__('displayName', function() {"
18328                      "  error = true;"
18329                      "  throw new Error();"
18330                      "});"
18331                      "function f() {};"
18332                      "f.displayName = { 'foo': 6, toString: function() {"
18333                      "  error = true;"
18334                      "  return 'wrong_display_name';"
18335                      "}};"
18336                      "var g = function() {"
18337                      "  arguments.callee.displayName = 'set_in_runtime';"
18338                      "}; g();"
18339                      ;
18340   v8::ScriptOrigin origin =
18341       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18342   v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
18343       ->Run();
18344   v8::Local<v8::Value> error =
18345       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
18346   v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
18347       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
18348   v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
18349       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
18350   v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
18351       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
18352   v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
18353       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
18354   v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
18355       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
18356   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18357       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18358   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18359       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18360   CHECK_EQ(false, error->BooleanValue());
18361   CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
18362   CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
18363   CHECK(c->GetDisplayName()->IsUndefined());
18364   CHECK(d->GetDisplayName()->IsUndefined());
18365   CHECK(e->GetDisplayName()->IsUndefined());
18366   CHECK(f->GetDisplayName()->IsUndefined());
18367   CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
18368 }
18369
18370
18371 THREADED_TEST(ScriptLineNumber) {
18372   LocalContext env;
18373   v8::HandleScope scope(env->GetIsolate());
18374   v8::ScriptOrigin origin =
18375       v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
18376   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18377       env->GetIsolate(), "function f() {}\n\nfunction g() {}");
18378   v8::Script::Compile(script, &origin)->Run();
18379   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18380       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18381   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18382       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18383   CHECK_EQ(0, f->GetScriptLineNumber());
18384   CHECK_EQ(2, g->GetScriptLineNumber());
18385 }
18386
18387
18388 THREADED_TEST(ScriptColumnNumber) {
18389   LocalContext env;
18390   v8::Isolate* isolate = env->GetIsolate();
18391   v8::HandleScope scope(isolate);
18392   v8::ScriptOrigin origin =
18393       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18394                        v8::Integer::New(isolate, 3),
18395                        v8::Integer::New(isolate, 2));
18396   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18397       isolate, "function foo() {}\n\n     function bar() {}");
18398   v8::Script::Compile(script, &origin)->Run();
18399   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18400       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18401   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18402       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18403   CHECK_EQ(14, foo->GetScriptColumnNumber());
18404   CHECK_EQ(17, bar->GetScriptColumnNumber());
18405 }
18406
18407
18408 THREADED_TEST(FunctionIsBuiltin) {
18409   LocalContext env;
18410   v8::Isolate* isolate = env->GetIsolate();
18411   v8::HandleScope scope(isolate);
18412   v8::Local<v8::Function> f;
18413   f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
18414   CHECK(f->IsBuiltin());
18415   f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
18416   CHECK(f->IsBuiltin());
18417   f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
18418   CHECK(f->IsBuiltin());
18419   f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
18420   CHECK(f->IsBuiltin());
18421   f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
18422   CHECK(!f->IsBuiltin());
18423 }
18424
18425
18426 THREADED_TEST(FunctionGetScriptId) {
18427   LocalContext env;
18428   v8::Isolate* isolate = env->GetIsolate();
18429   v8::HandleScope scope(isolate);
18430   v8::ScriptOrigin origin =
18431       v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
18432                        v8::Integer::New(isolate, 3),
18433                        v8::Integer::New(isolate, 2));
18434   v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18435       isolate, "function foo() {}\n\n     function bar() {}");
18436   v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
18437   script->Run();
18438   v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
18439       env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
18440   v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
18441       env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
18442   CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
18443   CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
18444 }
18445
18446
18447 THREADED_TEST(FunctionGetBoundFunction) {
18448   LocalContext env;
18449   v8::HandleScope scope(env->GetIsolate());
18450   v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
18451       env->GetIsolate(), "test"));
18452   v8::Handle<v8::String> script = v8::String::NewFromUtf8(
18453       env->GetIsolate(),
18454       "var a = new Object();\n"
18455       "a.x = 1;\n"
18456       "function f () { return this.x };\n"
18457       "var g = f.bind(a);\n"
18458       "var b = g();");
18459   v8::Script::Compile(script, &origin)->Run();
18460   v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
18461       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
18462   v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
18463       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
18464   CHECK(g->GetBoundFunction()->IsFunction());
18465   Local<v8::Function> original_function = Local<v8::Function>::Cast(
18466       g->GetBoundFunction());
18467   CHECK_EQ(f->GetName(), original_function->GetName());
18468   CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
18469   CHECK_EQ(f->GetScriptColumnNumber(),
18470            original_function->GetScriptColumnNumber());
18471 }
18472
18473
18474 static void GetterWhichReturns42(
18475     Local<String> name,
18476     const v8::PropertyCallbackInfo<v8::Value>& info) {
18477   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18478   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18479   info.GetReturnValue().Set(v8_num(42));
18480 }
18481
18482
18483 static void SetterWhichSetsYOnThisTo23(
18484     Local<String> name,
18485     Local<Value> value,
18486     const v8::PropertyCallbackInfo<void>& info) {
18487   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18488   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18489   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18490 }
18491
18492
18493 void FooGetInterceptor(Local<String> name,
18494                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18495   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18496   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18497   if (!name->Equals(v8_str("foo"))) return;
18498   info.GetReturnValue().Set(v8_num(42));
18499 }
18500
18501
18502 void FooSetInterceptor(Local<String> name,
18503                        Local<Value> value,
18504                        const v8::PropertyCallbackInfo<v8::Value>& info) {
18505   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
18506   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
18507   if (!name->Equals(v8_str("foo"))) return;
18508   Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18509   info.GetReturnValue().Set(v8_num(23));
18510 }
18511
18512
18513 TEST(SetterOnConstructorPrototype) {
18514   v8::Isolate* isolate = CcTest::isolate();
18515   v8::HandleScope scope(isolate);
18516   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18517   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18518                      SetterWhichSetsYOnThisTo23);
18519   LocalContext context;
18520   context->Global()->Set(v8_str("P"), templ->NewInstance());
18521   CompileRun("function C1() {"
18522              "  this.x = 23;"
18523              "};"
18524              "C1.prototype = P;"
18525              "function C2() {"
18526              "  this.x = 23"
18527              "};"
18528              "C2.prototype = { };"
18529              "C2.prototype.__proto__ = P;");
18530
18531   v8::Local<v8::Script> script;
18532   script = v8_compile("new C1();");
18533   for (int i = 0; i < 10; i++) {
18534     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18535     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18536     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18537   }
18538
18539 script = v8_compile("new C2();");
18540   for (int i = 0; i < 10; i++) {
18541     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18542     CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
18543     CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
18544   }
18545 }
18546
18547
18548 static void NamedPropertyGetterWhichReturns42(
18549     Local<String> name,
18550     const v8::PropertyCallbackInfo<v8::Value>& info) {
18551   info.GetReturnValue().Set(v8_num(42));
18552 }
18553
18554
18555 static void NamedPropertySetterWhichSetsYOnThisTo23(
18556     Local<String> name,
18557     Local<Value> value,
18558     const v8::PropertyCallbackInfo<v8::Value>& info) {
18559   if (name->Equals(v8_str("x"))) {
18560     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
18561   }
18562 }
18563
18564
18565 THREADED_TEST(InterceptorOnConstructorPrototype) {
18566   v8::Isolate* isolate = CcTest::isolate();
18567   v8::HandleScope scope(isolate);
18568   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18569   templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
18570                                  NamedPropertySetterWhichSetsYOnThisTo23);
18571   LocalContext context;
18572   context->Global()->Set(v8_str("P"), templ->NewInstance());
18573   CompileRun("function C1() {"
18574              "  this.x = 23;"
18575              "};"
18576              "C1.prototype = P;"
18577              "function C2() {"
18578              "  this.x = 23"
18579              "};"
18580              "C2.prototype = { };"
18581              "C2.prototype.__proto__ = P;");
18582
18583   v8::Local<v8::Script> script;
18584   script = v8_compile("new C1();");
18585   for (int i = 0; i < 10; i++) {
18586     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18587     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18588     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18589   }
18590
18591   script = v8_compile("new C2();");
18592   for (int i = 0; i < 10; i++) {
18593     v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
18594     CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
18595     CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
18596   }
18597 }
18598
18599
18600 TEST(Regress618) {
18601   const char* source = "function C1() {"
18602                        "  this.x = 23;"
18603                        "};"
18604                        "C1.prototype = P;";
18605
18606   LocalContext context;
18607   v8::Isolate* isolate = context->GetIsolate();
18608   v8::HandleScope scope(isolate);
18609   v8::Local<v8::Script> script;
18610
18611   // Use a simple object as prototype.
18612   v8::Local<v8::Object> prototype = v8::Object::New(isolate);
18613   prototype->Set(v8_str("y"), v8_num(42));
18614   context->Global()->Set(v8_str("P"), prototype);
18615
18616   // This compile will add the code to the compilation cache.
18617   CompileRun(source);
18618
18619   script = v8_compile("new C1();");
18620   // Allow enough iterations for the inobject slack tracking logic
18621   // to finalize instance size and install the fast construct stub.
18622   for (int i = 0; i < 256; i++) {
18623     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18624     CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
18625     CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
18626   }
18627
18628   // Use an API object with accessors as prototype.
18629   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18630   templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
18631                      SetterWhichSetsYOnThisTo23);
18632   context->Global()->Set(v8_str("P"), templ->NewInstance());
18633
18634   // This compile will get the code from the compilation cache.
18635   CompileRun(source);
18636
18637   script = v8_compile("new C1();");
18638   for (int i = 0; i < 10; i++) {
18639     v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
18640     CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
18641     CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
18642   }
18643 }
18644
18645 v8::Isolate* gc_callbacks_isolate = NULL;
18646 int prologue_call_count = 0;
18647 int epilogue_call_count = 0;
18648 int prologue_call_count_second = 0;
18649 int epilogue_call_count_second = 0;
18650 int prologue_call_count_alloc = 0;
18651 int epilogue_call_count_alloc = 0;
18652
18653 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18654   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18655   ++prologue_call_count;
18656 }
18657
18658
18659 void PrologueCallback(v8::Isolate* isolate,
18660                       v8::GCType,
18661                       v8::GCCallbackFlags flags) {
18662   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18663   CHECK_EQ(gc_callbacks_isolate, isolate);
18664   ++prologue_call_count;
18665 }
18666
18667
18668 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
18669   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18670   ++epilogue_call_count;
18671 }
18672
18673
18674 void EpilogueCallback(v8::Isolate* isolate,
18675                       v8::GCType,
18676                       v8::GCCallbackFlags flags) {
18677   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18678   CHECK_EQ(gc_callbacks_isolate, isolate);
18679   ++epilogue_call_count;
18680 }
18681
18682
18683 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18684   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18685   ++prologue_call_count_second;
18686 }
18687
18688
18689 void PrologueCallbackSecond(v8::Isolate* isolate,
18690                             v8::GCType,
18691                             v8::GCCallbackFlags flags) {
18692   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18693   CHECK_EQ(gc_callbacks_isolate, isolate);
18694   ++prologue_call_count_second;
18695 }
18696
18697
18698 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
18699   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18700   ++epilogue_call_count_second;
18701 }
18702
18703
18704 void EpilogueCallbackSecond(v8::Isolate* isolate,
18705                             v8::GCType,
18706                             v8::GCCallbackFlags flags) {
18707   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18708   CHECK_EQ(gc_callbacks_isolate, isolate);
18709   ++epilogue_call_count_second;
18710 }
18711
18712
18713 void PrologueCallbackAlloc(v8::Isolate* isolate,
18714                            v8::GCType,
18715                            v8::GCCallbackFlags flags) {
18716   v8::HandleScope scope(isolate);
18717
18718   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18719   CHECK_EQ(gc_callbacks_isolate, isolate);
18720   ++prologue_call_count_alloc;
18721
18722   // Simulate full heap to see if we will reenter this callback
18723   SimulateFullSpace(CcTest::heap()->new_space());
18724
18725   Local<Object> obj = Object::New(isolate);
18726   CHECK(!obj.IsEmpty());
18727
18728   CcTest::heap()->CollectAllGarbage(
18729       i::Heap::kAbortIncrementalMarkingMask);
18730 }
18731
18732
18733 void EpilogueCallbackAlloc(v8::Isolate* isolate,
18734                            v8::GCType,
18735                            v8::GCCallbackFlags flags) {
18736   v8::HandleScope scope(isolate);
18737
18738   CHECK_EQ(flags, v8::kNoGCCallbackFlags);
18739   CHECK_EQ(gc_callbacks_isolate, isolate);
18740   ++epilogue_call_count_alloc;
18741
18742   // Simulate full heap to see if we will reenter this callback
18743   SimulateFullSpace(CcTest::heap()->new_space());
18744
18745   Local<Object> obj = Object::New(isolate);
18746   CHECK(!obj.IsEmpty());
18747
18748   CcTest::heap()->CollectAllGarbage(
18749       i::Heap::kAbortIncrementalMarkingMask);
18750 }
18751
18752
18753 TEST(GCCallbacksOld) {
18754   LocalContext context;
18755
18756   v8::V8::AddGCPrologueCallback(PrologueCallback);
18757   v8::V8::AddGCEpilogueCallback(EpilogueCallback);
18758   CHECK_EQ(0, prologue_call_count);
18759   CHECK_EQ(0, epilogue_call_count);
18760   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18761   CHECK_EQ(1, prologue_call_count);
18762   CHECK_EQ(1, epilogue_call_count);
18763   v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
18764   v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
18765   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18766   CHECK_EQ(2, prologue_call_count);
18767   CHECK_EQ(2, epilogue_call_count);
18768   CHECK_EQ(1, prologue_call_count_second);
18769   CHECK_EQ(1, epilogue_call_count_second);
18770   v8::V8::RemoveGCPrologueCallback(PrologueCallback);
18771   v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
18772   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18773   CHECK_EQ(2, prologue_call_count);
18774   CHECK_EQ(2, epilogue_call_count);
18775   CHECK_EQ(2, prologue_call_count_second);
18776   CHECK_EQ(2, epilogue_call_count_second);
18777   v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
18778   v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18779   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18780   CHECK_EQ(2, prologue_call_count);
18781   CHECK_EQ(2, epilogue_call_count);
18782   CHECK_EQ(2, prologue_call_count_second);
18783   CHECK_EQ(2, epilogue_call_count_second);
18784 }
18785
18786
18787 TEST(GCCallbacks) {
18788   LocalContext context;
18789   v8::Isolate* isolate = context->GetIsolate();
18790   gc_callbacks_isolate = isolate;
18791   isolate->AddGCPrologueCallback(PrologueCallback);
18792   isolate->AddGCEpilogueCallback(EpilogueCallback);
18793   CHECK_EQ(0, prologue_call_count);
18794   CHECK_EQ(0, epilogue_call_count);
18795   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18796   CHECK_EQ(1, prologue_call_count);
18797   CHECK_EQ(1, epilogue_call_count);
18798   isolate->AddGCPrologueCallback(PrologueCallbackSecond);
18799   isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
18800   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18801   CHECK_EQ(2, prologue_call_count);
18802   CHECK_EQ(2, epilogue_call_count);
18803   CHECK_EQ(1, prologue_call_count_second);
18804   CHECK_EQ(1, epilogue_call_count_second);
18805   isolate->RemoveGCPrologueCallback(PrologueCallback);
18806   isolate->RemoveGCEpilogueCallback(EpilogueCallback);
18807   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18808   CHECK_EQ(2, prologue_call_count);
18809   CHECK_EQ(2, epilogue_call_count);
18810   CHECK_EQ(2, prologue_call_count_second);
18811   CHECK_EQ(2, epilogue_call_count_second);
18812   isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
18813   isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
18814   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18815   CHECK_EQ(2, prologue_call_count);
18816   CHECK_EQ(2, epilogue_call_count);
18817   CHECK_EQ(2, prologue_call_count_second);
18818   CHECK_EQ(2, epilogue_call_count_second);
18819
18820   CHECK_EQ(0, prologue_call_count_alloc);
18821   CHECK_EQ(0, epilogue_call_count_alloc);
18822   isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
18823   isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
18824   CcTest::heap()->CollectAllGarbage(
18825       i::Heap::kAbortIncrementalMarkingMask);
18826   CHECK_EQ(1, prologue_call_count_alloc);
18827   CHECK_EQ(1, epilogue_call_count_alloc);
18828   isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
18829   isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
18830 }
18831
18832
18833 THREADED_TEST(AddToJSFunctionResultCache) {
18834   i::FLAG_stress_compaction = false;
18835   i::FLAG_allow_natives_syntax = true;
18836   v8::HandleScope scope(CcTest::isolate());
18837
18838   LocalContext context;
18839
18840   const char* code =
18841       "(function() {"
18842       "  var key0 = 'a';"
18843       "  var key1 = 'b';"
18844       "  var r0 = %_GetFromCache(0, key0);"
18845       "  var r1 = %_GetFromCache(0, key1);"
18846       "  var r0_ = %_GetFromCache(0, key0);"
18847       "  if (r0 !== r0_)"
18848       "    return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
18849       "  var r1_ = %_GetFromCache(0, key1);"
18850       "  if (r1 !== r1_)"
18851       "    return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
18852       "  return 'PASSED';"
18853       "})()";
18854   CcTest::heap()->ClearJSFunctionResultCaches();
18855   ExpectString(code, "PASSED");
18856 }
18857
18858
18859 THREADED_TEST(FillJSFunctionResultCache) {
18860   i::FLAG_allow_natives_syntax = true;
18861   LocalContext context;
18862   v8::HandleScope scope(context->GetIsolate());
18863
18864   const char* code =
18865       "(function() {"
18866       "  var k = 'a';"
18867       "  var r = %_GetFromCache(0, k);"
18868       "  for (var i = 0; i < 16; i++) {"
18869       "    %_GetFromCache(0, 'a' + i);"
18870       "  };"
18871       "  if (r === %_GetFromCache(0, k))"
18872       "    return 'FAILED: k0CacheSize is too small';"
18873       "  return 'PASSED';"
18874       "})()";
18875   CcTest::heap()->ClearJSFunctionResultCaches();
18876   ExpectString(code, "PASSED");
18877 }
18878
18879
18880 THREADED_TEST(RoundRobinGetFromCache) {
18881   i::FLAG_allow_natives_syntax = true;
18882   LocalContext context;
18883   v8::HandleScope scope(context->GetIsolate());
18884
18885   const char* code =
18886       "(function() {"
18887       "  var keys = [];"
18888       "  for (var i = 0; i < 16; i++) keys.push(i);"
18889       "  var values = [];"
18890       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18891       "  for (var i = 0; i < 16; i++) {"
18892       "    var v = %_GetFromCache(0, keys[i]);"
18893       "    if (v.toString() !== values[i].toString())"
18894       "      return 'Wrong value for ' + "
18895       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18896       "  };"
18897       "  return 'PASSED';"
18898       "})()";
18899   CcTest::heap()->ClearJSFunctionResultCaches();
18900   ExpectString(code, "PASSED");
18901 }
18902
18903
18904 THREADED_TEST(ReverseGetFromCache) {
18905   i::FLAG_allow_natives_syntax = true;
18906   LocalContext context;
18907   v8::HandleScope scope(context->GetIsolate());
18908
18909   const char* code =
18910       "(function() {"
18911       "  var keys = [];"
18912       "  for (var i = 0; i < 16; i++) keys.push(i);"
18913       "  var values = [];"
18914       "  for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
18915       "  for (var i = 15; i >= 16; i--) {"
18916       "    var v = %_GetFromCache(0, keys[i]);"
18917       "    if (v !== values[i])"
18918       "      return 'Wrong value for ' + "
18919       "          keys[i] + ': ' + v + ' vs. ' + values[i];"
18920       "  };"
18921       "  return 'PASSED';"
18922       "})()";
18923   CcTest::heap()->ClearJSFunctionResultCaches();
18924   ExpectString(code, "PASSED");
18925 }
18926
18927
18928 THREADED_TEST(TestEviction) {
18929   i::FLAG_allow_natives_syntax = true;
18930   LocalContext context;
18931   v8::HandleScope scope(context->GetIsolate());
18932
18933   const char* code =
18934       "(function() {"
18935       "  for (var i = 0; i < 2*16; i++) {"
18936       "    %_GetFromCache(0, 'a' + i);"
18937       "  };"
18938       "  return 'PASSED';"
18939       "})()";
18940   CcTest::heap()->ClearJSFunctionResultCaches();
18941   ExpectString(code, "PASSED");
18942 }
18943
18944
18945 THREADED_TEST(TwoByteStringInAsciiCons) {
18946   // See Chromium issue 47824.
18947   LocalContext context;
18948   v8::HandleScope scope(context->GetIsolate());
18949
18950   const char* init_code =
18951       "var str1 = 'abelspendabel';"
18952       "var str2 = str1 + str1 + str1;"
18953       "str2;";
18954   Local<Value> result = CompileRun(init_code);
18955
18956   Local<Value> indexof = CompileRun("str2.indexOf('els')");
18957   Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
18958
18959   CHECK(result->IsString());
18960   i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
18961   int length = string->length();
18962   CHECK(string->IsOneByteRepresentation());
18963
18964   i::Handle<i::String> flat_string = i::String::Flatten(string);
18965
18966   CHECK(string->IsOneByteRepresentation());
18967   CHECK(flat_string->IsOneByteRepresentation());
18968
18969   // Create external resource.
18970   uint16_t* uc16_buffer = new uint16_t[length + 1];
18971
18972   i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
18973   uc16_buffer[length] = 0;
18974
18975   TestResource resource(uc16_buffer);
18976
18977   flat_string->MakeExternal(&resource);
18978
18979   CHECK(flat_string->IsTwoByteRepresentation());
18980
18981   // If the cons string has been short-circuited, skip the following checks.
18982   if (!string.is_identical_to(flat_string)) {
18983     // At this point, we should have a Cons string which is flat and ASCII,
18984     // with a first half that is a two-byte string (although it only contains
18985     // ASCII characters). This is a valid sequence of steps, and it can happen
18986     // in real pages.
18987     CHECK(string->IsOneByteRepresentation());
18988     i::ConsString* cons = i::ConsString::cast(*string);
18989     CHECK_EQ(0, cons->second()->length());
18990     CHECK(cons->first()->IsTwoByteRepresentation());
18991   }
18992
18993   // Check that some string operations work.
18994
18995   // Atom RegExp.
18996   Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
18997   CHECK_EQ(6, reresult->Int32Value());
18998
18999   // Nonatom RegExp.
19000   reresult = CompileRun("str2.match(/abe./g).length;");
19001   CHECK_EQ(6, reresult->Int32Value());
19002
19003   reresult = CompileRun("str2.search(/bel/g);");
19004   CHECK_EQ(1, reresult->Int32Value());
19005
19006   reresult = CompileRun("str2.search(/be./g);");
19007   CHECK_EQ(1, reresult->Int32Value());
19008
19009   ExpectTrue("/bel/g.test(str2);");
19010
19011   ExpectTrue("/be./g.test(str2);");
19012
19013   reresult = CompileRun("/bel/g.exec(str2);");
19014   CHECK(!reresult->IsNull());
19015
19016   reresult = CompileRun("/be./g.exec(str2);");
19017   CHECK(!reresult->IsNull());
19018
19019   ExpectString("str2.substring(2, 10);", "elspenda");
19020
19021   ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19022
19023   ExpectString("str2.charAt(2);", "e");
19024
19025   ExpectObject("str2.indexOf('els');", indexof);
19026
19027   ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19028
19029   reresult = CompileRun("str2.charCodeAt(2);");
19030   CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19031 }
19032
19033
19034 TEST(ContainsOnlyOneByte) {
19035   v8::V8::Initialize();
19036   v8::Isolate* isolate = CcTest::isolate();
19037   v8::HandleScope scope(isolate);
19038   // Make a buffer long enough that it won't automatically be converted.
19039   const int length = 512;
19040   // Ensure word aligned assignment.
19041   const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19042   i::SmartArrayPointer<uintptr_t>
19043   aligned_contents(new uintptr_t[aligned_length]);
19044   uint16_t* string_contents =
19045       reinterpret_cast<uint16_t*>(aligned_contents.get());
19046   // Set to contain only one byte.
19047   for (int i = 0; i < length-1; i++) {
19048     string_contents[i] = 0x41;
19049   }
19050   string_contents[length-1] = 0;
19051   // Simple case.
19052   Handle<String> string =
19053       String::NewExternal(isolate,
19054                           new TestResource(string_contents, NULL, false));
19055   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19056   // Counter example.
19057   string = String::NewFromTwoByte(isolate, string_contents);
19058   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19059   // Test left right and balanced cons strings.
19060   Handle<String> base = String::NewFromUtf8(isolate, "a");
19061   Handle<String> left = base;
19062   Handle<String> right = base;
19063   for (int i = 0; i < 1000; i++) {
19064     left = String::Concat(base, left);
19065     right = String::Concat(right, base);
19066   }
19067   Handle<String> balanced = String::Concat(left, base);
19068   balanced = String::Concat(balanced, right);
19069   Handle<String> cons_strings[] = {left, balanced, right};
19070   Handle<String> two_byte =
19071       String::NewExternal(isolate,
19072                           new TestResource(string_contents, NULL, false));
19073   USE(two_byte); USE(cons_strings);
19074   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
19075     // Base assumptions.
19076     string = cons_strings[i];
19077     CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19078     // Test left and right concatentation.
19079     string = String::Concat(two_byte, cons_strings[i]);
19080     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19081     string = String::Concat(cons_strings[i], two_byte);
19082     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19083   }
19084   // Set bits in different positions
19085   // for strings of different lengths and alignments.
19086   for (int alignment = 0; alignment < 7; alignment++) {
19087     for (int size = 2; alignment + size < length; size *= 2) {
19088       int zero_offset = size + alignment;
19089       string_contents[zero_offset] = 0;
19090       for (int i = 0; i < size; i++) {
19091         int shift = 8 + (i % 7);
19092         string_contents[alignment + i] = 1 << shift;
19093         string = String::NewExternal(
19094             isolate,
19095             new TestResource(string_contents + alignment, NULL, false));
19096         CHECK_EQ(size, string->Length());
19097         CHECK(!string->ContainsOnlyOneByte());
19098         string_contents[alignment + i] = 0x41;
19099       }
19100       string_contents[zero_offset] = 0x41;
19101     }
19102   }
19103 }
19104
19105
19106 // Failed access check callback that performs a GC on each invocation.
19107 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
19108                                  v8::AccessType type,
19109                                  Local<v8::Value> data) {
19110   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19111 }
19112
19113
19114 TEST(GCInFailedAccessCheckCallback) {
19115   // Install a failed access check callback that performs a GC on each
19116   // invocation. Then force the callback to be called from va
19117
19118   v8::V8::Initialize();
19119   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
19120
19121   v8::Isolate* isolate = CcTest::isolate();
19122   v8::HandleScope scope(isolate);
19123
19124   // Create an ObjectTemplate for global objects and install access
19125   // check callbacks that will block access.
19126   v8::Handle<v8::ObjectTemplate> global_template =
19127       v8::ObjectTemplate::New(isolate);
19128   global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
19129                                            IndexedGetAccessBlocker,
19130                                            v8::Handle<v8::Value>(),
19131                                            false);
19132
19133   // Create a context and set an x property on it's global object.
19134   LocalContext context0(NULL, global_template);
19135   context0->Global()->Set(v8_str("x"), v8_num(42));
19136   v8::Handle<v8::Object> global0 = context0->Global();
19137
19138   // Create a context with a different security token so that the
19139   // failed access check callback will be called on each access.
19140   LocalContext context1(NULL, global_template);
19141   context1->Global()->Set(v8_str("other"), global0);
19142
19143   // Get property with failed access check.
19144   ExpectUndefined("other.x");
19145
19146   // Get element with failed access check.
19147   ExpectUndefined("other[0]");
19148
19149   // Set property with failed access check.
19150   v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
19151   CHECK(result->IsObject());
19152
19153   // Set element with failed access check.
19154   result = CompileRun("other[0] = new Object()");
19155   CHECK(result->IsObject());
19156
19157   // Get property attribute with failed access check.
19158   ExpectFalse("\'x\' in other");
19159
19160   // Get property attribute for element with failed access check.
19161   ExpectFalse("0 in other");
19162
19163   // Delete property.
19164   ExpectFalse("delete other.x");
19165
19166   // Delete element.
19167   CHECK_EQ(false, global0->Delete(0));
19168
19169   // DefineAccessor.
19170   CHECK_EQ(false,
19171            global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
19172
19173   // Define JavaScript accessor.
19174   ExpectUndefined("Object.prototype.__defineGetter__.call("
19175                   "    other, \'x\', function() { return 42; })");
19176
19177   // LookupAccessor.
19178   ExpectUndefined("Object.prototype.__lookupGetter__.call("
19179                   "    other, \'x\')");
19180
19181   // HasOwnElement.
19182   ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
19183
19184   CHECK_EQ(false, global0->HasRealIndexedProperty(0));
19185   CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
19186   CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
19187
19188   // Reset the failed access check callback so it does not influence
19189   // the other tests.
19190   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19191 }
19192
19193
19194 TEST(IsolateNewDispose) {
19195   v8::Isolate* current_isolate = CcTest::isolate();
19196   v8::Isolate* isolate = v8::Isolate::New();
19197   CHECK(isolate != NULL);
19198   CHECK(current_isolate != isolate);
19199   CHECK(current_isolate == CcTest::isolate());
19200
19201   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19202   last_location = last_message = NULL;
19203   isolate->Dispose();
19204   CHECK_EQ(last_location, NULL);
19205   CHECK_EQ(last_message, NULL);
19206 }
19207
19208
19209 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
19210   v8::Isolate* isolate = v8::Isolate::New();
19211   {
19212     v8::Isolate::Scope i_scope(isolate);
19213     v8::HandleScope scope(isolate);
19214     LocalContext context(isolate);
19215     // Run something in this isolate.
19216     ExpectTrue("true");
19217     v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19218     last_location = last_message = NULL;
19219     // Still entered, should fail.
19220     isolate->Dispose();
19221     CHECK_NE(last_location, NULL);
19222     CHECK_NE(last_message, NULL);
19223   }
19224   isolate->Dispose();
19225 }
19226
19227
19228 TEST(RunTwoIsolatesOnSingleThread) {
19229   // Run isolate 1.
19230   v8::Isolate* isolate1 = v8::Isolate::New();
19231   isolate1->Enter();
19232   v8::Persistent<v8::Context> context1;
19233   {
19234     v8::HandleScope scope(isolate1);
19235     context1.Reset(isolate1, Context::New(isolate1));
19236   }
19237
19238   {
19239     v8::HandleScope scope(isolate1);
19240     v8::Local<v8::Context> context =
19241         v8::Local<v8::Context>::New(isolate1, context1);
19242     v8::Context::Scope context_scope(context);
19243     // Run something in new isolate.
19244     CompileRun("var foo = 'isolate 1';");
19245     ExpectString("function f() { return foo; }; f()", "isolate 1");
19246   }
19247
19248   // Run isolate 2.
19249   v8::Isolate* isolate2 = v8::Isolate::New();
19250   v8::Persistent<v8::Context> context2;
19251
19252   {
19253     v8::Isolate::Scope iscope(isolate2);
19254     v8::HandleScope scope(isolate2);
19255     context2.Reset(isolate2, Context::New(isolate2));
19256     v8::Local<v8::Context> context =
19257         v8::Local<v8::Context>::New(isolate2, context2);
19258     v8::Context::Scope context_scope(context);
19259
19260     // Run something in new isolate.
19261     CompileRun("var foo = 'isolate 2';");
19262     ExpectString("function f() { return foo; }; f()", "isolate 2");
19263   }
19264
19265   {
19266     v8::HandleScope scope(isolate1);
19267     v8::Local<v8::Context> context =
19268         v8::Local<v8::Context>::New(isolate1, context1);
19269     v8::Context::Scope context_scope(context);
19270     // Now again in isolate 1
19271     ExpectString("function f() { return foo; }; f()", "isolate 1");
19272   }
19273
19274   isolate1->Exit();
19275
19276   // Run some stuff in default isolate.
19277   v8::Persistent<v8::Context> context_default;
19278   {
19279     v8::Isolate* isolate = CcTest::isolate();
19280     v8::Isolate::Scope iscope(isolate);
19281     v8::HandleScope scope(isolate);
19282     context_default.Reset(isolate, Context::New(isolate));
19283   }
19284
19285   {
19286     v8::HandleScope scope(CcTest::isolate());
19287     v8::Local<v8::Context> context =
19288         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19289     v8::Context::Scope context_scope(context);
19290     // Variables in other isolates should be not available, verify there
19291     // is an exception.
19292     ExpectTrue("function f() {"
19293                "  try {"
19294                "    foo;"
19295                "    return false;"
19296                "  } catch(e) {"
19297                "    return true;"
19298                "  }"
19299                "};"
19300                "var isDefaultIsolate = true;"
19301                "f()");
19302   }
19303
19304   isolate1->Enter();
19305
19306   {
19307     v8::Isolate::Scope iscope(isolate2);
19308     v8::HandleScope scope(isolate2);
19309     v8::Local<v8::Context> context =
19310         v8::Local<v8::Context>::New(isolate2, context2);
19311     v8::Context::Scope context_scope(context);
19312     ExpectString("function f() { return foo; }; f()", "isolate 2");
19313   }
19314
19315   {
19316     v8::HandleScope scope(v8::Isolate::GetCurrent());
19317     v8::Local<v8::Context> context =
19318         v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
19319     v8::Context::Scope context_scope(context);
19320     ExpectString("function f() { return foo; }; f()", "isolate 1");
19321   }
19322
19323   {
19324     v8::Isolate::Scope iscope(isolate2);
19325     context2.Reset();
19326   }
19327
19328   context1.Reset();
19329   isolate1->Exit();
19330
19331   v8::V8::SetFatalErrorHandler(StoringErrorCallback);
19332   last_location = last_message = NULL;
19333
19334   isolate1->Dispose();
19335   CHECK_EQ(last_location, NULL);
19336   CHECK_EQ(last_message, NULL);
19337
19338   isolate2->Dispose();
19339   CHECK_EQ(last_location, NULL);
19340   CHECK_EQ(last_message, NULL);
19341
19342   // Check that default isolate still runs.
19343   {
19344     v8::HandleScope scope(CcTest::isolate());
19345     v8::Local<v8::Context> context =
19346         v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
19347     v8::Context::Scope context_scope(context);
19348     ExpectTrue("function f() { return isDefaultIsolate; }; f()");
19349   }
19350 }
19351
19352
19353 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
19354   v8::Isolate::Scope isolate_scope(isolate);
19355   v8::HandleScope scope(isolate);
19356   LocalContext context(isolate);
19357   i::ScopedVector<char> code(1024);
19358   i::SNPrintF(code, "function fib(n) {"
19359                     "  if (n <= 2) return 1;"
19360                     "  return fib(n-1) + fib(n-2);"
19361                     "}"
19362                     "fib(%d)", limit);
19363   Local<Value> value = CompileRun(code.start());
19364   CHECK(value->IsNumber());
19365   return static_cast<int>(value->NumberValue());
19366 }
19367
19368 class IsolateThread : public v8::base::Thread {
19369  public:
19370   IsolateThread(v8::Isolate* isolate, int fib_limit)
19371       : Thread(Options("IsolateThread")),
19372         isolate_(isolate),
19373         fib_limit_(fib_limit),
19374         result_(0) {}
19375
19376   void Run() {
19377     result_ = CalcFibonacci(isolate_, fib_limit_);
19378   }
19379
19380   int result() { return result_; }
19381
19382  private:
19383   v8::Isolate* isolate_;
19384   int fib_limit_;
19385   int result_;
19386 };
19387
19388
19389 TEST(MultipleIsolatesOnIndividualThreads) {
19390   v8::Isolate* isolate1 = v8::Isolate::New();
19391   v8::Isolate* isolate2 = v8::Isolate::New();
19392
19393   IsolateThread thread1(isolate1, 21);
19394   IsolateThread thread2(isolate2, 12);
19395
19396   // Compute some fibonacci numbers on 3 threads in 3 isolates.
19397   thread1.Start();
19398   thread2.Start();
19399
19400   int result1 = CalcFibonacci(CcTest::isolate(), 21);
19401   int result2 = CalcFibonacci(CcTest::isolate(), 12);
19402
19403   thread1.Join();
19404   thread2.Join();
19405
19406   // Compare results. The actual fibonacci numbers for 12 and 21 are taken
19407   // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
19408   CHECK_EQ(result1, 10946);
19409   CHECK_EQ(result2, 144);
19410   CHECK_EQ(result1, thread1.result());
19411   CHECK_EQ(result2, thread2.result());
19412
19413   isolate1->Dispose();
19414   isolate2->Dispose();
19415 }
19416
19417
19418 TEST(IsolateDifferentContexts) {
19419   v8::Isolate* isolate = v8::Isolate::New();
19420   Local<v8::Context> context;
19421   {
19422     v8::Isolate::Scope isolate_scope(isolate);
19423     v8::HandleScope handle_scope(isolate);
19424     context = v8::Context::New(isolate);
19425     v8::Context::Scope context_scope(context);
19426     Local<Value> v = CompileRun("2");
19427     CHECK(v->IsNumber());
19428     CHECK_EQ(2, static_cast<int>(v->NumberValue()));
19429   }
19430   {
19431     v8::Isolate::Scope isolate_scope(isolate);
19432     v8::HandleScope handle_scope(isolate);
19433     context = v8::Context::New(isolate);
19434     v8::Context::Scope context_scope(context);
19435     Local<Value> v = CompileRun("22");
19436     CHECK(v->IsNumber());
19437     CHECK_EQ(22, static_cast<int>(v->NumberValue()));
19438   }
19439   isolate->Dispose();
19440 }
19441
19442 class InitDefaultIsolateThread : public v8::base::Thread {
19443  public:
19444   enum TestCase {
19445     SetResourceConstraints,
19446     SetFatalHandler,
19447     SetCounterFunction,
19448     SetCreateHistogramFunction,
19449     SetAddHistogramSampleFunction
19450   };
19451
19452   explicit InitDefaultIsolateThread(TestCase testCase)
19453       : Thread(Options("InitDefaultIsolateThread")),
19454         testCase_(testCase),
19455         result_(false) {}
19456
19457   void Run() {
19458     v8::Isolate* isolate = v8::Isolate::New();
19459     isolate->Enter();
19460     switch (testCase_) {
19461       case SetResourceConstraints: {
19462         v8::ResourceConstraints constraints;
19463         constraints.set_max_semi_space_size(1);
19464         constraints.set_max_old_space_size(4);
19465         v8::SetResourceConstraints(CcTest::isolate(), &constraints);
19466         break;
19467       }
19468
19469       case SetFatalHandler:
19470         v8::V8::SetFatalErrorHandler(NULL);
19471         break;
19472
19473       case SetCounterFunction:
19474         CcTest::isolate()->SetCounterFunction(NULL);
19475         break;
19476
19477       case SetCreateHistogramFunction:
19478         CcTest::isolate()->SetCreateHistogramFunction(NULL);
19479         break;
19480
19481       case SetAddHistogramSampleFunction:
19482         CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
19483         break;
19484     }
19485     isolate->Exit();
19486     isolate->Dispose();
19487     result_ = true;
19488   }
19489
19490   bool result() { return result_; }
19491
19492  private:
19493   TestCase testCase_;
19494   bool result_;
19495 };
19496
19497
19498 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
19499   InitDefaultIsolateThread thread(testCase);
19500   thread.Start();
19501   thread.Join();
19502   CHECK_EQ(thread.result(), true);
19503 }
19504
19505
19506 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
19507   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
19508 }
19509
19510
19511 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
19512   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
19513 }
19514
19515
19516 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
19517   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
19518 }
19519
19520
19521 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
19522   InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
19523 }
19524
19525
19526 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
19527   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
19528 }
19529
19530
19531 TEST(StringCheckMultipleContexts) {
19532   const char* code =
19533       "(function() { return \"a\".charAt(0); })()";
19534
19535   {
19536     // Run the code twice in the first context to initialize the call IC.
19537     LocalContext context1;
19538     v8::HandleScope scope(context1->GetIsolate());
19539     ExpectString(code, "a");
19540     ExpectString(code, "a");
19541   }
19542
19543   {
19544     // Change the String.prototype in the second context and check
19545     // that the right function gets called.
19546     LocalContext context2;
19547     v8::HandleScope scope(context2->GetIsolate());
19548     CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
19549     ExpectString(code, "not a");
19550   }
19551 }
19552
19553
19554 TEST(NumberCheckMultipleContexts) {
19555   const char* code =
19556       "(function() { return (42).toString(); })()";
19557
19558   {
19559     // Run the code twice in the first context to initialize the call IC.
19560     LocalContext context1;
19561     v8::HandleScope scope(context1->GetIsolate());
19562     ExpectString(code, "42");
19563     ExpectString(code, "42");
19564   }
19565
19566   {
19567     // Change the Number.prototype in the second context and check
19568     // that the right function gets called.
19569     LocalContext context2;
19570     v8::HandleScope scope(context2->GetIsolate());
19571     CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
19572     ExpectString(code, "not 42");
19573   }
19574 }
19575
19576
19577 TEST(BooleanCheckMultipleContexts) {
19578   const char* code =
19579       "(function() { return true.toString(); })()";
19580
19581   {
19582     // Run the code twice in the first context to initialize the call IC.
19583     LocalContext context1;
19584     v8::HandleScope scope(context1->GetIsolate());
19585     ExpectString(code, "true");
19586     ExpectString(code, "true");
19587   }
19588
19589   {
19590     // Change the Boolean.prototype in the second context and check
19591     // that the right function gets called.
19592     LocalContext context2;
19593     v8::HandleScope scope(context2->GetIsolate());
19594     CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
19595     ExpectString(code, "");
19596   }
19597 }
19598
19599
19600 TEST(DontDeleteCellLoadIC) {
19601   const char* function_code =
19602       "function readCell() { while (true) { return cell; } }";
19603
19604   {
19605     // Run the code twice in the first context to initialize the load
19606     // IC for a don't delete cell.
19607     LocalContext context1;
19608     v8::HandleScope scope(context1->GetIsolate());
19609     CompileRun("var cell = \"first\";");
19610     ExpectBoolean("delete cell", false);
19611     CompileRun(function_code);
19612     ExpectString("readCell()", "first");
19613     ExpectString("readCell()", "first");
19614   }
19615
19616   {
19617     // Use a deletable cell in the second context.
19618     LocalContext context2;
19619     v8::HandleScope scope(context2->GetIsolate());
19620     CompileRun("cell = \"second\";");
19621     CompileRun(function_code);
19622     ExpectString("readCell()", "second");
19623     ExpectBoolean("delete cell", true);
19624     ExpectString("(function() {"
19625                  "  try {"
19626                  "    return readCell();"
19627                  "  } catch(e) {"
19628                  "    return e.toString();"
19629                  "  }"
19630                  "})()",
19631                  "ReferenceError: cell is not defined");
19632     CompileRun("cell = \"new_second\";");
19633     CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19634     ExpectString("readCell()", "new_second");
19635     ExpectString("readCell()", "new_second");
19636   }
19637 }
19638
19639
19640 TEST(DontDeleteCellLoadICForceDelete) {
19641   const char* function_code =
19642       "function readCell() { while (true) { return cell; } }";
19643
19644   // Run the code twice to initialize the load IC for a don't delete
19645   // cell.
19646   LocalContext context;
19647   v8::HandleScope scope(context->GetIsolate());
19648   CompileRun("var cell = \"value\";");
19649   ExpectBoolean("delete cell", false);
19650   CompileRun(function_code);
19651   ExpectString("readCell()", "value");
19652   ExpectString("readCell()", "value");
19653
19654   // Delete the cell using the API and check the inlined code works
19655   // correctly.
19656   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19657   ExpectString("(function() {"
19658                "  try {"
19659                "    return readCell();"
19660                "  } catch(e) {"
19661                "    return e.toString();"
19662                "  }"
19663                "})()",
19664                "ReferenceError: cell is not defined");
19665 }
19666
19667
19668 TEST(DontDeleteCellLoadICAPI) {
19669   const char* function_code =
19670       "function readCell() { while (true) { return cell; } }";
19671
19672   // Run the code twice to initialize the load IC for a don't delete
19673   // cell created using the API.
19674   LocalContext context;
19675   v8::HandleScope scope(context->GetIsolate());
19676   context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
19677   ExpectBoolean("delete cell", false);
19678   CompileRun(function_code);
19679   ExpectString("readCell()", "value");
19680   ExpectString("readCell()", "value");
19681
19682   // Delete the cell using the API and check the inlined code works
19683   // correctly.
19684   CHECK(context->Global()->ForceDelete(v8_str("cell")));
19685   ExpectString("(function() {"
19686                "  try {"
19687                "    return readCell();"
19688                "  } catch(e) {"
19689                "    return e.toString();"
19690                "  }"
19691                "})()",
19692                "ReferenceError: cell is not defined");
19693 }
19694
19695
19696 class Visitor42 : public v8::PersistentHandleVisitor {
19697  public:
19698   explicit Visitor42(v8::Persistent<v8::Object>* object)
19699       : counter_(0), object_(object) { }
19700
19701   virtual void VisitPersistentHandle(Persistent<Value>* value,
19702                                      uint16_t class_id) {
19703     if (class_id != 42) return;
19704     CHECK_EQ(42, value->WrapperClassId());
19705     v8::Isolate* isolate = CcTest::isolate();
19706     v8::HandleScope handle_scope(isolate);
19707     v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
19708     v8::Handle<v8::Value> object =
19709         v8::Local<v8::Object>::New(isolate, *object_);
19710     CHECK(handle->IsObject());
19711     CHECK_EQ(Handle<Object>::Cast(handle), object);
19712     ++counter_;
19713   }
19714
19715   int counter_;
19716   v8::Persistent<v8::Object>* object_;
19717 };
19718
19719
19720 TEST(PersistentHandleVisitor) {
19721   LocalContext context;
19722   v8::Isolate* isolate = context->GetIsolate();
19723   v8::HandleScope scope(isolate);
19724   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19725   CHECK_EQ(0, object.WrapperClassId());
19726   object.SetWrapperClassId(42);
19727   CHECK_EQ(42, object.WrapperClassId());
19728
19729   Visitor42 visitor(&object);
19730   v8::V8::VisitHandlesWithClassIds(&visitor);
19731   CHECK_EQ(1, visitor.counter_);
19732
19733   object.Reset();
19734 }
19735
19736
19737 TEST(WrapperClassId) {
19738   LocalContext context;
19739   v8::Isolate* isolate = context->GetIsolate();
19740   v8::HandleScope scope(isolate);
19741   v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
19742   CHECK_EQ(0, object.WrapperClassId());
19743   object.SetWrapperClassId(65535);
19744   CHECK_EQ(65535, object.WrapperClassId());
19745   object.Reset();
19746 }
19747
19748
19749 TEST(PersistentHandleInNewSpaceVisitor) {
19750   LocalContext context;
19751   v8::Isolate* isolate = context->GetIsolate();
19752   v8::HandleScope scope(isolate);
19753   v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
19754   CHECK_EQ(0, object1.WrapperClassId());
19755   object1.SetWrapperClassId(42);
19756   CHECK_EQ(42, object1.WrapperClassId());
19757
19758   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19759   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19760
19761   v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
19762   CHECK_EQ(0, object2.WrapperClassId());
19763   object2.SetWrapperClassId(42);
19764   CHECK_EQ(42, object2.WrapperClassId());
19765
19766   Visitor42 visitor(&object2);
19767   v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
19768   CHECK_EQ(1, visitor.counter_);
19769
19770   object1.Reset();
19771   object2.Reset();
19772 }
19773
19774
19775 TEST(RegExp) {
19776   LocalContext context;
19777   v8::HandleScope scope(context->GetIsolate());
19778
19779   v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
19780   CHECK(re->IsRegExp());
19781   CHECK(re->GetSource()->Equals(v8_str("foo")));
19782   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19783
19784   re = v8::RegExp::New(v8_str("bar"),
19785                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19786                                                       v8::RegExp::kGlobal));
19787   CHECK(re->IsRegExp());
19788   CHECK(re->GetSource()->Equals(v8_str("bar")));
19789   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
19790            static_cast<int>(re->GetFlags()));
19791
19792   re = v8::RegExp::New(v8_str("baz"),
19793                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19794                                                       v8::RegExp::kMultiline));
19795   CHECK(re->IsRegExp());
19796   CHECK(re->GetSource()->Equals(v8_str("baz")));
19797   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19798            static_cast<int>(re->GetFlags()));
19799
19800   re = CompileRun("/quux/").As<v8::RegExp>();
19801   CHECK(re->IsRegExp());
19802   CHECK(re->GetSource()->Equals(v8_str("quux")));
19803   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19804
19805   re = CompileRun("/quux/gm").As<v8::RegExp>();
19806   CHECK(re->IsRegExp());
19807   CHECK(re->GetSource()->Equals(v8_str("quux")));
19808   CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
19809            static_cast<int>(re->GetFlags()));
19810
19811   // Override the RegExp constructor and check the API constructor
19812   // still works.
19813   CompileRun("RegExp = function() {}");
19814
19815   re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
19816   CHECK(re->IsRegExp());
19817   CHECK(re->GetSource()->Equals(v8_str("foobar")));
19818   CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
19819
19820   re = v8::RegExp::New(v8_str("foobarbaz"),
19821                        static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
19822                                                       v8::RegExp::kMultiline));
19823   CHECK(re->IsRegExp());
19824   CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
19825   CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
19826            static_cast<int>(re->GetFlags()));
19827
19828   context->Global()->Set(v8_str("re"), re);
19829   ExpectTrue("re.test('FoobarbaZ')");
19830
19831   // RegExps are objects on which you can set properties.
19832   re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
19833   v8::Handle<v8::Value> value(CompileRun("re.property"));
19834   CHECK_EQ(32, value->Int32Value());
19835
19836   v8::TryCatch try_catch;
19837   re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
19838   CHECK(re.IsEmpty());
19839   CHECK(try_catch.HasCaught());
19840   context->Global()->Set(v8_str("ex"), try_catch.Exception());
19841   ExpectTrue("ex instanceof SyntaxError");
19842 }
19843
19844
19845 THREADED_TEST(Equals) {
19846   LocalContext localContext;
19847   v8::HandleScope handleScope(localContext->GetIsolate());
19848
19849   v8::Handle<v8::Object> globalProxy = localContext->Global();
19850   v8::Handle<Value> global = globalProxy->GetPrototype();
19851
19852   CHECK(global->StrictEquals(global));
19853   CHECK(!global->StrictEquals(globalProxy));
19854   CHECK(!globalProxy->StrictEquals(global));
19855   CHECK(globalProxy->StrictEquals(globalProxy));
19856
19857   CHECK(global->Equals(global));
19858   CHECK(!global->Equals(globalProxy));
19859   CHECK(!globalProxy->Equals(global));
19860   CHECK(globalProxy->Equals(globalProxy));
19861 }
19862
19863
19864 static void Getter(v8::Local<v8::String> property,
19865                    const v8::PropertyCallbackInfo<v8::Value>& info ) {
19866   info.GetReturnValue().Set(v8_str("42!"));
19867 }
19868
19869
19870 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
19871   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
19872   result->Set(0, v8_str("universalAnswer"));
19873   info.GetReturnValue().Set(result);
19874 }
19875
19876
19877 TEST(NamedEnumeratorAndForIn) {
19878   LocalContext context;
19879   v8::Isolate* isolate = context->GetIsolate();
19880   v8::HandleScope handle_scope(isolate);
19881   v8::Context::Scope context_scope(context.local());
19882
19883   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
19884   tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
19885   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
19886   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
19887         "var result = []; for (var k in o) result.push(k); result"));
19888   CHECK_EQ(1, result->Length());
19889   CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
19890 }
19891
19892
19893 TEST(DefinePropertyPostDetach) {
19894   LocalContext context;
19895   v8::HandleScope scope(context->GetIsolate());
19896   v8::Handle<v8::Object> proxy = context->Global();
19897   v8::Handle<v8::Function> define_property =
19898       CompileRun("(function() {"
19899                  "  Object.defineProperty("
19900                  "    this,"
19901                  "    1,"
19902                  "    { configurable: true, enumerable: true, value: 3 });"
19903                  "})").As<Function>();
19904   context->DetachGlobal();
19905   define_property->Call(proxy, 0, NULL);
19906 }
19907
19908
19909 static void InstallContextId(v8::Handle<Context> context, int id) {
19910   Context::Scope scope(context);
19911   CompileRun("Object.prototype").As<Object>()->
19912       Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
19913 }
19914
19915
19916 static void CheckContextId(v8::Handle<Object> object, int expected) {
19917   CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
19918 }
19919
19920
19921 THREADED_TEST(CreationContext) {
19922   v8::Isolate* isolate = CcTest::isolate();
19923   HandleScope handle_scope(isolate);
19924   Handle<Context> context1 = Context::New(isolate);
19925   InstallContextId(context1, 1);
19926   Handle<Context> context2 = Context::New(isolate);
19927   InstallContextId(context2, 2);
19928   Handle<Context> context3 = Context::New(isolate);
19929   InstallContextId(context3, 3);
19930
19931   Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
19932
19933   Local<Object> object1;
19934   Local<Function> func1;
19935   {
19936     Context::Scope scope(context1);
19937     object1 = Object::New(isolate);
19938     func1 = tmpl->GetFunction();
19939   }
19940
19941   Local<Object> object2;
19942   Local<Function> func2;
19943   {
19944     Context::Scope scope(context2);
19945     object2 = Object::New(isolate);
19946     func2 = tmpl->GetFunction();
19947   }
19948
19949   Local<Object> instance1;
19950   Local<Object> instance2;
19951
19952   {
19953     Context::Scope scope(context3);
19954     instance1 = func1->NewInstance();
19955     instance2 = func2->NewInstance();
19956   }
19957
19958   CHECK(object1->CreationContext() == context1);
19959   CheckContextId(object1, 1);
19960   CHECK(func1->CreationContext() == context1);
19961   CheckContextId(func1, 1);
19962   CHECK(instance1->CreationContext() == context1);
19963   CheckContextId(instance1, 1);
19964   CHECK(object2->CreationContext() == context2);
19965   CheckContextId(object2, 2);
19966   CHECK(func2->CreationContext() == context2);
19967   CheckContextId(func2, 2);
19968   CHECK(instance2->CreationContext() == context2);
19969   CheckContextId(instance2, 2);
19970
19971   {
19972     Context::Scope scope(context1);
19973     CHECK(object1->CreationContext() == context1);
19974     CheckContextId(object1, 1);
19975     CHECK(func1->CreationContext() == context1);
19976     CheckContextId(func1, 1);
19977     CHECK(instance1->CreationContext() == context1);
19978     CheckContextId(instance1, 1);
19979     CHECK(object2->CreationContext() == context2);
19980     CheckContextId(object2, 2);
19981     CHECK(func2->CreationContext() == context2);
19982     CheckContextId(func2, 2);
19983     CHECK(instance2->CreationContext() == context2);
19984     CheckContextId(instance2, 2);
19985   }
19986
19987   {
19988     Context::Scope scope(context2);
19989     CHECK(object1->CreationContext() == context1);
19990     CheckContextId(object1, 1);
19991     CHECK(func1->CreationContext() == context1);
19992     CheckContextId(func1, 1);
19993     CHECK(instance1->CreationContext() == context1);
19994     CheckContextId(instance1, 1);
19995     CHECK(object2->CreationContext() == context2);
19996     CheckContextId(object2, 2);
19997     CHECK(func2->CreationContext() == context2);
19998     CheckContextId(func2, 2);
19999     CHECK(instance2->CreationContext() == context2);
20000     CheckContextId(instance2, 2);
20001   }
20002 }
20003
20004
20005 THREADED_TEST(CreationContextOfJsFunction) {
20006   HandleScope handle_scope(CcTest::isolate());
20007   Handle<Context> context = Context::New(CcTest::isolate());
20008   InstallContextId(context, 1);
20009
20010   Local<Object> function;
20011   {
20012     Context::Scope scope(context);
20013     function = CompileRun("function foo() {}; foo").As<Object>();
20014   }
20015
20016   CHECK(function->CreationContext() == context);
20017   CheckContextId(function, 1);
20018 }
20019
20020
20021 void HasOwnPropertyIndexedPropertyGetter(
20022     uint32_t index,
20023     const v8::PropertyCallbackInfo<v8::Value>& info) {
20024   if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20025 }
20026
20027
20028 void HasOwnPropertyNamedPropertyGetter(
20029     Local<String> property,
20030     const v8::PropertyCallbackInfo<v8::Value>& info) {
20031   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20032 }
20033
20034
20035 void HasOwnPropertyIndexedPropertyQuery(
20036     uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20037   if (index == 42) info.GetReturnValue().Set(1);
20038 }
20039
20040
20041 void HasOwnPropertyNamedPropertyQuery(
20042     Local<String> property,
20043     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20044   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20045 }
20046
20047
20048 void HasOwnPropertyNamedPropertyQuery2(
20049     Local<String> property,
20050     const v8::PropertyCallbackInfo<v8::Integer>& info) {
20051   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20052 }
20053
20054
20055 void HasOwnPropertyAccessorGetter(
20056     Local<String> property,
20057     const v8::PropertyCallbackInfo<v8::Value>& info) {
20058   info.GetReturnValue().Set(v8_str("yes"));
20059 }
20060
20061
20062 TEST(HasOwnProperty) {
20063   LocalContext env;
20064   v8::Isolate* isolate = env->GetIsolate();
20065   v8::HandleScope scope(isolate);
20066   { // Check normal properties and defined getters.
20067     Handle<Value> value = CompileRun(
20068         "function Foo() {"
20069         "    this.foo = 11;"
20070         "    this.__defineGetter__('baz', function() { return 1; });"
20071         "};"
20072         "function Bar() { "
20073         "    this.bar = 13;"
20074         "    this.__defineGetter__('bla', function() { return 2; });"
20075         "};"
20076         "Bar.prototype = new Foo();"
20077         "new Bar();");
20078     CHECK(value->IsObject());
20079     Handle<Object> object = value->ToObject();
20080     CHECK(object->Has(v8_str("foo")));
20081     CHECK(!object->HasOwnProperty(v8_str("foo")));
20082     CHECK(object->HasOwnProperty(v8_str("bar")));
20083     CHECK(object->Has(v8_str("baz")));
20084     CHECK(!object->HasOwnProperty(v8_str("baz")));
20085     CHECK(object->HasOwnProperty(v8_str("bla")));
20086   }
20087   { // Check named getter interceptors.
20088     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20089     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20090     Handle<Object> instance = templ->NewInstance();
20091     CHECK(!instance->HasOwnProperty(v8_str("42")));
20092     CHECK(instance->HasOwnProperty(v8_str("foo")));
20093     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20094   }
20095   { // Check indexed getter interceptors.
20096     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20097     templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20098     Handle<Object> instance = templ->NewInstance();
20099     CHECK(instance->HasOwnProperty(v8_str("42")));
20100     CHECK(!instance->HasOwnProperty(v8_str("43")));
20101     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20102   }
20103   { // Check named query interceptors.
20104     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20105     templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
20106     Handle<Object> instance = templ->NewInstance();
20107     CHECK(instance->HasOwnProperty(v8_str("foo")));
20108     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20109   }
20110   { // Check indexed query interceptors.
20111     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20112     templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
20113     Handle<Object> instance = templ->NewInstance();
20114     CHECK(instance->HasOwnProperty(v8_str("42")));
20115     CHECK(!instance->HasOwnProperty(v8_str("41")));
20116   }
20117   { // Check callbacks.
20118     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20119     templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
20120     Handle<Object> instance = templ->NewInstance();
20121     CHECK(instance->HasOwnProperty(v8_str("foo")));
20122     CHECK(!instance->HasOwnProperty(v8_str("bar")));
20123   }
20124   { // Check that query wins on disagreement.
20125     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20126     templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
20127                                    0,
20128                                    HasOwnPropertyNamedPropertyQuery2);
20129     Handle<Object> instance = templ->NewInstance();
20130     CHECK(!instance->HasOwnProperty(v8_str("foo")));
20131     CHECK(instance->HasOwnProperty(v8_str("bar")));
20132   }
20133 }
20134
20135
20136 TEST(IndexedInterceptorWithStringProto) {
20137   v8::Isolate* isolate = CcTest::isolate();
20138   v8::HandleScope scope(isolate);
20139   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20140   templ->SetIndexedPropertyHandler(NULL,
20141                                    NULL,
20142                                    HasOwnPropertyIndexedPropertyQuery);
20143   LocalContext context;
20144   context->Global()->Set(v8_str("obj"), templ->NewInstance());
20145   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
20146   // These should be intercepted.
20147   CHECK(CompileRun("42 in obj")->BooleanValue());
20148   CHECK(CompileRun("'42' in obj")->BooleanValue());
20149   // These should fall through to the String prototype.
20150   CHECK(CompileRun("0 in obj")->BooleanValue());
20151   CHECK(CompileRun("'0' in obj")->BooleanValue());
20152   // And these should both fail.
20153   CHECK(!CompileRun("32 in obj")->BooleanValue());
20154   CHECK(!CompileRun("'32' in obj")->BooleanValue());
20155 }
20156
20157
20158 void CheckCodeGenerationAllowed() {
20159   Handle<Value> result = CompileRun("eval('42')");
20160   CHECK_EQ(42, result->Int32Value());
20161   result = CompileRun("(function(e) { return e('42'); })(eval)");
20162   CHECK_EQ(42, result->Int32Value());
20163   result = CompileRun("var f = new Function('return 42'); f()");
20164   CHECK_EQ(42, result->Int32Value());
20165 }
20166
20167
20168 void CheckCodeGenerationDisallowed() {
20169   TryCatch try_catch;
20170
20171   Handle<Value> result = CompileRun("eval('42')");
20172   CHECK(result.IsEmpty());
20173   CHECK(try_catch.HasCaught());
20174   try_catch.Reset();
20175
20176   result = CompileRun("(function(e) { return e('42'); })(eval)");
20177   CHECK(result.IsEmpty());
20178   CHECK(try_catch.HasCaught());
20179   try_catch.Reset();
20180
20181   result = CompileRun("var f = new Function('return 42'); f()");
20182   CHECK(result.IsEmpty());
20183   CHECK(try_catch.HasCaught());
20184 }
20185
20186
20187 bool CodeGenerationAllowed(Local<Context> context) {
20188   ApiTestFuzzer::Fuzz();
20189   return true;
20190 }
20191
20192
20193 bool CodeGenerationDisallowed(Local<Context> context) {
20194   ApiTestFuzzer::Fuzz();
20195   return false;
20196 }
20197
20198
20199 THREADED_TEST(AllowCodeGenFromStrings) {
20200   LocalContext context;
20201   v8::HandleScope scope(context->GetIsolate());
20202
20203   // eval and the Function constructor allowed by default.
20204   CHECK(context->IsCodeGenerationFromStringsAllowed());
20205   CheckCodeGenerationAllowed();
20206
20207   // Disallow eval and the Function constructor.
20208   context->AllowCodeGenerationFromStrings(false);
20209   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20210   CheckCodeGenerationDisallowed();
20211
20212   // Allow again.
20213   context->AllowCodeGenerationFromStrings(true);
20214   CheckCodeGenerationAllowed();
20215
20216   // Disallow but setting a global callback that will allow the calls.
20217   context->AllowCodeGenerationFromStrings(false);
20218   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
20219   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20220   CheckCodeGenerationAllowed();
20221
20222   // Set a callback that disallows the code generation.
20223   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20224   CHECK(!context->IsCodeGenerationFromStringsAllowed());
20225   CheckCodeGenerationDisallowed();
20226 }
20227
20228
20229 TEST(SetErrorMessageForCodeGenFromStrings) {
20230   LocalContext context;
20231   v8::HandleScope scope(context->GetIsolate());
20232   TryCatch try_catch;
20233
20234   Handle<String> message = v8_str("Message") ;
20235   Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
20236   V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
20237   context->AllowCodeGenerationFromStrings(false);
20238   context->SetErrorMessageForCodeGenerationFromStrings(message);
20239   Handle<Value> result = CompileRun("eval('42')");
20240   CHECK(result.IsEmpty());
20241   CHECK(try_catch.HasCaught());
20242   Handle<String> actual_message = try_catch.Message()->Get();
20243   CHECK(expected_message->Equals(actual_message));
20244 }
20245
20246
20247 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
20248 }
20249
20250
20251 THREADED_TEST(CallAPIFunctionOnNonObject) {
20252   LocalContext context;
20253   v8::Isolate* isolate = context->GetIsolate();
20254   v8::HandleScope scope(isolate);
20255   Handle<FunctionTemplate> templ =
20256       v8::FunctionTemplate::New(isolate, NonObjectThis);
20257   Handle<Function> function = templ->GetFunction();
20258   context->Global()->Set(v8_str("f"), function);
20259   TryCatch try_catch;
20260   CompileRun("f.call(2)");
20261 }
20262
20263
20264 // Regression test for issue 1470.
20265 THREADED_TEST(ReadOnlyIndexedProperties) {
20266   v8::Isolate* isolate = CcTest::isolate();
20267   v8::HandleScope scope(isolate);
20268   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20269
20270   LocalContext context;
20271   Local<v8::Object> obj = templ->NewInstance();
20272   context->Global()->Set(v8_str("obj"), obj);
20273   obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20274   obj->Set(v8_str("1"), v8_str("foobar"));
20275   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
20276   obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
20277   obj->Set(v8_num(2), v8_str("foobar"));
20278   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
20279
20280   // Test non-smi case.
20281   obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
20282   obj->Set(v8_str("2000000000"), v8_str("foobar"));
20283   CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
20284 }
20285
20286
20287 THREADED_TEST(Regress1516) {
20288   LocalContext context;
20289   v8::HandleScope scope(context->GetIsolate());
20290
20291   { v8::HandleScope temp_scope(context->GetIsolate());
20292     CompileRun("({'a': 0})");
20293   }
20294
20295   int elements;
20296   { i::MapCache* map_cache =
20297         i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
20298     elements = map_cache->NumberOfElements();
20299     CHECK_LE(1, elements);
20300   }
20301
20302   CcTest::heap()->CollectAllGarbage(
20303       i::Heap::kAbortIncrementalMarkingMask);
20304   { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
20305     if (raw_map_cache != CcTest::heap()->undefined_value()) {
20306       i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
20307       CHECK_GT(elements, map_cache->NumberOfElements());
20308     }
20309   }
20310 }
20311
20312
20313 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
20314                                                 Local<Value> name,
20315                                                 v8::AccessType type,
20316                                                 Local<Value> data) {
20317   // Only block read access to __proto__.
20318   if (type == v8::ACCESS_GET &&
20319       name->IsString() &&
20320       name->ToString()->Length() == 9 &&
20321       name->ToString()->Utf8Length() == 9) {
20322     char buffer[10];
20323     CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
20324     return strncmp(buffer, "__proto__", 9) != 0;
20325   }
20326
20327   return true;
20328 }
20329
20330
20331 THREADED_TEST(Regress93759) {
20332   v8::Isolate* isolate = CcTest::isolate();
20333   HandleScope scope(isolate);
20334
20335   // Template for object with security check.
20336   Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
20337   // We don't do indexing, so any callback can be used for that.
20338   no_proto_template->SetAccessCheckCallbacks(
20339       BlockProtoNamedSecurityTestCallback,
20340       IndexedSecurityTestCallback);
20341
20342   // Templates for objects with hidden prototypes and possibly security check.
20343   Local<FunctionTemplate> hidden_proto_template =
20344       v8::FunctionTemplate::New(isolate);
20345   hidden_proto_template->SetHiddenPrototype(true);
20346
20347   Local<FunctionTemplate> protected_hidden_proto_template =
20348       v8::FunctionTemplate::New(isolate);
20349   protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
20350       BlockProtoNamedSecurityTestCallback,
20351       IndexedSecurityTestCallback);
20352   protected_hidden_proto_template->SetHiddenPrototype(true);
20353
20354   // Context for "foreign" objects used in test.
20355   Local<Context> context = v8::Context::New(isolate);
20356   context->Enter();
20357
20358   // Plain object, no security check.
20359   Local<Object> simple_object = Object::New(isolate);
20360
20361   // Object with explicit security check.
20362   Local<Object> protected_object =
20363       no_proto_template->NewInstance();
20364
20365   // JSGlobalProxy object, always have security check.
20366   Local<Object> proxy_object =
20367       context->Global();
20368
20369   // Global object, the  prototype of proxy_object. No security checks.
20370   Local<Object> global_object =
20371       proxy_object->GetPrototype()->ToObject();
20372
20373   // Hidden prototype without security check.
20374   Local<Object> hidden_prototype =
20375       hidden_proto_template->GetFunction()->NewInstance();
20376   Local<Object> object_with_hidden =
20377     Object::New(isolate);
20378   object_with_hidden->SetPrototype(hidden_prototype);
20379
20380   // Hidden prototype with security check on the hidden prototype.
20381   Local<Object> protected_hidden_prototype =
20382       protected_hidden_proto_template->GetFunction()->NewInstance();
20383   Local<Object> object_with_protected_hidden =
20384     Object::New(isolate);
20385   object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
20386
20387   context->Exit();
20388
20389   // Template for object for second context. Values to test are put on it as
20390   // properties.
20391   Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
20392   global_template->Set(v8_str("simple"), simple_object);
20393   global_template->Set(v8_str("protected"), protected_object);
20394   global_template->Set(v8_str("global"), global_object);
20395   global_template->Set(v8_str("proxy"), proxy_object);
20396   global_template->Set(v8_str("hidden"), object_with_hidden);
20397   global_template->Set(v8_str("phidden"), object_with_protected_hidden);
20398
20399   LocalContext context2(NULL, global_template);
20400
20401   Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
20402   CHECK(result1->Equals(simple_object->GetPrototype()));
20403
20404   Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
20405   CHECK(result2.IsEmpty());
20406
20407   Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
20408   CHECK(result3->Equals(global_object->GetPrototype()));
20409
20410   Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
20411   CHECK(result4.IsEmpty());
20412
20413   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
20414   CHECK(result5->Equals(
20415       object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
20416
20417   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
20418   CHECK(result6.IsEmpty());
20419 }
20420
20421
20422 THREADED_TEST(Regress125988) {
20423   v8::HandleScope scope(CcTest::isolate());
20424   Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
20425   AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
20426   LocalContext env;
20427   env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
20428   CompileRun("var a = new Object();"
20429              "var b = new Intercept();"
20430              "var c = new Object();"
20431              "c.__proto__ = b;"
20432              "b.__proto__ = a;"
20433              "a.x = 23;"
20434              "for (var i = 0; i < 3; i++) c.x;");
20435   ExpectBoolean("c.hasOwnProperty('x')", false);
20436   ExpectInt32("c.x", 23);
20437   CompileRun("a.y = 42;"
20438              "for (var i = 0; i < 3; i++) c.x;");
20439   ExpectBoolean("c.hasOwnProperty('x')", false);
20440   ExpectInt32("c.x", 23);
20441   ExpectBoolean("c.hasOwnProperty('y')", false);
20442   ExpectInt32("c.y", 42);
20443 }
20444
20445
20446 static void TestReceiver(Local<Value> expected_result,
20447                          Local<Value> expected_receiver,
20448                          const char* code) {
20449   Local<Value> result = CompileRun(code);
20450   CHECK(result->IsObject());
20451   CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
20452   CHECK(expected_result->Equals(result->ToObject()->Get(0)));
20453 }
20454
20455
20456 THREADED_TEST(ForeignFunctionReceiver) {
20457   v8::Isolate* isolate = CcTest::isolate();
20458   HandleScope scope(isolate);
20459
20460   // Create two contexts with different "id" properties ('i' and 'o').
20461   // Call a function both from its own context and from a the foreign
20462   // context, and see what "this" is bound to (returning both "this"
20463   // and "this.id" for comparison).
20464
20465   Local<Context> foreign_context = v8::Context::New(isolate);
20466   foreign_context->Enter();
20467   Local<Value> foreign_function =
20468     CompileRun("function func() { return { 0: this.id, "
20469                "                           1: this, "
20470                "                           toString: function() { "
20471                "                               return this[0];"
20472                "                           }"
20473                "                         };"
20474                "}"
20475                "var id = 'i';"
20476                "func;");
20477   CHECK(foreign_function->IsFunction());
20478   foreign_context->Exit();
20479
20480   LocalContext context;
20481
20482   Local<String> password = v8_str("Password");
20483   // Don't get hit by security checks when accessing foreign_context's
20484   // global receiver (aka. global proxy).
20485   context->SetSecurityToken(password);
20486   foreign_context->SetSecurityToken(password);
20487
20488   Local<String> i = v8_str("i");
20489   Local<String> o = v8_str("o");
20490   Local<String> id = v8_str("id");
20491
20492   CompileRun("function ownfunc() { return { 0: this.id, "
20493              "                              1: this, "
20494              "                              toString: function() { "
20495              "                                  return this[0];"
20496              "                              }"
20497              "                             };"
20498              "}"
20499              "var id = 'o';"
20500              "ownfunc");
20501   context->Global()->Set(v8_str("func"), foreign_function);
20502
20503   // Sanity check the contexts.
20504   CHECK(i->Equals(foreign_context->Global()->Get(id)));
20505   CHECK(o->Equals(context->Global()->Get(id)));
20506
20507   // Checking local function's receiver.
20508   // Calling function using its call/apply methods.
20509   TestReceiver(o, context->Global(), "ownfunc.call()");
20510   TestReceiver(o, context->Global(), "ownfunc.apply()");
20511   // Making calls through built-in functions.
20512   TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
20513   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
20514   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
20515   CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
20516   // Calling with environment record as base.
20517   TestReceiver(o, context->Global(), "ownfunc()");
20518   // Calling with no base.
20519   TestReceiver(o, context->Global(), "(1,ownfunc)()");
20520
20521   // Checking foreign function return value.
20522   // Calling function using its call/apply methods.
20523   TestReceiver(i, foreign_context->Global(), "func.call()");
20524   TestReceiver(i, foreign_context->Global(), "func.apply()");
20525   // Calling function using another context's call/apply methods.
20526   TestReceiver(i, foreign_context->Global(),
20527                "Function.prototype.call.call(func)");
20528   TestReceiver(i, foreign_context->Global(),
20529                "Function.prototype.call.apply(func)");
20530   TestReceiver(i, foreign_context->Global(),
20531                "Function.prototype.apply.call(func)");
20532   TestReceiver(i, foreign_context->Global(),
20533                "Function.prototype.apply.apply(func)");
20534   // Making calls through built-in functions.
20535   TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
20536   // ToString(func()) is func()[0], i.e., the returned this.id.
20537   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
20538   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
20539   CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
20540
20541   // Calling with environment record as base.
20542   TestReceiver(i, foreign_context->Global(), "func()");
20543   // Calling with no base.
20544   TestReceiver(i, foreign_context->Global(), "(1,func)()");
20545 }
20546
20547
20548 uint8_t callback_fired = 0;
20549
20550
20551 void CallCompletedCallback1() {
20552   v8::base::OS::Print("Firing callback 1.\n");
20553   callback_fired ^= 1;  // Toggle first bit.
20554 }
20555
20556
20557 void CallCompletedCallback2() {
20558   v8::base::OS::Print("Firing callback 2.\n");
20559   callback_fired ^= 2;  // Toggle second bit.
20560 }
20561
20562
20563 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
20564   int32_t level = args[0]->Int32Value();
20565   if (level < 3) {
20566     level++;
20567     v8::base::OS::Print("Entering recursion level %d.\n", level);
20568     char script[64];
20569     i::Vector<char> script_vector(script, sizeof(script));
20570     i::SNPrintF(script_vector, "recursion(%d)", level);
20571     CompileRun(script_vector.start());
20572     v8::base::OS::Print("Leaving recursion level %d.\n", level);
20573     CHECK_EQ(0, callback_fired);
20574   } else {
20575     v8::base::OS::Print("Recursion ends.\n");
20576     CHECK_EQ(0, callback_fired);
20577   }
20578 }
20579
20580
20581 TEST(CallCompletedCallback) {
20582   LocalContext env;
20583   v8::HandleScope scope(env->GetIsolate());
20584   v8::Handle<v8::FunctionTemplate> recursive_runtime =
20585       v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
20586   env->Global()->Set(v8_str("recursion"),
20587                      recursive_runtime->GetFunction());
20588   // Adding the same callback a second time has no effect.
20589   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20590   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
20591   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
20592   v8::base::OS::Print("--- Script (1) ---\n");
20593   Local<Script> script = v8::Script::Compile(
20594       v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
20595   script->Run();
20596   CHECK_EQ(3, callback_fired);
20597
20598   v8::base::OS::Print("\n--- Script (2) ---\n");
20599   callback_fired = 0;
20600   env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
20601   script->Run();
20602   CHECK_EQ(2, callback_fired);
20603
20604   v8::base::OS::Print("\n--- Function ---\n");
20605   callback_fired = 0;
20606   Local<Function> recursive_function =
20607       Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
20608   v8::Handle<Value> args[] = { v8_num(0) };
20609   recursive_function->Call(env->Global(), 1, args);
20610   CHECK_EQ(2, callback_fired);
20611 }
20612
20613
20614 void CallCompletedCallbackNoException() {
20615   v8::HandleScope scope(CcTest::isolate());
20616   CompileRun("1+1;");
20617 }
20618
20619
20620 void CallCompletedCallbackException() {
20621   v8::HandleScope scope(CcTest::isolate());
20622   CompileRun("throw 'second exception';");
20623 }
20624
20625
20626 TEST(CallCompletedCallbackOneException) {
20627   LocalContext env;
20628   v8::HandleScope scope(env->GetIsolate());
20629   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
20630   CompileRun("throw 'exception';");
20631 }
20632
20633
20634 TEST(CallCompletedCallbackTwoExceptions) {
20635   LocalContext env;
20636   v8::HandleScope scope(env->GetIsolate());
20637   env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
20638   CompileRun("throw 'first exception';");
20639 }
20640
20641
20642 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
20643   v8::HandleScope scope(info.GetIsolate());
20644   CompileRun("ext1Calls++;");
20645 }
20646
20647
20648 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
20649   v8::HandleScope scope(info.GetIsolate());
20650   CompileRun("ext2Calls++;");
20651 }
20652
20653
20654 void* g_passed_to_three = NULL;
20655
20656
20657 static void MicrotaskThree(void* data) {
20658   g_passed_to_three = data;
20659 }
20660
20661
20662 TEST(EnqueueMicrotask) {
20663   LocalContext env;
20664   v8::HandleScope scope(env->GetIsolate());
20665   CompileRun(
20666       "var ext1Calls = 0;"
20667       "var ext2Calls = 0;");
20668   CompileRun("1+1;");
20669   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20670   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20671
20672   env->GetIsolate()->EnqueueMicrotask(
20673       Function::New(env->GetIsolate(), MicrotaskOne));
20674   CompileRun("1+1;");
20675   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20676   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20677
20678   env->GetIsolate()->EnqueueMicrotask(
20679       Function::New(env->GetIsolate(), MicrotaskOne));
20680   env->GetIsolate()->EnqueueMicrotask(
20681       Function::New(env->GetIsolate(), MicrotaskTwo));
20682   CompileRun("1+1;");
20683   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20684   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20685
20686   env->GetIsolate()->EnqueueMicrotask(
20687       Function::New(env->GetIsolate(), MicrotaskTwo));
20688   CompileRun("1+1;");
20689   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20690   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20691
20692   CompileRun("1+1;");
20693   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20694   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20695
20696   g_passed_to_three = NULL;
20697   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
20698   CompileRun("1+1;");
20699   CHECK_EQ(NULL, g_passed_to_three);
20700   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20701   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20702
20703   int dummy;
20704   env->GetIsolate()->EnqueueMicrotask(
20705       Function::New(env->GetIsolate(), MicrotaskOne));
20706   env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
20707   env->GetIsolate()->EnqueueMicrotask(
20708       Function::New(env->GetIsolate(), MicrotaskTwo));
20709   CompileRun("1+1;");
20710   CHECK_EQ(&dummy, g_passed_to_three);
20711   CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
20712   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20713   g_passed_to_three = NULL;
20714 }
20715
20716
20717 static void MicrotaskExceptionOne(
20718     const v8::FunctionCallbackInfo<Value>& info) {
20719   v8::HandleScope scope(info.GetIsolate());
20720   CompileRun("exception1Calls++;");
20721   info.GetIsolate()->ThrowException(
20722       v8::Exception::Error(v8_str("first")));
20723 }
20724
20725
20726 static void MicrotaskExceptionTwo(
20727     const v8::FunctionCallbackInfo<Value>& info) {
20728   v8::HandleScope scope(info.GetIsolate());
20729   CompileRun("exception2Calls++;");
20730   info.GetIsolate()->ThrowException(
20731       v8::Exception::Error(v8_str("second")));
20732 }
20733
20734
20735 TEST(RunMicrotasksIgnoresThrownExceptions) {
20736   LocalContext env;
20737   v8::Isolate* isolate = env->GetIsolate();
20738   v8::HandleScope scope(isolate);
20739   CompileRun(
20740       "var exception1Calls = 0;"
20741       "var exception2Calls = 0;");
20742   isolate->EnqueueMicrotask(
20743       Function::New(isolate, MicrotaskExceptionOne));
20744   isolate->EnqueueMicrotask(
20745       Function::New(isolate, MicrotaskExceptionTwo));
20746   TryCatch try_catch;
20747   CompileRun("1+1;");
20748   CHECK(!try_catch.HasCaught());
20749   CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
20750   CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
20751 }
20752
20753
20754 TEST(SetAutorunMicrotasks) {
20755   LocalContext env;
20756   v8::HandleScope scope(env->GetIsolate());
20757   CompileRun(
20758       "var ext1Calls = 0;"
20759       "var ext2Calls = 0;");
20760   CompileRun("1+1;");
20761   CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
20762   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20763
20764   env->GetIsolate()->EnqueueMicrotask(
20765       Function::New(env->GetIsolate(), MicrotaskOne));
20766   CompileRun("1+1;");
20767   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20768   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20769
20770   env->GetIsolate()->SetAutorunMicrotasks(false);
20771   env->GetIsolate()->EnqueueMicrotask(
20772       Function::New(env->GetIsolate(), MicrotaskOne));
20773   env->GetIsolate()->EnqueueMicrotask(
20774       Function::New(env->GetIsolate(), MicrotaskTwo));
20775   CompileRun("1+1;");
20776   CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20777   CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
20778
20779   env->GetIsolate()->RunMicrotasks();
20780   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20781   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20782
20783   env->GetIsolate()->EnqueueMicrotask(
20784       Function::New(env->GetIsolate(), MicrotaskTwo));
20785   CompileRun("1+1;");
20786   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20787   CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
20788
20789   env->GetIsolate()->RunMicrotasks();
20790   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20791   CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
20792
20793   env->GetIsolate()->SetAutorunMicrotasks(true);
20794   env->GetIsolate()->EnqueueMicrotask(
20795       Function::New(env->GetIsolate(), MicrotaskTwo));
20796   CompileRun("1+1;");
20797   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20798   CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20799
20800   env->GetIsolate()->EnqueueMicrotask(
20801       Function::New(env->GetIsolate(), MicrotaskTwo));
20802   {
20803     v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
20804     CompileRun("1+1;");
20805     CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20806     CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
20807   }
20808
20809   CompileRun("1+1;");
20810   CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
20811   CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
20812 }
20813
20814
20815 TEST(RunMicrotasksWithoutEnteringContext) {
20816   v8::Isolate* isolate = CcTest::isolate();
20817   HandleScope handle_scope(isolate);
20818   isolate->SetAutorunMicrotasks(false);
20819   Handle<Context> context = Context::New(isolate);
20820   {
20821     Context::Scope context_scope(context);
20822     CompileRun("var ext1Calls = 0;");
20823     isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
20824   }
20825   isolate->RunMicrotasks();
20826   {
20827     Context::Scope context_scope(context);
20828     CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
20829   }
20830   isolate->SetAutorunMicrotasks(true);
20831 }
20832
20833
20834 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
20835   v8::DebugEvent event = event_details.GetEvent();
20836   if (event != v8::Break) return;
20837   Handle<Object> exec_state = event_details.GetExecutionState();
20838   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
20839   CompileRun("function f(id) { new FrameDetails(id, 0); }");
20840   Handle<Function> fun = Handle<Function>::Cast(
20841       CcTest::global()->Get(v8_str("f"))->ToObject());
20842   fun->Call(CcTest::global(), 1, &break_id);
20843 }
20844
20845
20846 TEST(Regress385349) {
20847   i::FLAG_allow_natives_syntax = true;
20848   v8::Isolate* isolate = CcTest::isolate();
20849   HandleScope handle_scope(isolate);
20850   isolate->SetAutorunMicrotasks(false);
20851   Handle<Context> context = Context::New(isolate);
20852   v8::Debug::SetDebugEventListener(DebugEventInObserver);
20853   {
20854     Context::Scope context_scope(context);
20855     CompileRun("var obj = {};"
20856                "Object.observe(obj, function(changes) { debugger; });"
20857                "obj.a = 0;");
20858   }
20859   isolate->RunMicrotasks();
20860   isolate->SetAutorunMicrotasks(true);
20861   v8::Debug::SetDebugEventListener(NULL);
20862 }
20863
20864
20865 #ifdef DEBUG
20866 static int probes_counter = 0;
20867 static int misses_counter = 0;
20868 static int updates_counter = 0;
20869
20870
20871 static int* LookupCounter(const char* name) {
20872   if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
20873     return &probes_counter;
20874   } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
20875     return &misses_counter;
20876   } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
20877     return &updates_counter;
20878   }
20879   return NULL;
20880 }
20881
20882
20883 static const char* kMegamorphicTestProgram =
20884     "function ClassA() { };"
20885     "function ClassB() { };"
20886     "ClassA.prototype.foo = function() { };"
20887     "ClassB.prototype.foo = function() { };"
20888     "function fooify(obj) { obj.foo(); };"
20889     "var a = new ClassA();"
20890     "var b = new ClassB();"
20891     "for (var i = 0; i < 10000; i++) {"
20892     "  fooify(a);"
20893     "  fooify(b);"
20894     "}";
20895 #endif
20896
20897
20898 static void StubCacheHelper(bool primary) {
20899 #ifdef DEBUG
20900   i::FLAG_native_code_counters = true;
20901   if (primary) {
20902     i::FLAG_test_primary_stub_cache = true;
20903   } else {
20904     i::FLAG_test_secondary_stub_cache = true;
20905   }
20906   i::FLAG_crankshaft = false;
20907   LocalContext env;
20908   env->GetIsolate()->SetCounterFunction(LookupCounter);
20909   v8::HandleScope scope(env->GetIsolate());
20910   int initial_probes = probes_counter;
20911   int initial_misses = misses_counter;
20912   int initial_updates = updates_counter;
20913   CompileRun(kMegamorphicTestProgram);
20914   int probes = probes_counter - initial_probes;
20915   int misses = misses_counter - initial_misses;
20916   int updates = updates_counter - initial_updates;
20917   CHECK_LT(updates, 10);
20918   CHECK_LT(misses, 10);
20919   // TODO(verwaest): Update this test to overflow the degree of polymorphism
20920   // before megamorphism. The number of probes will only work once we teach the
20921   // serializer to embed references to counters in the stubs, given that the
20922   // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
20923   CHECK_GE(probes, 0);
20924 #endif
20925 }
20926
20927
20928 TEST(SecondaryStubCache) {
20929   StubCacheHelper(true);
20930 }
20931
20932
20933 TEST(PrimaryStubCache) {
20934   StubCacheHelper(false);
20935 }
20936
20937
20938 #ifdef DEBUG
20939 static int cow_arrays_created_runtime = 0;
20940
20941
20942 static int* LookupCounterCOWArrays(const char* name) {
20943   if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
20944     return &cow_arrays_created_runtime;
20945   }
20946   return NULL;
20947 }
20948 #endif
20949
20950
20951 TEST(CheckCOWArraysCreatedRuntimeCounter) {
20952 #ifdef DEBUG
20953   i::FLAG_native_code_counters = true;
20954   LocalContext env;
20955   env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
20956   v8::HandleScope scope(env->GetIsolate());
20957   int initial_cow_arrays = cow_arrays_created_runtime;
20958   CompileRun("var o = [1, 2, 3];");
20959   CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
20960   CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
20961   CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
20962   CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
20963   CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
20964 #endif
20965 }
20966
20967
20968 TEST(StaticGetters) {
20969   LocalContext context;
20970   i::Factory* factory = CcTest::i_isolate()->factory();
20971   v8::Isolate* isolate = CcTest::isolate();
20972   v8::HandleScope scope(isolate);
20973   i::Handle<i::Object> undefined_value = factory->undefined_value();
20974   CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
20975   i::Handle<i::Object> null_value = factory->null_value();
20976   CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
20977   i::Handle<i::Object> true_value = factory->true_value();
20978   CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
20979   i::Handle<i::Object> false_value = factory->false_value();
20980   CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
20981 }
20982
20983
20984 UNINITIALIZED_TEST(IsolateEmbedderData) {
20985   CcTest::DisableAutomaticDispose();
20986   v8::Isolate* isolate = v8::Isolate::New();
20987   isolate->Enter();
20988   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20989   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20990     CHECK_EQ(NULL, isolate->GetData(slot));
20991     CHECK_EQ(NULL, i_isolate->GetData(slot));
20992   }
20993   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20994     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20995     isolate->SetData(slot, data);
20996   }
20997   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
20998     void* data = reinterpret_cast<void*>(0xacce55ed + slot);
20999     CHECK_EQ(data, isolate->GetData(slot));
21000     CHECK_EQ(data, i_isolate->GetData(slot));
21001   }
21002   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21003     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21004     isolate->SetData(slot, data);
21005   }
21006   for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21007     void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21008     CHECK_EQ(data, isolate->GetData(slot));
21009     CHECK_EQ(data, i_isolate->GetData(slot));
21010   }
21011   isolate->Exit();
21012   isolate->Dispose();
21013 }
21014
21015
21016 TEST(StringEmpty) {
21017   LocalContext context;
21018   i::Factory* factory = CcTest::i_isolate()->factory();
21019   v8::Isolate* isolate = CcTest::isolate();
21020   v8::HandleScope scope(isolate);
21021   i::Handle<i::Object> empty_string = factory->empty_string();
21022   CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21023 }
21024
21025
21026 static int instance_checked_getter_count = 0;
21027 static void InstanceCheckedGetter(
21028     Local<String> name,
21029     const v8::PropertyCallbackInfo<v8::Value>& info) {
21030   CHECK_EQ(name, v8_str("foo"));
21031   instance_checked_getter_count++;
21032   info.GetReturnValue().Set(v8_num(11));
21033 }
21034
21035
21036 static int instance_checked_setter_count = 0;
21037 static void InstanceCheckedSetter(Local<String> name,
21038                       Local<Value> value,
21039                       const v8::PropertyCallbackInfo<void>& info) {
21040   CHECK_EQ(name, v8_str("foo"));
21041   CHECK_EQ(value, v8_num(23));
21042   instance_checked_setter_count++;
21043 }
21044
21045
21046 static void CheckInstanceCheckedResult(int getters, int setters,
21047                                        bool expects_callbacks,
21048                                        TryCatch* try_catch) {
21049   if (expects_callbacks) {
21050     CHECK(!try_catch->HasCaught());
21051     CHECK_EQ(getters, instance_checked_getter_count);
21052     CHECK_EQ(setters, instance_checked_setter_count);
21053   } else {
21054     CHECK(try_catch->HasCaught());
21055     CHECK_EQ(0, instance_checked_getter_count);
21056     CHECK_EQ(0, instance_checked_setter_count);
21057   }
21058   try_catch->Reset();
21059 }
21060
21061
21062 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21063   instance_checked_getter_count = 0;
21064   instance_checked_setter_count = 0;
21065   TryCatch try_catch;
21066
21067   // Test path through generic runtime code.
21068   CompileRun("obj.foo");
21069   CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21070   CompileRun("obj.foo = 23");
21071   CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21072
21073   // Test path through generated LoadIC and StoredIC.
21074   CompileRun("function test_get(o) { o.foo; }"
21075              "test_get(obj);");
21076   CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21077   CompileRun("test_get(obj);");
21078   CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21079   CompileRun("test_get(obj);");
21080   CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21081   CompileRun("function test_set(o) { o.foo = 23; }"
21082              "test_set(obj);");
21083   CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21084   CompileRun("test_set(obj);");
21085   CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21086   CompileRun("test_set(obj);");
21087   CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21088
21089   // Test path through optimized code.
21090   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21091              "test_get(obj);");
21092   CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21093   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21094              "test_set(obj);");
21095   CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21096
21097   // Cleanup so that closures start out fresh in next check.
21098   CompileRun("%DeoptimizeFunction(test_get);"
21099              "%ClearFunctionTypeFeedback(test_get);"
21100              "%DeoptimizeFunction(test_set);"
21101              "%ClearFunctionTypeFeedback(test_set);");
21102 }
21103
21104
21105 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
21106   v8::internal::FLAG_allow_natives_syntax = true;
21107   LocalContext context;
21108   v8::HandleScope scope(context->GetIsolate());
21109
21110   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21111   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21112   inst->SetAccessor(v8_str("foo"),
21113                     InstanceCheckedGetter, InstanceCheckedSetter,
21114                     Handle<Value>(),
21115                     v8::DEFAULT,
21116                     v8::None,
21117                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21118   context->Global()->Set(v8_str("f"), templ->GetFunction());
21119
21120   printf("Testing positive ...\n");
21121   CompileRun("var obj = new f();");
21122   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21123   CheckInstanceCheckedAccessors(true);
21124
21125   printf("Testing negative ...\n");
21126   CompileRun("var obj = {};"
21127              "obj.__proto__ = new f();");
21128   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21129   CheckInstanceCheckedAccessors(false);
21130 }
21131
21132
21133 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
21134   v8::internal::FLAG_allow_natives_syntax = true;
21135   LocalContext context;
21136   v8::HandleScope scope(context->GetIsolate());
21137
21138   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21139   Local<ObjectTemplate> inst = templ->InstanceTemplate();
21140   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21141   inst->SetAccessor(v8_str("foo"),
21142                     InstanceCheckedGetter, InstanceCheckedSetter,
21143                     Handle<Value>(),
21144                     v8::DEFAULT,
21145                     v8::None,
21146                     v8::AccessorSignature::New(context->GetIsolate(), templ));
21147   context->Global()->Set(v8_str("f"), templ->GetFunction());
21148
21149   printf("Testing positive ...\n");
21150   CompileRun("var obj = new f();");
21151   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21152   CheckInstanceCheckedAccessors(true);
21153
21154   printf("Testing negative ...\n");
21155   CompileRun("var obj = {};"
21156              "obj.__proto__ = new f();");
21157   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21158   CheckInstanceCheckedAccessors(false);
21159 }
21160
21161
21162 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
21163   v8::internal::FLAG_allow_natives_syntax = true;
21164   LocalContext context;
21165   v8::HandleScope scope(context->GetIsolate());
21166
21167   Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21168   Local<ObjectTemplate> proto = templ->PrototypeTemplate();
21169   proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
21170                      InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
21171                      v8::None,
21172                      v8::AccessorSignature::New(context->GetIsolate(), templ));
21173   context->Global()->Set(v8_str("f"), templ->GetFunction());
21174
21175   printf("Testing positive ...\n");
21176   CompileRun("var obj = new f();");
21177   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21178   CheckInstanceCheckedAccessors(true);
21179
21180   printf("Testing negative ...\n");
21181   CompileRun("var obj = {};"
21182              "obj.__proto__ = new f();");
21183   CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21184   CheckInstanceCheckedAccessors(false);
21185
21186   printf("Testing positive with modified prototype chain ...\n");
21187   CompileRun("var obj = new f();"
21188              "var pro = {};"
21189              "pro.__proto__ = obj.__proto__;"
21190              "obj.__proto__ = pro;");
21191   CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
21192   CheckInstanceCheckedAccessors(true);
21193 }
21194
21195
21196 TEST(TryFinallyMessage) {
21197   LocalContext context;
21198   v8::HandleScope scope(context->GetIsolate());
21199   {
21200     // Test that the original error message is not lost if there is a
21201     // recursive call into Javascript is done in the finally block, e.g. to
21202     // initialize an IC. (crbug.com/129171)
21203     TryCatch try_catch;
21204     const char* trigger_ic =
21205         "try {                      \n"
21206         "  throw new Error('test'); \n"
21207         "} finally {                \n"
21208         "  var x = 0;               \n"
21209         "  x++;                     \n"  // Trigger an IC initialization here.
21210         "}                          \n";
21211     CompileRun(trigger_ic);
21212     CHECK(try_catch.HasCaught());
21213     Local<Message> message = try_catch.Message();
21214     CHECK(!message.IsEmpty());
21215     CHECK_EQ(2, message->GetLineNumber());
21216   }
21217
21218   {
21219     // Test that the original exception message is indeed overwritten if
21220     // a new error is thrown in the finally block.
21221     TryCatch try_catch;
21222     const char* throw_again =
21223         "try {                       \n"
21224         "  throw new Error('test');  \n"
21225         "} finally {                 \n"
21226         "  var x = 0;                \n"
21227         "  x++;                      \n"
21228         "  throw new Error('again'); \n"  // This is the new uncaught error.
21229         "}                           \n";
21230     CompileRun(throw_again);
21231     CHECK(try_catch.HasCaught());
21232     Local<Message> message = try_catch.Message();
21233     CHECK(!message.IsEmpty());
21234     CHECK_EQ(6, message->GetLineNumber());
21235   }
21236 }
21237
21238
21239 static void Helper137002(bool do_store,
21240                          bool polymorphic,
21241                          bool remove_accessor,
21242                          bool interceptor) {
21243   LocalContext context;
21244   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
21245   if (interceptor) {
21246     templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
21247   } else {
21248     templ->SetAccessor(v8_str("foo"),
21249                        GetterWhichReturns42,
21250                        SetterWhichSetsYOnThisTo23);
21251   }
21252   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21253
21254   // Turn monomorphic on slow object with native accessor, then turn
21255   // polymorphic, finally optimize to create negative lookup and fail.
21256   CompileRun(do_store ?
21257              "function f(x) { x.foo = void 0; }" :
21258              "function f(x) { return x.foo; }");
21259   CompileRun("obj.y = void 0;");
21260   if (!interceptor) {
21261     CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
21262   }
21263   CompileRun("obj.__proto__ = null;"
21264              "f(obj); f(obj); f(obj);");
21265   if (polymorphic) {
21266     CompileRun("f({});");
21267   }
21268   CompileRun("obj.y = void 0;"
21269              "%OptimizeFunctionOnNextCall(f);");
21270   if (remove_accessor) {
21271     CompileRun("delete obj.foo;");
21272   }
21273   CompileRun("var result = f(obj);");
21274   if (do_store) {
21275     CompileRun("result = obj.y;");
21276   }
21277   if (remove_accessor && !interceptor) {
21278     CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
21279   } else {
21280     CHECK_EQ(do_store ? 23 : 42,
21281              context->Global()->Get(v8_str("result"))->Int32Value());
21282   }
21283 }
21284
21285
21286 THREADED_TEST(Regress137002a) {
21287   i::FLAG_allow_natives_syntax = true;
21288   i::FLAG_compilation_cache = false;
21289   v8::HandleScope scope(CcTest::isolate());
21290   for (int i = 0; i < 16; i++) {
21291     Helper137002(i & 8, i & 4, i & 2, i & 1);
21292   }
21293 }
21294
21295
21296 THREADED_TEST(Regress137002b) {
21297   i::FLAG_allow_natives_syntax = true;
21298   LocalContext context;
21299   v8::Isolate* isolate = context->GetIsolate();
21300   v8::HandleScope scope(isolate);
21301   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21302   templ->SetAccessor(v8_str("foo"),
21303                      GetterWhichReturns42,
21304                      SetterWhichSetsYOnThisTo23);
21305   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21306
21307   // Turn monomorphic on slow object with native accessor, then just
21308   // delete the property and fail.
21309   CompileRun("function load(x) { return x.foo; }"
21310              "function store(x) { x.foo = void 0; }"
21311              "function keyed_load(x, key) { return x[key]; }"
21312              // Second version of function has a different source (add void 0)
21313              // so that it does not share code with the first version.  This
21314              // ensures that the ICs are monomorphic.
21315              "function load2(x) { void 0; return x.foo; }"
21316              "function store2(x) { void 0; x.foo = void 0; }"
21317              "function keyed_load2(x, key) { void 0; return x[key]; }"
21318
21319              "obj.y = void 0;"
21320              "obj.__proto__ = null;"
21321              "var subobj = {};"
21322              "subobj.y = void 0;"
21323              "subobj.__proto__ = obj;"
21324              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21325
21326              // Make the ICs monomorphic.
21327              "load(obj); load(obj);"
21328              "load2(subobj); load2(subobj);"
21329              "store(obj); store(obj);"
21330              "store2(subobj); store2(subobj);"
21331              "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
21332              "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
21333
21334              // Actually test the shiny new ICs and better not crash. This
21335              // serves as a regression test for issue 142088 as well.
21336              "load(obj);"
21337              "load2(subobj);"
21338              "store(obj);"
21339              "store2(subobj);"
21340              "keyed_load(obj, 'foo');"
21341              "keyed_load2(subobj, 'foo');"
21342
21343              // Delete the accessor.  It better not be called any more now.
21344              "delete obj.foo;"
21345              "obj.y = void 0;"
21346              "subobj.y = void 0;"
21347
21348              "var load_result = load(obj);"
21349              "var load_result2 = load2(subobj);"
21350              "var keyed_load_result = keyed_load(obj, 'foo');"
21351              "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
21352              "store(obj);"
21353              "store2(subobj);"
21354              "var y_from_obj = obj.y;"
21355              "var y_from_subobj = subobj.y;");
21356   CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
21357   CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
21358   CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
21359   CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
21360   CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
21361   CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
21362 }
21363
21364
21365 THREADED_TEST(Regress142088) {
21366   i::FLAG_allow_natives_syntax = true;
21367   LocalContext context;
21368   v8::Isolate* isolate = context->GetIsolate();
21369   v8::HandleScope scope(isolate);
21370   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21371   templ->SetAccessor(v8_str("foo"),
21372                      GetterWhichReturns42,
21373                      SetterWhichSetsYOnThisTo23);
21374   context->Global()->Set(v8_str("obj"), templ->NewInstance());
21375
21376   CompileRun("function load(x) { return x.foo; }"
21377              "var o = Object.create(obj);"
21378              "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
21379              "load(o); load(o); load(o); load(o);");
21380 }
21381
21382
21383 THREADED_TEST(Regress3337) {
21384   LocalContext context;
21385   v8::Isolate* isolate = context->GetIsolate();
21386   v8::HandleScope scope(isolate);
21387   Local<v8::Object> o1 = Object::New(isolate);
21388   Local<v8::Object> o2 = Object::New(isolate);
21389   i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
21390   i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
21391   CHECK(io1->map() == io2->map());
21392   o1->SetIndexedPropertiesToExternalArrayData(
21393       NULL, v8::kExternalUint32Array, 0);
21394   o2->SetIndexedPropertiesToExternalArrayData(
21395       NULL, v8::kExternalUint32Array, 0);
21396   CHECK(io1->map() == io2->map());
21397 }
21398
21399
21400 THREADED_TEST(Regress137496) {
21401   i::FLAG_expose_gc = true;
21402   LocalContext context;
21403   v8::HandleScope scope(context->GetIsolate());
21404
21405   // Compile a try-finally clause where the finally block causes a GC
21406   // while there still is a message pending for external reporting.
21407   TryCatch try_catch;
21408   try_catch.SetVerbose(true);
21409   CompileRun("try { throw new Error(); } finally { gc(); }");
21410   CHECK(try_catch.HasCaught());
21411 }
21412
21413
21414 THREADED_TEST(Regress149912) {
21415   LocalContext context;
21416   v8::HandleScope scope(context->GetIsolate());
21417   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21418   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21419   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21420   CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
21421 }
21422
21423
21424 THREADED_TEST(Regress157124) {
21425   LocalContext context;
21426   v8::Isolate* isolate = context->GetIsolate();
21427   v8::HandleScope scope(isolate);
21428   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21429   Local<Object> obj = templ->NewInstance();
21430   obj->GetIdentityHash();
21431   obj->DeleteHiddenValue(v8_str("Bug"));
21432 }
21433
21434
21435 THREADED_TEST(Regress2535) {
21436   LocalContext context;
21437   v8::HandleScope scope(context->GetIsolate());
21438   Local<Value> set_value = CompileRun("new Set();");
21439   Local<Object> set_object(Local<Object>::Cast(set_value));
21440   CHECK_EQ(0, set_object->InternalFieldCount());
21441   Local<Value> map_value = CompileRun("new Map();");
21442   Local<Object> map_object(Local<Object>::Cast(map_value));
21443   CHECK_EQ(0, map_object->InternalFieldCount());
21444 }
21445
21446
21447 THREADED_TEST(Regress2746) {
21448   LocalContext context;
21449   v8::Isolate* isolate = context->GetIsolate();
21450   v8::HandleScope scope(isolate);
21451   Local<Object> obj = Object::New(isolate);
21452   Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
21453   obj->SetHiddenValue(key, v8::Undefined(isolate));
21454   Local<Value> value = obj->GetHiddenValue(key);
21455   CHECK(!value.IsEmpty());
21456   CHECK(value->IsUndefined());
21457 }
21458
21459
21460 THREADED_TEST(Regress260106) {
21461   LocalContext context;
21462   v8::Isolate* isolate = context->GetIsolate();
21463   v8::HandleScope scope(isolate);
21464   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
21465                                                         DummyCallHandler);
21466   CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
21467   Local<Function> function = templ->GetFunction();
21468   CHECK(!function.IsEmpty());
21469   CHECK(function->IsFunction());
21470 }
21471
21472
21473 THREADED_TEST(JSONParseObject) {
21474   LocalContext context;
21475   HandleScope scope(context->GetIsolate());
21476   Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
21477   Handle<Object> global = context->Global();
21478   global->Set(v8_str("obj"), obj);
21479   ExpectString("JSON.stringify(obj)", "{\"x\":42}");
21480 }
21481
21482
21483 THREADED_TEST(JSONParseNumber) {
21484   LocalContext context;
21485   HandleScope scope(context->GetIsolate());
21486   Local<Value> obj = v8::JSON::Parse(v8_str("42"));
21487   Handle<Object> global = context->Global();
21488   global->Set(v8_str("obj"), obj);
21489   ExpectString("JSON.stringify(obj)", "42");
21490 }
21491
21492
21493 #if V8_OS_POSIX
21494 class ThreadInterruptTest {
21495  public:
21496   ThreadInterruptTest() : sem_(0), sem_value_(0) { }
21497   ~ThreadInterruptTest() {}
21498
21499   void RunTest() {
21500     InterruptThread i_thread(this);
21501     i_thread.Start();
21502
21503     sem_.Wait();
21504     CHECK_EQ(kExpectedValue, sem_value_);
21505   }
21506
21507  private:
21508   static const int kExpectedValue = 1;
21509
21510   class InterruptThread : public v8::base::Thread {
21511    public:
21512     explicit InterruptThread(ThreadInterruptTest* test)
21513         : Thread(Options("InterruptThread")), test_(test) {}
21514
21515     virtual void Run() {
21516       struct sigaction action;
21517
21518       // Ensure that we'll enter waiting condition
21519       v8::base::OS::Sleep(100);
21520
21521       // Setup signal handler
21522       memset(&action, 0, sizeof(action));
21523       action.sa_handler = SignalHandler;
21524       sigaction(SIGCHLD, &action, NULL);
21525
21526       // Send signal
21527       kill(getpid(), SIGCHLD);
21528
21529       // Ensure that if wait has returned because of error
21530       v8::base::OS::Sleep(100);
21531
21532       // Set value and signal semaphore
21533       test_->sem_value_ = 1;
21534       test_->sem_.Signal();
21535     }
21536
21537     static void SignalHandler(int signal) {
21538     }
21539
21540    private:
21541      ThreadInterruptTest* test_;
21542   };
21543
21544   v8::base::Semaphore sem_;
21545   volatile int sem_value_;
21546 };
21547
21548
21549 THREADED_TEST(SemaphoreInterruption) {
21550   ThreadInterruptTest().RunTest();
21551 }
21552
21553
21554 #endif  // V8_OS_POSIX
21555
21556
21557 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
21558                                      Local<Value> name,
21559                                      v8::AccessType type,
21560                                      Local<Value> data) {
21561   i::PrintF("Named access blocked.\n");
21562   return false;
21563 }
21564
21565
21566 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
21567                                      uint32_t key,
21568                                      v8::AccessType type,
21569                                      Local<Value> data) {
21570   i::PrintF("Indexed access blocked.\n");
21571   return false;
21572 }
21573
21574
21575 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21576   CHECK(false);
21577 }
21578
21579
21580 TEST(JSONStringifyAccessCheck) {
21581   v8::V8::Initialize();
21582   v8::Isolate* isolate = CcTest::isolate();
21583   v8::HandleScope scope(isolate);
21584
21585   // Create an ObjectTemplate for global objects and install access
21586   // check callbacks that will block access.
21587   v8::Handle<v8::ObjectTemplate> global_template =
21588       v8::ObjectTemplate::New(isolate);
21589   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21590                                            IndexAccessAlwaysBlocked);
21591
21592   // Create a context and set an x property on it's global object.
21593   LocalContext context0(NULL, global_template);
21594   v8::Handle<v8::Object> global0 = context0->Global();
21595   global0->Set(v8_str("x"), v8_num(42));
21596   ExpectString("JSON.stringify(this)", "{\"x\":42}");
21597
21598   for (int i = 0; i < 2; i++) {
21599     if (i == 1) {
21600       // Install a toJSON function on the second run.
21601       v8::Handle<v8::FunctionTemplate> toJSON =
21602           v8::FunctionTemplate::New(isolate, UnreachableCallback);
21603
21604       global0->Set(v8_str("toJSON"), toJSON->GetFunction());
21605     }
21606     // Create a context with a different security token so that the
21607     // failed access check callback will be called on each access.
21608     LocalContext context1(NULL, global_template);
21609     context1->Global()->Set(v8_str("other"), global0);
21610
21611     CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
21612     CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
21613     CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
21614
21615     v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
21616     array->Set(0, v8_str("a"));
21617     array->Set(1, v8_str("b"));
21618     context1->Global()->Set(v8_str("array"), array);
21619     ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
21620     array->TurnOnAccessCheck();
21621     CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
21622     CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
21623     CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
21624   }
21625 }
21626
21627
21628 bool access_check_fail_thrown = false;
21629 bool catch_callback_called = false;
21630
21631
21632 // Failed access check callback that performs a GC on each invocation.
21633 void FailedAccessCheckThrows(Local<v8::Object> target,
21634                              v8::AccessType type,
21635                              Local<v8::Value> data) {
21636   access_check_fail_thrown = true;
21637   i::PrintF("Access check failed. Error thrown.\n");
21638   CcTest::isolate()->ThrowException(
21639       v8::Exception::Error(v8_str("cross context")));
21640 }
21641
21642
21643 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21644   for (int i = 0; i < args.Length(); i++) {
21645     i::PrintF("%s\n", *String::Utf8Value(args[i]));
21646   }
21647   catch_callback_called = true;
21648 }
21649
21650
21651 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
21652   args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
21653 }
21654
21655
21656 void CheckCorrectThrow(const char* script) {
21657   // Test that the script, when wrapped into a try-catch, triggers the catch
21658   // clause due to failed access check throwing an exception.
21659   // The subsequent try-catch should run without any exception.
21660   access_check_fail_thrown = false;
21661   catch_callback_called = false;
21662   i::ScopedVector<char> source(1024);
21663   i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
21664   CompileRun(source.start());
21665   CHECK(access_check_fail_thrown);
21666   CHECK(catch_callback_called);
21667
21668   access_check_fail_thrown = false;
21669   catch_callback_called = false;
21670   CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
21671   CHECK(!access_check_fail_thrown);
21672   CHECK(!catch_callback_called);
21673 }
21674
21675
21676 TEST(AccessCheckThrows) {
21677   i::FLAG_allow_natives_syntax = true;
21678   v8::V8::Initialize();
21679   v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
21680   v8::Isolate* isolate = CcTest::isolate();
21681   v8::HandleScope scope(isolate);
21682
21683   // Create an ObjectTemplate for global objects and install access
21684   // check callbacks that will block access.
21685   v8::Handle<v8::ObjectTemplate> global_template =
21686       v8::ObjectTemplate::New(isolate);
21687   global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
21688                                            IndexAccessAlwaysBlocked);
21689
21690   // Create a context and set an x property on it's global object.
21691   LocalContext context0(NULL, global_template);
21692   context0->Global()->Set(v8_str("x"), v8_num(42));
21693   v8::Handle<v8::Object> global0 = context0->Global();
21694
21695   // Create a context with a different security token so that the
21696   // failed access check callback will be called on each access.
21697   LocalContext context1(NULL, global_template);
21698   context1->Global()->Set(v8_str("other"), global0);
21699
21700   v8::Handle<v8::FunctionTemplate> catcher_fun =
21701       v8::FunctionTemplate::New(isolate, CatcherCallback);
21702   context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
21703
21704   v8::Handle<v8::FunctionTemplate> has_own_property_fun =
21705       v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
21706   context1->Global()->Set(v8_str("has_own_property"),
21707                           has_own_property_fun->GetFunction());
21708
21709   { v8::TryCatch try_catch;
21710     access_check_fail_thrown = false;
21711     CompileRun("other.x;");
21712     CHECK(access_check_fail_thrown);
21713     CHECK(try_catch.HasCaught());
21714   }
21715
21716   CheckCorrectThrow("other.x");
21717   CheckCorrectThrow("other[1]");
21718   CheckCorrectThrow("JSON.stringify(other)");
21719   CheckCorrectThrow("has_own_property(other, 'x')");
21720   CheckCorrectThrow("%GetProperty(other, 'x')");
21721   CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
21722   CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
21723   CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
21724   CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
21725   CheckCorrectThrow("%HasOwnProperty(other, 'x')");
21726   CheckCorrectThrow("%HasProperty(other, 'x')");
21727   CheckCorrectThrow("%HasElement(other, 1)");
21728   CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
21729   CheckCorrectThrow("%GetPropertyNames(other)");
21730   // PROPERTY_ATTRIBUTES_NONE = 0
21731   CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
21732   CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
21733                         "other, 'x', null, null, 1)");
21734
21735   // Reset the failed access check callback so it does not influence
21736   // the other tests.
21737   v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
21738 }
21739
21740
21741 THREADED_TEST(Regress256330) {
21742   i::FLAG_allow_natives_syntax = true;
21743   LocalContext context;
21744   v8::HandleScope scope(context->GetIsolate());
21745   Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
21746   AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
21747   context->Global()->Set(v8_str("Bug"), templ->GetFunction());
21748   CompileRun("\"use strict\"; var o = new Bug;"
21749              "function f(o) { o.x = 10; };"
21750              "f(o); f(o); f(o);"
21751              "%OptimizeFunctionOnNextCall(f);"
21752              "f(o);");
21753   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
21754 }
21755
21756
21757 THREADED_TEST(CrankshaftInterceptorSetter) {
21758   i::FLAG_allow_natives_syntax = true;
21759   v8::HandleScope scope(CcTest::isolate());
21760   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21761   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21762   LocalContext env;
21763   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21764   CompileRun("var obj = new Obj;"
21765              // Initialize fields to avoid transitions later.
21766              "obj.age = 0;"
21767              "obj.accessor_age = 42;"
21768              "function setter(i) { this.accessor_age = i; };"
21769              "function getter() { return this.accessor_age; };"
21770              "function setAge(i) { obj.age = i; };"
21771              "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
21772              "setAge(1);"
21773              "setAge(2);"
21774              "setAge(3);"
21775              "%OptimizeFunctionOnNextCall(setAge);"
21776              "setAge(4);");
21777   // All stores went through the interceptor.
21778   ExpectInt32("obj.interceptor_age", 4);
21779   ExpectInt32("obj.accessor_age", 42);
21780 }
21781
21782
21783 THREADED_TEST(CrankshaftInterceptorGetter) {
21784   i::FLAG_allow_natives_syntax = true;
21785   v8::HandleScope scope(CcTest::isolate());
21786   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21787   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21788   LocalContext env;
21789   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21790   CompileRun("var obj = new Obj;"
21791              // Initialize fields to avoid transitions later.
21792              "obj.age = 1;"
21793              "obj.accessor_age = 42;"
21794              "function getter() { return this.accessor_age; };"
21795              "function getAge() { return obj.interceptor_age; };"
21796              "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
21797              "getAge();"
21798              "getAge();"
21799              "getAge();"
21800              "%OptimizeFunctionOnNextCall(getAge);");
21801   // Access through interceptor.
21802   ExpectInt32("getAge()", 1);
21803 }
21804
21805
21806 THREADED_TEST(CrankshaftInterceptorFieldRead) {
21807   i::FLAG_allow_natives_syntax = true;
21808   v8::HandleScope scope(CcTest::isolate());
21809   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21810   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21811   LocalContext env;
21812   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21813   CompileRun("var obj = new Obj;"
21814              "obj.__proto__.interceptor_age = 42;"
21815              "obj.age = 100;"
21816              "function getAge() { return obj.interceptor_age; };");
21817   ExpectInt32("getAge();", 100);
21818   ExpectInt32("getAge();", 100);
21819   ExpectInt32("getAge();", 100);
21820   CompileRun("%OptimizeFunctionOnNextCall(getAge);");
21821   // Access through interceptor.
21822   ExpectInt32("getAge();", 100);
21823 }
21824
21825
21826 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
21827   i::FLAG_allow_natives_syntax = true;
21828   v8::HandleScope scope(CcTest::isolate());
21829   Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
21830   AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
21831   LocalContext env;
21832   env->Global()->Set(v8_str("Obj"), templ->GetFunction());
21833   CompileRun("var obj = new Obj;"
21834              "obj.age = 100000;"
21835              "function setAge(i) { obj.age = i };"
21836              "setAge(100);"
21837              "setAge(101);"
21838              "setAge(102);"
21839              "%OptimizeFunctionOnNextCall(setAge);"
21840              "setAge(103);");
21841   ExpectInt32("obj.age", 100000);
21842   ExpectInt32("obj.interceptor_age", 103);
21843 }
21844
21845
21846 class RequestInterruptTestBase {
21847  public:
21848   RequestInterruptTestBase()
21849       : env_(),
21850         isolate_(env_->GetIsolate()),
21851         sem_(0),
21852         warmup_(20000),
21853         should_continue_(true) {
21854   }
21855
21856   virtual ~RequestInterruptTestBase() { }
21857
21858   virtual void StartInterruptThread() = 0;
21859
21860   virtual void TestBody() = 0;
21861
21862   void RunTest() {
21863     StartInterruptThread();
21864
21865     v8::HandleScope handle_scope(isolate_);
21866
21867     TestBody();
21868
21869     isolate_->ClearInterrupt();
21870
21871     // Verify we arrived here because interruptor was called
21872     // not due to a bug causing us to exit the loop too early.
21873     CHECK(!should_continue());
21874   }
21875
21876   void WakeUpInterruptor() {
21877     sem_.Signal();
21878   }
21879
21880   bool should_continue() const { return should_continue_; }
21881
21882   bool ShouldContinue() {
21883     if (warmup_ > 0) {
21884       if (--warmup_ == 0) {
21885         WakeUpInterruptor();
21886       }
21887     }
21888
21889     return should_continue_;
21890   }
21891
21892   static void ShouldContinueCallback(
21893       const v8::FunctionCallbackInfo<Value>& info) {
21894     RequestInterruptTestBase* test =
21895         reinterpret_cast<RequestInterruptTestBase*>(
21896             info.Data().As<v8::External>()->Value());
21897     info.GetReturnValue().Set(test->ShouldContinue());
21898   }
21899
21900   LocalContext env_;
21901   v8::Isolate* isolate_;
21902   v8::base::Semaphore sem_;
21903   int warmup_;
21904   bool should_continue_;
21905 };
21906
21907
21908 class RequestInterruptTestBaseWithSimpleInterrupt
21909     : public RequestInterruptTestBase {
21910  public:
21911   RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
21912
21913   virtual void StartInterruptThread() {
21914     i_thread.Start();
21915   }
21916
21917  private:
21918   class InterruptThread : public v8::base::Thread {
21919    public:
21920     explicit InterruptThread(RequestInterruptTestBase* test)
21921         : Thread(Options("RequestInterruptTest")), test_(test) {}
21922
21923     virtual void Run() {
21924       test_->sem_.Wait();
21925       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
21926     }
21927
21928     static void OnInterrupt(v8::Isolate* isolate, void* data) {
21929       reinterpret_cast<RequestInterruptTestBase*>(data)->
21930           should_continue_ = false;
21931     }
21932
21933    private:
21934      RequestInterruptTestBase* test_;
21935   };
21936
21937   InterruptThread i_thread;
21938 };
21939
21940
21941 class RequestInterruptTestWithFunctionCall
21942     : public RequestInterruptTestBaseWithSimpleInterrupt {
21943  public:
21944   virtual void TestBody() {
21945     Local<Function> func = Function::New(
21946         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
21947     env_->Global()->Set(v8_str("ShouldContinue"), func);
21948
21949     CompileRun("while (ShouldContinue()) { }");
21950   }
21951 };
21952
21953
21954 class RequestInterruptTestWithMethodCall
21955     : public RequestInterruptTestBaseWithSimpleInterrupt {
21956  public:
21957   virtual void TestBody() {
21958     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21959     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21960     proto->Set(v8_str("shouldContinue"), Function::New(
21961         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21962     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21963
21964     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
21965   }
21966 };
21967
21968
21969 class RequestInterruptTestWithAccessor
21970     : public RequestInterruptTestBaseWithSimpleInterrupt {
21971  public:
21972   virtual void TestBody() {
21973     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21974     v8::Local<v8::Template> proto = t->PrototypeTemplate();
21975     proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
21976         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
21977     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21978
21979     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21980   }
21981 };
21982
21983
21984 class RequestInterruptTestWithNativeAccessor
21985     : public RequestInterruptTestBaseWithSimpleInterrupt {
21986  public:
21987   virtual void TestBody() {
21988     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
21989     t->InstanceTemplate()->SetNativeDataProperty(
21990         v8_str("shouldContinue"),
21991         &ShouldContinueNativeGetter,
21992         NULL,
21993         v8::External::New(isolate_, this));
21994     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
21995
21996     CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
21997   }
21998
21999  private:
22000   static void ShouldContinueNativeGetter(
22001       Local<String> property,
22002       const v8::PropertyCallbackInfo<v8::Value>& info) {
22003     RequestInterruptTestBase* test =
22004         reinterpret_cast<RequestInterruptTestBase*>(
22005             info.Data().As<v8::External>()->Value());
22006     info.GetReturnValue().Set(test->ShouldContinue());
22007   }
22008 };
22009
22010
22011 class RequestInterruptTestWithMethodCallAndInterceptor
22012     : public RequestInterruptTestBaseWithSimpleInterrupt {
22013  public:
22014   virtual void TestBody() {
22015     v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22016     v8::Local<v8::Template> proto = t->PrototypeTemplate();
22017     proto->Set(v8_str("shouldContinue"), Function::New(
22018         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22019     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22020     instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22021
22022     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22023
22024     CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22025   }
22026
22027  private:
22028   static void EmptyInterceptor(
22029       Local<String> property,
22030       const v8::PropertyCallbackInfo<v8::Value>& info) {
22031   }
22032 };
22033
22034
22035 class RequestInterruptTestWithMathAbs
22036     : public RequestInterruptTestBaseWithSimpleInterrupt {
22037  public:
22038   virtual void TestBody() {
22039     env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22040         isolate_,
22041         WakeUpInterruptorCallback,
22042         v8::External::New(isolate_, this)));
22043
22044     env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22045         isolate_,
22046         ShouldContinueCallback,
22047         v8::External::New(isolate_, this)));
22048
22049     i::FLAG_allow_natives_syntax = true;
22050     CompileRun("function loopish(o) {"
22051                "  var pre = 10;"
22052                "  while (o.abs(1) > 0) {"
22053                "    if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22054                "    if (pre > 0) {"
22055                "      if (--pre === 0) WakeUpInterruptor(o === Math);"
22056                "    }"
22057                "  }"
22058                "}"
22059                "var i = 50;"
22060                "var obj = {abs: function () { return i-- }, x: null};"
22061                "delete obj.x;"
22062                "loopish(obj);"
22063                "%OptimizeFunctionOnNextCall(loopish);"
22064                "loopish(Math);");
22065
22066     i::FLAG_allow_natives_syntax = false;
22067   }
22068
22069  private:
22070   static void WakeUpInterruptorCallback(
22071       const v8::FunctionCallbackInfo<Value>& info) {
22072     if (!info[0]->BooleanValue()) return;
22073
22074     RequestInterruptTestBase* test =
22075         reinterpret_cast<RequestInterruptTestBase*>(
22076             info.Data().As<v8::External>()->Value());
22077     test->WakeUpInterruptor();
22078   }
22079
22080   static void ShouldContinueCallback(
22081       const v8::FunctionCallbackInfo<Value>& info) {
22082     RequestInterruptTestBase* test =
22083         reinterpret_cast<RequestInterruptTestBase*>(
22084             info.Data().As<v8::External>()->Value());
22085     info.GetReturnValue().Set(test->should_continue());
22086   }
22087 };
22088
22089
22090 TEST(RequestInterruptTestWithFunctionCall) {
22091   RequestInterruptTestWithFunctionCall().RunTest();
22092 }
22093
22094
22095 TEST(RequestInterruptTestWithMethodCall) {
22096   RequestInterruptTestWithMethodCall().RunTest();
22097 }
22098
22099
22100 TEST(RequestInterruptTestWithAccessor) {
22101   RequestInterruptTestWithAccessor().RunTest();
22102 }
22103
22104
22105 TEST(RequestInterruptTestWithNativeAccessor) {
22106   RequestInterruptTestWithNativeAccessor().RunTest();
22107 }
22108
22109
22110 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
22111   RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
22112 }
22113
22114
22115 TEST(RequestInterruptTestWithMathAbs) {
22116   RequestInterruptTestWithMathAbs().RunTest();
22117 }
22118
22119
22120 class ClearInterruptFromAnotherThread
22121     : public RequestInterruptTestBase {
22122  public:
22123   ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
22124
22125   virtual void StartInterruptThread() {
22126     i_thread.Start();
22127   }
22128
22129   virtual void TestBody() {
22130     Local<Function> func = Function::New(
22131         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22132     env_->Global()->Set(v8_str("ShouldContinue"), func);
22133
22134     CompileRun("while (ShouldContinue()) { }");
22135   }
22136
22137  private:
22138   class InterruptThread : public v8::base::Thread {
22139    public:
22140     explicit InterruptThread(ClearInterruptFromAnotherThread* test)
22141         : Thread(Options("RequestInterruptTest")), test_(test) {}
22142
22143     virtual void Run() {
22144       test_->sem_.Wait();
22145       test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22146       test_->sem_.Wait();
22147       test_->isolate_->ClearInterrupt();
22148       test_->sem2_.Signal();
22149     }
22150
22151     static void OnInterrupt(v8::Isolate* isolate, void* data) {
22152       ClearInterruptFromAnotherThread* test =
22153           reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
22154       test->sem_.Signal();
22155       bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
22156       // Crash instead of timeout to make this failure more prominent.
22157       CHECK(success);
22158       test->should_continue_ = false;
22159     }
22160
22161    private:
22162      ClearInterruptFromAnotherThread* test_;
22163   };
22164
22165   InterruptThread i_thread;
22166   v8::base::Semaphore sem2_;
22167 };
22168
22169
22170 TEST(ClearInterruptFromAnotherThread) {
22171   ClearInterruptFromAnotherThread().RunTest();
22172 }
22173
22174
22175 static Local<Value> function_new_expected_env;
22176 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
22177   CHECK_EQ(function_new_expected_env, info.Data());
22178   info.GetReturnValue().Set(17);
22179 }
22180
22181
22182 THREADED_TEST(FunctionNew) {
22183   LocalContext env;
22184   v8::Isolate* isolate = env->GetIsolate();
22185   v8::HandleScope scope(isolate);
22186   Local<Object> data = v8::Object::New(isolate);
22187   function_new_expected_env = data;
22188   Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
22189   env->Global()->Set(v8_str("func"), func);
22190   Local<Value> result = CompileRun("func();");
22191   CHECK_EQ(v8::Integer::New(isolate, 17), result);
22192   // Verify function not cached
22193   int serial_number =
22194       i::Smi::cast(v8::Utils::OpenHandle(*func)
22195           ->shared()->get_api_func_data()->serial_number())->value();
22196   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22197   i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
22198   i::Handle<i::Object> elm =
22199       i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
22200   CHECK(elm->IsUndefined());
22201   // Verify that each Function::New creates a new function instance
22202   Local<Object> data2 = v8::Object::New(isolate);
22203   function_new_expected_env = data2;
22204   Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
22205   CHECK(!func2->IsNull());
22206   CHECK_NE(func, func2);
22207   env->Global()->Set(v8_str("func2"), func2);
22208   Local<Value> result2 = CompileRun("func2();");
22209   CHECK_EQ(v8::Integer::New(isolate, 17), result2);
22210 }
22211
22212
22213 TEST(EscapeableHandleScope) {
22214   HandleScope outer_scope(CcTest::isolate());
22215   LocalContext context;
22216   const int runs = 10;
22217   Local<String> values[runs];
22218   for (int i = 0; i < runs; i++) {
22219     v8::EscapableHandleScope inner_scope(CcTest::isolate());
22220     Local<String> value;
22221     if (i != 0) value = v8_str("escape value");
22222     values[i] = inner_scope.Escape(value);
22223   }
22224   for (int i = 0; i < runs; i++) {
22225     Local<String> expected;
22226     if (i != 0) {
22227       CHECK_EQ(v8_str("escape value"), values[i]);
22228     } else {
22229       CHECK(values[i].IsEmpty());
22230     }
22231   }
22232 }
22233
22234
22235 static void SetterWhichExpectsThisAndHolderToDiffer(
22236     Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
22237   CHECK(info.Holder() != info.This());
22238 }
22239
22240
22241 TEST(Regress239669) {
22242   LocalContext context;
22243   v8::Isolate* isolate = context->GetIsolate();
22244   v8::HandleScope scope(isolate);
22245   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22246   templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
22247   context->Global()->Set(v8_str("P"), templ->NewInstance());
22248   CompileRun(
22249       "function C1() {"
22250       "  this.x = 23;"
22251       "};"
22252       "C1.prototype = P;"
22253       "for (var i = 0; i < 4; i++ ) {"
22254       "  new C1();"
22255       "}");
22256 }
22257
22258
22259 class ApiCallOptimizationChecker {
22260  private:
22261   static Local<Object> data;
22262   static Local<Object> receiver;
22263   static Local<Object> holder;
22264   static Local<Object> callee;
22265   static int count;
22266
22267   static void OptimizationCallback(
22268       const v8::FunctionCallbackInfo<v8::Value>& info) {
22269     CHECK(callee == info.Callee());
22270     CHECK(data == info.Data());
22271     CHECK(receiver == info.This());
22272     if (info.Length() == 1) {
22273       CHECK_EQ(v8_num(1), info[0]);
22274     }
22275     CHECK(holder == info.Holder());
22276     count++;
22277     info.GetReturnValue().Set(v8_str("returned"));
22278   }
22279
22280  public:
22281   enum SignatureType {
22282     kNoSignature,
22283     kSignatureOnReceiver,
22284     kSignatureOnPrototype
22285   };
22286
22287   void RunAll() {
22288     SignatureType signature_types[] =
22289       {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
22290     for (unsigned i = 0; i < ARRAY_SIZE(signature_types); i++) {
22291       SignatureType signature_type = signature_types[i];
22292       for (int j = 0; j < 2; j++) {
22293         bool global = j == 0;
22294         int key = signature_type +
22295             ARRAY_SIZE(signature_types) * (global ? 1 : 0);
22296         Run(signature_type, global, key);
22297       }
22298     }
22299   }
22300
22301   void Run(SignatureType signature_type, bool global, int key) {
22302     v8::Isolate* isolate = CcTest::isolate();
22303     v8::HandleScope scope(isolate);
22304     // Build a template for signature checks.
22305     Local<v8::ObjectTemplate> signature_template;
22306     Local<v8::Signature> signature;
22307     {
22308       Local<v8::FunctionTemplate> parent_template =
22309         FunctionTemplate::New(isolate);
22310       parent_template->SetHiddenPrototype(true);
22311       Local<v8::FunctionTemplate> function_template
22312           = FunctionTemplate::New(isolate);
22313       function_template->Inherit(parent_template);
22314       switch (signature_type) {
22315         case kNoSignature:
22316           break;
22317         case kSignatureOnReceiver:
22318           signature = v8::Signature::New(isolate, function_template);
22319           break;
22320         case kSignatureOnPrototype:
22321           signature = v8::Signature::New(isolate, parent_template);
22322           break;
22323       }
22324       signature_template = function_template->InstanceTemplate();
22325     }
22326     // Global object must pass checks.
22327     Local<v8::Context> context =
22328         v8::Context::New(isolate, NULL, signature_template);
22329     v8::Context::Scope context_scope(context);
22330     // Install regular object that can pass signature checks.
22331     Local<Object> function_receiver = signature_template->NewInstance();
22332     context->Global()->Set(v8_str("function_receiver"), function_receiver);
22333     // Get the holder objects.
22334     Local<Object> inner_global =
22335         Local<Object>::Cast(context->Global()->GetPrototype());
22336     // Install functions on hidden prototype object if there is one.
22337     data = Object::New(isolate);
22338     Local<FunctionTemplate> function_template = FunctionTemplate::New(
22339         isolate, OptimizationCallback, data, signature);
22340     Local<Function> function = function_template->GetFunction();
22341     Local<Object> global_holder = inner_global;
22342     Local<Object> function_holder = function_receiver;
22343     if (signature_type == kSignatureOnPrototype) {
22344       function_holder = Local<Object>::Cast(function_holder->GetPrototype());
22345       global_holder = Local<Object>::Cast(global_holder->GetPrototype());
22346     }
22347     global_holder->Set(v8_str("g_f"), function);
22348     global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
22349     function_holder->Set(v8_str("f"), function);
22350     function_holder->SetAccessorProperty(v8_str("acc"), function, function);
22351     // Initialize expected values.
22352     callee = function;
22353     count = 0;
22354     if (global) {
22355       receiver = context->Global();
22356       holder = inner_global;
22357     } else {
22358       holder = function_receiver;
22359       // If not using a signature, add something else to the prototype chain
22360       // to test the case that holder != receiver
22361       if (signature_type == kNoSignature) {
22362         receiver = Local<Object>::Cast(CompileRun(
22363             "var receiver_subclass = {};\n"
22364             "receiver_subclass.__proto__ = function_receiver;\n"
22365             "receiver_subclass"));
22366       } else {
22367         receiver = Local<Object>::Cast(CompileRun(
22368           "var receiver_subclass = function_receiver;\n"
22369           "receiver_subclass"));
22370       }
22371     }
22372     // With no signature, the holder is not set.
22373     if (signature_type == kNoSignature) holder = receiver;
22374     // build wrap_function
22375     i::ScopedVector<char> wrap_function(200);
22376     if (global) {
22377       i::SNPrintF(
22378           wrap_function,
22379           "function wrap_f_%d() { var f = g_f; return f(); }\n"
22380           "function wrap_get_%d() { return this.g_acc; }\n"
22381           "function wrap_set_%d() { return this.g_acc = 1; }\n",
22382           key, key, key);
22383     } else {
22384       i::SNPrintF(
22385           wrap_function,
22386           "function wrap_f_%d() { return receiver_subclass.f(); }\n"
22387           "function wrap_get_%d() { return receiver_subclass.acc; }\n"
22388           "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
22389           key, key, key);
22390     }
22391     // build source string
22392     i::ScopedVector<char> source(1000);
22393     i::SNPrintF(
22394         source,
22395         "%s\n"  // wrap functions
22396         "function wrap_f() { return wrap_f_%d(); }\n"
22397         "function wrap_get() { return wrap_get_%d(); }\n"
22398         "function wrap_set() { return wrap_set_%d(); }\n"
22399         "check = function(returned) {\n"
22400         "  if (returned !== 'returned') { throw returned; }\n"
22401         "}\n"
22402         "\n"
22403         "check(wrap_f());\n"
22404         "check(wrap_f());\n"
22405         "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
22406         "check(wrap_f());\n"
22407         "\n"
22408         "check(wrap_get());\n"
22409         "check(wrap_get());\n"
22410         "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
22411         "check(wrap_get());\n"
22412         "\n"
22413         "check = function(returned) {\n"
22414         "  if (returned !== 1) { throw returned; }\n"
22415         "}\n"
22416         "check(wrap_set());\n"
22417         "check(wrap_set());\n"
22418         "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
22419         "check(wrap_set());\n",
22420         wrap_function.start(), key, key, key, key, key, key);
22421     v8::TryCatch try_catch;
22422     CompileRun(source.start());
22423     DCHECK(!try_catch.HasCaught());
22424     CHECK_EQ(9, count);
22425   }
22426 };
22427
22428
22429 Local<Object> ApiCallOptimizationChecker::data;
22430 Local<Object> ApiCallOptimizationChecker::receiver;
22431 Local<Object> ApiCallOptimizationChecker::holder;
22432 Local<Object> ApiCallOptimizationChecker::callee;
22433 int ApiCallOptimizationChecker::count = 0;
22434
22435
22436 TEST(TestFunctionCallOptimization) {
22437   i::FLAG_allow_natives_syntax = true;
22438   ApiCallOptimizationChecker checker;
22439   checker.RunAll();
22440 }
22441
22442
22443 static const char* last_event_message;
22444 static int last_event_status;
22445 void StoringEventLoggerCallback(const char* message, int status) {
22446     last_event_message = message;
22447     last_event_status = status;
22448 }
22449
22450
22451 TEST(EventLogging) {
22452   v8::Isolate* isolate = CcTest::isolate();
22453   isolate->SetEventLogger(StoringEventLoggerCallback);
22454   v8::internal::HistogramTimer histogramTimer(
22455       "V8.Test", 0, 10000, 50,
22456       reinterpret_cast<v8::internal::Isolate*>(isolate));
22457   histogramTimer.Start();
22458   CHECK_EQ("V8.Test", last_event_message);
22459   CHECK_EQ(0, last_event_status);
22460   histogramTimer.Stop();
22461   CHECK_EQ("V8.Test", last_event_message);
22462   CHECK_EQ(1, last_event_status);
22463 }
22464
22465
22466 TEST(Promises) {
22467   LocalContext context;
22468   v8::Isolate* isolate = context->GetIsolate();
22469   v8::HandleScope scope(isolate);
22470   Handle<Object> global = context->Global();
22471
22472   // Creation.
22473   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22474   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
22475   Handle<v8::Promise> p = pr->GetPromise();
22476   Handle<v8::Promise> r = rr->GetPromise();
22477
22478   // IsPromise predicate.
22479   CHECK(p->IsPromise());
22480   CHECK(r->IsPromise());
22481   Handle<Value> o = v8::Object::New(isolate);
22482   CHECK(!o->IsPromise());
22483
22484   // Resolution and rejection.
22485   pr->Resolve(v8::Integer::New(isolate, 1));
22486   CHECK(p->IsPromise());
22487   rr->Reject(v8::Integer::New(isolate, 2));
22488   CHECK(r->IsPromise());
22489
22490   // Chaining non-pending promises.
22491   CompileRun(
22492       "var x1 = 0;\n"
22493       "var x2 = 0;\n"
22494       "function f1(x) { x1 = x; return x+1 };\n"
22495       "function f2(x) { x2 = x; return x+1 };\n");
22496   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22497   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22498
22499   p->Chain(f1);
22500   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22501   isolate->RunMicrotasks();
22502   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22503
22504   p->Catch(f2);
22505   isolate->RunMicrotasks();
22506   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22507
22508   r->Catch(f2);
22509   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22510   isolate->RunMicrotasks();
22511   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22512
22513   r->Chain(f1);
22514   isolate->RunMicrotasks();
22515   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22516
22517   // Chaining pending promises.
22518   CompileRun("x1 = x2 = 0;");
22519   pr = v8::Promise::Resolver::New(isolate);
22520   rr = v8::Promise::Resolver::New(isolate);
22521
22522   pr->GetPromise()->Chain(f1);
22523   rr->GetPromise()->Catch(f2);
22524   isolate->RunMicrotasks();
22525   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22526   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22527
22528   pr->Resolve(v8::Integer::New(isolate, 1));
22529   rr->Reject(v8::Integer::New(isolate, 2));
22530   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22531   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22532
22533   isolate->RunMicrotasks();
22534   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22535   CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
22536
22537   // Multi-chaining.
22538   CompileRun("x1 = x2 = 0;");
22539   pr = v8::Promise::Resolver::New(isolate);
22540   pr->GetPromise()->Chain(f1)->Chain(f2);
22541   pr->Resolve(v8::Integer::New(isolate, 3));
22542   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22543   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22544   isolate->RunMicrotasks();
22545   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22546   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22547
22548   CompileRun("x1 = x2 = 0;");
22549   rr = v8::Promise::Resolver::New(isolate);
22550   rr->GetPromise()->Catch(f1)->Chain(f2);
22551   rr->Reject(v8::Integer::New(isolate, 3));
22552   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22553   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22554   isolate->RunMicrotasks();
22555   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22556   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22557 }
22558
22559
22560 TEST(PromiseThen) {
22561   LocalContext context;
22562   v8::Isolate* isolate = context->GetIsolate();
22563   v8::HandleScope scope(isolate);
22564   Handle<Object> global = context->Global();
22565
22566   // Creation.
22567   Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
22568   Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
22569   Handle<v8::Promise> p = pr->GetPromise();
22570   Handle<v8::Promise> q = qr->GetPromise();
22571
22572   CHECK(p->IsPromise());
22573   CHECK(q->IsPromise());
22574
22575   pr->Resolve(v8::Integer::New(isolate, 1));
22576   qr->Resolve(p);
22577
22578   // Chaining non-pending promises.
22579   CompileRun(
22580       "var x1 = 0;\n"
22581       "var x2 = 0;\n"
22582       "function f1(x) { x1 = x; return x+1 };\n"
22583       "function f2(x) { x2 = x; return x+1 };\n");
22584   Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
22585   Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
22586
22587   // Chain
22588   q->Chain(f1);
22589   CHECK(global->Get(v8_str("x1"))->IsNumber());
22590   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22591   isolate->RunMicrotasks();
22592   CHECK(!global->Get(v8_str("x1"))->IsNumber());
22593   CHECK_EQ(p, global->Get(v8_str("x1")));
22594
22595   // Then
22596   CompileRun("x1 = x2 = 0;");
22597   q->Then(f1);
22598   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22599   isolate->RunMicrotasks();
22600   CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
22601
22602   // Then
22603   CompileRun("x1 = x2 = 0;");
22604   pr = v8::Promise::Resolver::New(isolate);
22605   qr = v8::Promise::Resolver::New(isolate);
22606
22607   qr->Resolve(pr);
22608   qr->GetPromise()->Then(f1)->Then(f2);
22609
22610   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22611   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22612   isolate->RunMicrotasks();
22613   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22614   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22615
22616   pr->Resolve(v8::Integer::New(isolate, 3));
22617
22618   CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
22619   CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
22620   isolate->RunMicrotasks();
22621   CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
22622   CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
22623 }
22624
22625
22626 TEST(DisallowJavascriptExecutionScope) {
22627   LocalContext context;
22628   v8::Isolate* isolate = context->GetIsolate();
22629   v8::HandleScope scope(isolate);
22630   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22631       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22632   CompileRun("2+2");
22633 }
22634
22635
22636 TEST(AllowJavascriptExecutionScope) {
22637   LocalContext context;
22638   v8::Isolate* isolate = context->GetIsolate();
22639   v8::HandleScope scope(isolate);
22640   v8::Isolate::DisallowJavascriptExecutionScope no_js(
22641       isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
22642   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22643       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22644   { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
22645     CompileRun("1+1");
22646   }
22647 }
22648
22649
22650 TEST(ThrowOnJavascriptExecution) {
22651   LocalContext context;
22652   v8::Isolate* isolate = context->GetIsolate();
22653   v8::HandleScope scope(isolate);
22654   v8::TryCatch try_catch;
22655   v8::Isolate::DisallowJavascriptExecutionScope throw_js(
22656       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
22657   CompileRun("1+1");
22658   CHECK(try_catch.HasCaught());
22659 }
22660
22661
22662 TEST(Regress354123) {
22663   LocalContext current;
22664   v8::Isolate* isolate = current->GetIsolate();
22665   v8::HandleScope scope(isolate);
22666
22667   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
22668   templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
22669   current->Global()->Set(v8_str("friend"), templ->NewInstance());
22670
22671   // Test access using __proto__ from the prototype chain.
22672   named_access_count = 0;
22673   CompileRun("friend.__proto__ = {};");
22674   CHECK_EQ(2, named_access_count);
22675   CompileRun("friend.__proto__;");
22676   CHECK_EQ(4, named_access_count);
22677
22678   // Test access using __proto__ as a hijacked function (A).
22679   named_access_count = 0;
22680   CompileRun("var p = Object.prototype;"
22681              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
22682              "f.call(friend, {});");
22683   CHECK_EQ(1, named_access_count);
22684   CompileRun("var p = Object.prototype;"
22685              "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
22686              "f.call(friend);");
22687   CHECK_EQ(2, named_access_count);
22688
22689   // Test access using __proto__ as a hijacked function (B).
22690   named_access_count = 0;
22691   CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
22692              "f.call(friend, {});");
22693   CHECK_EQ(1, named_access_count);
22694   CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
22695              "f.call(friend);");
22696   CHECK_EQ(2, named_access_count);
22697
22698   // Test access using Object.setPrototypeOf reflective method.
22699   named_access_count = 0;
22700   CompileRun("Object.setPrototypeOf(friend, {});");
22701   CHECK_EQ(1, named_access_count);
22702   CompileRun("Object.getPrototypeOf(friend);");
22703   CHECK_EQ(2, named_access_count);
22704 }
22705
22706
22707 TEST(CaptureStackTraceForStackOverflow) {
22708   v8::internal::FLAG_stack_size = 150;
22709   LocalContext current;
22710   v8::Isolate* isolate = current->GetIsolate();
22711   v8::HandleScope scope(isolate);
22712   V8::SetCaptureStackTraceForUncaughtExceptions(
22713       true, 10, v8::StackTrace::kDetailed);
22714   v8::TryCatch try_catch;
22715   CompileRun("(function f(x) { f(x+1); })(0)");
22716   CHECK(try_catch.HasCaught());
22717 }
22718
22719
22720 TEST(ScriptNameAndLineNumber) {
22721   LocalContext env;
22722   v8::Isolate* isolate = env->GetIsolate();
22723   v8::HandleScope scope(isolate);
22724   const char* url = "http://www.foo.com/foo.js";
22725   v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
22726   v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
22727   Local<Script> script = v8::ScriptCompiler::Compile(
22728       isolate, &script_source);
22729   Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
22730   CHECK(!script_name.IsEmpty());
22731   CHECK(script_name->IsString());
22732   String::Utf8Value utf8_name(script_name);
22733   CHECK_EQ(url, *utf8_name);
22734   int line_number = script->GetUnboundScript()->GetLineNumber(0);
22735   CHECK_EQ(13, line_number);
22736 }
22737
22738
22739 void SourceURLHelper(const char* source, const char* expected_source_url,
22740                      const char* expected_source_mapping_url) {
22741   Local<Script> script = v8_compile(source);
22742   if (expected_source_url != NULL) {
22743     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
22744     CHECK_EQ(expected_source_url, *url);
22745   } else {
22746     CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
22747   }
22748   if (expected_source_mapping_url != NULL) {
22749     v8::String::Utf8Value url(
22750         script->GetUnboundScript()->GetSourceMappingURL());
22751     CHECK_EQ(expected_source_mapping_url, *url);
22752   } else {
22753     CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
22754   }
22755 }
22756
22757
22758 TEST(ScriptSourceURLAndSourceMappingURL) {
22759   LocalContext env;
22760   v8::Isolate* isolate = env->GetIsolate();
22761   v8::HandleScope scope(isolate);
22762   SourceURLHelper("function foo() {}\n"
22763                   "//# sourceURL=bar1.js\n", "bar1.js", NULL);
22764   SourceURLHelper("function foo() {}\n"
22765                   "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
22766
22767   // Both sourceURL and sourceMappingURL.
22768   SourceURLHelper("function foo() {}\n"
22769                   "//# sourceURL=bar3.js\n"
22770                   "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
22771
22772   // Two source URLs; the first one is ignored.
22773   SourceURLHelper("function foo() {}\n"
22774                   "//# sourceURL=ignoreme.js\n"
22775                   "//# sourceURL=bar5.js\n", "bar5.js", NULL);
22776   SourceURLHelper("function foo() {}\n"
22777                   "//# sourceMappingURL=ignoreme.js\n"
22778                   "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
22779
22780   // SourceURL or sourceMappingURL in the middle of the script.
22781   SourceURLHelper("function foo() {}\n"
22782                   "//# sourceURL=bar7.js\n"
22783                   "function baz() {}\n", "bar7.js", NULL);
22784   SourceURLHelper("function foo() {}\n"
22785                   "//# sourceMappingURL=bar8.js\n"
22786                   "function baz() {}\n", NULL, "bar8.js");
22787
22788   // Too much whitespace.
22789   SourceURLHelper("function foo() {}\n"
22790                   "//#  sourceURL=bar9.js\n"
22791                   "//#  sourceMappingURL=bar10.js\n", NULL, NULL);
22792   SourceURLHelper("function foo() {}\n"
22793                   "//# sourceURL =bar11.js\n"
22794                   "//# sourceMappingURL =bar12.js\n", NULL, NULL);
22795
22796   // Disallowed characters in value.
22797   SourceURLHelper("function foo() {}\n"
22798                   "//# sourceURL=bar13 .js   \n"
22799                   "//# sourceMappingURL=bar14 .js \n",
22800                   NULL, NULL);
22801   SourceURLHelper("function foo() {}\n"
22802                   "//# sourceURL=bar15\t.js   \n"
22803                   "//# sourceMappingURL=bar16\t.js \n",
22804                   NULL, NULL);
22805   SourceURLHelper("function foo() {}\n"
22806                   "//# sourceURL=bar17'.js   \n"
22807                   "//# sourceMappingURL=bar18'.js \n",
22808                   NULL, NULL);
22809   SourceURLHelper("function foo() {}\n"
22810                   "//# sourceURL=bar19\".js   \n"
22811                   "//# sourceMappingURL=bar20\".js \n",
22812                   NULL, NULL);
22813
22814   // Not too much whitespace.
22815   SourceURLHelper("function foo() {}\n"
22816                   "//# sourceURL=  bar21.js   \n"
22817                   "//# sourceMappingURL=  bar22.js \n", "bar21.js", "bar22.js");
22818 }
22819
22820
22821 TEST(GetOwnPropertyDescriptor) {
22822   LocalContext env;
22823   v8::Isolate* isolate = env->GetIsolate();
22824   v8::HandleScope scope(isolate);
22825   CompileRun(
22826     "var x = { value : 13};"
22827     "Object.defineProperty(x, 'p0', {value : 12});"
22828     "Object.defineProperty(x, 'p1', {"
22829     "  set : function(value) { this.value = value; },"
22830     "  get : function() { return this.value; },"
22831     "});");
22832   Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
22833   Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
22834   CHECK(desc->IsUndefined());
22835   desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
22836   CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
22837   desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
22838   Local<Function> set =
22839     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
22840   Local<Function> get =
22841     Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
22842   CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
22843   Handle<Value> args[] = { v8_num(14) };
22844   set->Call(x, 1, args);
22845   CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
22846 }